📄 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_bool
cyg_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_bool
cyg_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_bool
cyg_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_bool
cyg_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_bool
cyg_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 + -