📄 pci.c
字号:
// 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=0) { for (;dev < CYG_PCI_MAX_DEV; dev++, fn=0) { for (;fn < CYG_PCI_MAX_FN; fn++) { cyg_uint16 vendor; 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) { *next_devid = CYG_PCI_DEV_MAKE_ID(bus, devfn); return true; } } } } return false;}cyg_boolcyg_pci_find_device( cyg_uint16 vendor, cyg_uint16 device, 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_uint16 v, d; // Check that vendor matches. cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_VENDOR, &v); if (v != vendor) continue; // Check that device matches. cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_DEVICE, &d); if (d == device) 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;}//------------------------------------------------------------------------// Resource Allocationstatic CYG_PCI_ADDRESS64 cyg_pci_memory_base = HAL_PCI_ALLOC_BASE_MEMORY;static CYG_PCI_ADDRESS32 cyg_pci_io_base = HAL_PCI_ALLOC_BASE_IO;voidcyg_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 = false; // Check that device is inactive. if ((dev_info->command & CYG_PCI_CFG_COMMAND_ACTIVE) != 0) return false; for (bar = 0; bar < CYG_PCI_MAX_BAR; bar++) { flags = dev_info->base_size[bar]; // No reason to scan beyond first inactive BAR. if (0 == flags) break; 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); 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? if (CYG_PCI_CFG_BAR_SPACE_MEM != (flags & CYG_PCI_CFG_BAR_SPACE_MASK)) return false; // Check type of memory requested... mem_type = CYG_PRI_CFG_BAR_MEM_TYPE_MASK & flags; // We don't handle <1MB devices optimally yet. if (CYG_PRI_CFG_BAR_MEM_TYPE_1M == mem_type && (aligned_addr + size) > 1024*1024) return false; // Update the resource pointer and return values. *base = aligned_addr+size; *assigned_addr = aligned_addr; dev_info->base_map[bar] = (cyg_uint32) (aligned_addr+HAL_PCI_PHYSICAL_MEMORY_BASE) & 0xffffffff; // If a 64bit region, store upper 32 bits in the next bar. // Note: The CPU is not necessarily able to access the region // linearly - it may have to do it in segments. Driver must handle that. if (CYG_PRI_CFG_BAR_MEM_TYPE_64 == mem_type) { dev_info->base_map[bar+1] = (cyg_uint32) ((aligned_addr+HAL_PCI_PHYSICAL_MEMORY_BASE) >> 32) & 0xffffffff; } return true;}cyg_boolcyg_pci_allocate_memory( cyg_pci_device *dev_info, cyg_uint32 bar, CYG_PCI_ADDRESS64 *base){ cyg_uint8 bus = CYG_PCI_DEV_GET_BUS(dev_info->devid); cyg_uint8 devfn = CYG_PCI_DEV_GET_DEVFN(dev_info->devid); CYG_PCI_ADDRESS64 assigned_addr; cyg_bool ret; // Check that device is inactive. if ((dev_info->command & CYG_PCI_CFG_COMMAND_ACTIVE) != 0) return false; // Allocate memory space for the device. ret = cyg_pci_allocate_memory_priv(dev_info, bar, base, &assigned_addr); if (ret) { // Map the device and update the BAR in the dev_info structure. cyg_pcihw_write_config_uint32(bus, devfn, CYG_PCI_CFG_BAR_BASE+4*bar, (cyg_uint32) (assigned_addr & 0xffffffff)); cyg_pcihw_read_config_uint32(bus, devfn, CYG_PCI_CFG_BAR_BASE+4*bar, &dev_info->base_address[bar]); // Handle upper 32 bits if necessary. if (dev_info->base_size[bar] & CYG_PRI_CFG_BAR_MEM_TYPE_64) { cyg_pcihw_write_config_uint32(bus, devfn, CYG_PCI_CFG_BAR_BASE+4*(bar+1), (cyg_uint32) ((assigned_addr >> 32)& 0xffffffff)); cyg_pcihw_read_config_uint32(bus, devfn, CYG_PCI_CFG_BAR_BASE+4*(bar+1), &dev_info->base_address[bar+1]); } } return ret;} cyg_boolcyg_pci_allocate_io_priv( cyg_pci_device *dev_info, cyg_uint32 bar, CYG_PCI_ADDRESS32 *base, CYG_PCI_ADDRESS32 *assigned_addr){ cyg_uint32 flags, size; CYG_PCI_ADDRESS32 aligned_addr; // Get the probed size and flags flags = dev_info->base_size[bar]; // Decode size size = (~(flags & CYG_PRI_CFG_BAR_IO_MASK))+1; // Calculate address we will assign the device. // This can be made more clever. // For now, simply align to required size. aligned_addr = (*base+size-1) & ~(size-1); // Ensure the region fits within the 1MB IO space if (aligned_addr+size > 1024*1024) return false; // Is the request for IO space? if (CYG_PCI_CFG_BAR_SPACE_IO != (flags & CYG_PCI_CFG_BAR_SPACE_MASK)) return false; // Update the resource pointer and return values. *base = aligned_addr+size; dev_info->base_map[bar] = aligned_addr+HAL_PCI_PHYSICAL_IO_BASE; *assigned_addr = aligned_addr; return true;}cyg_boolcyg_pci_allocate_io( cyg_pci_device *dev_info, cyg_uint32 bar, CYG_PCI_ADDRESS32 *base){ cyg_uint8 bus = CYG_PCI_DEV_GET_BUS(dev_info->devid); cyg_uint8 devfn = CYG_PCI_DEV_GET_DEVFN(dev_info->devid); CYG_PCI_ADDRESS32 assigned_addr; cyg_bool ret; // Check that device is inactive. if ((dev_info->command & CYG_PCI_CFG_COMMAND_ACTIVE) != 0) return false; // Allocate IO space for the device. ret = cyg_pci_allocate_io_priv(dev_info, bar, base, &assigned_addr); if (ret) { // Map the device and update the BAR in the dev_info structure. cyg_pcihw_write_config_uint32(bus, devfn, CYG_PCI_CFG_BAR_BASE+4*bar, assigned_addr); cyg_pcihw_read_config_uint32(bus, devfn, CYG_PCI_CFG_BAR_BASE+4*bar, &dev_info->base_address[bar]); } return ret;}cyg_boolcyg_pci_translate_interrupt( cyg_pci_device *dev_info, CYG_ADDRWORD *vec ){ cyg_uint8 bus = CYG_PCI_DEV_GET_BUS(dev_info->devid); cyg_uint8 devfn = CYG_PCI_DEV_GET_DEVFN(dev_info->devid); return cyg_pcihw_translate_interrupt(bus, devfn, vec);}#endif // ifdef CYG_PCI_PRESENT//-----------------------------------------------------------------------------// end of pci.c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -