📄 pci.c
字号:
/************************************************************************
*
* pci.c
*
* Generic PCI code
*
*
* ######################################################################
*
* Copyright (c) 1999-2000 MIPS Technologies, Inc. All rights reserved.
*
* Unpublished rights reserved under the Copyright Laws of the United States of
* America.
*
* This document contains information that is proprietary to MIPS Technologies,
* Inc. ("MIPS Technologies"). Any copying, modifying or use of this information
* (in whole or in part) which is not expressly permitted in writing by MIPS
* Technologies or a contractually-authorized third party is strictly
* prohibited. At a minimum, this information is protected under unfair
* competition laws and the expression of the information contained herein is
* protected under federal copyright laws. Violations thereof may result in
* criminal penalties and fines.
* MIPS Technologies or any contractually-authorized third party reserves the
* right to change the information contained in this document to improve
* function, design or otherwise. MIPS Technologies does not assume any
* liability arising out of the application or use of this information. Any
* license under patent rights or any other intellectual property rights owned
* by MIPS Technologies or third parties shall be conveyed by MIPS Technologies
* or any contractually-authorized third party in a separate license agreement
* between the parties.
* The information contained in this document constitutes one or more of the
* following: commercial computer software, commercial computer software
* documentation or other commercial items. If the user of this information, 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 information, 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 information 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 information from MIPS Technologies or any
* contractually-authorized third party.
*
************************************************************************/
/************************************************************************
* Include files
************************************************************************/
#include <sysdefs.h>
#include <syserror.h>
#include <pci.h>
#include <pci_api.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 )
/* Definition of a PCI bus */
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 )
/* 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
************************************************************************/
/************************************************************************
* 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;
t_pci_bar_req *bar_reqs;
UINT32 bar_reqs_count;
/* 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 UINT32
detect_devices(
UINT32 maxbus,
UINT32 maxdev );
static UINT32
config_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 UINT32
config_dev(
t_pci_cfg_dev *dev, /* Device data */
UINT32 memlimit, /* Max valid mem address */
UINT32 mem_offset, /* Offset of PCI memory range */
UINT32 iolimit, /* Max valid io address */
UINT32 io_offset ); /* Offset of PCI IO range */
static UINT32
query_dev(
UINT32 bus, /* Bus number */
UINT32 devnum, /* Device number */
UINT32 function, /* Device function */
t_pci_cfg_dev *dev, /* Device data */
UINT32 maxbus );
static bool
fixed_memory_alloc(
t_pci_cfg_dev *dev );
static void
setup_fixed_memory_alloc(
t_pci_cfg_dev *dev );
static UINT32
calc_mem(
UINT32 mask );
static UINT32
alloc_mem(
bool io, /* TRUE -> IO space, FALSE -> memory space */
UINT32 mem_start,
UINT32 mem_end );
static UINT32
align(
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
*
************************************************************************/
UINT32
pci_init(
UINT32 mem_start, /* Start of PCI memory range */
UINT32 mem_size, /* Size of PCI memory range */
UINT32 mem_offset, /* Offset of PCI memory range */
UINT32 io_start, /* Start of PCI io range */
UINT32 io_size, /* Size of PCI io range */
UINT32 io_offset ) /* Offset of PCI io range */
{
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( mem_start, mem_size, mem_offset,
io_start, io_size, io_offset );
}
/************************************************************************
*
* pci_autoconfig
* Description :
* -------------
*
* Configure PCI based on platform requirements.
*
* Return values :
* ---------------
*
* 0: no pci error, else error
*
************************************************************************/
UINT32
pci_autoconfig(
UINT32 mem_start, /* Start of PCI memory range */
UINT32 mem_size, /* Size of PCI memory range */
UINT32 mem_offset, /* Offset of PCI memory range */
UINT32 io_start, /* Start of PCI io range */
UINT32 io_size, /* Size of PCI io range */
UINT32 io_offset, /* Offset of PCI io range */
t_pci_bar_req *bar_req, /* Special BAR requirements */
UINT32 bar_req_count, /* Number of special BARs */
UINT32 maxbus, /* Max number of PCI busses */
UINT32 maxdev, /* Max number of PCI devices */
t_known_dev *known_dev, /* Array of known devices */
UINT32 known_dev_count ) /* Count of known devices */
{
UINT32 rc, i;
UINT32 data;
/* 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 max number of busses and devices */
maxbus = MIN( maxbus, PCI_MAX_BUS );
maxdev = MIN( maxdev, PCI_MAX_DEV );
/* 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,
mem_offset,
io_start + io_size - 1,
io_offset );
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
*
************************************************************************/
UINT32
pci_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 );
}
UINT32
pci_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 );
}
UINT32
pci_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_device
* Description :
* -------------
*
* Obtains data for device.
*
* If more than one device fits the IDs and function number, the
* device is selected based on the following priority :
*
* 1) Known local (bus 0) device
* 2) First unknown local (bus 0) device found (based on device number)
* 3) First unknown remote (bus != 0) device found (based on device number)
*
* Return values :
* ---------------
*
* TRUE : Device found
* FALSE : Device not found
*
************************************************************************/
bool
pci_lookup_device(
UINT16 vendorid, /* Vendor ID */
UINT16 devid, /* Device ID */
UINT8 function, /* Function number */
t_pci_cfg_dev *data ) /* Pointer to structure where
device data will be written */
{
t_pci_cfg_dev *dev;
t_pci_cfg_dev *found = NULL;
UINT32 i,t;
/* Since function detect_devices() scanned busses from 0 and up, and
* device numbers from 0 and up,
* we will find unknown devices in the order corresponding to the
* priority described in the function header.
*/
for( i=0; i<dev_count; i++ )
{
dev = &dev_data[i];
if( DEV_EQUAL( dev, vendorid, devid, function ) )
{
if( found == NULL )
found = dev;
else
{
/* If the new one is a known local device,
* it is selected
*/
SEARCH_KNOWN( dev, t );
if( t != known_devs_count )
{
found = dev;
}
}
}
}
if( found != NULL )
{
memcpy( data, found, sizeof(t_pci_cfg_dev) );
return TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -