📄 pci.c
字号:
t_pci_bar **pptr;
t_pci_bar *bar;
t_pci_cfg_dev *dev;
t_pci_cfg_bus *bus;
UINT32 rc;
UINT32 i,t;
UINT8 slotnum;
/* Default bus settings */
for( i=0; i<maxbus; i++ )
{
bus = &bus_data[i];
bus->fastb2b = TRUE;
bus->mem_largest_ptr = NULL;
bus->io_largest_ptr = NULL;
bus->prefetch = (i == PCI_BUS_LOCAL) ? FALSE : TRUE;
}
/* There are two types of BARs :
*
* 1) Configurable (normal) BARs.
* 2) Fixed BARS, ie BARs with fixed requirements for memory mapping.
*/
/* Sort configurable BARs for each bus based on memory requirements */
for( i=0; i<dev_count; i++ )
{
dev = &dev_data[i];
bus = &bus_data[dev->bus];
if( !fixed_memory_alloc( dev ) )
{
/* Normal configurable device */
for( t=0; t<dev->bar_count; t++ )
{
bar = &dev->bar[t];
bar->size = calc_mem( bar->mask );
bar->fixed = FALSE;
pptr = bar->io ?
&bus->io_largest_ptr :
&bus->mem_largest_ptr;
/* Insert in ordered linked list */
while( (*pptr != NULL) && ((*pptr)->size > bar->size) )
pptr = &((*pptr)->next);
bar->next = *pptr;
*pptr = bar;
}
}
}
/* Add fixed BARs to front of list */
for( i=0; i<dev_count; i++ )
{
dev = &dev_data[i];
bus = &bus_data[dev->bus];
if( fixed_memory_alloc( dev ) )
{
setup_fixed_memory_alloc( dev );
for( t=0; t<dev->bar_count; t++ )
{
bar = &dev->bar[t];
bar->fixed = TRUE;
pptr = bar->io ?
&bus->io_largest_ptr :
&bus->mem_largest_ptr;
/* Insert at front of list */
bar->next = *pptr;
*pptr = bar;
}
}
}
/* BAR impact on bus prefetch */
for(i=0; i<dev_count; i++ )
{
dev = &dev_data[i];
bus = &bus_data[dev->bus];
for(t=0; t<dev->bar_count; t++)
{
bar = &dev->bar[t];
if(!bar->prefetch)
bus->prefetch = FALSE;
}
}
/* Alloc memory address space */
rc = alloc_mem( FALSE, freemem_start, freemem_end );
if( rc != OK ) return rc;
/* Alloc I/O address space */
rc = alloc_mem( TRUE, freeio_start, freeio_end );
if( rc != OK ) return rc;
/* Device impacts on bus settings and store offsets */
for( i=0; i<dev_count; i++ )
{
dev = &dev_data[i];
/* Determine device impact on bus fastb2b */
if( !(dev->status & PCI_SC_STATUS_FBB_BIT))
{
bus_data[dev->bus].fastb2b = FALSE;
}
}
/* Device private settings */
for( i=0; i<dev_count; i++ )
{
dev = &dev_data[i];
dev->lat_tim = arch_pci_lattim( dev );
/* Determine interrupt line */
if( dev->bus == PCI_BUS_LOCAL )
{
/* Is it a PCI slot */
if( arch_pci_slot( dev->dev, &slotnum ) )
{
dev->intline = arch_pci_slot_intline( dev->dev, dev->intpin );
}
else
{
SEARCH_KNOWN( dev, t )
if( t == known_devs_count )
return ERROR_PCI_UNKNOWN_DEVICE;
else
dev->intline = known_devs[t].intline;
}
}
else
{
dev->intline = arch_pci_remote_intline( dev->intpin );
}
}
return OK;
}
/************************************************************************
* fixed_memory_alloc
************************************************************************/
static bool
fixed_memory_alloc(
t_pci_cfg_dev *dev )
{
/* Determine whether this function of a device has fixed memory
* mapping requirements.
*/
UINT32 i;
for( i=0; i<bar_reqs_count; i++ )
{
if( KNOWN_DEV( dev, bar_reqs[i] ) )
{
return TRUE;
}
}
return FALSE;
}
/************************************************************************
* setup_fixed_memory_alloc
************************************************************************/
static void
setup_fixed_memory_alloc(
t_pci_cfg_dev *dev )
{
/* Copy fixed memory allocation requirements from requirements
* array to the BAR in question.
*/
UINT32 i;
dev->bar_count = 0;
for( i=0; i<bar_reqs_count; i++ )
{
if( KNOWN_DEV( dev, bar_reqs[i] ) )
{
memcpy( &dev->bar[dev->bar_count++],
&bar_reqs[i].bar,
sizeof(t_pci_bar) );
}
}
}
/************************************************************************
* config_dev
************************************************************************/
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 */
{
UINT32 data;
UINT32 rc;
UINT32 i;
/* Store offsets */
dev->mem_offset = mem_offset;
dev->io_offset = io_offset;
/* Setup COMMAND field */
data = PCI_SC_CMD_IOS_BIT |
PCI_SC_CMD_MS_BIT |
PCI_SC_CMD_BM_BIT |
PCI_SC_CMD_PERR_BIT |
PCI_SC_CMD_SERR_BIT;
if( bus_data[dev->bus].fastb2b )
data |= PCI_SC_CMD_FBB_BIT;
rc = pci_config_write32( dev->bus,
dev->dev,
dev->function,
PCI_SC,
data );
if( rc != OK ) return rc;
/* Setup latency timer field */
rc = pci_config_write8( dev->bus,
dev->dev,
dev->function,
PCI_LATTIM,
dev->lat_tim );
if( rc != OK ) return rc;
/* Setup Interrupt Line field */
rc = pci_config_write8( dev->bus,
dev->dev,
dev->function,
PCI_INTLINE,
dev->intline );
if( rc != OK ) return rc;
/* Setup BARs */
for( i=0; i<dev->bar_count; i++ )
{
t_pci_bar *bar;
bar = &dev->bar[i];
rc = pci_config_write32( dev->bus,
dev->dev,
dev->function,
bar->pos,
bar->start );
if( rc != OK ) return rc;
}
if( DEV_PPB(dev) )
{
t_pci_cfg_bus *bus;
/**** PCI-PCI Bridge ****/
/* Secondary bus data */
bus = &bus_data[dev->bus + 1];
/* Secondary latency timer */
rc = pci_config_write8( dev->bus,
dev->dev,
dev->function,
PCI_LATTIM,
dev->lat_tim );
if( rc != OK ) return rc;
/* Secondary I/O base and limit (bit 15:12) */
data = ((bus->start_io & 0xF000) >> 8) << PCI_IO_BASE_SHF;
data |= ((iolimit & 0xF000) >> 8) << PCI_IO_LIMIT_SHF;
rc = pci_config_write32( dev->bus, dev->dev, dev->function, PCI_IO, data );
if( rc != OK ) return rc;
/* I/O base and limit (bit 31:16) */
data = ((bus->start_io >> 16) << PCI_UPPERIO_BASE_SHF) |
((iolimit >> 16) << PCI_UPPERIO_LIMIT_SHF);
rc = pci_config_write32( dev->bus, dev->dev, dev->function, PCI_UPPERIO, data );
if( rc != OK ) return rc;
/* Secondary memory base and limit */
if( bus->prefetch )
{
/* Disable non-prefetchable memory */
data = (0xFFF0 << PCI_MEM_BASE_SHF) |
(0x0000 << PCI_MEM_LIMIT_SHF);
}
else
{
/* Setup non-prefetchable memory (bit 31:20) */
data = ((bus->start_mem & 0xFFF00000) >> 16) << PCI_MEM_BASE_SHF;
data |= ((memlimit & 0xFFF00000) >> 16) << PCI_MEM_LIMIT_SHF;
}
rc = pci_config_write32( dev->bus, dev->dev, dev->function, PCI_MEM, data );
if( rc != OK ) return rc;
/* Secondary prefetchable memory base and limit */
if( bus->prefetch )
{
/* Setup prefetchable memory (bit 31:20) */
data = ((bus->start_mem & 0xFFF00000) >> 16) << PCI_PREFMEM_BASE_SHF;
data |= ((memlimit & 0xFFF00000) >> 16) << PCI_PREFMEM_LIMIT_SHF;
}
else
{
/* Disable prefetchable memory */
data = (0xFFF0 << PCI_PREFMEM_BASE_SHF) |
(0x0000 << PCI_PREFMEM_LIMIT_SHF);
}
rc = pci_config_write32( dev->bus, dev->dev, dev->function, PCI_PREFMEM, data );
if( rc != OK ) return rc;
/* Bridge control */
rc = pci_config_write16( dev->bus,
dev->dev,
dev->function,
PCI_BC,
PCI_BCII_BC_PERR_BIT |
PCI_BCII_BC_SERR_BIT |
PCI_BCII_BC_MA_BIT |
(bus->fastb2b ? PCI_BCII_BC_FBB_BIT : 0) );
if( rc != OK ) return rc;
}
return OK;
}
/************************************************************************
* calc_mem
************************************************************************/
static UINT32
calc_mem(
UINT32 mask )
{
UINT32 memory_required;
if( mask == 0 )
{
memory_required = 0;
}
else
{
for( memory_required = 1;
(mask & 1) == 0;
memory_required <<= 1, mask >>= 1 );
}
return memory_required;
}
/************************************************************************
* alloc_mem
************************************************************************/
static UINT32
alloc_mem(
bool io, /* TRUE -> IO space, FALSE -> memory space */
UINT32 mem_start,
UINT32 mem_end )
{
UINT32 i;
t_pci_cfg_bus *bus;
t_pci_bar *bar;
for( i=0; i < bus_count; i++ )
{
bus = &bus_data[i];
if( io )
{
mem_start = align( mem_start, PCI_ALIGN_IO );
bar = bus->io_largest_ptr;
bus->start_io =
( bar && bar->fixed ) ?
bar->start :
mem_start;
}
else
{
mem_start = align( mem_start, PCI_ALIGN_MEM );
bar = bus->mem_largest_ptr;
bus->start_mem =
( bar && bar->fixed ) ?
bar->start :
mem_start;
}
/* First the fixed */
while( bar && bar->fixed )
{
mem_start = MAX( mem_start, bar->start + bar->size );
if( mem_start > mem_end )
return ERROR_PCI_MALLOC;
bar = bar->next;
}
/* Now the configurable */
while( bar )
{
/* Alignment requirement for BAR */
mem_start = align( mem_start, bar->size );
bar->start = mem_start;
mem_start += bar->size;
if( mem_start > mem_end )
return ERROR_PCI_MALLOC;
bar = bar->next;
}
}
return OK;
}
/************************************************************************
* align
************************************************************************/
static UINT32
align(
UINT32 addr, /* Address to be aligned */
UINT32 alignment ) /* Alignment requirement */
{
UINT32 aligned_addr;
aligned_addr = addr & ~(alignment - 1);
return (aligned_addr == addr) ?
aligned_addr : aligned_addr + alignment;
}
/************************************************************************
* error_lookup
************************************************************************/
static INT32
error_lookup(
t_sys_error_string *param )
{
UINT32 index;
index = SYSERROR_ID( param->syserror );
if( index < sizeof(error_strings)/sizeof(char*) )
{
param->strings[SYSCON_ERRORMSG_IDX] = error_strings[index];
param->count = 1;
}
else
param->count = 0;
return OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -