📄 pci.c
字号:
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_IO_BASE, dev_info->header.bridge.io_base); cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_IO_LIMIT, dev_info->header.bridge.io_limit); cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_SEC_STATUS, dev_info->header.bridge.sec_status); cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_MEM_BASE, dev_info->header.bridge.mem_base); cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_MEM_LIMIT, dev_info->header.bridge.mem_limit); cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_PREFETCH_BASE, dev_info->header.bridge.prefetch_base); cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_PREFETCH_LIMIT, dev_info->header.bridge.prefetch_limit); cyg_pcihw_write_config_uint32(bus, devfn, CYG_PCI_CFG_PREFETCH_BASE_UPPER32, dev_info->header.bridge.prefetch_base_upper32); cyg_pcihw_write_config_uint32(bus, devfn, CYG_PCI_CFG_PREFETCH_LIMIT_UPPER32, dev_info->header.bridge.prefetch_limit_upper32); cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_IO_BASE_UPPER16, dev_info->header.bridge.io_base_upper16); cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_IO_LIMIT_UPPER16, dev_info->header.bridge.io_limit_upper16); cyg_pcihw_write_config_uint32(bus, devfn, CYG_PCI_CFG_BRIDGE_ROM_ADDRESS, dev_info->header.bridge.rom_address); cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_INT_LINE, dev_info->header.bridge.int_line); cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_BRIDGE_CONTROL, dev_info->header.bridge.control); break; case CYG_PCI_HEADER_CARDBUS_BRIDGE: CYG_FAIL("PCI device header 'cardbus bridge' support not implemented"); break; default: CYG_FAIL("Unknown PCI device header type"); break; } // Update values in dev_info. cyg_pci_get_device_info(devid, dev_info);}//---------------------------------------------------------------------------// Specific device configuration access functionsvoid cyg_pci_read_config_uint8( cyg_pci_device_id devid, cyg_uint8 offset, cyg_uint8 *val){ cyg_pcihw_read_config_uint8(CYG_PCI_DEV_GET_BUS(devid), CYG_PCI_DEV_GET_DEVFN(devid), offset, val);}void cyg_pci_read_config_uint16( cyg_pci_device_id devid, cyg_uint8 offset, cyg_uint16 *val){ cyg_pcihw_read_config_uint16(CYG_PCI_DEV_GET_BUS(devid), CYG_PCI_DEV_GET_DEVFN(devid), offset, val);}voidcyg_pci_read_config_uint32( cyg_pci_device_id devid, cyg_uint8 offset, cyg_uint32 *val){ cyg_pcihw_read_config_uint32(CYG_PCI_DEV_GET_BUS(devid), CYG_PCI_DEV_GET_DEVFN(devid), offset, val);}// Write functionsvoidcyg_pci_write_config_uint8( cyg_pci_device_id devid, cyg_uint8 offset, cyg_uint8 val){ cyg_pcihw_write_config_uint8(CYG_PCI_DEV_GET_BUS(devid), CYG_PCI_DEV_GET_DEVFN(devid), offset, val);}voidcyg_pci_write_config_uint16( cyg_pci_device_id devid, cyg_uint8 offset, cyg_uint16 val){ cyg_pcihw_write_config_uint16(CYG_PCI_DEV_GET_BUS(devid), CYG_PCI_DEV_GET_DEVFN(devid), offset, val);}voidcyg_pci_write_config_uint32( cyg_pci_device_id devid, cyg_uint8 offset, cyg_uint32 val){ cyg_pcihw_write_config_uint32(CYG_PCI_DEV_GET_BUS(devid), CYG_PCI_DEV_GET_DEVFN(devid), offset, val);}//------------------------------------------------------------------------// Device find functionscyg_boolcyg_pci_find_next( cyg_pci_device_id cur_devid, cyg_pci_device_id *next_devid ){ cyg_uint8 bus = CYG_PCI_DEV_GET_BUS(cur_devid); cyg_uint8 devfn = CYG_PCI_DEV_GET_DEVFN(cur_devid); cyg_uint8 dev = CYG_PCI_DEV_GET_DEV(devfn); cyg_uint8 fn = CYG_PCI_DEV_GET_FN(devfn);#ifdef CYGPKG_IO_PCI_DEBUG diag_printf("cyg_pci_find_next: start[%x] ...\n",(unsigned)cur_devid);#endif // If this is the initializer, start with 0/0/0 if (CYG_PCI_NULL_DEVID == cur_devid) { bus = dev = fn = 0; dev = CYG_PCI_MIN_DEV; } else if (CYG_PCI_NULL_DEVFN == (cur_devid & CYG_PCI_NULL_DEVFN)) { dev = fn = 0; dev = CYG_PCI_MIN_DEV; } else { // Otherwise, check multi-function bit of device's first function cyg_uint8 header; devfn = CYG_PCI_DEV_MAKE_DEVFN(dev, 0); cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_HEADER_TYPE, &header); if (header & CYG_PCI_CFG_HEADER_TYPE_MF) { // Multi-function device. Increase fn. fn++; if (fn >= CYG_PCI_MAX_FN) { fn = 0; dev++; } } else { // Single-function device. Skip to next. dev++; } } // Note: Reset iterators in enclosing statement's "next" part. // Allows resuming scan with given input values. for (;bus < CYG_PCI_MAX_BUS; bus++, dev=CYG_PCI_MIN_DEV) { for (;dev < CYG_PCI_MAX_DEV; dev++, fn=0) { for (;fn < CYG_PCI_MAX_FN; fn++) { cyg_uint16 vendor; if (CYG_PCI_IGNORE_DEVICE(bus, dev, fn)) continue; devfn = CYG_PCI_DEV_MAKE_DEVFN(dev, fn); cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_VENDOR, &vendor); if (CYG_PCI_VENDOR_UNDEFINED != vendor) {#ifdef CYGPKG_IO_PCI_DEBUG diag_printf(" Bus: %d, Dev: %d, Fn: %d, Vendor: %x\n", bus, dev, fn, vendor);#endif *next_devid = CYG_PCI_DEV_MAKE_ID(bus, devfn); return true; } } } }#ifdef CYGPKG_IO_PCI_DEBUG diag_printf("nothing.\n");#endif return false;}//// Scan for a particular device, starting with 'devid'// 'devid' is updated with the next device if found.// is not changed if no suitable device is found.cyg_boolcyg_pci_find_device( cyg_uint16 vendor, cyg_uint16 device, cyg_pci_device_id *devid ){ cyg_pci_device_id new_devid = *devid;#ifdef CYGPKG_IO_PCI_DEBUG diag_printf("cyg_pci_find_device - vendor: %x, device: %x\n", vendor, device);#endif // Scan entire bus, check for matches on valid devices. while (cyg_pci_find_next(new_devid, &new_devid)) { cyg_uint8 bus = CYG_PCI_DEV_GET_BUS(new_devid); cyg_uint8 devfn = CYG_PCI_DEV_GET_DEVFN(new_devid); cyg_uint16 v, d; // Check that vendor matches. cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_VENDOR, &v); cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_DEVICE, &d);#ifdef CYGPKG_IO_PCI_DEBUG diag_printf("... PCI vendor = %x, device = %x\n", v, d);#endif if (v != vendor) continue; // Check that device matches. if (d == device) {#ifdef CYGPKG_IO_PCI_DEBUG diag_printf("Found it!\n");#endif *devid = new_devid; return true; } } return false;}cyg_boolcyg_pci_find_class( cyg_uint32 dev_class, cyg_pci_device_id *devid ){ // Scan entire bus, check for matches on valid devices. while (cyg_pci_find_next(*devid, devid)) { cyg_uint8 bus = CYG_PCI_DEV_GET_BUS(*devid); cyg_uint8 devfn = CYG_PCI_DEV_GET_DEVFN(*devid); cyg_uint32 c; // Check that class code matches. cyg_pcihw_read_config_uint32(bus, devfn, CYG_PCI_CFG_CLASS_REV, &c); c >>= 8; if (c == dev_class) return true; } return false;}cyg_boolcyg_pci_find_matching( cyg_pci_match_func *matchp, void * match_callback_data, cyg_pci_device_id *devid ){ cyg_pci_device_id new_devid = *devid;#ifdef CYGPKG_IO_PCI_DEBUG diag_printf("cyg_pci_find_matching - func is at %x\n", (unsigned int)matchp);#endif // Scan entire bus, check for matches on valid devices. while (cyg_pci_find_next(new_devid, &new_devid)) { cyg_uint8 bus = CYG_PCI_DEV_GET_BUS(new_devid); cyg_uint8 devfn = CYG_PCI_DEV_GET_DEVFN(new_devid); cyg_uint16 v, d; cyg_uint32 c; // Check that vendor, device and class match. cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_VENDOR, &v); cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_DEVICE, &d); cyg_pcihw_read_config_uint32(bus, devfn, CYG_PCI_CFG_CLASS_REV, &c); c >>= 8;#ifdef CYGPKG_IO_PCI_DEBUG diag_printf("... PCI vendor = %x, device = %x, class %x\n", v, d, c);#endif // Check that device matches as the caller desires: if ( (*matchp)(v, d, c, match_callback_data) ) { *devid = new_devid; return true; } } return false;}//------------------------------------------------------------------------// Resource Allocationvoidcyg_pci_set_memory_base(CYG_PCI_ADDRESS64 base){ cyg_pci_memory_base = base;}voidcyg_pci_set_io_base(CYG_PCI_ADDRESS32 base){ cyg_pci_io_base = base;}cyg_boolcyg_pci_configure_device( cyg_pci_device *dev_info ){ int bar; cyg_uint32 flags; cyg_bool ret = true; // If device is already active, just return true as // cyg_pci_get_device_info has presumably filled in // the base_map already. if ((dev_info->command & CYG_PCI_CFG_COMMAND_ACTIVE) != 0) return true; if (dev_info->num_bars > 0) { for (bar = 0; bar < CYG_PCI_MAX_BAR; bar++) { if (!dev_info->base_address[bar]) { continue; } flags = dev_info->base_size[bar]; ret = false; if ((flags & CYG_PCI_CFG_BAR_SPACE_MASK) == CYG_PCI_CFG_BAR_SPACE_MEM){ ret |= cyg_pci_allocate_memory(dev_info, bar, &cyg_pci_memory_base); // If this is a 64bit memory region, skip the next bar // since it will contain the top 32 bits. if (flags & CYG_PRI_CFG_BAR_MEM_TYPE_64) bar++; } else ret |= cyg_pci_allocate_io(dev_info, bar, &cyg_pci_io_base); if (!ret) return ret; } } cyg_pci_translate_interrupt(dev_info, &dev_info->hal_vector); return ret;}// This is the function that handles resource allocation. It doesn't// affect the device state.// Should not be called with top32bit-bar of a 64bit pair.inline cyg_boolcyg_pci_allocate_memory_priv( cyg_pci_device *dev_info, cyg_uint32 bar, CYG_PCI_ADDRESS64 *base, CYG_PCI_ADDRESS64 *assigned_addr){ cyg_uint32 mem_type, flags; CYG_PCI_ADDRESS64 size, aligned_addr; // Get the probed size and flags flags = dev_info->base_size[bar]; // Decode size size = (CYG_PCI_ADDRESS64) ((~(flags & CYG_PRI_CFG_BAR_MEM_MASK))+1); // Calculate address we will assign the device. // This can be made more clever, specifically: // 1) The lowest 1MB should be reserved for devices with 1M memory type. // : Needs to be handled. // 2) The low 32bit space should be reserved for devices with 32bit type. // : With the usual handful of devices it is unlikely that the // low 4GB space will become full. // 3) A bitmap can be used to avoid fragmentation. // : Again, unlikely to be necessary. // // For now, simply align to required size. aligned_addr = (*base+size-1) & ~(size-1); // Is the request for memory space?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -