📄 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 functions
void
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);
}
void
cyg_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 functions
void
cyg_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);
}
void
cyg_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);
}
void
cyg_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 functions
cyg_bool
cyg_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_bool
cyg_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_bool
cyg_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_bool
cyg_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 Allocation
void
cyg_pci_set_memory_base(CYG_PCI_ADDRESS64 base)
{
cyg_pci_memory_base = base;
}
void
cyg_pci_set_io_base(CYG_PCI_ADDRESS32 base)
{
cyg_pci_io_base = base;
}
cyg_bool
cyg_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_bool
cyg_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 + -