📄 pciiomaplib.c
字号:
/* pciIomapLib.c - Support for PCI drivers */
/* Copyright 1984-2002 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/*
modification history
--------------------
01g,25apr02,to use more appropriate macro.
01f,03dec01,rec fix compiler warnings
01e,10sep01,jb Fix PCI memory mapping
01d,17may00,jgn fix pciFindDevice.
01c,08mar00,jpd changed include of pciIomapLib.h to be from local directory.
01b,17feb00,jpd made more style-guide-conformant.
01a,13jan00,pr adapted from cma220.
*/
/*
DESCRIPTION
This library is PCI Revision 2.1 compliant.
This module contains routines to support PCI bus mapped on IO address space
for x86 and PowerPC architecture. Functions in this library should not be
called from the interrupt level, except pciInt(), since it uses a mutual
exclusion semaphore for consecutive register access.
The functions addressed here include:
- Initialize the library.
- Locate the device by deviceID and vendorID.
- Locate the device by classCode.
- Generate the special cycle.
- Access its configuration registers.
- Connect a shared interrupt handler.
- Disconnect a shared interrupt handler.
- Master shared interrupt handler.
There are functions to access the IO address space. In x86 architecture,
they are sysInXXX() and sysOutXXX(). Macro PCI_IN_XXX() and PCI_OUT_XXX()
are provided to use other IO address space functions.
The PCI IO base address is defined by the static variable pciIoBase.
Each new IO space will increment this variable (see function
pciAllocateIOSpace().
The V3 chip provides three windows through which accesses can be made by
system bus masters to the PCI bus. We use overlaping windows so to access
the IO space the mapping needs to be changed otherwise accesses will result in
a data error. For this window 1 is re-used and remapped to CPU_PCI_CNFG_ADRS.
However, before that window 0 must be remapped to ensure that application
software can access the address space normally assigned to window 1 while
window 1 is re-used for configuration cycles (cf. v3OpenConfigWindow())
Shared PCI interrupt are supported by three functions: pciInt(),
pciIntConnect(), pciIntDisconnect(). pciIntConnect() adds the specified
interrupt handler to the link list and pciIntDisconnect() removes it from
the link list. Master interrupt handler pciInt() executes these interrupt
handlers in the link list for a PCI interrupt. Each interrupt handler must
check the device dependent interrupt status bit to determine the source of
the interrupt, since it simply execute all interrupt handlers in the link
list. pciInt() should be attached by intConnect() function in the BSP
initialization with its parameter. The parameter is an IRQ associated
to the PCI interrupt.
The maximum number of Type-1 Configuration Space buses supported in the 2.1
Specifications is 256 (0x00 - 0xFF), far greater than most systems currently
support. Most buses are numbered sequentially from 0. An optional define
called PCI_MAX_BUS may be declared in config.h to override the default
definition of 256. Similarly, the default number of devices and functions
may be overriden by defining PCI_MAX_DEV and/or PCI_MAX_FUNC. Note that
the number of devices applies only to bus zero, all others being restricted
to 16 by the 2.1 spec.
*/
#if defined(INCLUDE_PCI)
#include "vxWorks.h"
#include "config.h"
#include "dllLib.h"
#include "sysLib.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "intLib.h"
/*
* We currently wish to include this from locally rather than from
* there as that version is out-dated. However, as it has been included
* in sysLib.c already, this will do no harm.
*/
#include "pciIomapLib.h"
#include "ks8695p.h"
/* defines */
/*
* The following defines specify, by default, the maximum number of busses,
* devices and functions allowed by the PCI 2.1 Specification.
*
* Any or all may be overriden by defining them in config.h.
*/
#ifndef PCI_MAX_BUS
# define PCI_MAX_BUS 256
#endif /* PCI_MAX_BUS */
#ifndef PCI_MAX_DEV
# define PCI_MAX_DEV 21
#endif /* PCI_MAX_DEV */
#ifndef PCI_MAX_FUNC
# define PCI_MAX_FUNC 8
#endif /* PCI_MAX_FUNC */
/* globals */
STATUS pciLibInitStatus = NONE; /* initialization done */
DL_LIST pciIntList[PCI_IRQ_LINES]; /* link list of int handlers */
int pciConfigMech = NONE; /* 1=mechanism-1, 2=mechanism-2 */
static UINT32 pciIoBase = PCI_IO_ADRS; /* value for start of PCI IO */
static UINT32 pciMemBase = PCI_MEM_ADRS;/* value for start of PCI memory */
#define MAX(val1, val2) ( ((val1) > (val2)) ? val1 : val2 )
#define DEFAULT_MEMORY_ALIGNMENT 0x1000
#define DEFAULT_IO_ALIGNMENT 0x800
/* locals */
LOCAL int pciConfigAddr0; /* config-addr-reg, CSE-reg*/
LOCAL int pciConfigAddr1; /* config-data-reg, forward-reg */
LOCAL int pciConfigAddr2; /* not-used, base-addr */
/*******************************************************************************
*
* align - returns an aligned value
*
* RETURNS: aligned value
*/
static unsigned int align
(
unsigned int val, /* value to align */
unsigned int align
)
{
/*
* Some heuristics:
* if the value is zero, it is aligned, no matter what the size is.
*/
if (val == 0)
return val;
/* if the value is less than the alignment, return the alignment */
if (val < align)
return align;
/* finally, if there is need to move the value upwards, do so... */
if ((val & ~(align - 1)) != 0)
return (((val) + ((align) - 1)) & ~((align) - 1));
else
return val;
}
/*******************************************************************************
*
* pciMapInterrupt - map a PCI interrupt
*
* This routine caclculates the interrupt number that this slot/pin
* combination will use.
*
* RETURNS: board-specific interrupt number
*/
UINT8 pciMapInterrupt
(
UINT8 pin, /* pin number (A=1, B=2, C=3, D=4) */
UINT8 slot /* slot number (IDSEL = slot + 11) */
)
{
/* For KS8695P demo board, the PCI interrupt pin is hard-wired to External I/O Pin 0 */
return INT_LVL_EXTI0S;
}
/*******************************************************************************
*
* pciAllocateMemSpace - allocate space in PCI memory
*
* This routine allocates space within PCI memory space.
*
* RETURNS: Where in PCI memory allocated
*
* NOTE: Calling this code has a side effect of moving the global
* Memory base on.
*/
static unsigned int pciAllocateMemSpace
(
unsigned int size
)
{
unsigned int alignto;
unsigned int base;
/* align in minimum sized chunks of DEFAULT_MEMORY_ALIGNMENT */
alignto = MAX (size, DEFAULT_MEMORY_ALIGNMENT);
base = align (pciMemBase, alignto);
pciMemBase = base + size;
return base;
}
/*******************************************************************************
*
* pciAllocateIOSpace - allocate space in PCI I/O memory
*
* This routine allocates space requested within the PCI I/O space.
*
* RETURNS: where in PCI memory allocated
*
* NOTE: Calling this code has a side effect of moving the global
* I/O base on.
*/
static unsigned int pciAllocateIOSpace
(
unsigned int size
)
{
unsigned int alignto;
unsigned int base;
/* align in minimum sized chunks of DEFAULT_IO_ALIGNMENT */
alignto = MAX (size, DEFAULT_IO_ALIGNMENT);
base = align (pciIoBase, alignto);
pciIoBase = base + size;
return base;
}
/*******************************************************************************
*
* pciAllocateInterrupt - allocate an interrupt number
*
* This routine allocates an interrupt number.
*
* RETURNS: N/A
*/
void pciAllocateInterrupt
(
int bus, /* bus number */
int slot, /* device number */
int func /* function number */
)
{
char pin;
unsigned char interrupt;
/* read the interrupt pin from the device */
pciConfigInByte (bus, slot, func, PCI_CFG_DEV_INT_PIN, &pin);
/* work out the interrupt number from the slot/pin */
interrupt = pciMapInterrupt (pin, slot);
/* write it to the device (this will be read later by a device driver) */
pciConfigOutByte (bus, slot, func, PCI_CFG_DEV_INT_LINE, interrupt);
}
/*******************************************************************************
*
* pciAssignResources - assign PCI resources
*
* This routine will attempt to glean resource requirements from the
* device specified.
*
* RETURNS: N/A
*/
void pciAssignResources
(
int bus, /* bus number */
int slot, /* device number */
int func /* function number */
)
{
unsigned int offset = PCI_MEM_BAR;
unsigned int base, mask, size;
int i, barFlag = 0;
/*
* set up the bus, slot and func
*
* Disable PCI I/O and memory accesses
*/
pciConfigOutWord (bus, slot, func, PCI_CFG_COMMAND, 0);
/* allocate an irq number */
pciAllocateInterrupt (bus, slot, func);
/* Scan each of the BARS for this device */
for (i = 0; i < PCI_MAX_BAR; i++)
{
/* write PCI_INVALID to BAR to get size, then read it back */
pciConfigOutLong (bus, slot, func, offset, PCI_INVALID);
pciConfigInLong (bus, slot, func, offset, (int *) &base);
/* check if this is an implemented BAR (size != 0) */
if (base != 0)
{
/* Assign some PCI memory (IO or Memory) space to this BAR */
if (base & PCI_CMD_IO_ENABLE)
{
/* -- IO space BAR --
*
* The bottom 2 bits of the BAR for PCI IO look like this:
* 0 must be 1 (0 = memory, 1 = IO)
* 1 reserved
*
* figure out how much memory is wanted
*/
base &= (~0x3);
mask = (~base << 1) | 0x1;
size = (mask & base) & 0xFFFFFFFF;
/* allocate (aligned) space in IO */
base = pciAllocateIOSpace (size);
pciConfigOutLong(bus, slot, func, offset, base | 0x1);
barFlag |= PCI_CMD_IO_ENABLE;
}
else
{
/* -- MEM space BAR --
*
* WARNING: we assume only one type of memory - dangerous!
*/
unsigned int type;
/*
* The bottom 4 bits of the BAR for PCI memory look like this:
* 0 must be zero (0 = memory, 1 = IO)
* 1:2 type of space needed
* (00 = 32 bit, 01 = below 1M, 10 = 64 bit address)
* 3 prefetchable
*/
type = base & 0x6;
base &= (~0xf);
mask = (~base << 1) | 0x1;
size = (mask & base) & 0xFFFFFFFF;
/* cope (or rather don't) with different flavours of memory */
switch (type)
{
case 0x00: /* 32 bit */
break;
case 0x02: /* below 1M */
continue;
case 0x04: /* 64 bit */
offset += 4;
continue;
default:
continue;
}
/* allocate some (aligned) space in PCI memory */
base = pciAllocateMemSpace (size);
pciConfigOutLong(bus, slot, func, offset, base);
barFlag |= PCI_CMD_MEM_ENABLE;
}
}
/* increment the BAR offset value */
offset += 4;
}
/* now do the ROM stuff */
pciConfigOutLong (bus, slot, func, PCI_ROM_BAR, PCI_INVALID);
pciConfigInLong (bus, slot, func, PCI_ROM_BAR, (int *) &base);
if (base & 0x1)
{
/* valid ROM space, figure out how much it wants/needs */
base &= ~0x1;
size = (~base + 1);
/* Allocate some (aligned) memory space */
base = pciAllocateMemSpace (size);
/*
* Let the device see it, but don't enable accesses.
* This is because, according to the specification,
* the device may share an address decoder between
* the Expansion ROM base and other base address
* registers. In other words, any device driver wishing
* to access the ROM must set the enable bit (bit 0) before
* proceeding and clear it afterwards.
*/
pciConfigOutLong (bus, slot, func, PCI_ROM_BAR, base);
/* ROM gets added to PCI memory, so allow accesses */
barFlag |= PCI_CMD_MEM_ENABLE;
}
/* Enable PCI IO and memory accesses as found by scan, with MASTER */
barFlag |= PCI_CMD_MASTER_ENABLE;
pciConfigOutWord (bus, slot, func, PCI_CFG_COMMAND, barFlag);
pciConfigOutByte (bus, slot, func, PCI_CFG_LATENCY_TIMER, 0xFF);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -