c64xx_pci.c
上传用户:dahaojd
上传日期:2008-01-29
资源大小:14357k
文件大小:22k
- /*
- * Copyright 2003 by Texas Instruments Incorporated.
- * All rights reserved. Property of Texas Instruments Incorporated.
- * Restricted rights to use, duplicate or disclose this code are
- * granted through contract.
- *
- */
- /* "@(#) DDK 1.10.00.23 07-02-03 (ddk-b12)" */
- /*
- * ======== c64xx_pci.c ========
- *
- * DSP/BIOS PCI IOM mini-driver for the c64xx DSPs
- * Uses the BIOS PCI Chip Support Library(CSL).
- */
- #include <std.h>
- #include <csl_pci.h>
- #include <hwi.h>
- #include <mem.h>
- #include <que.h>
- #include <iom.h>
- #include <c64xx_pci.h>
- /* PCI Interrupt mapped to HWI Vector 4 */
- #define ISR_VECTOR_ID 4
- #define GET_BYTE_COUNT(count)
- (((count)<< 16) & C64XX_PCI_MASK_PCIMC_CNT)
- #define CALLBACK(chan, packet, result) { (packet)->status = (result);
- ((chan)->callback)((Ptr)(chan)->callbackArg, (packet));}
- /* Channel variables */
- typedef struct ChanObj {
- QUE_Handle queue; /* priority queue */
- Uns writeCount; /* count for number of IOM_WRITE IOPs */
- IOM_Packet *flushAbortIop; /* hold IOM_FLUSH/IOM_ABORT IOP */
- /* callback used to notify client when I/O complete */
- IOM_TiomCallback callback;
- Ptr callbackArg;
- } ChanObj, *ChanHandle;
- /* Device object */
- typedef struct PCIDeviceObj
- {
- IOM_Packet *curPacket; /* current packet in process */
- QUE_Obj highPrioQue;
- QUE_Obj lowPrioQue;
- C64XX_PCI_TerrCallback errCallback; /* async error callback */
- Uns evtMask; /* registered events ored together */
- C64XX_PCI_ErrInfo *errInfo; /* detailed info for async error */
- Int openCount; /* count number of open channels */
- } PCIDeviceObj, PCIDeviceHandle;
- /* static device object */
- static PCIDeviceObj device;
- static Void doTransfer(C64XX_PCI_Request *request);
- static Void isr();
- #ifdef PCI_ERROR_ISR_IMPL
- static Void pciErrorIsr();
- #endif
- static Void processQueue();
- static Void removePackets(Ptr chanp, Int cmd);
- static Void resetChannel(Ptr chanp);
- static Void resetDevice();
- /*
- * Forward declaration of mini driver interface functions. They are only
- * exposed via the IOM_Fxns function table to avoid namespace pollution.
- */
- static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams);
- static Int mdControlChan(Ptr chanp, Uns command, Ptr arg);
- static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
- Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg);
- static Int mdDeleteChan(Ptr chanp);
- static Int mdSubmitChan(Ptr chanp, IOM_Packet* pPacket);
- static Int mdUnBindDev(Ptr devp);
- /*
- * Public mini driver interface table.
- */
- IOM_Fxns C64XX_PCI_FXNS = {
- &mdBindDev,
- &mdUnBindDev,
- &mdControlChan,
- &mdCreateChan,
- &mdDeleteChan,
- &mdSubmitChan
- };
- /*
- * ======== mdBindDev ========
- * This function will init the queues, set up interrupt.
- * it does not allocate memory, so return NULL.
- */
- static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams)
- {
- Int intrId;
- C64XX_PCI_DevParams *pciDevParams = (C64XX_PCI_DevParams *)devParams;
- HWI_Attrs hwiAttrs;
- QUE_new(&device.highPrioQue);
- QUE_new(&device.lowPrioQue);
-
- device.curPacket = NULL;
- device.openCount = 0;
-
- if (pciDevParams != NULL) {
- /* Check the version number */
- if (pciDevParams->versionId != C64XX_PCI_VERSION_1){
- /* Unsupported version */
- return(IOM_EBADARGS);
- }
- if (pciDevParams->pciIntrId > 0) {
- intrId = pciDevParams->pciIntrId;
- }
- else {
- intrId = ISR_VECTOR_ID;
- }
-
- hwiAttrs.intrMask = pciDevParams->intrMask;
- if (pciDevParams->errCallback != NULL) {
- device.errCallback = pciDevParams->errCallback->errFxn;
- device.evtMask = pciDevParams->errCallback->evtMask;
- device.errInfo = pciDevParams->errCallback->errInfo;
- }
- else {
- device.errCallback = NULL;
- }
- #ifdef PCI_ERROR_ISR_IMPL
- /*
- * pciErrIntrId plug in depend on board hardware design.
- * ERR_ISR_VECTOR_ID: TBD.
- */
-
- Int pciErrIntrId;
- if (pciDevParams->pciErrIntrId > 0) {
- pciErrIntrId = pciDevParams->pciErrIntrId;
- }
- else {
- pciErrIntrId = ERR_ISR_VECTOR_ID;
- }
- #endif
- }
- else {
- intrId = ISR_VECTOR_ID;
- hwiAttrs.intrMask = C64XX_PCI_INTR_MASK_DEFAULT;
- device.errCallback = NULL;
- }
-
- hwiAttrs.ccMask = IRQ_CCMASK_NONE; /* the default value */
- hwiAttrs.arg = NULL;
- /* plug in normal pci isr routine */
- IRQ_map(IRQ_EVT_DSPINT, intrId);
- /* dmachan parameter set to -1 since 6416 has EDMA instead of DMA */
- HWI_dispatchPlug(intrId, (Fxn)isr, -1, &hwiAttrs);
- #ifdef PCI_ERROR_ISR_IMPL
- /* plug in error pci isr routine if registered. IRQ_EVT_XXX: TBD.
- * need to enable two bits in PCI Command Register: TBD
- * bit6 - parity error reporting enable bit
- * bit8 - system error reporting ebable bit
- */
- IRQ_map(IRQ_EVT_XXX, pciErrIntrId);
- HWI_dispatchPlug(pciErrIntrId, (Fxn)pciErrIsr, -1, NULL);
- IRQ_enable(IRQ_EVT_XXX);
- #endif
- return (IOM_COMPLETED);
-
- }
- /*
- * ======== mdControlChan ========
- * This function could be implemented by using function table, avoid complier
- * link each function and also avoid using "switch" call.
- * return status
- */
- static Int mdControlChan(Ptr chanp, Uns command, Ptr arg)
- {
- C64XX_PCI_EEPROMData *promData = (C64XX_PCI_EEPROMData *)arg;
- Uns result;
- Uns imask;
-
- #ifdef TEST_ERROR_HANDLER
- Bool report;
- C64XX_PCI_Request *req;
- IOM_Packet *packet;
- Uns error;
- Uns event;
- #endif
-
- switch (command) {
- /* EEPROM call. */
- case C64XX_PCI_EEPROM_ERASE:
- promData->eeData = PCI_eepromErase((Uns)promData->eeAddr);
- return (IOM_COMPLETED);
- case C64XX_PCI_EEPROM_ERASE_ALL:
- promData->eeData = PCI_eepromEraseAll();
- return (IOM_COMPLETED);
- case C64XX_PCI_EEPROM_IS_AUTO_CFG:
- promData->eeData = PCI_eepromIsAutoCfg();
- return (IOM_COMPLETED);
- case C64XX_PCI_EEPROM_READ:
- promData->eeData = PCI_eepromRead((Uns)promData->eeAddr);
- return (IOM_COMPLETED);
- case C64XX_PCI_EEPROM_SIZE:
- promData->eeData = PCI_eepromSize();
- return (IOM_COMPLETED);
- case C64XX_PCI_EEPROM_TEST:
- promData->eeData = PCI_eepromTest();
- return (IOM_COMPLETED);
- case C64XX_PCI_EEPROM_WRITE:
- result = PCI_eepromWrite((Uns)promData->eeAddr, promData->eeData);
- promData->eeData = result;
- return (IOM_COMPLETED);
- case C64XX_PCI_EEPROM_WRITE_ALL:
- result = PCI_eepromWriteAll(promData->eeData);
- promData->eeData = result;
- return (IOM_COMPLETED);
- /* Host interrupt call */
- case C64XX_PCI_DSP_INT_REQ_SET:
- PCI_dspIntReqSet();
- return (IOM_COMPLETED);
- case C64XX_PCI_DSP_INT_REQ_CLEAR:
- PCI_dspIntReqClear();
- return (IOM_COMPLETED);
- /* reset calls */
- case C64XX_PCI_RESET_CHANNEL:
- resetChannel(chanp);
- return (IOM_COMPLETED);
- case C64XX_PCI_RESET_ALL_CHANNELS:
- resetDevice();
- return (IOM_COMPLETED);
- #ifdef TEST_ERROR_HANDLER
- case C64XX_PCI_TEST_ERROR_HANDLER:
- error = 0;
- report = FALSE;
- event = *((Uns *)arg);
- imask = HWI_disable();
- if (device.errCallback == NULL) {
- HWI_restore(imask);
- return (IOM_COMPLETED);
- }
- if ((event == C64XX_PCI_EVT_PARITY_ERR) &&
- (device.evtMask & C64XX_PCI_EVT_PARITY_ERR)) {
- error = error | C64XX_PCI_EVT_PARITY_ERR;
- report = TRUE;
- }
- else if ((event == C64XX_PCI_EVT_SYSTEM_ERR) &&
- (device.evtMask & C64XX_PCI_EVT_SYSTEM_ERR)) {
- error = error | C64XX_PCI_EVT_SYSTEM_ERR;
- report = TRUE;
- }
- if (!report) {
- HWI_restore(imask);
- return (IOM_COMPLETED);
- }
- if (device.curPacket != NULL) {
- packet = device.curPacket;
- req = (C64XX_PCI_Request *)packet->addr;
- device.errInfo->inprogressDstAddr = req->dstAddr;
- device.errInfo->inprogressSrcAddr = req->srcAddr;
- /* device.errInfo->statusReg = PCI_STATUS_REGISTER; */
- }
- else {
- device.errInfo->inprogressDstAddr = NULL;
- device.errInfo->inprogressSrcAddr = NULL;
- /* device.errInfo->statusReg = PCI_STATUS_REGISTER; */
- }
- (device.errCallback)(error, (Ptr)device.errInfo);
- HWI_restore(imask);
- return (IOM_COMPLETED);
- #endif
- default:
- break;
- }
-
- return (IOM_ENOTIMPL);
- }
- /*
- * ======== mdCreateChan ========
- * This function allocates memory for channel object and initializes it.
- * return IOM_COMPLETED if success return IOM_EALLOC if fails
- */
- static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
- Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg)
- {
- ChanHandle chan;
- C64XX_PCI_Attrs *pciAttrs = (C64XX_PCI_Attrs *)chanParams;
- Uns imask;
-
- chan = MEM_alloc(0, sizeof(ChanObj), 0);
- if ( chan == MEM_ILLEGAL ) {
- return (IOM_EALLOC);
- }
-
- if (mode != IOM_INOUT) {
- return (IOM_EBADMODE);
- }
- /* Initialize the channel structure */
- if ( pciAttrs != NULL &&
- pciAttrs->queuePriority == C64XX_PCI_QUEUE_PRIORITY_HIGH) {
- chan->queue = &device.highPrioQue;
- }
- else {
- chan->queue = &device.lowPrioQue;
- }
-
- chan->writeCount = 0;
- chan->flushAbortIop = NULL;
- chan->callback = cbFxn;
- chan->callbackArg = cbArg;
-
- imask = HWI_disable();
- if (device.openCount == 0) {
- /* enable PCI events */
- PCI_intEnable(PCI_EVT_PCIMASTER);
- PCI_intEnable(PCI_EVT_PCITARGET);
- PCI_intEnable(PCI_EVT_MASTEROK);
- IRQ_enable(IRQ_EVT_DSPINT);
- }
- device.openCount++;
- HWI_restore(imask);
- *chanp = chan;
- return (IOM_COMPLETED);
- }
- /*
- * ======== mdDeleteChan ========
- * frees memory
- * return status
- */
- static Int mdDeleteChan(Ptr chanp)
- {
- ChanHandle chan = (ChanHandle)chanp;
- Uns imask;
- MEM_free(0, chan, sizeof(ChanObj));
- imask = HWI_disable();
- device.openCount--;
- if (device.openCount == 0) {
- /* disable PCI events */
- PCI_intDisable(PCI_EVT_PCIMASTER);
- PCI_intDisable(PCI_EVT_PCITARGET);
- PCI_intDisable(PCI_EVT_MASTEROK);
- IRQ_disable(IRQ_EVT_DSPINT);
- }
- HWI_restore(imask);
- return (IOM_COMPLETED);
- }
- /*
- * ======== mdSubmitChan ========
- * return submit status
- */
- static Int mdSubmitChan(Ptr chanp, IOM_Packet *pPacket)
- {
- ChanHandle chan = (ChanHandle)chanp;
- IOM_Packet* packet = pPacket;
- Uns imask;
- C64XX_PCI_Request *req;
- C64XX_PCI_Request *curReq;
- req = (C64XX_PCI_Request *)packet->addr;
- req->reserved = chan;
-
- /* IOM_READ or IOM_WRITE command handle in the same way */
- if (packet->cmd == IOM_READ || packet->cmd == IOM_WRITE) {
- imask = HWI_disable();
- QUE_enqueue(chan->queue, packet);
- if (device.curPacket == NULL) {
- #ifndef TEST_RESET
- processQueue();
- #endif
- }
- HWI_restore(imask);
- return (IOM_PENDING);
- }
- if (packet->cmd == IOM_FLUSH || packet->cmd == IOM_ABORT) {
-
- imask = HWI_disable();
- chan->flushAbortIop = packet;
- /* check the channel of pending packet */
- if (device.curPacket != NULL) {
- curReq = (C64XX_PCI_Request *)device.curPacket->addr;
- /* The pending packet is this channel. Let isr handles it */
- if ((ChanHandle)curReq->reserved == chan) {
- HWI_restore(imask);
- return (IOM_PENDING);
- }
- }
-
- /* the pending packet is not FLUSH/ABORT channel */
- removePackets(chan, packet->cmd);
- /* FLUSH/ABORT done */
- if (chan->writeCount == 0) {
- chan->flushAbortIop = NULL;
- HWI_restore(imask);
- return (IOM_COMPLETED);
- }
- HWI_restore(imask);
- return (IOM_PENDING);
- }
- return (IOM_EBADIO);
- }
- /*
- * ======== mdUnBindDev ========
- * return status
- */
- static Int mdUnBindDev(Ptr devp)
- {
- /* empty for now */
- return (IOM_COMPLETED);
- }
- /*
- * ======== C64XX_PCI_init ========
- */
- Void C64XX_PCI_init(Void)
- {
- /* empty for now */
- }
- /*
- * ======== isr ========
- * interrupt service routine is runtime pluged in
- */
- static Void isr(Void)
- {
- ChanHandle chan;
- IOM_Packet *oldPacket;
- C64XX_PCI_Request *oldReq;
- Int status = IOM_EBADIO;
-
- if (PCI_FGET(PCIIS, MASTEROK)) {
- /* pci master transfer complete */
- PCI_FSET(PCIIS, MASTEROK, 1);
- status = IOM_COMPLETED;
-
- }
- else if (PCI_FGET(PCIIS, PCIMASTER)) {
- /* pci master abort */
- PCI_FSET(PCIIS, PCIMASTER, 1);
-
- }
- else if (PCI_FGET(PCIIS, PCITARGET)) {
- /* pci target abort */
- PCI_FSET(PCIIS, PCITARGET, 1);
-
- }
- else {
- /* not registered interrupt, clear intr here */
- PCI_RSET(PCIIS, 0x00000FFF);
- /* error handling TBD */
- return;
- }
- if (device.curPacket != NULL) {
- oldPacket = device.curPacket;
- oldReq = (C64XX_PCI_Request *)oldPacket->addr;
- chan = (ChanHandle)oldReq->reserved;
-
- device.curPacket = NULL;
- if (chan->flushAbortIop == NULL) {
- /* normal. process next request in the queues */
- processQueue();
-
- /* callback */
- CALLBACK(chan,oldPacket,status);
- return;
- }
-
- /* flush or abort cmd */
- /* first do callback */
- CALLBACK(chan,oldPacket,status);
-
- if (chan->writeCount) {
- chan->writeCount--;
- }
- else {
- removePackets(chan, chan->flushAbortIop->cmd);
- }
-
- /* process next request in the queues */
- processQueue();
- /* if all write IOPs are done, call the callback for the FLUSH IOP */
- if (chan->writeCount == 0) {
- CALLBACK(chan,chan->flushAbortIop,IOM_COMPLETED);
- chan->flushAbortIop = NULL;
- }
- return;
- }
- /* process next request in the queues */
- processQueue();
- }
- /*
- * ======== pciErrorIsr ========
- * interrupt service routine is runtime pluged in for asynchronous error TBD
- */
- #ifdef PCI_ERROR_ISR_IMPL
- static Void pciErrorIsr(Void)
- {
- /* How to check PCI status register to identify the error source --
- parity/system: TBD (on C6416, not accessable) use 'event' here to
- represent the status register related content */
-
- Bool report = FALSE;
- Uns error = 0;
- C64XX_PCI_Request *req;
- IOM_Packet *packet;
- if (device.errCallback == NULL) {
- return;
- }
- if ((event == C64XX_PCI_EVT_PARITY_ERR) &&
- (device.evtMask & C64XX_PCI_EVT_PARITY_ERR)) {
- error = error | C64XX_PCI_EVT_PARITY_ERR;
- report = TRUE;
- }
- else if ((event == C64XX_PCI_EVT_SYSTEM_ERR) &&
- (device.evtMask & C64XX_PCI_EVT_SYSTEM_ERR)) {
- error = error | C64XX_PCI_EVT_SYSTEM_ERR;
- report = TRUE;
- }
- if (!report) {
- return;
- }
- if (device.curPacket != NULL) {
- packet = device.curPacket;
- req = (C64XX_PCI_Request *)packet->addr;
- device.errInfo->inprogressDstAddr = req->dstAddr;
- device.errInfo->inprogressSrcAddr = req->srcAddr;
- device.errInfo->statusReg = PCI_STATUS_REGISTER;
- }
- else {
- device.errInfo->inprogressDstAddr = NULL;
- device.errInfo->inprogressSrcAddr = NULL;
- device.errInfo->statusReg = PCI_STATUS_REGISTER;
- }
- (device.errCallback)(error, (Ptr)device.errorInfo);
-
- }
- #endif
- /*
- * ======== doTransfer ========
- */
- static Void doTransfer(C64XX_PCI_Request *request)
- {
- C64XX_PCI_Request *req = request;
- PCI_ConfigXfr config;
- Uns xfrMode;
-
- xfrMode = C64XX_PCI_GETXFERMODE(request->options);
-
- if (xfrMode == PCI_WRITE) {
- config.dspma = (Uns)req->srcAddr;
- config.pcima = (Uns)req->dstAddr;
- config.pcimc = GET_BYTE_COUNT(req->byteCnt);
-
- }
- else if (xfrMode == PCI_READ_PREF || xfrMode == PCI_READ_NOPREF) {
- config.dspma = (Uns)req->dstAddr;
- config.pcima = (Uns)req->srcAddr;
- config.pcimc = GET_BYTE_COUNT(req->byteCnt);
- }
-
- PCI_xfrConfig(&config);
- PCI_xfrStart(xfrMode);
- }
- /*
- * ======== processQueue ========
- */
- static Void processQueue()
- {
- QUE_Handle que;
- C64XX_PCI_Request *req;
- que = &device.highPrioQue;
- /* process next packet in queue */
- if (QUE_empty(que)) {
- que = &device.lowPrioQue;
- if (QUE_empty(que)) {
- return;
- }
- }
- device.curPacket = QUE_dequeue(que);
- req = (C64XX_PCI_Request *)device.curPacket->addr;
- doTransfer(req);
- }
- /*
- * ======== removePackets ========
- */
- static Void removePackets(Ptr chanp, Int cmd)
- {
- ChanHandle chan = (ChanHandle)chanp;
- QUE_Elem *next;
- QUE_Elem *current;
- C64XX_PCI_Request *curReq;
- Int status;
- if (cmd != IOM_FLUSH && cmd != IOM_ABORT) {
- return;
- }
-
- current = QUE_head(chan->queue);
- curReq = (C64XX_PCI_Request *)((IOM_Packet *)current)->addr;
-
- while (chan->queue != current) {
- next = QUE_next(current);
-
- /* check the channel of the each IOM_Packet in the queue */
- /* find the match. The packet and remove channels are identical */
- if ((ChanHandle)curReq->reserved == chan) {
- /* for write flush wait for complete */
- if ( cmd == IOM_FLUSH &&
- ((IOM_Packet *)current)->cmd == IOM_WRITE ) {
- chan->writeCount++;
- } else {
- /* for read flush or abort, do flush */
- if (cmd == IOM_FLUSH) {
- status = IOM_FLUSHED;
- }
- else {
- status = IOM_ABORTED;
- }
- QUE_remove(current);
- CALLBACK(chan, (IOM_Packet *)current, status);
- }
- }
-
- current = next;
- curReq = (C64XX_PCI_Request*)((IOM_Packet *)current)->addr;
- } /* end while */
- }
- /*
- * ======== resetChannel ========
- */
- static Void resetChannel(Ptr chanp)
- {
- ChanHandle chan = (ChanHandle)chanp;
- C64XX_PCI_Request *curReq;
- Uns imask;
-
- imask = HWI_disable();
- /* assume reset async ? */
- if (device.curPacket != NULL) {
- curReq = (C64XX_PCI_Request *)((IOM_Packet *)device.curPacket)->addr;
- if ((ChanHandle)curReq->reserved == chan) {
- CALLBACK((ChanHandle)curReq->reserved,
- (IOM_Packet *)device.curPacket, IOM_ABORTED);
- device.curPacket = NULL;
- }
- }
-
- removePackets(chanp, IOM_ABORT);
- HWI_restore(imask);
- }
- /*
- * ======== resetDevice ========
- */
- static Void resetDevice()
- {
- QUE_Elem *next;
- QUE_Elem *current;
- QUE_Handle queue;
- C64XX_PCI_Request *curReq;
- Int i;
- Uns imask;
-
- imask = HWI_disable();
- /* assume reset async ? */
- if (device.curPacket != NULL) {
- curReq = (C64XX_PCI_Request *)((IOM_Packet *)device.curPacket)->addr;
- CALLBACK((ChanHandle)curReq->reserved,
- (IOM_Packet *)device.curPacket, IOM_ABORTED);
- device.curPacket = NULL;
- }
-
- for (i = 0; i < 2; i++) {
- if (i == 0 ) {
- queue = &device.highPrioQue;
- }
- else {
- queue = &device.lowPrioQue;
- }
- /* remove all the elements in the high/low priority queue */
- current = QUE_head(queue);
- curReq = (C64XX_PCI_Request *)((IOM_Packet *)current)->addr;
-
- while (queue != current) {
- next = QUE_next(current);
-
- QUE_remove(current);
- CALLBACK((ChanHandle)curReq->reserved,
- (IOM_Packet *)current, IOM_ABORTED);
-
- current = next;
- curReq = (C64XX_PCI_Request*)((IOM_Packet *)current)->addr;
- } /* end while */
- } /* end for */
-
- HWI_restore(imask);
- }