📄 pci.c
字号:
pcii->u.h1.secondary_bus = read_pci_config(bus, dev, func, PCI_secondary_bus, 1); pcii->u.h1.secondary_latency = read_pci_config(bus, dev, func, PCI_secondary_latency, 1); pcii->u.h1.secondary_status = read_pci_config(bus, dev, func, PCI_secondary_status, 2); pcii->u.h1.subordinate_bus = read_pci_config(bus, dev, func, PCI_subordinate_bus, 1); pcii->u.h1.memory_base = read_pci_config(bus, dev, func, PCI_memory_base, 2); pcii->u.h1.memory_limit = read_pci_config(bus, dev, func, PCI_memory_limit, 2); pcii->u.h1.prefetchable_memory_base = read_pci_config(bus, dev, func, PCI_prefetchable_memory_base, 2); pcii->u.h1.prefetchable_memory_limit = read_pci_config(bus, dev, func, PCI_prefetchable_memory_limit, 2); pcii->u.h1.bridge_control = read_pci_config(bus, dev, func, PCI_bridge_control, 1); pcii->u.h1.subsystem_vendor_id = read_pci_config(bus, dev, func, PCI_sub_vendor_id_1, 2); pcii->u.h1.subsystem_id = read_pci_config(bus, dev, func, PCI_sub_device_id_1, 2); pcii->u.h1.interrupt_line = read_pci_config(bus, dev, func, PCI_interrupt_line, 1); pcii->u.h1.interrupt_pin = read_pci_config(bus, dev, func, PCI_interrupt_pin, 1) & PCI_pin_mask; { struct pci_device *pd = pci_devices; while (pd && pd->next) pd = pd->next; if (pd) pd->next = pcid; else pci_devices = pcid; } { struct pci_bus *pb = pci_busses; while (pb && pb->next) pb = pb->next; if (pb) pb->next = pcib; else pci_busses = pcib; } show_pci_details(pcii);pci_bridge_skip_infolist: command |= 0x03; write_pci_config(bus, dev, func, PCI_command, 2, command); return;}/** This is a very, very brief 2 liner for a device... */static voiddebug_show_device(pci_info *pcii){ uint16 status = read_pci_config(pcii->bus, pcii->device, pcii->function, PCI_status, 2); dprintf("device @ %d:%d:%d > %s [%04x:%04x]\n", pcii->bus, pcii->device, pcii->function, decode_class(pcii->class_base, pcii->class_sub), pcii->vendor_id, pcii->device_id); if ((status & PCI_status_capabilities)) { dprintf("Capabilities: "); if (pci_get_capability(pcii->bus, pcii->device, pcii->function, PCI_cap_id_agp, NULL)) dprintf("AGP "); if (pci_get_capability(pcii->bus, pcii->device, pcii->function, PCI_cap_id_pm, NULL)) dprintf("Pwr Mgmt "); if (pci_get_capability(pcii->bus, pcii->device, pcii->function, PCI_cap_id_vpd, NULL)) dprintf("VPD "); if (pci_get_capability(pcii->bus, pcii->device, pcii->function, PCI_cap_id_slotid, NULL)) dprintf("slotID "); if (pci_get_capability(pcii->bus, pcii->device, pcii->function, PCI_cap_id_msi, NULL)) dprintf("MSI "); if (pci_get_capability(pcii->bus, pcii->device, pcii->function, PCI_cap_id_hotplug, NULL)) dprintf("hotplug "); dprintf("\n"); } else dprintf("\t(No capabilities exist for this device)\n");}static voidpci_device_probe(uint8 bus, uint8 dev, uint8 func){ uint8 base_class, sub_class; uint8 type; pci_info *pcii; struct pci_device *pcid; TRACE(("pci_device_probe()\n")); if (func > 0) { uint16 vend = read_pci_config(bus, dev, func, PCI_vendor_id, 2); if (vend == 0xffff) return; } type = read_pci_config(bus, dev, func, PCI_header_type, 1); type &= PCI_header_type_mask; base_class = read_pci_config(bus, dev, func, PCI_class_base, 1); sub_class = read_pci_config(bus, dev, func, PCI_class_sub, 1); if (base_class == PCI_bridge) { fixup_bridge(bus, dev, func); if (sub_class == PCI_pci) { pci_bridge(bus, dev, func); return; } } /* If we get here then it's not a bridge, so we add it... */ pcii = (pci_info *)kmalloc(sizeof(pci_info)); if (!pcii) return; pcid = (struct pci_device *)kmalloc(sizeof(struct pci_device)); if (!pcid) { kfree(pcii); return; } pcid->info = pcii; pcid->type = PCI_DEVICE; pcid->next = NULL; pcii->bus = bus; pcii->device = dev; pcii->function = func; fill_basic_pci_structure(pcii); if (pcii->class_base == PCI_bridge && pcii->class_sub == PCI_host) pcid->type = PCI_HOST_BUS; pcii->u.h0.cardbus_cis = read_pci_config(bus, dev, func, PCI_cardbus_cis, 4); pcii->u.h0.subsystem_id = read_pci_config(bus, dev, func, PCI_subsystem_id, 2); pcii->u.h0.subsystem_vendor_id = read_pci_config(bus, dev, func, PCI_subsystem_vendor_id, 2); pcii->u.h0.rom_base_pci = read_pci_config(bus, dev, func, PCI_rom_base, 4); pcii->u.h0.interrupt_line = read_pci_config(bus, dev, func, PCI_interrupt_line, 1); pcii->u.h0.interrupt_pin = read_pci_config(bus, dev, func, PCI_interrupt_pin, 1) & PCI_pin_mask; pcii->u.h0.max_latency = read_pci_config(bus, dev, func, PCI_max_latency, 1); pcii->u.h0.min_grant = read_pci_config(bus, dev, func, PCI_min_grant, 1); /* now add to list (at end) */ { struct pci_device *pd = pci_devices; while (pd && pd->next) pd = pd->next; if (pd) pd->next = pcid; else pci_devices = pcid; } pci_set_power_state(bus, dev, func, PCI_pm_state_d0); // if the device appears to want to be a bus master, we'll set // it as one. // XXX This may not be the right place to do this, but as nowhere else // seems to attempt to do configuration of the device beyond powering // up, and that's done here, it seems like as good a place as any. if (pcii->u.h0.max_latency != 0 && pcii->u.h0.min_grant != 0) pci_set_bus_master(bus, dev, func); debug_show_device(pcii);}/** Scan a bus for PCI devices. For each device that's a possible * we get the vendor_id. If it's 0xffff then it's not a valid * device so we move on. * Valid devices then have their header_type checked to detrmine how * many functions we need to check. However, some devices that support * multiple functions have a header_type of 0 (generic) so we also check * for these using pci_quirk_multifunction(). * If it's a multifunction device we scan all 8 possible functions, * otherwise we just probe the first one. */static voidpci_scan_bus(uint8 bus){ uint8 dev = 0, func = 0; uint16 vend = 0; TRACE(("pci_scan_bus()\n")); for (dev = 0; dev < 32; dev++) { vend = read_pci_config(bus, dev, 0, PCI_vendor_id, 2); if (vend != 0xffff) { uint16 device = read_pci_config(bus, dev, func, PCI_device_id, 2); uint8 type = read_pci_config(bus, dev, func, PCI_header_type, 1); uint8 nfunc = 8; type &= PCI_header_type_mask; if ((type & PCI_multifunction) == 0 && !pci_quirk_multifunction(vend, device)) nfunc = 1; for (func = 0; func < nfunc; func++) pci_device_probe(bus, dev, func); } }}// unused#if 0static voidscan_pci(void){ int bus, dev, func; TRACE(("scan_pci()\n")); /* We can have up to 255 busses */ for (bus = 0; bus < 255; bus++) { /* Each bus can have up to 'bus_max_devices' devices on it */ for (dev = 0; dev <= bus_max_devices; dev++) { /* Each device can have up to 8 functions */ uint16 sv_vendor_id = 0, sv_device_id = 0; for (func = 0; func < 8; func++) { pci_info *pcii = NULL; uint16 vendor_id = read_pci_config(bus, dev, func, 0, 2); uint16 device_id; uint8 offset; /* If we get 0xffff then there is no device here. As there can't * be any gaps in function allocation this tells us that we * can move onto the next device/bus */ if (vendor_id == 0xffff) break; device_id = read_pci_config(bus, dev, func, PCI_device_id, 2); /* Is this a new device? As we're scanning the functions here, many devices * will supply identical information for all 8 accesses! Try to catch this and * simply move past duplicates. We need to continue scanning in case we miss * a different device at the end. * XXX - is this correct???? */ if (vendor_id == sv_vendor_id && sv_device_id == device_id) { /* It's a duplicate */ continue; } sv_vendor_id = vendor_id; sv_device_id = device_id; /* At present we will add a device to our list if we get here, * but we may want to review if we need to add 8 version of the * same device if only the functions differ? */ if ((pcii = (pci_info *)kmalloc(sizeof(pci_info))) == NULL) { dprintf("Failed to get memory for a pic_info structure in scan_pci\n"); return; } if (pci_get_capability(bus, dev, func, PCI_cap_id_agp, &offset)) dprintf("Device @ %d:%d:%d has AGP capability\n", bus, dev, func); pci_set_power_state(bus, dev, func, PCI_pm_state_d0); /* basic header */ pcii->bus = bus; pcii->device = dev; pcii->function = func; pcii->vendor_id = vendor_id; pcii->device_id = device_id; pcii->revision = read_pci_config(bus, dev, func, PCI_revision, 1); pcii->class_api = read_pci_config(bus, dev, func, PCI_class_api, 1); pcii->class_sub = read_pci_config(bus, dev, func, PCI_class_sub, 1); pcii->class_base = read_pci_config(bus, dev, func, PCI_class_base, 1); pcii->header_type = read_pci_config(bus, dev, func, PCI_header_type, 1); pcii->header_type &= PCI_header_type_mask; } } }}#endifstatic voidfill_basic_pci_structure(pci_info *pcii){ uint8 bus = pcii->bus, dev = pcii->device, func = pcii->function; uint8 int_line = 0, int_pin = 0; int i; pcii->vendor_id = read_pci_config(bus, dev, func, PCI_vendor_id, 2); pcii->device_id = read_pci_config(bus, dev, func, PCI_device_id, 2); pcii->revision = read_pci_config(bus, dev, func, PCI_revision, 1); pcii->class_api = read_pci_config(bus, dev, func, PCI_class_api, 1); pcii->class_sub = read_pci_config(bus, dev, func, PCI_class_sub, 1); pcii->class_base = read_pci_config(bus, dev, func, PCI_class_base, 1); pcii->header_type = read_pci_config(bus, dev, func, PCI_header_type, 1); pcii->header_type &= PCI_header_type_mask; pcii->latency = read_pci_config(bus, dev, func, PCI_latency, 1); pcii->bist = read_pci_config(bus, dev, func, PCI_bist, 1); pcii->line_size = read_pci_config(bus, dev, func, PCI_line_size, 1); if(pcii->header_type == 0) { for(i = 0; i < 6; i++) { uint32 temp, temp2; temp = read_pci_config(bus, dev, func, PCI_base_registers + i*4, 4); if(temp) { write_pci_config(bus, dev, func, PCI_base_registers + i*4, 4, 0xffffffff); temp2 = read_pci_config(bus, dev, func, PCI_base_registers + i*4, 4) & 0xfffffff0; write_pci_config(bus, dev, func, PCI_base_registers + i*4, 4, temp); temp2 = 1 + ~temp2; if(temp & 1) { pcii->u.h0.base_registers[i] = temp & 0xfff0; pcii->u.h0.base_register_sizes[i] = temp2 & 0xffff; } else { pcii->u.h0.base_registers[i] = temp & 0xfffffff0; pcii->u.h0.base_register_sizes[i] = temp2; } } else { pcii->u.h0.base_registers[i] = 0; pcii->u.h0.base_register_sizes[i] = 0; }// dprintf("basereg %d:%d:%d 0x%x\n", bus, dev, func, pcii->u.h0.base_registers[i]);// dprintf("size %d:%d:%d 0x%x\n", bus, dev, func, pcii->u.h0.base_register_sizes[i]); } } int_line = read_pci_config(bus, dev, func, PCI_interrupt_line, 1); int_pin = read_pci_config(bus, dev, func, PCI_interrupt_pin, 1); int_pin &= PCI_pin_mask;}static longget_nth_pci_info(long index, pci_info *copyto){ struct pci_device *pd = pci_devices; while (index-- > 0 && pd) pd = pd->next; if (index > 0 || !pd || !pd->info) return ERR_NOT_FOUND; TRACE(("pci_nth_pci_info: returning %d:%d:%d\n", pd->info->bus, pd->info->device, pd->info->function)); memcpy(copyto, pd->info, sizeof(pci_info)); return 0;}/* I/O routines */static uint8pci_read_io_8(int mapped_io_addr){ return in8(mapped_io_addr);}static voidpci_write_io_8(int mapped_io_addr, uint8 value){ out8(value, mapped_io_addr);}static uint16pci_read_io_16(int mapped_io_addr){ return in16(mapped_io_addr);}static voidpci_write_io_16(int mapped_io_addr, uint16 value){ out16(value, mapped_io_addr);}static uint32pci_read_io_32(int mapped_io_addr ){ return in32(mapped_io_addr);}static voidpci_write_io_32(int mapped_io_addr, uint32 value){ out32(value, mapped_io_addr);}/* pci_module_init * This is where we start all the PCI work, or not as the case may be. * We start by trying to detect and set the correct configuration mechanism * to use. We don't handle PCI BIOS's as that method seems to be falling out * of fashion and is Intel specific. * * Next we try to check if we have working PCI on this machine. check_pci() * isn't the smartest routine as it essentially just looks for a Host-PCI * bridge, but it will show us if we can continue. * NB Until this has been tested with a wider audience we don't consider * success/failure here but spew a large debug message and try to continue. * XXX - once we're happy with check_pci() make failing a criminal offense! * * Next we check to see if we can find a PIR table. * NB This is Intel specific and currently included here as a test. * * Finally we scan for devices starting at bus 0. */static intpci_module_init(void){ struct pir_table *pirt = NULL; TRACE(("pci_module_init()\n")); if (set_pci_mechanism() == -1) { return -1; } check_pci(); pci_region = vm_map_physical_memory(vm_get_kernel_aspace_id(), "pci_bios", &pci_bios_ptr, REGION_ADDR_ANY_ADDRESS, 0x10000, LOCK_RO | LOCK_KERNEL, (addr_t)0xf0000); pirt = find_pir_table(); if (pirt) { dprintf("PCI IRQ Routing table found\n");#if TRACE_PCI print_pir_table(pirt);#endif } pci_scan_bus(0); return 0;}/** Finish the module by releasing the memory we grabbed for * the pci_bios :) */static intpci_module_uninit(void){ vm_delete_region(vm_get_kernel_aspace_id(), pci_region); return 0;}static struct pci_module_hooks pci_mod_hooks = { &pci_read_io_8, &pci_write_io_8, &pci_read_io_16, &pci_write_io_16, &pci_read_io_32, &pci_write_io_32, &get_nth_pci_info, &read_pci_config, &write_pci_config, NULL, // &ram_address};static module_header pci_module_header = { PCI_BUS_MODULE_NAME, MODULE_CURR_VERSION, MODULE_KEEP_LOADED, &pci_mod_hooks, &pci_module_init, &pci_module_uninit};module_header *modules[] = { &pci_module_header, NULL};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -