📄 pciiomaplib.c
字号:
*
*/
STATUS pciIomapLibInit
(
int mechanism, /* configuration mechanism: 1, 2 or 3 */
int addr0, /* config-addr-reg / CSE-reg */
int addr1, /* config-data-reg / Forward-reg */
int addr2 /* none / Base-address */
)
{
int ix;
if (pciLibInitStatus != NONE)
return (pciLibInitStatus);
switch (mechanism)
{
case PCI_MECHANISM_1:
case PCI_MECHANISM_2:
case PCI_MECHANISM_3:
pciConfigMech = mechanism;
pciConfigAddr0 = addr0;
pciConfigAddr1 = addr1;
pciConfigAddr2 = addr2;
pciLibInitStatus = OK;
break;
default:
pciLibInitStatus = ERROR;
break;
}
for (ix = 0; ix < PCI_IRQ_LINES; ix++)
dllInit (&pciIntList[ix]);
return (pciLibInitStatus);
}
/*******************************************************************************
*
* pciFindDevice - find the nth device with the given device & vendor ID
*
* This routine finds the nth device with the given device & vendor ID.
*
* RETURNS: OK or ERROR if the deviceId and vendorId didn't match.
*
*/
STATUS pciFindDevice
(
int vendorId, /* vendor ID */
int deviceId, /* device ID */
int index, /* desired instance of device */
int * pBusNo, /* bus number */
int * pDeviceNo, /* device number */
int * pFuncNo /* function number */
)
{
STATUS status = ERROR;
BOOL cont = TRUE;
int busNo;
int deviceNo;
int funcNo;
UINT16 device;
UINT16 vendor;
UINT8 header;
UINT32 devClass;
int is_a_multi_function_device = 0;
if (pciLibInitStatus != OK)
cont = FALSE;
for (busNo = 0; cont == TRUE && busNo < PCI_MAX_BUS; busNo++)
for (deviceNo = 0; cont == TRUE && deviceNo < 31; ++deviceNo)
{
is_a_multi_function_device = 0;
for (funcNo = 0; cont == TRUE && funcNo < PCI_MAX_FUNC; funcNo++)
{
if ( (funcNo != 0) && !is_a_multi_function_device)
continue;
pciConfigInWord (busNo, deviceNo, funcNo, PCI_CFG_VENDOR_ID,
(short *) &vendor);
/* If nonexistent device, skip to next (PCI_NOTFITTED)*/
if (vendor == 0xFFFF)
break;
pciConfigInByte(busNo, deviceNo, funcNo, PCI_CFG_HEADER_TYPE,
&header);
if (funcNo == 0)
{
is_a_multi_function_device = ((header & 0x80) != 0);
}
pciConfigInWord(busNo, deviceNo, funcNo, PCI_CFG_DEVICE_ID,
(short *) &device);
if ((vendor == (UINT16)vendorId) &&
(device == (UINT16)deviceId) &&
(index-- == 0))
{
pciConfigInLong (busNo, deviceNo, funcNo,
PCI_CFG_REVISION, (int *) &devClass);
devClass = (devClass & 0xFFFFFF00) >> 8;
if ( (devClass >> 16) == 0x06) {
/* BRIDGE... */
}
*pBusNo = busNo;
*pDeviceNo = deviceNo;
*pFuncNo = funcNo;
status = OK;
/* terminate all loops */
cont = FALSE;
continue;
}
}
}
return (status);
}
/*******************************************************************************
*
* pciFindClass - find the nth occurence of a device by PCI class code.
*
* This routine finds the nth device with the given 24-bit PCI class code
* (class subclass prog_if).
*
* RETURNS: OK or ERROR if the class didn't match.
*
*/
STATUS pciFindClass
(
int classCode, /* 24-bit class code */
int index, /* desired instance of device */
int * pBusNo, /* bus number */
int * pDeviceNo, /* device number */
int * pFuncNo /* function number */
)
{
STATUS status = ERROR;
BOOL cont = TRUE;
int busNo;
int deviceNo;
int funcNo;
int classCodeReg;
char header;
if (pciLibInitStatus != OK)
cont = FALSE;
for (busNo = 0; cont == TRUE && busNo < PCI_MAX_BUS; busNo++)
for (deviceNo = 0;
cont == TRUE && deviceNo < ((busNo == 0) ? PCI_MAX_DEV : 16);
++deviceNo)
for (funcNo = 0; cont == TRUE && funcNo < PCI_MAX_FUNC; funcNo++)
{
#if (PCI_MAX_DEV > 31) && (PCI_MAX_FUNC > 7)
/* avoid a special bus cycle */
if ((deviceNo == 0x1f) && (funcNo == 0x07))
continue;
#endif
pciConfigInLong (busNo, deviceNo, funcNo, PCI_CFG_REVISION,
&classCodeReg);
/* If nonexistent device, skip to next */
if (((UINT32)classCodeReg == 0xFFFFFFFF) && (funcNo == 0))
break;
if ((((classCodeReg >> 8) & 0x00ffffff) == classCode) &&
(index-- == 0))
{
*pBusNo = busNo;
*pDeviceNo = deviceNo;
*pFuncNo = funcNo;
status = OK;
/* terminate all loops */
cont = FALSE;
continue;
}
/* goto next if current device is single function */
pciConfigInByte (busNo, deviceNo, funcNo, PCI_CFG_HEADER_TYPE,
&header);
if ((header & PCI_HEADER_MULTI_FUNC) != PCI_HEADER_MULTI_FUNC &&
funcNo == 0)
break;
}
return (status);
}
/******************************************************************************
*
* pciDevConfig - configure a device on a PCI bus
*
* This routine configures a device that is on a Peripheral Component
* Interconnect (PCI) bus by writing to the configuration header of the
* selected device.
* It first disables the device by clearing the command register in the
* configuration header. It then sets the I/O and/or memory space base
* address registers, the latency timer value and the cache line size.
* Finally, it re-enables the device by loading the command register with
* the specified command.
*
* NOTE: This routine is designed for Type 0 PCI Configuration Headers ONLY.
* It is NOT usable for configuring, for example, a PCI-to-PCI bridge.
*
* RETURNS: OK always.
*/
STATUS pciDevConfig
(
int pciBusNo, /* PCI bus number */
int pciDevNo, /* PCI device number */
int pciFuncNo, /* PCI function number */
ULONG devIoBaseAdrs, /* device IO base address */
ULONG devMemBaseAdrs, /* device memory base address */
ULONG command /* command to issue */
)
{
INT32 ix;
UINT32 tmp32;
/*
* Disable device by clearing its command register field in its
* configuration header.
*/
pciConfigOutWord (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_COMMAND, 0);
/*
* Due to system constraints, this is a partial implementation
* of enabling the Base Address Registers (BARs).
* It is hoped that all PCI devices only require at most one
* I/O space and/or one memory space.
* If not, this code will re-allocate the device's memory to
* each BAR implemented. Sounds like future trouble!
*/
for (ix = PCI_CFG_BASE_ADDRESS_0; ix <= PCI_CFG_BASE_ADDRESS_5; ix+=4)
{
/* Write all f's and read back value */
pciConfigOutLong (pciBusNo, pciDevNo, pciFuncNo, ix, 0xffffffff);
pciConfigInLong (pciBusNo, pciDevNo, pciFuncNo, ix, (int *) &tmp32);
/* BAR implemented? */
if (tmp32 == 0)
{
/*
* No! According to the spec, BARs must be implemented
* in sequence starting at BAR 0. So, all done.
*/
break;
}
if (tmp32 & 0x1)
{
/* I/O space requested, set specified I/O space base address */
pciConfigOutLong (pciBusNo, pciDevNo, pciFuncNo, ix,
devIoBaseAdrs | 0x1);
}
else
{
/* Memory space required, set specified base address */
pciConfigOutLong (pciBusNo, pciDevNo, pciFuncNo, ix,
devMemBaseAdrs & ~0x1);
}
}
/* Configure Latency Timer */
pciConfigOutByte (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_LATENCY_TIMER,
0xFF);
/* Enable the device's capabilities as specified */
pciConfigOutWord (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_COMMAND,
(UINT16)command);
return (OK);
}
/*******************************************************************************
*
* pciPack - pack parameters for the Configuration Address Register
*
* This routine packs three parameters into one integer for accessing the
* Configuration Address Register
*
* RETURNS: packed integer
*
*/
LOCAL int pciPack
(
int busNo, /* bus number */
int deviceNo, /* device number */
int funcNo /* function number */
)
{
return (((busNo << 16) & 0x00ff0000) |
((deviceNo << 11) & 0x0000f800) |
((funcNo << 8) & 0x00000700));
}
/*******************************************************************************
*
* pciSpecialCycle - generate a special cycle with a message
*
* This routine generates a special cycle with a message.
*
* RETURNS: OK or ERROR if this library is not initialized.
*
*/
STATUS pciSpecialCycle
(
int busNo, /* bus number */
int message /* data on AD[31:0] during the special cycle */
)
{
int deviceNo = 0x0000001f;
int funcNo = 0x00000007;
int key;
if (pciLibInitStatus != OK)
return (ERROR);
/* mutual exclusion start */
key = intLock();
switch (pciConfigMech)
{
case PCI_MECHANISM_1:
PCI_OUT_LONG (pciConfigAddr0, pciPack (busNo, deviceNo, funcNo) |
0x80000000);
PCI_OUT_LONG (pciConfigAddr1, message);
break;
case PCI_MECHANISM_2:
PCI_OUT_BYTE (pciConfigAddr0, 0xff);
PCI_OUT_BYTE (pciConfigAddr1, 0x00);
PCI_OUT_LONG ((pciConfigAddr2 | ((deviceNo & 0x000f) << 8)),
message);
PCI_OUT_BYTE (pciConfigAddr0, 0);
break;
default:
break;
}
/* mutual exclusion stop */
intUnlock(key);
return (OK);
}
/*******************************************************************************
*
* pciInt - interrupt handler for shared PCI interrupt.
*
* This routine executes multiple interrupt handlers 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.
*
* RETURNS: N/A
*
*/
VOID pciInt
(
int irq /* IRQ associated to the PCI interrupt */
)
{
PCI_INT_RTN *pRtn;
for (pRtn = (PCI_INT_RTN *)DLL_FIRST (&pciIntList[irq]); pRtn != NULL;
pRtn = (PCI_INT_RTN *)DLL_NEXT (&pRtn->node))
(* pRtn->routine) (pRtn->parameter);
}
/*******************************************************************************
*
* pciIntConnect - connect the interrupt handler to the PCI interrupt.
*
* This routine connects an interrupt handler to the PCI interrupt line(A - D).
* Link list is created if multiple handlers are assigned to the single PCI
* interrupt.
*
* RETURNS: OK or ERROR if the interrupt handler cannot be built.
*
*/
STATUS pciIntConnect
(
VOIDFUNCPTR *vector, /* interrupt vector to attach to */
VOIDFUNCPTR routine, /* routine to be called */
int parameter /* parameter to be passed to routine */
)
{
int irq = IVEC_TO_INUM ((int)vector) - INT_NUM_IRQ0;
PCI_INT_RTN *pRtn;
int oldLevel;
if (pciLibInitStatus != OK)
return (ERROR);
pRtn = (PCI_INT_RTN *)malloc (sizeof (PCI_INT_RTN));
if (pRtn == NULL)
return (ERROR);
pRtn->routine = routine;
pRtn->parameter = parameter;
oldLevel = intLock (); /* LOCK INTERRUPT */
dllAdd (&pciIntList[irq], &pRtn->node);
intUnlock (oldLevel); /* UNLOCK INTERRUPT */
return (OK);
}
/*******************************************************************************
*
* pciIntDisconnect - disconnect the interrupt handler from the PCI interrupt.
*
* This routine disconnects the interrupt handler from the PCI interrupt line.
*
* RETURNS: OK or ERROR if the interrupt handler cannot be removed.
*
*/
STATUS pciIntDisconnect
(
VOIDFUNCPTR *vector, /* interrupt vector to attach to */
VOIDFUNCPTR routine /* routine to be called */
)
{
int irq = IVEC_TO_INUM ((int)vector) - INT_NUM_IRQ0;
PCI_INT_RTN *pRtn;
int oldLevel;
if (pciLibInitStatus != OK)
return (ERROR);
for (pRtn = (PCI_INT_RTN *)DLL_FIRST (&pciIntList[irq]); pRtn != NULL;
pRtn = (PCI_INT_RTN *)DLL_NEXT (&pRtn->node))
{
if (pRtn->routine == routine)
{
oldLevel = intLock (); /* LOCK INTERRUPT */
dllRemove (&pciIntList[irq], &pRtn->node);
intUnlock (oldLevel); /* UNLOCK INTERRUPT */
free ((char *)pRtn);
return (OK);
}
}
return (ERROR);
}
#endif /* defined(INCLUDE_PCI) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -