You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1424 lines
35 KiB

/*VxbFtPcie.c - FT PCI bus controller VxBus driver */
/*
*
* This program is OPEN SOURCE software: you can redistribute it and/or modify it;
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#include <vxWorks.h>
#include <vsbConfig.h>
#include <intLib.h>
#include <iv.h>
#include <taskLib.h>
#include <stdio.h>
#include <string.h>
#include <vxBusLib.h>
#include <hwif/util/hwMemLib.h>
#include <hwif/vxbus/hwConf.h>
#include <hwif/vxbus/vxBus.h>
#include <hwif/vxbus/vxbPlbLib.h>
#include <hwif/vxbus/vxbPciLib.h>
#include <drv/pci/pciIntLib.h>
#include <drv/pci/pciConfigLib.h>
#include <drv/pci/pciAutoConfigLib.h>
#include "../h/vxbus/vxbPciBus.h"
#include "../h/vxbus/vxbAccess.h"
#include <../src/hwif/intCtlr/vxbIntCtlrLib.h>
#include <../src/hwif/intCtlr/vxbIntDynaCtlrLib.h>
#include <spinLockLib.h>
#if defined(DRV_PCIBUS_FT)
/* debug */
#ifdef FT_DEBUG_ENABLE
UINT32 ftPciDebugLevel = 0;
#ifndef FT_DEBUG_MSG
#define FT_DEBUG_MSG(level,fmt,a,b,c,d,e,f) \
{ \
if ( ftPciDebugLevel >= level ) \
{ \
uartf(fmt,a,b,c,d,e,f); \
} \
};
#endif /* FT_DEBUG_MSG */
#else /* FT_DEBUG_ENABLE */
#define FT_DEBUG_MSG(level,fmt,a,b,c,d,e,f)
#endif /* FT_DEBUG_ENABLE */
/* typedefs */
LOCAL void ftPciInstInit(VXB_DEVICE_ID pInst);
LOCAL void ftPciInstInit2(VXB_DEVICE_ID pInst);
LOCAL void ftPciInstConnect(VXB_DEVICE_ID pInst);
void (*funcPirqEnable)(BOOL enable);
LOCAL STATUS ftPciMethodDevCfgRead
(
VXB_DEVICE_ID pInst, /* device info */
PCI_HARDWARE * pPciDev, /* PCI device info */
UINT32 offset, /* offset into the configuration space */
UINT32 width, /* width to be read */
void * pData /* data buffer read from the offset */
);
LOCAL STATUS ftPciMethodDevCfgWrite
(
VXB_DEVICE_ID pInst, /* device info */
PCI_HARDWARE * pPciDev, /* PCI device info */
UINT32 offset, /* offset into the configuration space */
UINT32 width, /* width to be read */
UINT32 data /* data write to the offset */
);
LOCAL STATUS ftPciDevControl
(
VXB_DEVICE_ID devID,
pVXB_DEVCTL_HDR pBusDevControl
);
LOCAL STATUS ftPciConfigInfo
(
VXB_DEVICE_ID pInst,
char * pArgs
);
LOCAL STATUS ftPciInterruptInfo
(
VXB_DEVICE_ID pInst,
char * pArgs
);
LOCAL STATUS ftPciMSIProgram
(
VXB_DEVICE_ID pInst,
struct vxbIntDynaVecInfo *dynaVec
);
LOCAL STATUS ftPciMethodConvertBaseAddress
(
VXB_DEVICE_ID devID,
UINT32 * pBaseAddr
);
IMPORT STATUS vxbPciMSIProgram
(
VXB_DEVICE_ID pInst,
struct vxbIntDynaVecInfo *dynaVec
);
IMPORT STATUS vxbPciMSIEnable
(
VXB_DEVICE_ID pInst,
struct vxbIntDynaVecInfo *dynaVec
);
IMPORT STATUS vxbPciMSIDisable
(
VXB_DEVICE_ID pInst,
struct vxbIntDynaVecInfo *dynaVec
);
IMPORT BOOL vxbPciMSIIsCap
(
VXB_DEVICE_ID pInst
);
#ifdef MSI_READ_ENABLE
LOCAL STATUS ftPciMSIRead
(
VXB_DEVICE_ID pDev,
struct vxbIntDynaVecInfo *dynaVec
)
#endif
IMPORT VXB_DEVICE_ID globalBusCtrlID;
/*
* The driver publishes driver methods. The following driver
* methods are for serial devices. Change these as appropriate
* for your device.
*/
LOCAL device_method_t ftPci_methods[] =
{
DEVMETHOD(busCtlrDevCfgRead, ftPciMethodDevCfgRead),
DEVMETHOD(busCtlrDevCfgWrite, ftPciMethodDevCfgWrite),
DEVMETHOD(busCtlrDevCtlr, ftPciDevControl),
DEVMETHOD(busCtlrCfgInfo, ftPciConfigInfo),
DEVMETHOD(busCtlrInterruptInfo, ftPciInterruptInfo),
DEVMETHOD(vxbIntDynaVecProgram, ftPciMSIProgram),
DEVMETHOD(vxbIntDynaVecEnable, vxbPciMSIEnable),
DEVMETHOD(vxbIntDynaVecDisable, vxbPciMSIDisable),
DEVMETHOD(busCtlrBaseAddrCvt, ftPciMethodConvertBaseAddress),
{ 0, 0}
};
LOCAL struct drvBusFuncs ftPciFuncs =
{
ftPciInstInit, /* devInstanceInit */
ftPciInstInit2, /* devInstanceInit2 */
ftPciInstConnect /* devConnect */
};
LOCAL struct vxbDevRegInfo ftPciDevRegistration =
{
(struct vxbDevRegInfo *)NULL, /* pNext */
VXB_DEVID_DEVICE, /* devID */
VXB_BUSID_PLB, /* busID = PLB */
VXB_VER_4_0_0, /* busVer */
"ftPcie", /* drvName */
&ftPciFuncs, /* pDrvBusFuncs */
&ftPci_methods[0], /* pMethods */
NULL /* devProbe */
};
typedef struct ftPciDrvCtrl
{
VXB_DEVICE_ID pInst;
void * regBase;
void * handle;
UINT32 magicNumber1;
UINT32 magicNumber2;
int pciMaxBus; /* Max number of sub-busses */
void * mem32Addr;
UINT32 mem32Size;
void * memIo32Addr;
UINT32 memIo32Size;
void * io32Addr;
UINT32 io32Size;
void * pimmrBase;
void * mstrMemBus;
void * lclMemAddr;
UINT32 lclMemMapSize;
UINT32 owAttrMem;
UINT32 owAttrMemIo;
UINT32 owAttrIo;
UINT32 iwAttr;
UINT32 singleLawBar;
UINT32 singleLawBarSize;
UINT32 pciExpressHost;
UINT32 msiEnable;
UINT32 dynamicInterrupts;
UINT32 msiAddress;
UINT32 msiData;
UINT32 msiDataWorkaround;
UINT32 msiDataWorkaroundAddr;
UINT32 autoConfig;
BOOL initDone;
BOOL bridgeInitFailed;
struct vxbPciConfig *pPciConfig;
struct vxbPciInt *pIntInfo;
struct hcfDevice * pHcf;
spinlockIsr_t spinlockIsr; /* ISR-callable spinlock */
/* external bridge interrupt map */
int * extIntMap;
int extIntMapSize;
/* a flag to invoke PCI EXT2 errata workaround */
void (*funcPirqEnable)(BOOL enable);
BOOL pciEx2ErrataFlag;
} FT_PCI_DRV_CTRL;
/* defines */
#define FT_PCI_CFG_READ(pInst, offset, width, data) \
ftPciMethodDevCfgRead(pInst, pPciDev, offset, width, (void *) &data)
#define FT_PCI_CFG_WRITE(pInst, offset, width, data) \
ftPciMethodDevCfgWrite(pInst, pPciDev, offset, width, (UINT32) data)
LOCAL VIRT_ADDR ft_pcicfg_va_base;
typedef enum pci_cfg_trans_width_t
{
PCI_CFG_TRANS_8BIT = 1,
PCI_CFG_TRANS_16BIT = 2,
PCI_CFG_TRANS_32BIT = 4,
PCI_CFG_TRANS_INVALID
} pci_cfg_trans_width_t;
typedef struct pci_dev_addr_t
{
UINT8 busno;
UINT8 devno;
UINT8 fnno;
} pci_dev_addr_t;
/* locals */
LOCAL FT_PCI_DRV_CTRL * pFtPciDrvCtrl0 = NULL;
LOCAL int ftPciIntNumGet
(
VXB_DEVICE_ID devID,
pVXB_DEVCTL_HDR pBusDevControl,
int devNo
);
/* extern */
IMPORT void vxbMsDelay(int);
/*
DESCRIPTION
This is the VxBus driver for the PCI bus controller on the
m85xx CPUs.
This driver work on PLB bus, and gets configuration information
from the hwconf.c file entry. This driver supports only 1-1
address mappings, so it uses the PCI addresses and sizes specified
in hwconf as the local addresses.
*/
IMPORT int ftPciCfgRead
(
UINT8 b,
UINT8 d,
UINT8 f,
unsigned int offset,
unsigned int size,
void *data
);
IMPORT int ftPciCfgWrite
(
UINT8 b,
UINT8 d,
UINT8 f,
unsigned int offset,
unsigned int size,
UINT32 data
);
/*******************************************************************************
*
* ftPciMethodDevCfgRead - read from the PCI configuration space
*
* This routine reads either a byte, word or a long word specified by
* the argument <width>, from the PCI configuration space
* This routine works around a problem in the hardware which hangs
* PCI bus if device no 12 is accessed from the PCI configuration space.
*
* \NOMANUAL
*
* RETURNS: OK, or ERROR if this library is not initialized
*
* ERRNO
*/
LOCAL STATUS ftPciMethodDevCfgRead
(
VXB_DEVICE_ID pInst, /* device info */
PCI_HARDWARE * pPciDev, /* PCI device info */
UINT32 offset, /* offset into the configuration space */
UINT32 width, /* width to be read */
void * pData /* data buffer read from the offset */
)
{
FT_PCI_DRV_CTRL * pDrvCtrl;
UINT8 busNo = pPciDev->pciBus;
UINT8 deviceNo = pPciDev->pciDev;
UINT8 funcNo = pPciDev->pciFunc;
pDrvCtrl = pInst->pDrvCtrl;
return ftPciCfgRead(busNo, deviceNo, funcNo, offset, width, pData);
}
/*******************************************************************************
*
* ftPciMethodDevCfgWrite - write to the PCI configuration space
*
* This routine writes either a byte, word or a long word specified by
* the argument <width>, to the PCI configuration space
* This routine works around a problem in the hardware which hangs
* PCI bus if device no 12 is accessed from the PCI configuration space.
*
* \NOMANUAL
*
* RETURNS: OK, or ERROR if this library is not initialized
*
* ERRNO
*/
LOCAL STATUS ftPciMethodDevCfgWrite
(
VXB_DEVICE_ID pInst, /* device info */
PCI_HARDWARE * pPciDev, /* PCI device info */
UINT32 offset, /* offset into the configuration space */
UINT32 width, /* width to write */
UINT32 data /* data to write */
)
{
UINT8 busNo = pPciDev->pciBus;
UINT8 deviceNo = pPciDev->pciDev;
UINT8 funcNo = pPciDev->pciFunc;
return ftPciCfgWrite(busNo, deviceNo, funcNo, offset, width, data);
}
/*****************************************************************************
*
* ftPciConfigInfo - Returns the PCI config info ptr from bus controller.
*
* \NOMANUAL
*
* RETURNS: OK, or ERROR if this library is not initialized
*
* ERRNO
*/
LOCAL STATUS ftPciConfigInfo
(
VXB_DEVICE_ID pInst,
char * pArgs
)
{
FT_PCI_DRV_CTRL *pDrvCtrl = pInst->pDrvCtrl;
*(UINT32*)pArgs = (UINT32)pDrvCtrl->pPciConfig;
return(OK);
}
/*****************************************************************************
*
* ftPciMSIProgram - Returns the converted vector address for MSI
*
* \NOMANUAL
*
* RETURNS: OK
*
* ERRNO
*/
LOCAL STATUS ftPciMSIProgram
(
VXB_DEVICE_ID pDev,
struct vxbIntDynaVecInfo *dynaVec
)
{
/* routine expect reg offset from internal memory map base addr
* we can then just or in the pci internal memory map offset
*/
FT_DEBUG_MSG(0, "\nConvert PIMMR data 0x%x conerted 0x%x\n",
(int)dynaVec->vecAddr,dynaVec->vecAddr | (UINT64)pDrvCtrl->pimmrBase,
3,4,5,6);
/* TODO: */
/* dynaVec->vecAddr |= (UINT64)((UINT32)pDrvCtrl->pimmrBase); */
/* uartf("%s,%d: Addr of MSI: .\r\n",__FILE__,__LINE__); */
return (vxbPciMSIProgram (pDev,dynaVec));
}
/*****************************************************************************
*
* ftPciInterruptInfo - Returns the PCI interrupt info ptr from the bus
* controller.
*
* \NOMANUAL
*
* RETURNS: OK, or ERROR if this library is not initialized
*
* ERRNO
*/
LOCAL STATUS ftPciInterruptInfo
(
VXB_DEVICE_ID pInst,
char * pArgs
)
{
FT_PCI_DRV_CTRL *pDrvCtrl = (FT_PCI_DRV_CTRL *)pInst->pDrvCtrl;
*(UINT32*)pArgs = (UINT32)pDrvCtrl->pIntInfo;
return(OK);
}
/******************************************************************************
*
* ftPciRegister - register ftPci driver
*
* We use a two-function method here, to delay registration of the driver
* during debug. This should be left in place when the driver is released.
*
*/
void ftPciRegister(void)
{
vxbDevRegister((struct vxbDevRegInfo *)&ftPciDevRegistration);
}
/******************************************************************************
*
* ftPciInstInit - initialize ftPci device
*
* This is the ftPci initialization routine.
*
* NOTE:
*
* This routine is called early during system initialization, and
* *MUST NOT* make calls to OS facilities such as memory allocation
* and I/O.
*
* RETURNS: N/A
*
* ERRNO
*/
LOCAL void ftPciInstInit
(
VXB_DEVICE_ID pInst
)
{
STATUS stat;
FT_PCI_DRV_CTRL * pDrvCtrl;
struct hcfDevice * pHcf;
/* allocate pDrvCtrl */
pDrvCtrl = (FT_PCI_DRV_CTRL *)hwMemAlloc(sizeof(*pDrvCtrl));
if (pDrvCtrl == NULL)
return;
vxbRegMap (pInst, 0, &pDrvCtrl->handle);
pDrvCtrl->regBase = pInst->pRegBase[0];
ft_pcicfg_va_base =(VIRT_ADDR) pDrvCtrl->regBase ;
pDrvCtrl->initDone = FALSE;
pDrvCtrl->pInst = pInst;
/* magic number = "ftPci" */
pDrvCtrl->magicNumber1 = 0x6D383578;
pDrvCtrl->magicNumber2 = 0x78506369;
/* extract BSP information */
pHcf = (struct hcfDevice *)hcfDeviceGet(pInst);
pDrvCtrl->pHcf = pHcf;
/*
* resourceDesc {
* The mem32Addr resource specifies the
* 32-bit prefetchable memory address pool base address. }
*/
stat = devResourceGet(pHcf, "mem32Addr", HCF_RES_ADDR, &pDrvCtrl->mem32Addr);
/*
* resourceDesc {
* The mem32Size resource specifies the
* 32-bit prefetchable memory address pool size. }
*/
stat = devResourceGet(pHcf, "mem32Size", HCF_RES_INT, (void *)&pDrvCtrl->mem32Size);
/*
* resourceDesc {
* The memIo32Addr resource specifies the
* 32-bit non-prefetchable memory address pool base address. }
*/
stat = devResourceGet(pHcf, "memIo32Addr", HCF_RES_ADDR, &pDrvCtrl->memIo32Addr);
/*
* resourceDesc {
* The memIo32Size resource specifies the
* 32-bit non-prefetchable memory address pool size. }
*/
stat = devResourceGet(pHcf, "memIo32Size", HCF_RES_INT, (void *)&pDrvCtrl->memIo32Size);
/*
* resourceDesc {
* The io32Addr resource specifies the
* 32-bit I/O address pool base address. }
*/
stat = devResourceGet(pHcf, "io32Addr", HCF_RES_ADDR, &pDrvCtrl->io32Addr);
/*
* resourceDesc {
* The io32Size resource specifies the
* 32-bit I/O address pool size. }
*/
stat = devResourceGet(pHcf, "io32Size", HCF_RES_INT, (void *)&pDrvCtrl->io32Size);
/*
* resourceDesc {
* The pimmrBase resource specifies the
* PIMMR base address. }
*/
stat = devResourceGet(pHcf, "pimmrBase", HCF_RES_ADDR, &pDrvCtrl->pimmrBase);
/*
* resourceDesc {
* The mstrMemBus resource specifies the
* address on CPU from PCI buss. }
*/
stat = devResourceGet(pHcf, "mstrMemBus", HCF_RES_ADDR, &pDrvCtrl->mstrMemBus);
/*
* resourceDesc {
* The lclMemAddr resource specifies the
* local memory address on the BSP. }
*/
stat = devResourceGet(pHcf, "lclMemAddr", HCF_RES_ADDR, &pDrvCtrl->lclMemAddr);
/*
* resourceDesc {
* The lclMemMapSize resource specifies the
* mappable local memory size on the BSP. }
*/
stat = devResourceGet(pHcf, "lclMemMapSize", HCF_RES_INT, (void *)&pDrvCtrl->lclMemMapSize);
/*
* resourceDesc {
* The owAttrMem resource specifies the
* outbound attributes register setting for prefetchable memory. }
*/
stat = devResourceGet(pHcf, "owAttrMem", HCF_RES_INT, (void *)&pDrvCtrl->owAttrMem);
/*
* resourceDesc {
* The owAttrMemIo resource specifies the
* outbound attributes register setting for non-prefetchable memory. }
*/
stat = devResourceGet(pHcf, "owAttrMemIo", HCF_RES_INT, (void *)&pDrvCtrl->owAttrMemIo);
/*
* resourceDesc {
* The owAttrMem resource specifies the
* outbound attributes register setting for I/O. }
*/
stat = devResourceGet(pHcf, "owAttrIo", HCF_RES_INT, (void *)&pDrvCtrl->owAttrIo);
/*
* resourceDesc {
* The iwAttr resource specifies the
* inbound attributes. }
*/
stat = devResourceGet(pHcf, "iwAttr", HCF_RES_INT, (void *)&pDrvCtrl->iwAttr);
/*
* resourceDesc {
* The maxBusSet resource specifies the
* highest sub-bus number. }
*/
stat = devResourceGet(pHcf, "maxBusSet", HCF_RES_INT, (void *)&pDrvCtrl->pciMaxBus);
/*
* resourceDesc {
* The pciExpressHost resource specifies the
* PCI Express Host is enabled or not. }
*/
stat = devResourceGet(pHcf, "pciExpressHost", HCF_RES_INT, (void*)&pDrvCtrl->pciExpressHost);
/*
* resourceDesc {
* The autoConfig resource specifies whether
* Auto Configuration is enabled or not. }
*/
stat = devResourceGet(pHcf, "autoConfig", HCF_RES_INT, (void*)&pDrvCtrl->autoConfig);
/*
* resourceDesc {
* The funcPirqEnable resource specifies the
* function pointer points to the BSP specific
* function which enables or disbables PCI
* PIRQ direct handlig. }
*/
stat = devResourceGet(pHcf, "funcPirqEnable", HCF_RES_ADDR, (void*)&pDrvCtrl->funcPirqEnable);
/*
* resourceDesc {
* The msiEnable resource specifies the
* MSI is enabled or not. }
*/
stat = devResourceGet(pHcf, "msiEnable", HCF_RES_INT, (void*)&pDrvCtrl->msiEnable);
/*
* resourceDesc {
* The dynamicInterrupts resource specifies the
* Dynamic Interrupts are enabled or not. }
*/
stat = devResourceGet(pHcf, "dynamicInterrupts", HCF_RES_INT, (void*)&pDrvCtrl->dynamicInterrupts);
/*
* resourceDesc {
* The msiAddress resource specifies the
* MSI base address. }
*/
stat = devResourceGet(pHcf, "msiAddress", HCF_RES_INT, (void*)&pDrvCtrl->msiAddress);
/*
* resourceDesc {
* The msiData resource specifies the
* MSI data. }
*/
stat = devResourceGet(pHcf, "msiData", HCF_RES_INT, (void*)&pDrvCtrl->msiData);
/*
* resourceDesc {
* The msiDataWorkaround resource specifies the
* MSI data workaround is required or not. }
*/
stat = devResourceGet(pHcf, "msiDataWorkaround", HCF_RES_INT, (void*)&pDrvCtrl->msiDataWorkaround);
/*
* resourceDesc {
* The msiDataWorkaroundAddr resource specifies the
* MSI data workaround base address. }
*/
stat = devResourceGet(pHcf, "msiDataWorkaroundAddr", HCF_RES_INT, (void*)&pDrvCtrl->msiDataWorkaroundAddr);
/*
* resourceDesc {
* The extIntMap resource specifies the
* address of the PCI interrupt mapping table. }
*/
stat = devResourceGet(pHcf, "extIntMap", HCF_RES_ADDR, (void*)&pDrvCtrl->extIntMap);
/*
* resourceDesc {
* The extIntMap resource specifies the
* size of the PCI interrupt mapping table. }
*/
stat = devResourceGet(pHcf, "extIntMapSize", HCF_RES_INT, (void*)&pDrvCtrl->extIntMapSize);
/*
* resourceDesc {
* The pciEx2ErrataFlag resource specifies the
* flag to use workaround for PCI-Express EX2 Errata. }
*/
stat = devResourceGet(pHcf, "pciEx2ErrataFlag",HCF_RES_INT,(void*)&pDrvCtrl->pciEx2ErrataFlag);
pInst->pDrvCtrl = pDrvCtrl;
pDrvCtrl->bridgeInitFailed = FALSE;
globalBusCtrlID = pInst;
/* initialize PCI configuration library */
pDrvCtrl->pIntInfo = (struct vxbPciInt *)hwMemAlloc(sizeof(struct vxbPciInt));
if(pDrvCtrl->pIntInfo == NULL)
return;
vxbPciIntLibInit(pDrvCtrl->pIntInfo);
pDrvCtrl->pPciConfig = (struct vxbPciConfig*)hwMemAlloc(sizeof(struct vxbPciConfig));
if(pDrvCtrl->pPciConfig == NULL)
return;
SPIN_LOCK_ISR_INIT (&pDrvCtrl->spinlockIsr, 0);
if (vxbPciConfigLibInit(pDrvCtrl->pPciConfig,
pDrvCtrl->pciMaxBus) != OK)
return;
/* initialize PCI interrupt library */
pInst->pMethods = &ftPci_methods[0];
}
/******************************************************************************
*
* ftPciInstInit2 - initialize ftPci device
*
*/
LOCAL void ftPciInstInit2
(
VXB_DEVICE_ID pInst
)
{
FT_PCI_DRV_CTRL * pDrvCtrl = pInst->pDrvCtrl;
vxbBusAnnounce(pInst, VXB_BUSID_PCI);
if(pDrvCtrl->autoConfig==TRUE)
{
vxbPciAutoConfig(pInst);
}
if (pDrvCtrl->funcPirqEnable != NULL)
(*pDrvCtrl->funcPirqEnable) (TRUE);
vxbPciBusTypeInit(pInst);
}
/******************************************************************************
*
* ftPciInstConnect - connect ftPci device to I/O system
*
* Nothing to do here. We want serial channels available for output reasonably
* early during the boot process. Because this is a serial channel, we connect
* to the I/O system in ftPciInstInit2() instead of here.
*
* RETURNS: N/A
*
* ERRNO
*/
LOCAL void ftPciInstConnect
(
VXB_DEVICE_ID pInst
)
{
FT_DEBUG_MSG(1,"ftPciInstConnect(): called \n",1,2,3,4,5,6);
}
#ifdef FT_DEBUG_ENABLE
/******************************************************************************
*
* ftPcipDrvCtrlShow - show pDrvCtrl for ftPci bus controller
*
*/
int ftPcipDrvCtrlShow
(
VXB_DEVICE_ID pInst
)
{
FT_PCI_DRV_CTRL * pDrvCtrl;
int i;
union
{
UINT32 i[2];
char magic[10];
} magic;
if ( pInst == NULL )
pInst = pFtPciDrvCtrl0->pInst;
pDrvCtrl = pInst->pDrvCtrl;
printf("pDrvCtrl @ 0x%08x\n", pDrvCtrl);
printf(" pInst @ 0x%08x\n", pDrvCtrl->pInst);
printf(" pHcf @ 0x%08x\n", pDrvCtrl->pHcf);
bzero(magic.magic,10);
magic.i[0] = pDrvCtrl->magicNumber1;
magic.i[1] = pDrvCtrl->magicNumber2;
printf(" magic = \"%s\"\n", &magic.magic[0]);
printf(" mem @ 0x%08x, size %d (0x%08x)\n",
pDrvCtrl->mem32Addr, pDrvCtrl->mem32Size,
pDrvCtrl->mem32Size);
printf(" memIO @ 0x%08x, size %d (0x%08x)\n",
pDrvCtrl->memIo32Addr, pDrvCtrl->mem32Size,
pDrvCtrl->memIo32Size);
printf(" io32 @ 0x%08x, size %d (0x%08x)\n",
pDrvCtrl->io32Addr, pDrvCtrl->mem32Size,
pDrvCtrl->io32Size);
printf(" pimmr @ 0x%08x\n", pDrvCtrl->pimmrBase);
printf(" mstrMemBus @ 0x%08x\n", pDrvCtrl->mstrMemBus);
printf(" lclMemAddr @ 0x%08x\n", pDrvCtrl->lclMemAddr);
printf(" lclMemMapSize = 0x%08x\n", pDrvCtrl->lclMemMapSize);
printf(" autoConfig = 0x%08x\n", pDrvCtrl->autoConfig);
printf(" pciExpressHost = 0x%08x\n", pDrvCtrl->pciExpressHost);
printf(" Init done: %s\n",
pDrvCtrl->initDone ? "TRUE" : "FALSE");
return(0);
}
#endif /* FT_DEBUG_ENABLE */
/*******************************************************************************
*
* ftPciDevControl - device control routine
*
* This routine handles manipulation of downstream devices, such as
* interrupt management.
*
*/
LOCAL STATUS ftPciDevControl
(
VXB_DEVICE_ID devID,
pVXB_DEVCTL_HDR pBusDevControl
)
{
VXB_DEVICE_ID busCtrlID;
struct vxbIntDynaVecInfo dynaVec;
FT_PCI_DRV_CTRL *pDrvCtrl;
VXB_ASSERT(devID != NULL && pBusDevControl != NULL, ERROR)
busCtrlID = vxbDevParent(devID);
pDrvCtrl = ((FT_PCI_DRV_CTRL *)busCtrlID->pDrvCtrl);
switch ( pBusDevControl->vxbAccessId)
{
case VXB_ACCESS_INT_VEC_GET:
{
pVXB_ACCESS_INT_VECTOR_GET accessVectorGet;
struct pciIntrEntry * pciIntInfo;
pciIntInfo = (struct pciIntrEntry *)(devID->pIntrInfo);
accessVectorGet = (pVXB_ACCESS_INT_VECTOR_GET) pBusDevControl;
/*
* Check if MSI is enabled and if device is MSI capable
* while it is getting registered.
*/
if ((pDrvCtrl->dynamicInterrupts==TRUE) &&
(pDrvCtrl->msiEnable == TRUE) &&
(vxbPciMSIIsCap (devID) == TRUE))
{
accessVectorGet->pIntVector = (VOIDFUNCPTR*)VXB_INTR_DYNAMIC;
return(OK);
}
if (pDrvCtrl->extIntMap != NULL)
{
struct vxbPciDevice * pPciDev;
int devNo;
int intNum;
pPciDev = (struct vxbPciDevice *)devID->pBusSpecificDevInfo;
devNo = pPciDev->pciDev;
intNum = ftPciIntNumGet (devID, pBusDevControl, devNo);
if (intNum == ERROR)
return ERROR;
accessVectorGet->pIntVector = (VOIDFUNCPTR*)INUM_TO_IVEC(intNum);
return(OK);
}
/* check if the index is valid */
if (accessVectorGet->intIndex >= 255)
return ERROR;
accessVectorGet->pIntVector =
(VOIDFUNCPTR*)INUM_TO_IVEC(pciIntInfo->intVecInfo[accessVectorGet->intIndex].index);
return(OK);
}
case VXB_ACCESS_INT_CONNECT:
{
pVXB_ACCESS_INTERRUPT_INFO accessIntrInfo;
struct pciIntrEntry * pInterruptInfo;
STATUS retVal;
/* get appropriate structures */
accessIntrInfo = (pVXB_ACCESS_INTERRUPT_INFO) pBusDevControl;
pInterruptInfo = (struct pciIntrEntry *)(devID->pIntrInfo);
/*
* check if the interrupt vector is set to a dynamic one;
* This only happens when the device is already registered
* and checked for MSI enable and MSI capability.
*/
if (pInterruptInfo->intVecInfo[accessIntrInfo->intIndex].intVector
==(VOIDFUNCPTR*) VXB_INTR_DYNAMIC)
{
dynaVec.isr = accessIntrInfo->pISR;
dynaVec.pArg = accessIntrInfo->pParameter;
retVal=ERROR;
if(_func_vxbIntDynaConnect!=NULL)
retVal = _func_vxbIntDynaConnect(devID,
1,
&dynaVec);
if (retVal == OK)
return(OK);
/* Drop through to the original mechanism and prevent further
attempts if function not available or fails */
pDrvCtrl->dynamicInterrupts=FALSE;
}
/* connect the interrupt */
retVal = vxbPciIntConnect(devID,
(VOIDFUNCPTR*)pInterruptInfo->intVecInfo[accessIntrInfo->intIndex].intVector,
(VOIDFUNCPTR)accessIntrInfo->pISR,
(int)accessIntrInfo->pParameter
);
return(retVal);
}
case VXB_ACCESS_INT_ENABLE:
{
pVXB_ACCESS_INTERRUPT_INFO accessIntrInfo;
struct pciIntrEntry * pInterruptInfo;
STATUS retVal;
accessIntrInfo = (pVXB_ACCESS_INTERRUPT_INFO) pBusDevControl;
pInterruptInfo = (struct pciIntrEntry *)(devID->pIntrInfo);
/*
* check if the interrupt vector is set to a dynamic one;
* This only happens when the device is already registered
* and checked for MSI enable and MSI capability.
*/
if (pInterruptInfo->intVecInfo[accessIntrInfo->intIndex].intVector
== (VOIDFUNCPTR*)VXB_INTR_DYNAMIC )
{
retVal = vxbIntEnable(devID,
0,
(VOIDFUNCPTR)accessIntrInfo->pISR,
(void*)accessIntrInfo->pParameter);
return (retVal);
}
retVal = intEnable(IVEC_TO_INUM(pInterruptInfo->intVecInfo[accessIntrInfo->intIndex].intVector));
return(retVal);
}
case VXB_ACCESS_INT_DISABLE:
{
pVXB_ACCESS_INTERRUPT_INFO accessIntrInfo;
struct pciIntrEntry * pInterruptInfo;
STATUS retVal;
accessIntrInfo = (pVXB_ACCESS_INTERRUPT_INFO) pBusDevControl;
pInterruptInfo = (struct pciIntrEntry *)(devID->pIntrInfo);
/*
* check if the interrupt vector is set to a dynamic one;
* This only happens when the device is already registered
* and checked for MSI enable and MSI capability.
*/
if (pInterruptInfo->intVecInfo[accessIntrInfo->intIndex].intVector
==(VOIDFUNCPTR*)VXB_INTR_DYNAMIC )
{
retVal = vxbIntDisable(devID,
0,
(VOIDFUNCPTR)accessIntrInfo->pISR,
(void*)accessIntrInfo->pParameter);
return(retVal);
}
/* disable the interrupt */
retVal = intDisable(IVEC_TO_INUM(pInterruptInfo->intVecInfo[accessIntrInfo->intIndex].intVector));
return(retVal);
}
case VXB_ACCESS_INT_ACKNOWLEDGE:
return OK;
case VXB_ACCESS_INT_DISCONN:
return(ERROR);
default:
return ERROR;
}
}
/*******************************************************************************
*
* ftPciIntNumGet - get int num for specified device
*
* This routine looks through the interrupt table passed in as extIntMap and
* and returns the appropriate value, or ERROR, if the device number is not
* found.
*
*/
LOCAL int ftPciIntNumGet
(
VXB_DEVICE_ID devID,
pVXB_DEVCTL_HDR pBusDevControl,
int devNo
)
{
pVXB_ACCESS_INTERRUPT_INFO accessIntrInfo;
int l;
UINT8 header;
#ifndef VXB_LEGACY_ACCESS
PCI_HARDWARE * pPciDev = (PCI_HARDWARE *) devID->pBusSpecificDevInfo;
#endif /* !VXB_LEGACY_ACCESS */
int pciIntSlots = pFtPciDrvCtrl0->extIntMapSize;
int * pciIntMap = pFtPciDrvCtrl0->extIntMap;
int * pPciInt;
accessIntrInfo = (pVXB_ACCESS_INTERRUPT_INFO) pBusDevControl;
if (accessIntrInfo->intIndex == 0)
{
for (pPciInt = pciIntMap, l = 0; l < pciIntSlots; pPciInt += 5, l++)
{
if (devNo == pPciInt[0])
return pPciInt[accessIntrInfo->intIndex + 1];
}
return ERROR;
}
else if (0 < accessIntrInfo->intIndex && accessIntrInfo->intIndex < 4)
{
FT_PCI_CFG_READ(devID, PCI_CFG_HEADER_TYPE, 1, header);
if ((header & PCI_HEADER_MULTI_FUNC) != PCI_HEADER_MULTI_FUNC)
{
FT_DEBUG_MSG(1,"device is not multifunction , illegal intPin %d\n",accessIntrInfo->intIndex,2,3,4,5,6);
return ERROR;
}
else
{
for (pPciInt = pciIntMap, l = 0; l < pciIntSlots; pPciInt += 5, l++)
{
if (devNo == pPciInt[0])
return pPciInt[accessIntrInfo->intIndex + 1];
}
return ERROR;
}
}
else
{
FT_DEBUG_MSG(1,"illegal intPin %d, allowed 0,1,2,3\n",accessIntrInfo->intIndex,2,3,4,5,6);
return ERROR;
}
return ERROR;
}
int pci_config_bdf_pack_ex
(
int busno,
int devno,
int fnno
)
{
return(((busno << 20) & 0x0ff00000) |
((devno << 15) & 0x000f8000) |
((fnno << 12) & 0x00007000));
}
BOOL ft_pci_isbridge
(
int busno, /* bus number */
int devno, /* device number */
int fnno /* function number */
)
{
volatile UINT32 addr = 0;
volatile UINT16 pci_class = 0;
volatile UINT8 pci_head = 0;
/* Header Type: bit7: 0:single func. 1: multi func
* bit6-0: 00: normal dev. 01: normal bridge. 02: CARDBUS bridge
*/
addr = (ft_pcicfg_va_base +
pci_config_bdf_pack_ex (busno, devno, fnno) + PCI_CFG_HEADER_TYPE );
pci_head = *(volatile UINT8*) addr;
pci_head &= PCI_HEADER_TYPE_MASK;
addr = (ft_pcicfg_va_base +
pci_config_bdf_pack_ex (busno, devno, fnno) + PCI_CFG_SUBCLASS );
pci_class = *(volatile UINT16*) addr;
if((pci_class == ((PCI_CLASS_BRIDGE_CTLR << 8) + PCI_SUBCLASS_P2P_BRIDGE)) ||
(pci_class == ((PCI_CLASS_BRIDGE_CTLR << 8) + PCI_SUBCLASS_CARDBUS_BRIDGE)) ||
(pci_head == PCI_HEADER_PCI_PCI) ||(pci_head == PCI_HEADER_PCI_CARDBUS))
{
return TRUE; /* is bridge */
}
else
{
return FALSE;
}
}
int ft_pci_cfg_read
(
pci_dev_addr_t *dev,
UINT32 offset,
pci_cfg_trans_width_t size,
void *data
)
{
UINT8 busno = 0;
UINT8 devno = 0;
UINT8 fnno = 0;
volatile UINT32 addr = 0;
if(NULL == dev)
{
return ERROR;
}
busno = dev->busno;
devno = dev->devno;
fnno = dev->fnno;
addr = (ft_pcicfg_va_base +
pci_config_bdf_pack_ex (busno, devno, fnno) + offset);
switch(size)
{
case PCI_CFG_TRANS_8BIT:
*((UINT8*)data) = *((volatile UINT8*) addr);
break;
case PCI_CFG_TRANS_16BIT:
*((UINT16*)data) = *((volatile UINT16*) addr);
break;
case PCI_CFG_TRANS_32BIT:
*((UINT32*)data) = *((volatile UINT32*) addr);
break;
default:
return ERROR;
}
return(OK);
}
int ft_pci_cfg_write
(
pci_dev_addr_t *dev,
UINT32 offset,
pci_cfg_trans_width_t size,
UINT32 data
)
{
UINT8 busno = 0;
UINT8 devno = 0;
UINT8 fnno = 0;
volatile UINT32 addr = 0;
if(NULL == dev)
{
return ERROR;
}
busno = dev->busno;
devno = dev->devno;
fnno = dev->fnno;
addr = (ft_pcicfg_va_base +
pci_config_bdf_pack_ex (busno, devno, fnno) + offset);
switch(size)
{
case PCI_CFG_TRANS_8BIT:
*((volatile UINT8*)addr) = (UINT8)data;
break;
case PCI_CFG_TRANS_16BIT:
*((volatile UINT16*)addr) = (UINT16)data;
break;
case PCI_CFG_TRANS_32BIT:
*((volatile UINT32*)addr) = (UINT32)data;
break;
default:
return ERROR;
}
return(OK);
}
int ftPciCfgRead
(
UINT8 b,
UINT8 d,
UINT8 f,
unsigned int offset,
unsigned int size,
void *data
)
{
pci_dev_addr_t dev;
dev.busno = b;
dev.devno = d;
dev.fnno = f;
return ft_pci_cfg_read(&dev,(UINT32)offset,
(pci_cfg_trans_width_t)size,data);
}
int ftPciCfgWrite
(
UINT8 b,
UINT8 d,
UINT8 f,
unsigned int offset,
unsigned int size,
UINT32 data
)
{
pci_dev_addr_t dev;
dev.busno = b;
dev.devno = d;
dev.fnno = f;
return ft_pci_cfg_write(&dev, (UINT32)offset,
(pci_cfg_trans_width_t)size,data);
}
/******************************************************************************
*
* ftPciMethodConvertBaseAddress - PCI BAR address conversion method
*
* This routine implements the convertBaseAddress method exported by this
* driver via its VxBus methods table. The vxbPci.c module uses this
* routine to apply fixups to the addresses read from the BARs on
* devices that are enumerated on this bus.
*
* RETURNS: ERROR if base address is invalid, otherwise OK
*
* ERRNO: N/A
*/
LOCAL STATUS ftPciMethodConvertBaseAddress
(
VXB_DEVICE_ID devID, /* device info */
UINT32 * pBaseAddr /* pointer to base address */
)
{
UINT32 baseAddress;
FT_PCI_DRV_CTRL * pDrvCtrl;
UINT32 param1 = 0;
pDrvCtrl = devID->pDrvCtrl;
/* if base address pointer is NULL, return ERROR */
if (pBaseAddr == NULL)
return ERROR;
baseAddress = *pBaseAddr;
/* Use the mask values to get the base address */
if ((baseAddress & PCI_BAR_SPACE_MASK) == PCI_BAR_SPACE_IO)
{
/*
* resourceDesc {
* See the previous description for the ioStart resource. }
*/
devResourceGet (pDrvCtrl->pHcf, "ioStart",
HCF_RES_ADDR, (void *)&param1);
baseAddress &= 0xFFFFFFFC;
baseAddress += param1;
}
else
baseAddress &= 0xFFFFFFF0;
/* update the converted base address */
*pBaseAddr = baseAddress;
return (OK);
}
#endif