📄 pci.c
字号:
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); // 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);}// Initialize devices on a given bus and all subordinate busses.cyg_boolcyg_pci_configure_bus( cyg_uint8 bus, cyg_uint8 *next_bus ){ cyg_uint8 devfn, header_type; cyg_pci_device_id devid; cyg_pci_device dev_info; CYG_PCI_ADDRESS64 mem_start, mem_limit, mem_base; CYG_PCI_ADDRESS32 io_start, io_limit, io_base; // Scan only this bus for valid devices. devid = CYG_PCI_DEV_MAKE_ID(bus, 0) | CYG_PCI_NULL_DEVFN;#ifdef CYGPKG_IO_PCI_DEBUG diag_printf("Configuring bus %d.\n", bus);#endif while (cyg_pci_find_next(devid, &devid) && bus == CYG_PCI_DEV_GET_BUS(devid)) { devfn = CYG_PCI_DEV_GET_DEVFN(devid); // Get the device info cyg_pci_get_device_info(devid, &dev_info);#ifdef CYGPKG_IO_PCI_DEBUG diag_printf("\n"); diag_printf("Configuring PCI Bus : %d\n", bus); diag_printf(" PCI Device: %d\n", CYG_PCI_DEV_GET_DEV(devfn)); diag_printf(" PCI Func : %d\n", CYG_PCI_DEV_GET_FN(devfn)); diag_printf(" Vendor Id : 0x%08X\n", dev_info.vendor); diag_printf(" Device Id : 0x%08X\n", dev_info.device);#endif header_type = dev_info.header_type & CYG_PCI_CFG_HEADER_TYPE_MASK; // Check for supported header types. if (header_type != CYG_PCI_HEADER_NORMAL && header_type != CYG_PCI_HEADER_BRIDGE) { CYG_FAIL("Unsupported PCI header type"); continue; } // Only PCI-to-PCI bridges if (header_type == CYG_PCI_HEADER_BRIDGE && (dev_info.class_rev >> 8) != CYG_PCI_CLASS_BRIDGE_PCI_PCI) { CYG_FAIL("Unsupported PCI bridge class"); continue; } // Configure the base registers if (!cyg_pci_configure_device(&dev_info)) { // Apparently out of resources. CYG_FAIL("cyg_pci_configure_device failed"); break; } // Activate non-bridge devices. if (header_type != CYG_PCI_HEADER_BRIDGE) { dev_info.command |= (CYG_PCI_CFG_COMMAND_IO // enable I/O space | CYG_PCI_CFG_COMMAND_MEMORY // enable memory space | CYG_PCI_CFG_COMMAND_MASTER); // enable bus master cyg_pci_write_config_uint16(dev_info.devid, CYG_PCI_CFG_COMMAND, dev_info.command); } else { // Bridge Configuration // Set up the bus numbers that define the bridge dev_info.header.bridge.pri_bus = bus; cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_PRI_BUS, dev_info.header.bridge.pri_bus); dev_info.header.bridge.sec_bus = *next_bus; cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_SEC_BUS, dev_info.header.bridge.sec_bus); // Temporarily set to maximum so config cycles get passed along. dev_info.header.bridge.sub_bus = CYG_PCI_MAX_BUS - 1; cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_SUB_BUS, dev_info.header.bridge.sub_bus); // increment bus counter *next_bus += 1; // To figure the sizes of the memory and I/O windows, save the // current base of memory and I/O before configuring the bus // or busses on the secondary side of the bridge. After the // secondary side is configured, the difference between the // current values and saved values will tell the size. // For bridges, the memory window must start and end on a 1M // boundary and the I/O window must start and end on a 4K // boundary. We round up the mem and I/O allocation bases // to appropriate boundaries before configuring the secondary // bus. Save the pre-rounded values in case no mem or I/O // is needed we can recover any space lost due to rounding. // round up start of PCI memory space to a 1M boundary mem_base = cyg_pci_memory_base; cyg_pci_memory_base += 0xfffff; cyg_pci_memory_base &= ~0xfffff; mem_start = cyg_pci_memory_base; // round up start of PCI I/O space to a 4 Kbyte start address io_base = cyg_pci_io_base; cyg_pci_io_base += 0xfff; cyg_pci_io_base &= ~0xfff; io_start = cyg_pci_io_base; // configure the subordinate PCI bus cyg_pci_configure_bus (dev_info.header.bridge.sec_bus, next_bus); // set subordinate bus number to last assigned bus number dev_info.header.bridge.sub_bus = *next_bus - 1; cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_SUB_BUS, dev_info.header.bridge.sub_bus); // Did sub bus configuration use any I/O? if (cyg_pci_io_base > io_start) { // round up end of bridge's I/O space to a 4K boundary cyg_pci_io_base += 0xfff; cyg_pci_io_base &= ~0xfff; io_limit = cyg_pci_io_base - 0x1000; // Enable I/O cycles across bridge dev_info.command |= CYG_PCI_CFG_COMMAND_IO; // 32 Bit I/O? if ((dev_info.header.bridge.io_base & 0x0f) == 0x01) { // I/O Base Upper 16 Bits Register dev_info.header.bridge.io_base_upper16 = io_start >> 16; cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_IO_BASE_UPPER16, dev_info.header.bridge.io_base_upper16); // I/O Limit Upper 16 Bits Register dev_info.header.bridge.io_limit_upper16 = io_limit >> 16; cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_IO_LIMIT_UPPER16, dev_info.header.bridge.io_limit_upper16); } // I/O Base Register dev_info.header.bridge.io_base = (io_start & 0xf000) >> 8; cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_IO_BASE, dev_info.header.bridge.io_base); // I/O Limit Register dev_info.header.bridge.io_limit = (io_limit & 0xf000) >> 8; cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_IO_LIMIT, dev_info.header.bridge.io_limit); } else { // No I/O space used on secondary bus. // Recover any space lost on unnecessary rounding cyg_pci_io_base = io_base; } // Did sub bus configuration use any memory? if (cyg_pci_memory_base > mem_start) { // round up end of bridge's PCI memory space to a 1M boundary cyg_pci_memory_base += 0xfffff; cyg_pci_memory_base &= ~0xfffff; mem_limit = cyg_pci_memory_base - 0x100000; // Enable memory cycles across bridge dev_info.command |= CYG_PCI_CFG_COMMAND_MEMORY; // Memory Base Register dev_info.header.bridge.mem_base = (mem_start >> 16) & 0xfff0; cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_MEM_BASE, dev_info.header.bridge.mem_base); // Memory Limit Register dev_info.header.bridge.mem_limit = (mem_limit >> 16) & 0xfff0; cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_MEM_LIMIT, dev_info.header.bridge.mem_limit); // Prefetchable memory not yet supported across bridges. // Disable by making limit < base { cyg_uint16 tmp_word; tmp_word = 0; cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_PREFETCH_LIMIT, tmp_word); tmp_word = 0xfff0; cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_PREFETCH_BASE, tmp_word); } } else { // No memory space used on secondary bus. // Recover any space lost on unnecessary rounding cyg_pci_memory_base = mem_base; } // Setup the bridge command register dev_info.command |= CYG_PCI_CFG_COMMAND_MASTER; dev_info.command |= CYG_PCI_CFG_COMMAND_SERR; cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_COMMAND, dev_info.command); /* Setup the Bridge Control Register */ dev_info.header.bridge.control |= CYG_PCI_CFG_BRIDGE_CTL_PARITY; dev_info.header.bridge.control |= CYG_PCI_CFG_BRIDGE_CTL_SERR; dev_info.header.bridge.control |= CYG_PCI_CFG_BRIDGE_CTL_MASTER; cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_BRIDGE_CONTROL, dev_info.header.bridge.control); } }#ifdef CYGPKG_IO_PCI_DEBUG diag_printf("Finished configuring bus %d.\n", bus);#endif return true;}#endif // ifdef CYG_PCI_PRESENT//-----------------------------------------------------------------------------// end of pci.c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -