|
/* * 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.11.00.00 11-04-03 (ddk-b13)" */ /* * ======== 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); }
|