📄 pciconfiglib.c
字号:
return (ERROR);
}
#endif
#endif
key = intLock (); /* mutual exclusion start */
#if 0
switch (pciConfigMech)
{
case PCI_MECHANISM_0:
pciConfigWrite (busNo, deviceNo, funcNo, offset, 4, data);
break;
case PCI_MECHANISM_1:
PCI_OUT_LONG (pciConfigAddr0, pciConfigBdfPack (busNo, deviceNo, funcNo) |
(offset & 0xfc) | 0x80000000);
PCI_OUT_LONG (pciConfigAddr1, data);
break;
case PCI_MECHANISM_2:
PCI_OUT_BYTE (pciConfigAddr0, 0xf0 | (funcNo << 1));
PCI_OUT_BYTE (pciConfigAddr1, busNo);
PCI_OUT_LONG ((pciConfigAddr2 | ((deviceNo & 0x000f) << 8) |
(offset & 0xfc)), data);
PCI_OUT_BYTE (pciConfigAddr0, 0);
break;
default:
break;
}
#else
bslPciConfigWrite32(busNo, deviceNo, funcNo, offset, data);
#endif
intUnlock (key); /* mutual exclusion stop */
return (OK);
}
/*****************************************************************************
*
* pciConfigModifyLong - Perform a masked longword register update
*
* This function writes a field into a PCI configuration header without
* altering any bits not present in the field. It does this by first
* doing a PCI configuration read (into a temporary location) of the PCI
* configuration header word which contains the field to be altered.
* It then alters the bits in the temporary location to match the desired
* value of the field. It then writes back the temporary location with
* a configuration write. All configuration accesses are long and the
* field to alter is specified by the "1" bits in the 'bitMask' parameter.
*
* Be careful to using pciConfigModifyLong for updating the Command and
* status register. The status bits must be written back as zeroes, else
* they will be cleared. Proper use involves including the status bits in
* the mask value, but setting their value to zero in the data value.
*
* The following example will set the PCI_CMD_IO_ENABLE bit without clearing any
* status bits. The macro PCI_CMD_MASK includes all the status bits as
* part of the mask. The fact that PCI_CMD_MASTER doesn't include these bits,
* causes them to be written back as zeroes, therefore they aren't cleared.
*
* .CS
* pciConfigModifyLong (b,d,f,PCI_CFG_COMMAND,
* (PCI_CMD_MASK | PCI_CMD_IO_ENABLE), PCI_CMD_IO_ENABLE);
* .CE
*
* Use of explicit longword read and write operations for dealing with any
* register containing "write 1 to clear" bits is sound policy.
*
* RETURNS: OK if operation succeeds, ERROR if operation fails.
*/
STATUS pciConfigModifyLong
(
int busNo, /* bus number */
int deviceNo, /* device number */
int funcNo, /* function number */
int offset, /* offset into the configuration space */
UINT32 bitMask, /* Mask which defines field to alter */
UINT32 data /* data written to the offset */
)
{
UINT32 temp;
STATUS stat;
int key;
/* check for library initialization or unaligned access */
#ifdef PCI_CONFIG_OFFSET_NOCHECK
if (pciLibInitStatus != OK)
{
return (ERROR);
}
#else
if ((pciLibInitStatus != OK) || ((offset & (int)0x3) > 0) )
{
return (ERROR);
}
#endif
key = intLock ();
stat = pciConfigInLong (busNo, deviceNo, funcNo, offset, &temp);
if (stat == OK)
{
temp = (temp & ~bitMask) | (data & bitMask);
stat = pciConfigOutLong (busNo, deviceNo, funcNo, offset, temp);
}
intUnlock (key);
return (stat);
}
/*****************************************************************************
*
* pciConfigModifyWord - Perform a masked longword register update
*
* This function writes a field into a PCI configuration header without
* altering any bits not present in the field. It does this by first
* doing a PCI configuration read (into a temporary location) of the PCI
* configuration header word which contains the field to be altered.
* It then alters the bits in the temporary location to match the desired
* value of the field. It then writes back the temporary location with
* a configuration write. All configuration accesses are long and the
* field to alter is specified by the "1" bits in the 'bitMask' parameter.
*
* Do not use this routine to modify any register that contains 'write 1
* to clear' type of status bits in the same longword. This specifically
* applies to the command register. Modify byte operations could potentially
* be implemented as longword operations with bit shifting and masking. This
* could have the effect of clearing status bits in registers that aren't being
* updated. Use pciConfigInLong and pciConfigOutLong, or pciModifyLong,
* to read and update the entire longword.
*
* RETURNS: OK if operation succeeds. ERROR if operation fails.
*/
STATUS pciConfigModifyWord
(
int busNo, /* bus number */
int deviceNo, /* device number */
int funcNo, /* function number */
int offset, /* offset into the configuration space */
UINT16 bitMask, /* Mask which defines field to alter */
UINT16 data /* data written to the offset */
)
{
UINT16 temp;
STATUS stat;
int key;
/* check for library initialization or unaligned access */
#ifdef PCI_CONFIG_OFFSET_NOCHECK
if (pciLibInitStatus != OK)
{
return (ERROR);
}
#else
if ((pciLibInitStatus != OK) || ((offset & (int)0x1) > 0) )
{
return (ERROR);
}
#endif
key = intLock ();
stat = pciConfigInWord (busNo, deviceNo, funcNo, offset, &temp);
if (stat == OK)
{
temp = (temp & ~bitMask) | (data & bitMask);
stat = pciConfigOutWord (busNo, deviceNo, funcNo, offset, temp);
}
intUnlock (key);
return (stat);
}
/*****************************************************************************
*
* pciConfigModifyByte - Perform a masked longword register update
*
* This function writes a field into a PCI configuration header without
* altering any bits not present in the field. It does this by first
* doing a PCI configuration read (into a temporary location) of the PCI
* configuration header word which contains the field to be altered.
* It then alters the bits in the temporary location to match the desired
* value of the field. It then writes back the temporary location with
* a configuration write. All configuration accesses are long and the
* field to alter is specified by the "1" bits in the 'bitMask' parameter.
*
* Do not use this routine to modify any register that contains 'write 1
* to clear' type of status bits in the same longword. This specifically
* applies to the command register. Modify byte operations could potentially
* be implemented as longword operations with bit shifting and masking. This
* could have the effect of clearing status bits in registers that aren't being
* updated. Use pciConfigInLong and pciConfigOutLong, or pciModifyLong,
* to read and update the entire longword.
*
* RETURNS: OK if operation succeeds, ERROR if operation fails.
*/
STATUS pciConfigModifyByte
(
int busNo, /* bus number */
int deviceNo, /* device number */
int funcNo, /* function number */
int offset, /* offset into the configuration space */
UINT8 bitMask, /* Mask which defines field to alter */
UINT8 data /* data written to the offset */
)
{
UINT8 temp;
STATUS stat;
int key;
/* check for library initialization or unaligned access */
if (pciLibInitStatus != OK)
{
return (ERROR);
}
key = intLock ();
stat = pciConfigInByte (busNo, deviceNo, funcNo, offset, &temp);
if (stat == OK)
{
temp = (temp & ~bitMask) | (data & bitMask);
stat = pciConfigOutByte (busNo, deviceNo, funcNo, offset, temp);
}
intUnlock (key);
return (stat);
}
/*******************************************************************************
*
* 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 */
UINT32 message /* data driven onto AD[31:0] */
)
{
int deviceNo = 0x0000001f;
int funcNo = 0x00000007;
int key;
if (pciLibInitStatus != OK) /* sanity check */
return (ERROR);
key = intLock (); /* mutual exclusion start */
switch (pciConfigMech)
{
case PCI_MECHANISM_0:
if (pciConfigSpcl != NULL)
pciConfigSpcl (busNo, message);
break;
case PCI_MECHANISM_1:
PCI_OUT_LONG (pciConfigAddr0,
pciConfigBdfPack (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;
}
intUnlock (key); /* mutual exclusion stop */
return (OK);
}
#endif /* USE_PCI_SIMULATOR */
/**********************************************************************
*
* pciConfigForeachFunc - check condition on specified bus
*
* pciConfigForeachFunc() discovers the PCI functions present on the
* bus and calls a specified C-function for each one. If the
* function returns ERROR, further processing stops.
*
* pciConfigForeachFunc() does not affect any HOST<->PCI
* bridge on the system.
*
* ERRNO: not set
*
* RETURNS: OK normally, or ERROR if funcCheckRtn() doesn't return OK.
*/
STATUS pciConfigForeachFunc
(
UINT8 bus, /* bus to start on */
BOOL recurse, /* if TRUE, do subordinate busses */
PCI_FOREACH_FUNC funcCheckRtn, /* routine to call for each PCI func */
void *pArg /* argument to funcCheckRtn */
)
{
int pciLocBus; /* PCI bus/device/function structure */
int pciLocDevice; /* PCI bus/device/function structure */
int pciLocFunction; /* PCI bus/device/function structure */
int device; /* loop over devices */
int function; /* loop over functions */
UINT devVend;
UINT16 pciClass; /* PCI class/subclass contents */
int status;
UINT8 btemp;
UINT8 secBus; /* secondary bus, for recursion */
UINT16 hostBridge = (PCI_CLASS_BRIDGE_CTLR<<8) |
PCI_SUBCLASS_HOST_PCI_BRIDGE;
/* Begin the scanning process at [bus,0,0] */
pciLocBus = (UINT8)bus;
pciLocDevice = (UINT8)0;
pciLocFunction = (UINT8)0;
/* discover devices and perform check */
/* Locate each active function on the current bus */
for (device = 0; device < PCI_MAX_DEV; device++)
{
pciLocDevice = device;
/* Check each function until an unused one is detected */
for (function = 0; function < PCI_MAX_FUNC; function++)
{
pciLocFunction = function;
/* Check for a valid device/vendor number */
pciConfigInLong (pciLocBus, pciLocDevice, pciLocFunction,
PCI_CFG_VENDOR_ID, &devVend);
/* If function 0 then check next dev else check next function */
if ( ((devVend & 0x0ffff) == PCI_CONFIG_ABSENT_WORD_F) ||
((devVend & 0x0ffff) == PCI_CONFIG_ABSENT_WORD_0) )
{
if (function == 0)
{
break; /* non-existent device, goto next device */
}
else
{
continue; /* function empty, try the next function */
}
}
/* Check to see if this function belongs to a PCI-PCI bridge */
pciConfigInWord (pciLocBus, pciLocDevice, pciLocFunction,
PCI_CFG_SUBCLASS, &pciClass);
if ( pciClass != hostBridge )
{
/* call specified function */
status = (*funcCheckRtn)(pciLocBus, pciLocDevice,
pciLocFunction, pArg);
if ( status != OK )
return(ERROR);
}
if ( recurse )
{
/* if P2P bridge, check that bus recursively */
if ( pciClass == ((PCI_CLASS_BRIDGE_CTLR << 8) + PCI_SUBCLASS_P2P_BRIDGE) )
{
pciConfigInByte (pciLocBus, pciLocDevice, pciLocFunction,
PCI_CFG_SECONDARY_BUS, &secBus);
if ( secBus > 0 )
status = pciConfigForeachFunc(secBus, recurse,
funcCheckRtn, pArg)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -