#include "kernel/kernel.h" #include "log.h" #include "asm_x86.h" #include "e1000.h" #define PCI_CONFIG_DATA 0xCFC #define PCI_CONFIG_ADDRESS 0xCF8 static uint32_t e1000_addr; static char *get_class(uint8_t v) { switch(v) { case 0x00: return "Unclassified"; } return "Unknown"; } 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); } uint32_t 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); if((bar_low&1)==0) // mem space { klog("type=0x%x,base_addr=0x%08X",0b110&bar_low,(bar_low+(bar_high<<16))&0xFFFFFFF0); } return (bar_low+(bar_high<<16))&0xFFFFFFF0; } uint16_t pciCheck(uint8_t bus, uint8_t slot) { //https://pci-ids.ucw.cz/v2.2/pci.ids uint16_t vendor, device, irq; /* 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); //pciConfigSet(bus,slot,0,0x3c+2,0x3); irq = pciConfigReadWord(bus,slot,0,0x3c); uint8_t header = pciConfigReadWord(bus,slot,0,0xd)&0xff; klog("[%d,%d]: vendor: 0x%x / device: 0x%x",bus,slot,vendor,device); klog("header_typ=%x, %d,pin=%d , irq=%d",header,irq,irq&0xFf00,irq&0xFf); // check for: E1000 (82540EM). PCI Ethernet Controller if(vendor==0x8086&&device==0x100e) { uint16_t command = pciConfigReadWord(bus,slot,0,0x04); pciConfigSet(bus,slot,0,0x04,command|1<<2); command = pciConfigReadWord(bus,slot,0,0x04); klog("enable busmastering / command register: %04X",command); // uint16_t irq=pciConfigReadWord(bus,slot,0,0x3C); // uint16_t irq2=pciConfigReadWord(bus,slot,0,0x3E); // e1000_addr=test_bar(bus,slot,0x10); test_bar(bus,slot,0x14); // scr_put_hex(irq); // scr_put_hex(irq2); // scr_put_string_nl(";"); } } return (vendor); } uint32_t 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); } } return e1000_addr; }