📄 pci.c
字号:
/************************************************************************ * * pci.c * * Generic PCI code * * ###################################################################### * * mips_start_of_legal_notice * * Copyright (c) 2004 MIPS Technologies, Inc. All rights reserved. * * * Unpublished rights (if any) reserved under the copyright laws of the * United States of America and other countries. * * This code is proprietary to MIPS Technologies, Inc. ("MIPS * Technologies"). Any copying, reproducing, modifying or use of this code * (in whole or in part) that is not expressly permitted in writing by MIPS * Technologies or an authorized third party is strictly prohibited. At a * minimum, this code is protected under unfair competition and copyright * laws. Violations thereof may result in criminal penalties and fines. * * MIPS Technologies reserves the right to change this code to improve * function, design or otherwise. MIPS Technologies does not assume any * liability arising out of the application or use of this code, or of any * error or omission in such code. Any warranties, whether express, * statutory, implied or otherwise, including but not limited to the implied * warranties of merchantability or fitness for a particular purpose, are * excluded. Except as expressly provided in any written license agreement * from MIPS Technologies or an authorized third party, the furnishing of * this code does not give recipient any license to any intellectual * property rights, including any patent rights, that cover this code. * * This code shall not be exported, reexported, transferred, or released, * directly or indirectly, in violation of the law of any country or * international law, regulation, treaty, Executive Order, statute, * amendments or supplements thereto. Should a conflict arise regarding the * export, reexport, transfer, or release of this code, the laws of the * United States of America shall be the governing law. * * This code constitutes one or more of the following: commercial computer * software, commercial computer software documentation or other commercial * items. If the user of this code, or any related documentation of any * kind, including related technical data or manuals, is an agency, * department, or other entity of the United States government * ("Government"), the use, duplication, reproduction, release, * modification, disclosure, or transfer of this code, or any related * documentation of any kind, is restricted in accordance with Federal * Acquisition Regulation 12.212 for civilian agencies and Defense Federal * Acquisition Regulation Supplement 227.7202 for military agencies. The use * of this code by the Government is further restricted in accordance with * the terms of the license agreement(s) and/or applicable contract terms * and conditions covering this code from MIPS Technologies or an authorized * third party. * * * * * mips_end_of_legal_notice * * ************************************************************************//************************************************************************ * Include files ************************************************************************/#include <sysdefs.h>#include <syserror.h>#include <pci.h>#include <pci_api.h>#include <product.h>#include <atlas.h>#include <syscon_api.h>#include <sys_api.h>#include <shell_api.h>#include <string.h>#include <stdio.h>/************************************************************************ * Definitions ************************************************************************//* Determine whether devices is of type 0 or 1 based on header type */#define DEV_PPB(dev) ( (dev)->ht == PCI_HEADERTYPE1 )/* PCI bus definition */typedef struct{ bool fastb2b; t_pci_bar *mem_largest_ptr; t_pci_bar *io_largest_ptr; UINT32 start_mem; UINT32 start_io; bool prefetch;}t_pci_cfg_bus;/* Determine whether device IDs equal device data */#define DEV_EQUAL( dev, vendor, device, func ) \ ( \ (dev->vendorid == vendor) && \ (dev->devid == device) && \ (dev->function == func) \ )/* Determine whether a device is known to YAMON */#define KNOWN_DEV( dev, known_dev ) \ DEV_EQUAL( dev, known_dev.vendorid, known_dev.devid, known_dev.function )#define KNOWN_BAR( dev, pos, bar_req ) \ (KNOWN_DEV( dev, bar_req ) && \ (pos == bar_req.bar.pos))/* Search for known device */#define SEARCH_KNOWN( dev, loopvar ) \ for( loopvar=0; \ (loopvar < known_devs_count) && \ !KNOWN_DEV( dev, known_devs[loopvar] ); \ loopvar++ ) \ { \ ; \ } /************************************************************************ * Public variables ************************************************************************/bool pci_alloc_err;/************************************************************************ * Static variables ************************************************************************//* Variables for device and bus data */static t_pci_cfg_dev dev_data[PCI_MAX_DEV];static t_pci_cfg_bus bus_data[PCI_MAX_BUS];static UINT32 dev_count;static UINT8 bus_count;/* Variables for holding parameters used by several functions */static t_known_dev *known_devs;static UINT32 known_devs_count;static t_pci_bar_req *bar_reqs;static UINT32 bar_reqs_count;/* Offsets : * The system controller supports remapping of memory * and IO ranges so that the addresses seen on the CPU side (SysAD) of * the controller and the addresses seen on PCI are offset by some amount. * The CPU side start address is found by adding the offset to the * PCI side start address. */static UINT32 pci_mem_offset;static UINT32 pci_io_offset;/* Error strings */static char* error_strings[] ={ /* ERROR_PCI_MALLOC */ "Not enough space for autoconfiguration", /* ERROR_PCI_RANGE */ "Illegal ram range", /* ERROR_PCI_UNKNOWN_DEVICE */ "Unknown PCI device", /* ERROR_PCI_ABORT */ "PCI master or target abort", /* ERROR_PCI_STRUCTURE */ "Structural error in PCI module"};/************************************************************************ * Static function prototypes ************************************************************************/static UINT32detect_devices( UINT32 maxbus, UINT32 maxdev );static UINT32config_system( UINT32 freemem_start, /* First valid mem address */ UINT32 freemem_end, /* First non valid mem address */ UINT32 freeio_start, /* First valid IO address */ UINT32 freeio_end, /* First non valid IO address */ UINT32 maxbus );static UINT32config_dev( t_pci_cfg_dev *dev, /* Device data */ UINT32 memlimit, /* Max valid mem address */ UINT32 iolimit ); /* Max valid io address */static UINT32query_dev( UINT32 bus, /* Bus number */ UINT32 devnum, /* Device number */ UINT32 function, /* Device function */ t_pci_cfg_dev *dev, /* Device data */ UINT32 maxbus );static boolfixed_memory_alloc( t_pci_cfg_dev *dev, UINT32 bar_index );static voidsetup_fixed_memory_alloc( t_pci_cfg_dev *dev );static UINT32alloc_space( UINT32 red_start, /* redpage, 0 -> IO space, !=0 -> memory space */ UINT32 red_end, UINT32 mem_start, UINT32 mem_end );static UINT32align( UINT32 addr, /* Address to be aligned */ UINT32 alignment ); /* Alignment requirement */static INT32 error_lookup( t_sys_error_string *param );/************************************************************************ * Implementation : Public functions ************************************************************************//************************************************************************ * * pci_init * Description : * ------------- * * PCI module initialisation function * * Return values : * --------------- * * OK if no error, else error code * ************************************************************************/UINT32pci_init( void ){ t_sys_error_lookup_registration registration; /* register error lookup function */ registration.prefix = SYSERROR_DOMAIN( ERROR_PCI ); registration.lookup = error_lookup; SYSCON_write( SYSCON_ERROR_REGISTER_LOOKUP_ID, ®istration, sizeof( registration ) ); /* Call platform specific configuration function */ return pci_config();} /************************************************************************ * * pci_autoconfig * Description : * ------------- * * Configure PCI based on platform requirements. * * Return values : * --------------- * * 0: no pci error, else error * ************************************************************************/UINT32pci_autoconfig( t_pci_bar_req *bar_req, /* Special BAR requirements */ UINT32 bar_req_count, /* Number of special BARs */ t_known_dev *known_dev, /* Array of known devices */ UINT32 known_dev_count ) /* Count of known devices */{ UINT32 rc, i; UINT32 mem_start; /* Start of PCI memory range */ UINT32 mem_size; /* Size of PCI memory range */ UINT32 io_start; /* Start of PCI io range */ UINT32 io_size; /* Size of PCI io range */ UINT32 maxbus, maxdev; /* Store data used by other functions */ known_devs = known_dev; known_devs_count = known_dev_count; bar_reqs = bar_req; bar_reqs_count = bar_req_count; /* Determine ranges : * * 1) Start of range as seen from PCI. * 2) Size of range. * 3) Offset of range. The system controller supports remapping of memory * and IO ranges so that the addresses seen on the CPU side (SysAD) of * the controller and the addresses seen on PCI are offset by some amount. * The CPU side start address is found by adding the offset to the * PCI side start address. */ SYSCON_read( SYSCON_CORE_PCI_MEM_START, (void *)&mem_start, sizeof(UINT32) ); SYSCON_read( SYSCON_CORE_PCI_MEM_SIZE, (void *)&mem_size, sizeof(UINT32) ); SYSCON_read( SYSCON_CORE_PCI_MEM_OFFSET, (void *)&pci_mem_offset, sizeof(UINT32) ); SYSCON_read( SYSCON_CORE_PCI_IO_START, (void *)&io_start, sizeof(UINT32) ); SYSCON_read( SYSCON_CORE_PCI_IO_SIZE, (void *)&io_size, sizeof(UINT32) ); SYSCON_read( SYSCON_CORE_PCI_IO_OFFSET, (void *)&pci_io_offset, sizeof(UINT32) ); /* Determine max number of busses and devices */ maxbus = PCI_MAX_BUS; /* Max number of PCI busses */ maxdev = PCI_MAX_DEV; /* Max number of PCI devices */ /* Detect devices */ rc = detect_devices( maxbus, maxdev ); if( rc != OK ) return rc; /* Configure system */ rc = config_system( mem_start, mem_start + mem_size, io_start, io_start + io_size, maxbus ); if( rc != OK ) return rc; /* Configure devices */ for(i=0; i<dev_count; i++) { rc = config_dev( &dev_data[i], mem_start + mem_size - 1, io_start + io_size - 1 ); if( rc != OK ) return rc; } return OK;}/************************************************************************ * * pci_config_write32/16/8 * Description : * ------------- * * Low level pci configuration space write routines (32/16/8 bit) * * Return values : * --------------- * * 0 (No error) or ERROR_PCI_ABORT * ************************************************************************/UINT32 pci_config_write32( UINT32 busnum, UINT32 devnum, UINT32 func, UINT32 reg, UINT32 data ){ return arch_pci_config_access( busnum, devnum, func, reg, TRUE, sizeof(UINT32), (void *)&data );}UINT32 pci_config_write16( UINT32 busnum, UINT32 devnum, UINT32 func, UINT32 reg, UINT16 data ){ return arch_pci_config_access( busnum, devnum, func, reg, TRUE, sizeof(UINT16), (void *)&data );}UINT32 pci_config_write8( UINT32 busnum, UINT32 devnum, UINT32 func, UINT32 reg, UINT8 data ){ return arch_pci_config_access( busnum, devnum, func, reg, TRUE, sizeof(UINT8), (void *)&data );}/************************************************************************ * * pci_config_read32/16/8 * Description : * ------------- * * Low level pci configuration space read routines (32/16/8 bit) * * Return values : * --------------- * * 0 (No error) or ERROR_PCI_ABORT * ************************************************************************/UINT32pci_config_read32( UINT32 busnum, UINT32 devnum, UINT32 func, UINT32 reg, UINT32 *data ){ return arch_pci_config_access( busnum, devnum, func, reg, FALSE, sizeof(UINT32), (void *)data );}UINT32pci_config_read16( UINT32 busnum, UINT32 devnum, UINT32 func, UINT32 reg, UINT16 *data ){ return arch_pci_config_access( busnum, devnum, func, reg, FALSE, sizeof(UINT16), (void *)data );}UINT32pci_config_read8( UINT32 busnum, UINT32 devnum, UINT32 func, UINT32 reg, UINT8 *data ){ return arch_pci_config_access( busnum, devnum, func, reg, FALSE, sizeof(UINT8), (void *)data );}/************************************************************************ * * pci_lookup_bar * Description : * ------------- * * Determine base address (physical) of specific BAR of specific device. * * Return values : * --------------- * * TRUE : BAR found * FALSE : BAR not found * ************************************************************************/boolpci_lookup_bar( UINT8 busnum, /* Bus number */ UINT8 devnum, /* Device number */ UINT8 func, /* Function number */ UINT8 bar, /* Address of BAR register */ void **param ) /* OUT : Base address of BAR */{ t_pci_cfg_dev *dev; UINT32 i; /* Default */ *param = NULL; for( i=0; i<dev_count; i++ ) { dev = &dev_data[i]; if (dev->bus == busnum && dev->dev == devnum && dev->function == func) break; } if( i<dev_count ) { for( i=0; i<dev->bar_count; i++ ) { if( dev->bar[i].pos == bar ) { *param = (void *) ( dev->bar[i].start + (dev->bar[i].io ? pci_io_offset : pci_mem_offset) );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -