]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/vmx/pci.c
ndb/dnsquery, ndb/csquery: handle long lines
[plan9front.git] / sys / src / cmd / vmx / pci.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "dat.h"
5 #include "fns.h"
6
7 PCIDev *pcidevs;
8 PCIBar membars, iobars;
9
10 PCIDev *
11 mkpcidev(u32int bdf, u32int viddid, u32int clrev, int needirq)
12 {
13         PCIDev *d;
14         int n;
15         
16         d = emalloc(sizeof(PCIDev));
17         d->bdf = bdf;
18         d->viddid = viddid;
19         d->clrev = clrev;
20         d->next = pcidevs;
21         d->irqno = needirq ? 0 : 0xff;
22         for(n = 0; n < nelem(d->bar); n++){
23                 d->bar[n].d = d;
24                 d->bar[n].busnext = &d->bar[n];
25                 d->bar[n].busprev = &d->bar[n];
26         }
27         d->capalloc = 64;
28         pcidevs = d;
29         return d;
30 }
31
32 u32int
33 allocbdf(void)
34 {
35         static int dev = 1;
36         
37         return BDF(0, dev++, 0);
38 }
39
40 u32int
41 roundpow2(u32int l)
42 {
43         l = -l;
44         l &= (int)l >> 16;
45         l &= (int)l >> 8;
46         l &= (int)l >> 4;
47         l &= (int)l >> 2;
48         l &= (int)l >> 1;
49         return -l;
50 }
51
52 PCIBar *
53 mkpcibar(PCIDev *d, u8int t, u32int a, u32int l, void *fn, void *aux)
54 {
55         PCIBar *b;
56
57         assert((t & 1) == 0 || (t & 2) == 0);
58         assert((t & 1) != 0 || (t & 6) == 0);
59         if((t & 1) != 0 && l < 4) l = 4;
60         if((t & 1) == 0 && l < 4096) l = 4096;
61         if((l & l-1) != 0)
62                 l = roundpow2(l);
63         for(b = d->bar; b < d->bar + nelem(d->bar); b++)
64                 if(b->length == 0)
65                         break;
66         if(b == d->bar + nelem(d->bar))
67                 sysfatal("pci bdf %6ux: too many bars", d->bdf);
68         b->addr = a;
69         b->type = t;
70         b->length = l;
71         b->busnext = b;
72         b->busprev = b;
73         b->d = d;
74         if((b->type & 1) != 0)
75                 b->io = fn;
76         b->aux = aux;
77         return b;
78 }
79
80 static void
81 updatebar(PCIBar *b)
82 {
83         b->busnext->busprev = b->busprev;
84         b->busprev->busnext = b->busnext;
85         b->busnext = b;
86         b->busprev = b;
87         if(b->length == 0) return;
88         if((b->type & 1) == 0){
89                 if((b->d->ctrl & 2) == 0) return;
90                 b->busnext = &membars;
91                 b->busprev = membars.busprev;
92                 b->busnext->busprev = b;
93                 b->busprev->busnext = b;
94         }else{
95                 if((b->d->ctrl & 1) == 0 || b->addr == 0 || b->io == nil) return;
96                 b->busnext = &iobars;
97                 b->busprev = iobars.busprev;
98                 b->busnext->busprev = b;
99                 b->busprev->busnext = b;
100         }
101 }
102
103 static void
104 pciirqupdate(void)
105 {
106         PCIDev *d;
107         int irqs, act, i;
108         
109         irqs = 0;
110         act = 0;
111         for(d = pcidevs; d != nil; d = d->next){
112                 if(d->irqno < 16){
113                         irqs |= 1<<d->irqno;
114                         act |= d->irqactive<<d->irqno;
115                 }
116         }
117         for(i = 0; i < 16; i++)
118                 if((irqs & 1<<i) != 0)
119                         irqline(i, ~act>>i & 1);
120 }
121
122 PCICap *
123 mkpcicap(PCIDev *d, u8int length, u32int (*readf)(PCICap *, u8int), void (*writef)(PCICap *, u8int, u32int, u32int))
124 {
125         PCICap *c, **p;
126
127         assert(readf != nil);
128         if(d->capalloc + length > 256)
129                 sysfatal("mkpcicap (dev %#ux): out of configuration space", d->bdf);
130         c = emalloc(sizeof(PCICap));
131         c->dev = d;
132         c->read = readf;
133         c->write = writef;
134         c->length = length;
135         
136         c->addr = d->capalloc;
137         d->capalloc += length;
138         for(p = &d->cap; *p != nil; p = &(*p)->next)
139                 ;
140         *p = c;
141         return c;
142 }
143
144 static PCIDev *
145 findpcidev(u32int bdf)
146 {
147         PCIDev *d;
148
149         for(d = pcidevs; d != nil; d = d->next)
150                 if(d->bdf == bdf)
151                         return d;
152         return nil;
153 }
154
155 static PCICap *
156 findpcicap(PCIDev *d, u8int addr)
157 {
158         PCICap *c;
159         
160         for(c = d->cap; c != nil; c = c->next)
161                 if((uint)(addr - c->addr) < c->length)
162                         return c;
163         return nil;
164 }
165
166 static u32int
167 pciread(PCIDev *d, int addr)
168 {
169         u32int val;
170         PCICap *c;
171         int n;
172
173         switch(addr){
174         case 0x00: return d->viddid;
175         case 0x04: return 0xa00000 | (d->cap != nil ? 1<<20 : 0) | d->ctrl;
176         case 0x08: return d->clrev;
177         case 0x0c: return 0; /* BIST, Header Type, Latency Timer, Cache Size */
178         case 0x10: case 0x14: case 0x18: case 0x1c: case 0x20: case 0x24:
179                 n = addr - 0x10 >> 2;
180                 return d->bar[n].addr | d->bar[n].type;
181         case 0x28: return 0; /* Cardbus */
182         case 0x2c: return d->subid; /* Subsystem ID */
183         case 0x30: return 0; /* Expansion ROM */
184         case 0x34: return d->cap != nil ? d->cap->addr : 0; /* Capabilities */
185         case 0x38: return 0; /* Reserved */
186         case 0x3c: return 1 << 8 | d->irqno; /* Max_Lat, Min_Gnt, IRQ Pin, IRQ Line */
187         }
188         c = findpcicap(d, addr);
189         if(c != nil){
190                 val = c->read(c, addr - c->addr);
191                 if(addr == c->addr){
192                         val &= ~0xff00;
193                         if(c->next != nil)
194                                 val |= c->next->addr << 8;
195                 }
196                 return val;
197         }
198         vmdebug("pcidev %.6ux: ignoring read from addr %#ux", d->bdf, addr);
199         return 0;
200 }
201
202 static void
203 pciwrite(PCIDev *d, int addr, u32int val, u32int mask)
204 {
205         int n;
206         PCICap *c;
207         
208         switch(addr){
209         case 0x04:
210                 d->ctrl = (d->ctrl & ~mask | val & mask) & 0x21f;
211                 for(n = 0; n < nelem(d->bar); n++)
212                         updatebar(&d->bar[n]);
213                 return;
214         case 0x10: case 0x14: case 0x18: case 0x1c: case 0x20: case 0x24:
215                 n = addr - 0x10 >> 2;
216                 val &= (d->bar[n].type & 1) != 0 ? ~15 : ~3;
217                 d->bar[n].addr = (d->bar[n].addr & ~mask | val & mask) & ~(d->bar[n].length - 1);
218                 updatebar(&d->bar[n]);
219                 return;
220         case 0x30: return;
221         case 0x3c: d->irqno = (d->irqno & ~mask | val & mask) & 0xff; pciirqupdate(); return;
222         }
223         c = findpcicap(d, addr);
224         if(c != nil && c->write != nil){
225                 c->write(c, addr - c->addr, val, mask);
226                 return;
227         }
228         vmdebug("pcidev %.6ux: ignoring write to addr %#ux, val %#ux", d->bdf, addr, val);
229 }
230
231 u32int
232 pciio(int isin, u16int port, u32int val, int sz, void *)
233 {
234         static u32int cfgaddr;
235         u32int mask;
236         PCIDev *d;
237
238         switch(isin << 16 | port){
239         case 0x0cf8: cfgaddr = val; return 0;
240         case 0x10cf8: return cfgaddr;
241         case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff:
242                 val <<= 8 * (port & 3);
243                 mask = -1UL >> 32 - 8 * sz << 8 * (port & 3);
244                 if((cfgaddr & 1<<31) != 0 && (d = findpcidev(cfgaddr & 0xffff00), d != nil))
245                         pciwrite(d, cfgaddr & 0xfc, val, mask);
246                 return 0;
247         case 0x10cfc: case 0x10cfd: case 0x10cfe: case 0x10cff:
248                 if((cfgaddr & 1<<31) == 0 || (d = findpcidev(cfgaddr & 0xffff00), d == nil))
249                         return -1;
250                 return pciread(d, cfgaddr & 0xfc) >> 8 * (port & 3);
251         }
252         return iowhine(isin, port, val, sz, "pci");
253 }
254
255 void
256 pciirq(PCIDev *d, int status)
257 {
258         d->irqactive = status != 0;
259         pciirqupdate();
260 }
261
262 void
263 pciinit(void)
264 {
265         iobars.busnext = &iobars;
266         iobars.busprev = &iobars;
267         membars.busprev = &membars;
268         membars.busnext = &membars;
269         mkpcidev(BDF(0,0,0), 0x01008086, 0x06000000, 0);
270 }
271
272 void
273 pcibusmap(void)
274 {
275         u16int iop;
276         u16int irqs, uirqs;
277         PCIDev *d;
278         PCIBar *b;
279         int irq;
280         int i;
281         
282         iop = 0x1000;
283         irqs = 1<<5|1<<7|1<<9|1<<10|1<<11;
284         uirqs = 0;
285         irq = 0;
286         for(d = pcidevs; d != nil; d = d->next){
287                 d->ctrl |= 3;
288                 for(b = d->bar; b < d->bar + nelem(d->bar); b++){
289                         if(b->length == 0 || b->addr != 0)
290                                 continue;
291                         if((b->type & 1) == 0){
292                                 vmerror("pci device %.6ux: memory bars unsupported", d->bdf);
293                                 continue;
294                         }
295                         if(iop + b->length >= 0x10000){
296                                 vmerror("pci device %.6ux: not enough I/O address space for BAR%d (len=%d)", d->bdf, (int)(b - d->bar), b->length);
297                                 continue;
298                         }
299                         b->addr = iop;
300                         iop += b->length;
301                         updatebar(b);
302                 }
303                 if(d->irqno == 0){
304                         do
305                                 irq = irq + 1 & 15;
306                         while((irqs & 1<<irq) == 0);
307                         d->irqno = irq;
308                         uirqs |= 1<<irq;
309                 }
310         }
311         elcr(uirqs);
312         for(i = 0; i < 16; i++)
313                 if((uirqs & 1<<i) != 0)
314                         irqline(i, 1);
315 }