📄 pci.c
字号:
//=============================================================================
//
// pci.c
//
// PCI library
//
//=============================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): jskov, from design by nickg
// Contributors: jskov
// Date: 1999-08-09
// Purpose: PCI configuration
// Description:
// PCI bus support library.
// Handles simple resource allocation for devices.
// Can configure 64bit devices, but drivers may need special
// magic to access all of this memory space - this is platform
// specific and the driver must know how to handle it on its own.
//####DESCRIPTIONEND####
//
//=============================================================================
#include <pkgconf/hal.h>
#include <pkgconf/io_pci.h>
#include <cyg/io/pci_hw.h>
// CYG_PCI_PRESENT only gets defined for targets that provide PCI HAL support.
// See pci_hw.h for details.
#ifdef CYG_PCI_PRESENT
#include <cyg/io/pci.h>
#include <cyg/infra/cyg_ass.h>
static cyg_bool cyg_pci_lib_initialized = false;
static CYG_PCI_ADDRESS64 cyg_pci_memory_base;
static CYG_PCI_ADDRESS32 cyg_pci_io_base;
void
cyg_pci_init( void )
{
if (!cyg_pci_lib_initialized) {
cyg_pci_set_memory_base(HAL_PCI_ALLOC_BASE_MEMORY);
cyg_pci_set_io_base(HAL_PCI_ALLOC_BASE_IO);
// Initialize the PCI bus, preparing it for general access.
cyg_pcihw_init();
cyg_pci_lib_initialized = true;
}
}
//---------------------------------------------------------------------------
// Common device configuration access functions
void
cyg_pci_get_device_info ( cyg_pci_device_id devid, cyg_pci_device *dev_info )
{
int i;
unsigned char bar_count;
cyg_uint8 bus = CYG_PCI_DEV_GET_BUS(devid);
cyg_uint8 devfn = CYG_PCI_DEV_GET_DEVFN(devid);
cyg_uint8 header_type;
dev_info->devid = devid;
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_VENDOR,
&dev_info->vendor);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_DEVICE,
&dev_info->device);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_COMMAND,
&dev_info->command);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_STATUS,
&dev_info->status);
cyg_pcihw_read_config_uint32(bus, devfn, CYG_PCI_CFG_CLASS_REV,
&dev_info->class_rev);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_CACHE_LINE_SIZE,
&dev_info->cache_line_size);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_LATENCY_TIMER,
&dev_info->latency_timer);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_HEADER_TYPE,
&header_type);
dev_info->header_type = (cyg_pci_header_type) header_type;
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_BIST,
&dev_info->bist);
if ((dev_info->header_type & CYG_PCI_CFG_HEADER_TYPE_MASK) == CYG_PCI_HEADER_BRIDGE)
dev_info->num_bars = 2;
else
dev_info->num_bars = 6;
// Clear out all address info (the code below stops short)
for (i = 0; i < CYG_PCI_MAX_BAR; i++) {
dev_info->base_map[i] = 0xffffffff;
dev_info->base_address[i] = 0;
dev_info->base_size[i] = 0;
}
for (i = 0; i < dev_info->num_bars; i++) {
cyg_pcihw_read_config_uint32(bus, devfn,
CYG_PCI_CFG_BAR_BASE + 4*i,
&dev_info->base_address[i]);
}
// If device is disabled, probe BARs for sizes.
if ((dev_info->command & CYG_PCI_CFG_COMMAND_ACTIVE) == 0) {
bar_count = 0;
for (i = 0; i < dev_info->num_bars; i++){
cyg_uint32 size;
cyg_pcihw_write_config_uint32(bus, devfn,
CYG_PCI_CFG_BAR_BASE + 4*i,
0xffffffff);
cyg_pcihw_read_config_uint32(bus, devfn,
CYG_PCI_CFG_BAR_BASE + 4*i,
&size);
dev_info->base_size[i] = size;
dev_info->base_map[i] = 0xffffffff;
// Increment BAR count only if it has valid entry. BARs may not
// be in contiguous locations.
if (size != 0) {
++bar_count;
}
// Check for a 64bit memory region.
if (CYG_PCI_CFG_BAR_SPACE_MEM ==
(size & CYG_PCI_CFG_BAR_SPACE_MASK)) {
if (size & CYG_PRI_CFG_BAR_MEM_TYPE_64) {
// Clear fields for next BAR - it's the upper 32 bits.
i++;
dev_info->base_size[i] = 0;
dev_info->base_map[i] = 0xffffffff;
}
}
// Fix any IO devices that only implement the bottom 16
// bits of the the BAR. Just fill in these bits so it
// looks like a full 32 bit BAR.
if ((CYG_PCI_CFG_BAR_SPACE_IO ==
(size & CYG_PCI_CFG_BAR_SPACE_MASK)) &&
((size & 0xFFFF0000) == 0)
)
{
dev_info->base_size[i] |= 0xFFFF0000;
}
}
dev_info->num_bars = bar_count;
} else {
// If the device is already configured. Fill in the base_map.
CYG_PCI_ADDRESS64 tmp_addr;
cyg_uint32 bar;
bar_count = 0;
for (i = 0; i < dev_info->num_bars; i++){
dev_info->base_size[i] = 0;
bar = dev_info->base_address[i];
// Increment BAR count only if it has valid entry. BARs may not
// be in contiguous locations.
if (bar != 0) {
++bar_count;
}
if ((bar & CYG_PCI_CFG_BAR_SPACE_MASK) == CYG_PCI_CFG_BAR_SPACE_IO) {
dev_info->base_map[i] = (bar & CYG_PRI_CFG_BAR_IO_MASK) + HAL_PCI_PHYSICAL_IO_BASE;
bar &= CYG_PRI_CFG_BAR_IO_MASK;
if ((bar < 0xFF000000) && (bar >= cyg_pci_io_base)) {
// Assume that this device owns 512 'registers'
cyg_pci_io_base = bar + 0x200;
#ifdef CYGPKG_IO_PCI_DEBUG
diag_printf("Update I/O base to %x from bar: %d\n", cyg_pci_io_base, i);
#endif
}
} else {
tmp_addr = bar & CYG_PRI_CFG_BAR_MEM_MASK;
if ((bar & CYG_PRI_CFG_BAR_MEM_TYPE_MASK) == CYG_PRI_CFG_BAR_MEM_TYPE_64)
tmp_addr |= ((CYG_PCI_ADDRESS64)(dev_info->base_address[i+1] & CYG_PRI_CFG_BAR_MEM_MASK)) << 32;
if ((tmp_addr < 0xFF000000) && (tmp_addr >= cyg_pci_memory_base)) {
// Assume that this device owns 1M
cyg_pci_memory_base = tmp_addr + 0x100000;
#ifdef CYGPKG_IO_PCI_DEBUG
diag_printf("Update memory base to %llx from bar: %d\n", cyg_pci_memory_base, i);
#endif
}
tmp_addr += HAL_PCI_PHYSICAL_MEMORY_BASE;
dev_info->base_map[i] = tmp_addr;
if ((bar & CYG_PRI_CFG_BAR_MEM_TYPE_MASK) == CYG_PRI_CFG_BAR_MEM_TYPE_64)
dev_info->base_map[++i] = tmp_addr >> 32;
}
}
dev_info->num_bars = bar_count;
}
switch (dev_info->header_type & CYG_PCI_CFG_HEADER_TYPE_MASK) {
case CYG_PCI_HEADER_NORMAL:
cyg_pcihw_read_config_uint32(bus, devfn, CYG_PCI_CFG_CARDBUS_CIS,
&dev_info->header.normal.cardbus_cis);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_SUB_VENDOR,
&dev_info->header.normal.sub_vendor);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_SUB_ID,
&dev_info->header.normal.sub_id);
cyg_pcihw_read_config_uint32(bus, devfn, CYG_PCI_CFG_ROM_ADDRESS,
&dev_info->header.normal.rom_address);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_CAP_LIST,
&dev_info->header.normal.cap_list);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_INT_LINE,
&dev_info->header.normal.int_line);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_INT_PIN,
&dev_info->header.normal.int_pin);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_MIN_GNT,
&dev_info->header.normal.min_gnt);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_MAX_LAT,
&dev_info->header.normal.max_lat);
break;
case CYG_PCI_HEADER_BRIDGE:
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_PRI_BUS,
&dev_info->header.bridge.pri_bus);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_SEC_BUS,
&dev_info->header.bridge.sec_bus);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_SUB_BUS,
&dev_info->header.bridge.sub_bus);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_SEC_LATENCY_TIMER,
&dev_info->header.bridge.sec_latency_timer);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_IO_BASE,
&dev_info->header.bridge.io_base);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_IO_LIMIT,
&dev_info->header.bridge.io_limit);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_SEC_STATUS,
&dev_info->header.bridge.sec_status);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_MEM_BASE,
&dev_info->header.bridge.mem_base);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_MEM_LIMIT,
&dev_info->header.bridge.mem_limit);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_PREFETCH_BASE,
&dev_info->header.bridge.prefetch_base);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_PREFETCH_LIMIT,
&dev_info->header.bridge.prefetch_limit);
cyg_pcihw_read_config_uint32(bus, devfn, CYG_PCI_CFG_PREFETCH_BASE_UPPER32,
&dev_info->header.bridge.prefetch_base_upper32);
cyg_pcihw_read_config_uint32(bus, devfn, CYG_PCI_CFG_PREFETCH_LIMIT_UPPER32,
&dev_info->header.bridge.prefetch_limit_upper32);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_IO_BASE_UPPER16,
&dev_info->header.bridge.io_base_upper16);
cyg_pcihw_read_config_uint16(bus, devfn, CYG_PCI_CFG_IO_LIMIT_UPPER16,
&dev_info->header.bridge.io_limit_upper16);
cyg_pcihw_read_config_uint32(bus, devfn, CYG_PCI_CFG_BRIDGE_ROM_ADDRESS,
&dev_info->header.bridge.rom_address);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_INT_LINE,
&dev_info->header.bridge.int_line);
cyg_pcihw_read_config_uint8(bus, devfn, CYG_PCI_CFG_INT_PIN,
&dev_info->header.bridge.int_pin);
cyg_pcihw_read_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;
}
}
void
cyg_pci_set_device_info ( cyg_pci_device_id devid, cyg_pci_device *dev_info )
{
cyg_uint8 bus = CYG_PCI_DEV_GET_BUS(devid);
cyg_uint8 devfn = CYG_PCI_DEV_GET_DEVFN(devid);
int i;
// Only writable entries are updated.
cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_COMMAND,
dev_info->command);
cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_STATUS,
dev_info->status);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_CACHE_LINE_SIZE,
dev_info->cache_line_size);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_LATENCY_TIMER,
dev_info->latency_timer);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_BIST,
dev_info->bist);
// Check for all possible BARs because they may be non-contiguous
for (i = 0; i < CYG_PCI_MAX_BAR; i++) {
if (dev_info->base_address[i]) {
cyg_pcihw_write_config_uint32 (bus, devfn,
CYG_PCI_CFG_BAR_BASE+4*i,
dev_info->base_address[i]);
}
}
switch (dev_info->header_type & CYG_PCI_CFG_HEADER_TYPE_MASK) {
case CYG_PCI_HEADER_NORMAL:
cyg_pcihw_write_config_uint32(bus, devfn, CYG_PCI_CFG_CARDBUS_CIS,
dev_info->header.normal.cardbus_cis);
cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_SUB_VENDOR,
dev_info->header.normal.sub_vendor);
cyg_pcihw_write_config_uint16(bus, devfn, CYG_PCI_CFG_SUB_ID,
dev_info->header.normal.sub_id);
cyg_pcihw_write_config_uint32(bus, devfn, CYG_PCI_CFG_ROM_ADDRESS,
dev_info->header.normal.rom_address);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_INT_LINE,
dev_info->header.normal.int_line);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_INT_PIN,
dev_info->header.normal.int_pin);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_MIN_GNT,
dev_info->header.normal.min_gnt);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_MAX_LAT,
dev_info->header.normal.max_lat);
break;
case CYG_PCI_HEADER_BRIDGE:
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_PRI_BUS,
dev_info->header.bridge.pri_bus);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_SEC_BUS,
dev_info->header.bridge.sec_bus);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_SUB_BUS,
dev_info->header.bridge.sub_bus);
cyg_pcihw_write_config_uint8(bus, devfn, CYG_PCI_CFG_SEC_LATENCY_TIMER,
dev_info->header.bridge.sec_latency_timer);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -