📄 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;voidcyg_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 functionsvoid 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 + -