#include "kernel/kernel.h" #include "asm_x86.h" #include "e1000.h" #define PCI_CONFIG_DATA 0xCFC #define PCI_CONFIG_ADDRESS 0xCF8 void pciConfigSet (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint32_t data) { uint32_t address; uint32_t lbus = (uint32_t)bus; uint32_t lslot = (uint32_t)slot; uint32_t lfunc = (uint32_t)func; uint16_t tmp = 0; /* create configuration address as per Figure 1 */ address = (uint32_t)((lbus << 16) | (lslot << 11) | (lfunc << 8) | (offset & 0xfc) | ((uint32_t)0x80000000)); /* write out the address */ x86_outl (0xCF8, address); x86_outl (0xCFC,data); } uint16_t pciConfigReadWord (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { uint32_t address; uint32_t lbus = (uint32_t)bus; uint32_t lslot = (uint32_t)slot; uint32_t lfunc = (uint32_t)func; uint16_t tmp = 0; /* create configuration address as per Figure 1 */ address = (uint32_t)((lbus << 16) | (lslot << 11) | (lfunc << 8) | (offset & 0xfc) | ((uint32_t)0x80000000)); /* write out the address */ x86_outl (0xCF8, address); /* read in the data */ /* (offset & 2) * 8) = 0 will choose the first word of the 32 bits register */ tmp = (uint16_t)((x86_inl (0xCFC) >> ((offset & 2) * 8)) & 0xffff); return (tmp); } void test_bar(uint8_t bus, uint8_t slot, uint8_t offset) { uint16_t bar_low=pciConfigReadWord(bus,slot,0,offset); uint16_t bar_high=pciConfigReadWord(bus,slot,0,offset+2); // check size pciConfigSet(bus,slot,0,offset,0xffffffff); uint16_t size_low=pciConfigReadWord(bus,slot,0,offset); uint16_t size_high=pciConfigReadWord(bus,slot,0,offset+2); uint32_t size=(size_high<<16)+size_low; size=~size; size++; // // restore original values pciConfigSet(bus,slot,0,offset,(bar_high<<16)+bar_low); klog("%s bar: (0x%x 0x%x) size: 0x%x" ,bar_low&1?"i/o":"mem",bar_high, bar_low, size); } uint16_t pciCheck(uint8_t bus, uint8_t slot) { uint16_t vendor, device; /* try and read the first configuration register. Since there are no */ /* vendors that == 0xFFFF, it must be a non-existent device. */ if ((vendor = pciConfigReadWord(bus,slot,0,0)) != 0xFFFF) { device = pciConfigReadWord(bus,slot,0,2); klog("[%d,%d]: vendor: 0x%x / device: 0x%x",bus,slot,vendor,device); // check for: E1000 (82540EM). PCI Ethernet Controller if(vendor==0x8086&&device==0x100e) { // uint16_t irq=pciConfigReadWord(bus,slot,0,0x3C); // uint16_t irq2=pciConfigReadWord(bus,slot,0,0x3E); // init_e1000(); test_bar(bus,slot,0x10); test_bar(bus,slot,0x14); test_bar(bus,slot,0x18); // scr_put_hex(irq); // scr_put_hex(irq2); // scr_put_string_nl(";"); } } return (vendor); } void pci_init() { klog("scanning bus"); // todo: recurse on pci to pci bridges! // todo: support multiple pci host controllers! // (check more funcitons of device 0:0) uint16_t bus; uint8_t device; for(bus = 0; bus < 256; bus++) { for(device = 0; device < 32; device++) { pciCheck(bus, device); } } }