⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pci.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
        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 + -