#include "kernel.h" #include "mem.h" #include "ioport.h" #include "pci.h" #include /* TODO figure this out better */ struct pci_class_code_desc { uint8_t code; char description[63]; } pci_class_code_description[256] = { /* Class Code Description */ {0x00, "Unclassified Device" }, {0x01, "Mass Storage Controller" }, {0x02, "Network Controller" }, {0x03, "Display Controller" }, {0x04, "Multimedia Controller" }, {0x05, "Memory Controller" }, {0x06, "Bridge" }, {0x07, "Communication Controller" }, {0x08, "Generic System Peripheral" }, {0x09, "Input Device Controller" }, {0x0A, "Docking Station" }, {0x0B, "Processor" }, {0x0C, "Serial Bus Controller" }, {0x0D, "Wireless Controller" }, {0x0E, "Intelligent Controller" }, {0x0F, "Satellite Communications Controller" }, {0x10, "Encryption Controller" }, {0x11, "Signal Processing Controller" }, {0x12, "Processing accelerators"}, {0x13, "Non-Essential Instrumentation"}, {0x14, "Reserved"}, {0x15, "Reserved"}, {0x16, "Reserved"}, {0x17, "Reserved"}, {0x18, "Reserved"}, {0x19, "Reserved"}, {0x1A, "Reserved"}, {0x1B, "Reserved"}, {0x1C, "Reserved"}, {0x1D, "Reserved"}, {0x1E, "Reserved"}, {0x1F, "Reserved"}, {0x20, "Reserved"}, {0x21, "Reserved"}, {0x22, "Reserved"}, {0x23, "Reserved"}, {0x24, "Reserved"}, {0x25, "Reserved"}, {0x26, "Reserved"}, {0x27, "Reserved"}, {0x28, "Reserved"}, {0x29, "Reserved"}, {0x2A, "Reserved"}, {0x2B, "Reserved"}, {0x2C, "Reserved"}, {0x2D, "Reserved"}, {0x2E, "Reserved"}, {0x2F, "Reserved"}, {0x30, "Reserved"}, {0x31, "Reserved"}, {0x32, "Reserved"}, {0x33, "Reserved"}, {0x34, "Reserved"}, {0x35, "Reserved"}, {0x36, "Reserved"}, {0x37, "Reserved"}, {0x38, "Reserved"}, {0x39, "Reserved"}, {0x3A, "Reserved"}, {0x3B, "Reserved"}, {0x3C, "Reserved"}, {0x3D, "Reserved"}, {0x3E, "Reserved"}, {0x3F, "Reserved"}, {0x40, "Reserved"}, {0x41, "Reserved"}, {0x42, "Reserved"}, {0x43, "Reserved"}, {0x44, "Reserved"}, {0x45, "Reserved"}, {0x46, "Reserved"}, {0x47, "Reserved"}, {0x48, "Reserved"}, {0x49, "Reserved"}, {0x4A, "Reserved"}, {0x4B, "Reserved"}, {0x4C, "Reserved"}, {0x4D, "Reserved"}, {0x4E, "Reserved"}, {0x4F, "Reserved"}, {0x50, "Reserved"}, {0x51, "Reserved"}, {0x52, "Reserved"}, {0x53, "Reserved"}, {0x54, "Reserved"}, {0x55, "Reserved"}, {0x56, "Reserved"}, {0x57, "Reserved"}, {0x58, "Reserved"}, {0x59, "Reserved"}, {0x5A, "Reserved"}, {0x5B, "Reserved"}, {0x5C, "Reserved"}, {0x5D, "Reserved"}, {0x5E, "Reserved"}, {0x5F, "Reserved"}, {0x60, "Reserved"}, {0x61, "Reserved"}, {0x62, "Reserved"}, {0x63, "Reserved"}, {0x64, "Reserved"}, {0x65, "Reserved"}, {0x66, "Reserved"}, {0x67, "Reserved"}, {0x68, "Reserved"}, {0x69, "Reserved"}, {0x6A, "Reserved"}, {0x6B, "Reserved"}, {0x6C, "Reserved"}, {0x6D, "Reserved"}, {0x6E, "Reserved"}, {0x6F, "Reserved"}, {0x70, "Reserved"}, {0x71, "Reserved"}, {0x72, "Reserved"}, {0x73, "Reserved"}, {0x74, "Reserved"}, {0x75, "Reserved"}, {0x76, "Reserved"}, {0x77, "Reserved"}, {0x78, "Reserved"}, {0x79, "Reserved"}, {0x7A, "Reserved"}, {0x7B, "Reserved"}, {0x7C, "Reserved"}, {0x7D, "Reserved"}, {0x7E, "Reserved"}, {0x7F, "Reserved"}, {0x80, "Reserved"}, {0x81, "Reserved"}, {0x82, "Reserved"}, {0x83, "Reserved"}, {0x84, "Reserved"}, {0x85, "Reserved"}, {0x86, "Reserved"}, {0x87, "Reserved"}, {0x88, "Reserved"}, {0x89, "Reserved"}, {0x8A, "Reserved"}, {0x8B, "Reserved"}, {0x8C, "Reserved"}, {0x8D, "Reserved"}, {0x8E, "Reserved"}, {0x8F, "Reserved"}, {0x90, "Reserved"}, {0x91, "Reserved"}, {0x92, "Reserved"}, {0x93, "Reserved"}, {0x94, "Reserved"}, {0x95, "Reserved"}, {0x96, "Reserved"}, {0x97, "Reserved"}, {0x98, "Reserved"}, {0x99, "Reserved"}, {0x9A, "Reserved"}, {0x9B, "Reserved"}, {0x9C, "Reserved"}, {0x9D, "Reserved"}, {0x9E, "Reserved"}, {0x9F, "Reserved"}, {0xA0, "Reserved"}, {0xA1, "Reserved"}, {0xA2, "Reserved"}, {0xA3, "Reserved"}, {0xA4, "Reserved"}, {0xA5, "Reserved"}, {0xA6, "Reserved"}, {0xA7, "Reserved"}, {0xA8, "Reserved"}, {0xA9, "Reserved"}, {0xAA, "Reserved"}, {0xAB, "Reserved"}, {0xAC, "Reserved"}, {0xAD, "Reserved"}, {0xAE, "Reserved"}, {0xAF, "Reserved"}, {0xB0, "Reserved"}, {0xB1, "Reserved"}, {0xB2, "Reserved"}, {0xB3, "Reserved"}, {0xB4, "Reserved"}, {0xB5, "Reserved"}, {0xB6, "Reserved"}, {0xB7, "Reserved"}, {0xB8, "Reserved"}, {0xB9, "Reserved"}, {0xBA, "Reserved"}, {0xBB, "Reserved"}, {0xBC, "Reserved"}, {0xBD, "Reserved"}, {0xBE, "Reserved"}, {0xBF, "Reserved"}, {0xC0, "Reserved"}, {0xC1, "Reserved"}, {0xC2, "Reserved"}, {0xC3, "Reserved"}, {0xC4, "Reserved"}, {0xC5, "Reserved"}, {0xC6, "Reserved"}, {0xC7, "Reserved"}, {0xC8, "Reserved"}, {0xC9, "Reserved"}, {0xCA, "Reserved"}, {0xCB, "Reserved"}, {0xCC, "Reserved"}, {0xCD, "Reserved"}, {0xCE, "Reserved"}, {0xCF, "Reserved"}, {0xD0, "Reserved"}, {0xD1, "Reserved"}, {0xD2, "Reserved"}, {0xD3, "Reserved"}, {0xD4, "Reserved"}, {0xD5, "Reserved"}, {0xD6, "Reserved"}, {0xD7, "Reserved"}, {0xD8, "Reserved"}, {0xD9, "Reserved"}, {0xDA, "Reserved"}, {0xDB, "Reserved"}, {0xDC, "Reserved"}, {0xDD, "Reserved"}, {0xDE, "Reserved"}, {0xDF, "Reserved"}, {0xE0, "Reserved"}, {0xE1, "Reserved"}, {0xE2, "Reserved"}, {0xE3, "Reserved"}, {0xE4, "Reserved"}, {0xE5, "Reserved"}, {0xE6, "Reserved"}, {0xE7, "Reserved"}, {0xE8, "Reserved"}, {0xE9, "Reserved"}, {0xEA, "Reserved"}, {0xEB, "Reserved"}, {0xEC, "Reserved"}, {0xED, "Reserved"}, {0xEE, "Reserved"}, {0xEF, "Reserved"}, {0xF0, "Reserved"}, {0xF1, "Reserved"}, {0xF2, "Reserved"}, {0xF3, "Reserved"}, {0xF4, "Reserved"}, {0xF5, "Reserved"}, {0xF6, "Reserved"}, {0xF7, "Reserved"}, {0xF8, "Reserved"}, {0xF9, "Reserved"}, {0xFA, "Reserved"}, {0xFB, "Reserved"}, {0xFC, "Reserved"}, {0xFD, "Reserved"}, {0xFE, "Reserved"}, {0xFF, "Device does not fit any defined class." } }; #define PCI_ADDR(bus, dev, func, offset) ( (uint32_t) ( \ ((uint32_t)bus << 16) \ | ((uint32_t)device << 11) \ | ((uint32_t)function << 8) \ | ((uint32_t)0x80000000U) \ | (offset & 0xfc) ) ) uint32_t pci_read_config(uint32_t base, uint8_t offset) { uint32_t data; base = base | (offset & 0xfc); outport32(0xcf8, base); data = inport32(0xcfc); return data; } void pci_write_config(uint32_t base, uint8_t offset, uint32_t val) { base = base | (offset & 0xfc); outport32(0xcf8, base); outport32(0xcfc, val); return; } int pci_read_header(struct pci_header *h, uint8_t bus, uint8_t device, uint8_t function) { uint32_t addr, data; int offset; uint32_t *hb; int size = 0; hb = (uint32_t *)h; addr = 0; addr = PCI_ADDR(bus,device,function,0); /* offset 0 for device and vendor id */ outport32(0xcf8, addr); data = inport32(0xcfc); h->vendorid = data & 0xffff; h->deviceid = data >> 16; if (h->vendorid == 0xffff) return 0; hb++; /* might as well read in the rest */ //printk("read in vendor id %x\n", h->vendorid); switch (h->headertype & 0x7F) { case 0x00: size = 0x40; break; /* general device */ case 0x01: size = 0x40; break; /* PCI to PCI bridge */ case 0x02: size = 0x48; break; /* PCI to CardBus bridge */ default: size = 0x10; break; } for (offset = 4; offset < size ; offset += 4) { addr = PCI_ADDR(bus,device,function,offset); outport32(0xcf8, addr); data = inport32(0xcfc); *hb++ = data; } return 1; } void pci_debug_info(struct pci_header *h) { printk("pci: id %0x:%0x, type %0x, class %0x:%0x, %s / %s\n", h->vendorid, h->deviceid, h->headertype, h->classcode, h->subclass, pci_class_code_description[h->classcode].description, pci_func_desc(h->classcode, h->subclass, h->progif) ); } void pci_scan_bus(uint8_t bus); void pci_scan_device(uint8_t bus, uint8_t device) { union pci_device h; uint8_t function = 0; struct pci_info *pci; pci_read_header((struct pci_header *)&h, 0, device, function); if (h.header.vendorid == 0xffff) return; //printk("read pci header\n"); //pci_debug_info((struct pci_header *)&h); if (h.header.classcode == 0x06 && h.header.subclass == 0x04) { /* this is a bridge */ uint8_t secbus = h.bridge.secondary_bus_number; pci_scan_bus(secbus); } if (h.header.headertype & 0x80 != 0) { for (function = 1; function < 8; function++) { pci_read_header((struct pci_header *)&h, 0, device, function); if (h.header.vendorid == 0xffff) continue; // pci_debug_info((struct pci_header *)&h); if (h.header.classcode == 0x06 && h.header.subclass == 0x04) { /* this is a bridge */ uint8_t secbus = h.bridge.secondary_bus_number; pci_scan_bus(secbus); } } } pci = koalloc(sizeof *pci); memcpy(&pci->device, &h, sizeof h); pci->base = PCI_ADDR(bus,device,function,0); if (pci_devices == NULL) { // printk("setting up list\n"); pci_devices = pci; pci->next = pci; pci->prev = pci; } else { // printk("adding to list\n"); pci->prev = pci_devices->prev; pci->next = pci_devices; pci_devices->prev->next = pci; pci_devices->prev = pci; } } void pci_scan_bus(uint8_t bus) { uint8_t device; for (device = 0; device < 32; device++) { pci_scan_device(bus, device); } } struct pci_info *pci_devices; paddr_t pci_start; /* the start of pci space */ void pci_init() { struct pci_info *dev; /* align the start of PCI memory to 1 MB */ /* TODO we could probably free any remaining physical pages * between the _kernel_phys_end and the new alignment */ pci_start = mem_align(_kernel_phys_end, MB(1)); //printk("sizeof pci_header = %x\n", sizeof h); // /* TODO free the list if it's not null? */ pci_devices = 0; pci_scan_bus(0); for (dev = pci_devices; dev; dev = dev->next) { pci_debug_info(&dev->device.header); if (dev->next == pci_devices) break; } }