X-Git-Url: https://pd.if.org/git/?p=zos;a=blobdiff_plain;f=pci%2Fpci.c;fp=pci%2Fpci.c;h=1f810b912054bcb9289cee2c3ba81392f2984db3;hp=0000000000000000000000000000000000000000;hb=f2359f827a0e6e0803e959a38ef9594bff62ad1e;hpb=75986ab9ae7e4b5b0e397559c16710ac014ecfa8 diff --git a/pci/pci.c b/pci/pci.c new file mode 100644 index 0000000..1f810b9 --- /dev/null +++ b/pci/pci.c @@ -0,0 +1,422 @@ +#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; + } +}