static Pcidev * mgapcimatch(void) { Pcidev *p; p = pcimatch(nil, MATROX, MGA4xx); if(p == nil) p = pcimatch(nil, MATROX, MGA550); if(p == nil) p = pcimatch(nil, MATROX, MGA200); return p; }
int dbpci(Vga *vga, Ndbtuple *tuple) { int did, vid; Ndbtuple *t, *td; Pcidev *pci; for(t = tuple->entry; t; t = t->entry){ if(strcmp(t->attr, "vid") != 0 || (vid=atoi(t->val)) == 0) continue; for(td = t->line; td != t; td = td->line){ if(strcmp(td->attr, "did") != 0) continue; if(strcmp(td->val, "*") == 0) did = 0; else if((did=atoi(td->val)) == 0) continue; for(pci=nil; pci=pcimatch(pci, vid, did);) if(pci->ccrb == 3) break; if(pci == nil) continue; vga->pci = pci; addattr(&vga->attr, t); addattr(&vga->attr, td); return 1; } } return 0; }
static void hiqvideoenable(VGAscr* scr) { Pcidev *p; int vmsize; /* * Only once, can't be disabled for now. */ if(scr->mmio) return; if(p = pcimatch(nil, 0x102C, 0)){ switch(p->did){ case 0x00C0: /* 69000 HiQVideo */ vmsize = 2*1024*1024; break; case 0x00E0: /* 65550 HiQV32 */ case 0x00E4: /* 65554 HiQV32 */ case 0x00E5: /* 65555 HiQV32 */ switch((hiqvideoxi(Xrx, 0x43)>>1) & 0x03){ default: case 0: vmsize = 1*1024*1024; break; case 1: vmsize = 2*1024*1024; break; } break; default: return; } } else return;
void main(void) { cgapost(0); mach0init(); options(); ioinit(); i8250console(); quotefmtinstall(); screeninit(); print("\nPlan 9\n"); trapinit0(); mmuinit0(); kbdinit(); i8253init(); cpuidentify(); meminit(); confinit(); archinit(); if(!isa20on()) panic("bootstrap didn't leave a20 address line enabled"); xinit(); if(i8237alloc != nil) i8237alloc(); trapinit(); printinit(); cpuidprint(); mmuinit(); fpsavealloc(); if(arch->intrinit) /* launches other processors on an mp */ arch->intrinit(); timersinit(); mathinit(); kbdenable(); if(arch->clockenable) arch->clockenable(); procinit0(); initseg(); if(delaylink){ bootlinks(); pcimatch(0, 0, 0); }else links(); conf.monitor = 1; chandevreset(); cgapost(0xcd); pageinit(); i8253link(); swapinit(); userinit(); active.thunderbirdsarego = 1; cgapost(0x99); schedinit(); }
static Vdev* viopnpdevs(int typ) { Vdev *vd, *h, *t; Pcidev *p; int n, i; h = t = nil; for(p = nil; p = pcimatch(p, 0, 0);){ if(p->vid != 0x1AF4) continue; if((p->did < 0x1000) || (p->did >= 0x1040)) continue; if(p->rid != 0) continue; if(pcicfgr16(p, 0x2E) != typ) continue; if((vd = malloc(sizeof(*vd))) == nil){ print("virtio: no memory for Vdev\n"); break; } vd->port = p->mem[0].bar & ~0x1; if(ioalloc(vd->port, p->mem[0].size, 0, "virtio") < 0){ print("virtio: port %lux in use\n", vd->port); free(vd); continue; } vd->typ = typ; vd->pci = p; /* reset */ outb(vd->port+Status, 0); vd->feat = inl(vd->port+Devfeat); outb(vd->port+Status, Acknowledge|Driver); for(i=0; i<nelem(vd->queue); i++){ outs(vd->port+Qselect, i); n = ins(vd->port+Qsize); if(n == 0 || (n & (n-1)) != 0) break; if((vd->queue[i] = mkvqueue(n)) == nil) break; coherence(); outl(vd->port+Qaddr, PADDR(vd->queue[i]->desc)/BY2PG); } vd->nqueue = i; if(h == nil) h = vd; else t->next = vd; t = vd; } return h; }
void pcireset(void) { Pcidev *p; for(p = nil; p = pcimatch(p, 0, 0); ) /* don't mess with the bridges */ if(p->ccrb != 0x06) pciclrbme(p); }
Pcidev* pcimatchtbdf(int tbdf) { Pcidev *p; for(p = nil; p = pcimatch(p, 0, 0); ) if(p->tbdf == tbdf) break; return p; }
static void pcireservemem(void) { int i; Pcidev *p; for(p = nil; p = pcimatch(p, 0, 0); ) for(i=0; i<nelem(p->mem); i++) if(p->mem[i].bar && (p->mem[i].bar&1) == 0) asmmapinit(p->mem[i].bar&~0x0F, p->mem[i].size, 5); }
static void tdfxenable(VGAscr* scr) { Pcidev *p; int i, *mmio; if(scr->mmio) return; if(p = pcimatch(nil, 0x121A, 0)){ switch(p->did){ case 0x0003: /* Banshee */ case 0x0005: /* Avenger (a.k.a. Voodoo3) */ break; default: return; } } else return; scr->mmio = vmap(p->mem[0].bar&~0x0F, p->mem[0].size); if(scr->mmio == nil) return; scr->pci = p; addvgaseg("3dfxmmio", p->mem[0].bar&~0x0F, p->mem[0].size); vgalinearpci(scr); if(scr->apsize) addvgaseg("3dfxscreen", scr->paddr, scr->apsize); /* * Find a place for the cursor data in display memory. * If SDRAM then there's 16MB memory else it's SGRAM * and can count it based on the power-on straps - * chip size can be 8Mb or 16Mb, and there can be 4 or * 8 of them. * Use the last 1KB of the framebuffer. */ mmio = (void*)((uchar*)scr->mmio+dramInit0); if(*(mmio+1) & 0x40000000) i = 16*1024*1024; else{ if(*mmio & 0x08000000) i = 16*1024*1024/8; else i = 8*1024*1024/8; if(*mmio & 0x04000000) i *= 8; else i *= 4; } scr->storage = i - 1024; }
static Uart* axppnp(void) { Pcidev *p; int ctlrno; Uart *head, *tail, *uart; /* * Loop through all PCI devices looking for simple serial * controllers (ccrb == 0x07) and configure the ones which * are familiar. */ head = tail = nil; ctlrno = 0; for(p = pcimatch(nil, 0, 0); p != nil; p = pcimatch(p, 0, 0)){ if(p->ccrb != 0x07) continue; switch((p->did<<16)|p->vid){ default: continue; case (0x6001<<16)|0x114F: /* AvanstarXp */ if((uart = axpalloc(ctlrno, p)) == nil) continue; break; } if(head != nil) tail->next = uart; else head = uart; for(tail = uart; tail->next != nil; tail = tail->next) ; ctlrno++; } return head; }
static void ne2000pnp(Ether* edev) { int i, id; Pcidev *p; Ctlr *ctlr; /* * Make a list of all ethernet controllers * if not already done. */ if(ctlrhead == nil){ p = nil; while(p = pcimatch(p, 0, 0)){ if(p->ccrb != 0x02 || p->ccru != 0) continue; ctlr = malloc(sizeof(Ctlr)); if(ctlr == nil) error(Enomem); ctlr->pcidev = p; if(ctlrhead != nil) ctlrtail->next = ctlr; else ctlrhead = ctlr; ctlrtail = ctlr; } } /* * Is it a card with an unrecognised vid+did? * Normally a search is made through all the found controllers * for one which matches any of the known vid+did pairs. * If a vid+did pair is specified a search is made for that * specific controller only. */ id = 0; for(i = 0; i < edev->nopt; i++){ if(cistrncmp(edev->opt[i], "id=", 3) == 0) id = strtol(&edev->opt[i][3], nil, 0); } if(id != 0) ne2000match(edev, id); else for(i = 0; ne2000pci[i].name; i++){ if(ne2000match(edev, ne2000pci[i].id) != nil) break; } }
static void wpipci(void) { Pcidev *pdev; pdev = nil; while(pdev = pcimatch(pdev, 0x8086, 0)){ Ctlr *ctlr; void *mem; switch(pdev->did){ default: continue; case 0x4227: break; } /* Clear device-specific "PCI retry timeout" register (41h). */ if(pcicfgr8(pdev, 0x41) != 0) pcicfgw8(pdev, 0x41, 0); pcisetbme(pdev); pcisetpms(pdev, 0); ctlr = malloc(sizeof(Ctlr)); if(ctlr == nil) { print("wpi: unable to alloc Ctlr\n"); continue; } ctlr->port = pdev->mem[0].bar & ~0x0F; mem = vmap(pdev->mem[0].bar & ~0x0F, pdev->mem[0].size); if(mem == nil) { print("wpi: can't map %8.8luX\n", pdev->mem[0].bar); free(ctlr); continue; } ctlr->nic = mem; ctlr->pdev = pdev; if(wpihead != nil) wpitail->link = ctlr; else wpihead = ctlr; wpitail = ctlr; } }
void vgalinearpciid(VGAscr *scr, int vid, int did) { Pcidev *p; p = nil; while((p = pcimatch(p, vid, 0)) != nil){ if(p->ccrb != 3) /* video card */ continue; if(did != 0 && p->did != did) continue; break; } if(p == nil) error("pci video card not found"); scr->pci = p; vgalinearpci(scr); }
/* figure out what kind of interface we could have */ void lm78reset(void) { int pcs; Pcidev *p; lm78.ifc = None; p = nil; while((p = pcimatch(p, IntelVendID, 0)) != nil){ switch(p->did){ /* these bridges use the PCSC to map the lm78 into port space. */ /* for this case the lm78's CS# select is connected to the PIIX's */ /* PCS# output and the bottom 3 bits of address are passed to the */ /* LM78's A0-A2 inputs. */ case PiixID: case Piix3ID: pcs = pcicfgr16(p, PCSC); if(pcs & 3) { /* already enabled */ lm78.port = pcs & ~3; lm78.ifc = Parallel; return; } /* enable the chip, use default address 0x50 */ pcicfgw16(p, PCSC, 0x50|PCSC8bytes); pcs = pcicfgr16(p, PCSC); lm78.port = pcs & ~3; lm78.ifc = Parallel; return; /* this bridge puts the lm78's serial interface on the smbus */ case Piix4PMID: lm78.smbus = piix4smbus(); if(lm78.smbus == nil) continue; print("found piix4 smbus, base %lud\n", lm78.smbus->base); lm78.ifc = Smbus; return; } } }
static void iigreset(void) { iig.scr.pci = pcimatch(nil, 0x8086, 0x0116); if (iig.scr.pci) print("Found sandybridge at 0x%x\n", iig.scr.pci->tbdf); else { print("NO sandybridge found\n"); return; } /* on coreboot systems, which is what this is mainly for, the graphics memory is allocated and * reserved. This little hack won't be permanent but we might as well see if we can get to that * memory. */ void *x = vmap(iig.scr.pci->mem[1].bar, iig.scr.pci->mem[1].size); print("x is THIS! %p\n", x); if (x) { iig.scr.vaddr = x; iig.scr.paddr = iig.scr.pci->mem[1].bar; iig.scr.apsize = iig.scr.pci->mem[1].size; } }
static Uart * oxpnp(void) { Pcidev *p; Ctlr *ctlr; Port *port; int i; char *model; char name[12+1]; Uart *head, *tail; static int ctlrno; p = nil; head = tail = nil; while(p = pcimatch(p, 0x1415, 0)){ switch(p->did){ case 0xc101: case 0xc105: case 0xc11b: case 0xc11f: case 0xc120: case 0xc124: case 0xc138: case 0xc13d: case 0xc140: case 0xc141: case 0xc144: case 0xc145: case 0xc158: case 0xc15d: model = "OXPCIe952"; break; case 0xc208: case 0xc20d: model = "OXPCIe954"; break; case 0xc308: case 0xc30d: model = "OXPCIe958"; break; default: continue; } ctlr = malloc(sizeof *ctlr); if(ctlr == nil){ print("oxpnp: out of memory\n"); continue; } ctlr->pcidev = p; ctlr->mem = vmap(p->mem[0].bar & ~0xf, p->mem[0].size); if(ctlr->mem == nil){ print("oxpnp: vmap failed\n"); free(ctlr); continue; } snprint(name, sizeof name, "uartox%d", ctlrno); kstrdup(&ctlr->name, name); ctlr->nport = ctlr->mem[Nuart] & 0x1f; for(i = 0; i < ctlr->nport; ++i){ port = &ctlr->port[i]; port->ctlr = ctlr; port->mem = (u8int *)ctlr->mem + 0x1000 + 0x200*i; port->regs = port; snprint(name, sizeof name, "%s.%d", ctlr->name, i); kstrdup(&port->name, name); port->phys = &oxphysuart; if(head == nil) head = port; else tail->next = port; tail = port; } print("%s: %s: %d ports irq %d\n", ctlr->name, model, ctlr->nport, p->intl); ctlrno++; } return head; }
static Uart* uartpcipnp(void) { Pcidev *p; char *name; int ctlrno, n, subid; Uart *head, *tail, *uart; /* * Loop through all PCI devices looking for simple serial * controllers (ccrb == 0x07) and configure the ones which * are familiar. All suitable devices are configured to * simply point to the generic i8250 driver. */ head = tail = nil; ctlrno = 0; for(p = pcimatch(nil, 0, 0); p != nil; p = pcimatch(p, 0, 0)){ if(p->ccrb != 0x07 || p->ccru > 2) continue; switch((p->did<<16)|p->vid){ default: continue; case (0x9835<<16)|0x9710: /* StarTech PCI2S550 */ uart = uartpci(ctlrno, p, 0, 1, 1843200, "PCI2S550-0"); if(uart == nil) continue; uart->next = uartpci(ctlrno, p, 1, 1, 1843200, "PCI2S550-1"); break; case (0x950A<<16)|0x1415: /* Oxford Semi OX16PCI954 */ /* * These are common devices used by 3rd-party * manufacturers. * Must check the subsystem VID and DID for correct * match, mostly to get the clock frequency right. */ subid = pcicfgr16(p, PciSVID); subid |= pcicfgr16(p, PciSID)<<16; switch(subid){ default: continue; case (0x2000<<16)|0x131F:/* SIIG CyberSerial PCIe */ uart = uartpci(ctlrno, p, 0, 1, 18432000, "CyberSerial-1S"); if(uart == nil) continue; break; } break; case (0x9501<<16)|0x1415: /* Oxford Semi OX16PCI954 */ /* * These are common devices used by 3rd-party * manufacturers. * Should check the subsystem VID and DID for correct * match, mostly to get the clock frequency right. */ subid = pcicfgr16(p, PciSVID); subid |= pcicfgr16(p, PciSID)<<16; switch(subid){ default: continue; case (0<<16)|0x1415: /* StarTech PCI4S550 */ uart = uartpci(ctlrno, p, 0, 1, 18432000, "PCI4S550-0"); if(uart == nil) continue; break; } break; case (0x9050<<16)|0x10B5: /* Perle PCI-Fast4 series */ case (0x9030<<16)|0x10B5: /* Perle Ultraport series */ /* * These devices consists of a PLX bridge (the above * PCI VID+DID) behind which are some 16C654 UARTs. * Must check the subsystem VID and DID for correct * match. */ subid = pcicfgr16(p, PciSVID); subid |= pcicfgr16(p, PciSID)<<16; switch(subid){ default: continue; case (0x0011<<16)|0x12E0: /* Perle PCI-Fast16 */ n = 16; name = "PCI-Fast16"; break; case (0x0021<<16)|0x12E0: /* Perle PCI-Fast8 */ n = 8; name = "PCI-Fast8"; break; case (0x0031<<16)|0x12E0: /* Perle PCI-Fast4 */ n = 4; name = "PCI-Fast4"; break; case (0x0021<<16)|0x155F: /* Perle Ultraport8 */ n = 8; name = "Ultraport8"; /* 16C754 UARTs */ break; } uart = uartpci(ctlrno, p, 2, n, 7372800, name); if(uart == nil) continue; break; } if(head != nil) tail->next = uart; else head = uart; for(tail = uart; tail->next != nil; tail = tail->next) ; ctlrno++; } return head; }
void main(void) { Proc *savup; static ulong vfy = Datamagic; static char novga[] = "\nno vga; serial console only\n"; savup = up; up = nil; /* m has been set by l32v.s */ /* * disable address wraps at 1MB boundaries. * if we're 9boot, ldecomp.s already did this. */ a20init(); mach0init(); // options(); /* we don't get options passed to us */ ioinit(); /* we later call i8250console after plan9.ini has been read */ i8250config("0"); /* configure serial port 0 with defaults */ quotefmtinstall(); fmtinstall('i', eipfmt); fmtinstall('I', eipfmt); fmtinstall('E', eipfmt); fmtinstall('V', eipfmt); fmtinstall('M', eipfmt); screeninit(); /* cga setup */ cgapost(0xc); trapinit0(); mmuinit0(); kbdinit(); i8253init(); cpuidentify(); readlsconf(); meminit(); confinit(); archinit(); xinit(); if(i8237alloc != nil) i8237alloc(); /* dma (for floppy) init */ trapinit(); printinit(); sanity(); cgapost(1); /* * soekris servers have no built-in video but each has a serial port. * they must see serial output, if any, before cga output because * otherwise the soekris bios will translate cga output to serial * output, which will garble serial console output. */ pcimatch(nil, 0, 0); /* force scan of pci table */ if (!pcivga) { screenputs = nil; uartputs(novga, sizeof novga - 1); } print(" %s\n\n", hellomsg); if (vfy != Datamagic) panic("data segment incorrectly aligned or loaded"); if (savup) print("up was non-nil (%#p) upon entry to main; bss wasn't zeroed!\n", savup); // xsummary(); cpuidprint(); mmuinit(); if(arch->intrinit) /* launches other processors on an mp */ arch->intrinit(); timersinit(); mathinit(); kbdenable(); /* * 9loadusb runs much faster if we don't use the clock. * perhaps we're competing with the bios for the use of it? */ if(!noclock && arch->clockenable) arch->clockenable(); procinit0(); initseg(); if(delaylink){ bootlinks(); pcimatch(0, 0, 0); }else links(); conf.monitor = 1; cgapost(0xcd); chandevreset(); cgapost(2); pageinit(); /* must follow xinit, and conf.mem must be populated */ i8253link(); userinit(); active.thunderbirdsarego = 1; cgapost(0xb0); schedinit(); }
static void i82563pci(void) { int port, type, cls; Pcidev *p; Ctlr *ctlr; static int first = 1; if (first) first = 0; else return; p = nil; while(p = pcimatch(p, 0x8086, 0)){ if(p->ccrb != 0x02 || p->ccru != 0) continue; //print("i82563pci: did %4.4#x\n", p->did); switch(p->did){ case 0x1096: case 0x10ba: type = i82563; break; case 0x1049: /* mm */ case 0x104a: /* dm */ case 0x104d: /* v */ case 0x10bd: /* dm */ type = i82566; break; case 0x10cd: /* lf */ type = i82567; break; case 0x10a4: case 0x105e: type = i82571; break; case 0x10b9: /* sic, 82572 */ type = i82572; break; case 0x108b: /* e */ case 0x108c: /* e (iamt) */ case 0x109a: /* l */ type = i82573; break; case 0x10a7: /* 82575eb */ type = i82575; break; default: continue; } port = upamalloc(p->mem[0].bar & ~0x0F, p->mem[0].size, 0); if(port == 0){ print("%s: can't map %d @ 0x%8.8lux\n", tname[type], p->mem[0].size, p->mem[0].bar); continue; } if(p->pcr & MemWrInv){ cls = pcicfgr8(p, PciCLS) * 4; if(cls != CACHELINESZ) pcicfgw8(p, PciCLS, CACHELINESZ/4); } cls = pcicfgr8(p, PciCLS); switch(cls){ default: print("%s: unexpected CLS - %d bytes\n", tname[type], cls*sizeof(long)); break; case 0x00: case 0xFF: /* alphapc 164lx returns 0 */ print("%s: unusable PciCLS: %d, using %d longs\n", tname[type], cls, CACHELINESZ/sizeof(long)); cls = CACHELINESZ/sizeof(long); pcicfgw8(p, PciCLS, cls); break; case 0x08: case 0x10: break; } ctlr = malloc(sizeof(Ctlr)); ctlr->port = port; ctlr->pcidev = p; ctlr->cls = cls*4; ctlr->type = type; ctlr->nic = KADDR(ctlr->port); if(i82563reset(ctlr)){ free(ctlr); continue; } pcisetbme(p); if(ctlrhead != nil) ctlrtail->next = ctlr; else ctlrhead = ctlr; ctlrtail = ctlr; } }
static void vesalinear(VGAscr *scr, int _1, int _2) { int i, mode, size, havesize; uint8_t *p; uint32_t paddr; Pcidev *pci; if(hardscreen) { scr->vaddr = 0; scr->paddr = scr->apsize = 0; return; } vbecheck(); mode = vbegetmode(); /* * bochs loses the top bits - cannot use this if((mode&(1<<14)) == 0) error("not in linear graphics mode"); */ mode &= 0x3FFF; p = vbemodeinfo(mode); if(!(WORD(p+0) & (1<<4))) error("not in VESA graphics mode"); if(!(WORD(p+0) & (1<<7))) error("not in linear graphics mode"); paddr = LONG(p+40); size = WORD(p+20)*WORD(p+16); size = ROUNDUP(size, PGSZ); /* * figure out max size of memory so that we have * enough if the screen is resized. */ pci = nil; havesize = 0; while(!havesize && (pci = pcimatch(pci, 0, 0)) != nil){ if(pci->ccrb != Pcibcdisp) continue; for(i=0; i<nelem(pci->mem); i++) if(paddr == (pci->mem[i].bar&~0x0F)){ if(pci->mem[i].size > size) size = pci->mem[i].size; havesize = 1; break; } } /* no pci - heuristic guess */ if (!havesize) if(size < 4*1024*1024) size = 4*1024*1024; else size = ROUND(size, 1024*1024); if(size > 16*1024*1024) /* arbitrary */ size = 16*1024*1024; vgalinearaddr(scr, paddr, size); if(scr->apsize) addvgaseg("vesascreen", scr->paddr, scr->apsize); if(Usesoftscreen){ hardscreen = scr->vaddr; scr->vaddr = 0; scr->paddr = scr->apsize = 0; } }