8 PCIBar membars, iobars;
11 mkpcidev(u32int bdf, u32int viddid, u32int clrev, int needirq)
16 d = emalloc(sizeof(PCIDev));
21 d->irqno = needirq ? 0 : 0xff;
22 for(n = 0; n < nelem(d->bar); n++){
24 d->bar[n].busnext = &d->bar[n];
25 d->bar[n].busprev = &d->bar[n];
37 return BDF(0, dev++, 0);
53 mkpcibar(PCIDev *d, u8int t, u32int a, u32int l, void *fn, void *aux)
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;
63 for(b = d->bar; b < d->bar + nelem(d->bar); b++)
66 if(b == d->bar + nelem(d->bar))
67 sysfatal("pci bdf %6ux: too many bars", d->bdf);
74 if((b->type & 1) != 0)
83 b->busnext->busprev = b->busprev;
84 b->busprev->busnext = b->busnext;
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;
95 if((b->d->ctrl & 1) == 0 || b->addr == 0 || b->io == nil) return;
97 b->busprev = iobars.busprev;
98 b->busnext->busprev = b;
99 b->busprev->busnext = b;
111 for(d = pcidevs; d != nil; d = d->next){
114 act |= d->irqactive<<d->irqno;
117 for(i = 0; i < 16; i++)
118 if((irqs & 1<<i) != 0)
119 irqline(i, ~act>>i & 1);
123 mkpcicap(PCIDev *d, u8int length, u32int (*readf)(PCICap *, u8int), void (*writef)(PCICap *, u8int, u32int, u32int))
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));
136 c->addr = d->capalloc;
137 d->capalloc += length;
138 for(p = &d->cap; *p != nil; p = &(*p)->next)
145 findpcidev(u32int bdf)
149 for(d = pcidevs; d != nil; d = d->next)
156 findpcicap(PCIDev *d, u8int addr)
160 for(c = d->cap; c != nil; c = c->next)
161 if((uint)(addr - c->addr) < c->length)
167 pciread(PCIDev *d, int 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 */
188 c = findpcicap(d, addr);
190 val = c->read(c, addr - c->addr);
194 val |= c->next->addr << 8;
198 vmdebug("pcidev %.6ux: ignoring read from addr %#ux", d->bdf, addr);
203 pciwrite(PCIDev *d, int addr, u32int val, u32int mask)
210 d->ctrl = (d->ctrl & ~mask | val & mask) & 0x21f;
211 for(n = 0; n < nelem(d->bar); n++)
212 updatebar(&d->bar[n]);
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]);
221 case 0x3c: d->irqno = (d->irqno & ~mask | val & mask) & 0xff; pciirqupdate(); return;
223 c = findpcicap(d, addr);
224 if(c != nil && c->write != nil){
225 c->write(c, addr - c->addr, val, mask);
228 vmdebug("pcidev %.6ux: ignoring write to addr %#ux, val %#ux", d->bdf, addr, val);
232 pciio(int isin, u16int port, u32int val, int sz, void *)
234 static u32int cfgaddr;
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);
247 case 0x10cfc: case 0x10cfd: case 0x10cfe: case 0x10cff:
248 if((cfgaddr & 1<<31) == 0 || (d = findpcidev(cfgaddr & 0xffff00), d == nil))
250 return pciread(d, cfgaddr & 0xfc) >> 8 * (port & 3);
252 return iowhine(isin, port, val, sz, "pci");
256 pciirq(PCIDev *d, int status)
258 d->irqactive = status != 0;
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);
283 irqs = 1<<5|1<<7|1<<9|1<<10|1<<11;
286 for(d = pcidevs; d != nil; d = d->next){
288 for(b = d->bar; b < d->bar + nelem(d->bar); b++){
289 if(b->length == 0 || b->addr != 0)
291 if((b->type & 1) == 0){
292 vmerror("pci device %.6ux: memory bars unsupported", d->bdf);
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);
306 while((irqs & 1<<irq) == 0);
312 for(i = 0; i < 16; i++)
313 if((uirqs & 1<<i) != 0)