/* * ======== edma3OsProtectExit ======== * OS critical section protect (Exit) function */ void edma3OsProtectExit(unsigned int edma3InstanceId, int level, unsigned int intState) { /* (void)edma3InstanceId;*/ switch (level) { /* Enable all (global) interrupts */ case EDMA3_OS_PROTECT_INTERRUPT : HWI_restore(intState); break; /* Enable scheduler */ case EDMA3_OS_PROTECT_SCHEDULER : break; case EDMA3_OS_PROTECT_INTERRUPT_XFER_COMPLETION : TSK_enable(); break; case EDMA3_OS_PROTECT_INTERRUPT_CC_ERROR : TSK_enable(); break; /* Enable EDMA3 TC error interrupt only */ case EDMA3_OS_PROTECT_INTERRUPT_TC_ERROR : switch (intState) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: /* Fall through... */ /* Enable the corresponding interrupt */ TSK_enable(); break; default: break; } break; default: break; } }
/** * \brief EDMA3 OS Protect Exit * * This function undoes the protection enforced to original state * as is specified by the variable 'intState' passed, if the protection * level is EDMA3_OS_PROTECT_INTERRUPT. * For EDMA3_OS_PROTECT_INTERRUPT_XFER_COMPLETION and * EDMA3_OS_PROTECT_INTERRUPT_CC_ERROR, variable 'intState' is ignored, * and the requested interrupt is enabled. * For EDMA3_OS_PROTECT_INTERRUPT_TC_ERROR, 'intState' specifies the * Transfer Controller number whose interrupt needs to be enabled. * \param level is numeric identifier of the desired degree of protection. * \param intState is original state of protection at time when the * corresponding edma3OsProtectEntry() was called (Only * for EDMA3_OS_PROTECT_INTERRUPT protection level). * \return None */ void edma3OsProtectExit (int level, unsigned int intState) { #if 0 //wj switch (level) { /* Enable all (global) interrupts */ case EDMA3_OS_PROTECT_INTERRUPT : HWI_restore(intState); break; /* Enable scheduler */ case EDMA3_OS_PROTECT_SCHEDULER : TSK_enable(); break; /* Enable EDMA3 transfer completion interrupt only */ case EDMA3_OS_PROTECT_INTERRUPT_XFER_COMPLETION : ECM_enableEvent(ccXferCompInt); break; /* Enable EDMA3 CC error interrupt only */ case EDMA3_OS_PROTECT_INTERRUPT_CC_ERROR : ECM_enableEvent(ccErrorInt); break; /* Enable EDMA3 TC error interrupt only */ case EDMA3_OS_PROTECT_INTERRUPT_TC_ERROR : switch (intState) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: /* Fall through... */ /* Enable the corresponding interrupt */ ECM_enableEvent(tcErrorInt[intState]); break; default: break; } break; default: break; } #endif }
/* * ======== freeBlock ======== */ static Bool freeBlock(RMM_Handle rmm, UInt32 addr, UInt32 size) { RMM_Header *head; RMM_Header *poolHead; RMM_Header *curr; RMM_Header *next = NULL; RMM_Header *rhead; RMM_Header *headers; Int nextIdx; Int currIdx; Int tmpIdx; Bool joined = FALSE; Bool retVal = TRUE; //DBC_assert(size > 0); GT_assert(ti_sdo_fc_dman3_GTMask, size > 0); /* Get the head of the free list */ head = &(rmm->freeList); /* Array of RMM Headers */ headers = (RMM_Header *)((UInt32)rmm + (UInt32)rmm->headers); /* Protect queues in case of context switch */ TSK_disable(); /* * Search down the list of free blocks for the right place to put a * header with address "addr". List is sorted by address, with lowest * address first in the list. */ curr = head; currIdx = nextIdx = curr->next; while ((nextIdx != -1) && (addr > headers[nextIdx].addr)) { curr = headers + nextIdx; currIdx = nextIdx; nextIdx = curr->next; } if (nextIdx != -1) { next = headers + nextIdx; } if (currIdx != -1) { curr = headers + currIdx; } /* * The freed block should be put in between curr and next, and the * it should not extend into the next block. * In the case that curr and next are in the middle of the list, * we should have * curr->addr < addr and (addr + size) <= next->addr */ /* * List is empty, or found element to insert after, or inserting at * the beginning of the list */ //DBC_assert((currIdx == -1) || (curr->addr < addr) || //(currIdx == head->next)); /* Got to the end of the list or found element to insert before */ //DBC_assert((nextIdx == -1) || (addr + size <= next->addr)); GT_assert(ti_sdo_fc_dman3_GTMask, (currIdx == -1) || (curr->addr < addr) || (currIdx == head->next)); GT_assert(ti_sdo_fc_dman3_GTMask, (nextIdx == -1) || (addr + size <= next->addr)); /* Join with upper block, if possible */ if ((nextIdx != -1) && ((addr + size) == next->addr)) { next->size += size; next->addr = addr; joined = TRUE; } /* Join with the lower block, if possible */ if ((currIdx != -1) && (currIdx != nextIdx) && ((curr->addr + curr->size) == addr)) { if (joined) { //DBC_assert(next != NULL); /* * We need to join the upper block and lower blocks, returning * one of the headers back to the free pool. */ curr->size += next->size; /* Take "next" out of the free block list */ curr->next = next->next; /* Put "next" in the pool of free headers */ poolHead = &(rmm->headerPool); next->next = poolHead->next; poolHead->next = nextIdx; } else { curr->size += size; joined = TRUE; } } /* * If we can't join the block we're freeing to an existing free block, * we need to get an RMM_Header from the free pool, initialize it, and * insert it in the free list. */ if (!joined) { poolHead = &(rmm->headerPool); /* If the pool of headers is empty, we're stuck */ if (poolHead->next == -1) { /* List is empty */ //DBC_assert(FALSE); GT_assert(ti_sdo_fc_dman3_GTMask, FALSE); retVal = FALSE; } else { /* Take the first header in the free pool. */ tmpIdx = poolHead->next; rhead = headers + tmpIdx; poolHead->next = rhead->next; /* * Now insert rhead into the free block list: * curr --> rhead --> next */ if (currIdx == nextIdx) { /* Insert at the beginning of the list */ curr = head; } curr->next = tmpIdx; rhead->next = nextIdx; rhead->addr = addr; rhead->size = size; } } TSK_enable(); return (retVal); }
/* * ======== allocBlock ======== * This allocation function allocates memory from the lowest addresses * first. */ static Bool allocBlock(RMM_Handle rmm, UInt32 size, UInt32 *addr) { RMM_Header *head; RMM_Header *poolHead; RMM_Header *prev; RMM_Header *curr; RMM_Header *headers; Int nextIdx; Int currIdx; UInt32 blockSize; Bool retVal = FALSE; /* Initialize head pointer to point to beginning of free list */ head = &(rmm->freeList); /* prev pointer should point to the previous entry, start by pointing to the head of free list */ prev = head; /* Array of RMM Headers */ headers = (RMM_Header *)((UInt32)rmm + (UInt32)rmm->headers); /* Protect queues in case of context switch */ TSK_disable(); /* Loop through free list till you reach the end (-1) */ while ((currIdx = prev->next) != -1) { /* curr pointer should point to the current freeList entry */ curr = headers + prev->next; /* nextIdx should point to the next entry in the linked list */ nextIdx = curr->next; /* size of the current free block */ blockSize = curr->size; if (blockSize >= size) { /* big enough */ /* If the block is a perfect match */ if (blockSize == size) { /* * Remove current header from the list of free blocks * and put it back in the pool of "allocated" headers, at the * beginning of the list. */ /* To remove entry from freeList, adjust the next pointer of the prev entry */ prev->next = nextIdx; /* poolHead points to headerPool which is list of allocated blocks */ poolHead = &(rmm->headerPool); /* Adjust next pointer of curr */ curr->next = poolHead->next; /* current entry will become the new beginning of headerPool */ poolHead->next = currIdx; } /* This is the allocated address, return it */ *addr = curr->addr; /* Adjust current entries size and addr to account for allocated memory */ curr->size -= size; curr->addr += size; retVal = TRUE; break; } prev = curr; } TSK_enable(); return (retVal); }
/* * DEV_createDevice creates device(DEV_Device) entry in the OBJ table * if device by that name do not exist in the system. * This API is not reentrant */ Int DEV_createDevice (String name, Void *fxns, Fxn initFxn, DEV_Attrs *attrs) { DEV_TableElem *objDevHead = (DEV_TableElem*) &DEV_table; DEV_TableElem *objDev, *objEntry; DEV_Device *dptr, *entry; IOM_Fxns *iomfxns; Int status; Uns key; /* * Crate a device entry, if not successful return * SYS_EALLOC. */ objEntry = MEM_calloc(0, sizeof(DEV_TableElem), 0); if (objEntry == NULL) { return(SYS_EALLOC); } TSK_disable(); /* * Check if device already exists in the Device table, if yes return * SYS_EINVAL */ DEV_find(name, &entry); if (entry != NULL) { TSK_enable(); MEM_free(0, objEntry, sizeof(DEV_TableElem)); SYS_error("DEV", SYS_EINVAL); return(SYS_EINVAL); } /* * Initialize new device entry(DEV_Device) in the OBJ table with * the parameters passed to API */ entry = &objEntry->device; entry->name = name; entry->fxns = fxns; if (attrs == NULL) { attrs = &DEV_ATTRS; } entry->devid = attrs->devid; entry->params = attrs->params; entry->type = attrs->type; entry->devp = attrs->devp; /* * Call the Device init function if its not NULL, with interrupts * disabled. */ if (initFxn != NULL) { key = HWI_disable(); (*initFxn)(); HWI_restore(key); } /* * If device created is of type IOM then call mini driver function * mdBindDev with interrupts disabled. */ if (entry->type == DEV_IOMTYPE) { iomfxns = (IOM_Fxns *) entry->fxns; key = HWI_disable(); status = iomfxns->mdBindDev(&entry->devp, entry->devid, entry->params); HWI_restore(key); if (status != IOM_COMPLETED) { TSK_enable(); /* Delete the just created device entry in device table */ MEM_free(0, objEntry, sizeof(DEV_TableElem)); SYS_error("DEV", SYS_EBADIO); return(status); } } /* * Device is ready for addition into OBJ_Table. Check new device * name length against existing device name lengths. If length of * new device is greater than one in OBJ_table, mark the location * and insert device ahead of device whose name length is shorter * else add it to the end. * * This will keep all the devices sorted in descending order, which is * required to pass additional parameters along with device name in * DEV_open() */ objDev = (DEV_TableElem *)QUE_next((Ptr)objDevHead); while (objDev != objDevHead) { dptr = &objDev->device; if (strlen(name) > strlen(dptr->name)) { break; } objDev = (DEV_TableElem *)QUE_next((Ptr)objDev); } /* Insert objEntry ahead of objDev */ QUE_insert(objDev, objEntry); TSK_enable(); return(SYS_OK); }
/* * ======== DPI_issue ======== */ Static Int DPI_issue(DEV_Handle dev) { PipeObj *pipe = (PipeObj *)dev->object; SPipeObj *sPipe = pipe->sPipe; DEV_Handle otherdev = sPipe->device[dev->mode ^ 0x1]; SEM_Handle otherReady = sPipe->readySem[dev->mode ^ 0x1]; DEV_Frame *otherframe; DEV_Frame *frame; #ifdef COPYBUFS DEV_Frame *srcframe; DEV_Frame *dstframe; #endif /* * Atomically check that each side has a frame so we can do an * exchange. We can't be sure that a frame is on the * dev->todevice queue (just put there by SIO) since a task * switch to the task on the other side might intervene and * take the frame from this side. */ TSK_disable(); if (otherdev != NULL && !QUE_empty(dev->todevice) && !QUE_empty(otherdev->todevice)) { otherframe = QUE_get(otherdev->todevice); frame = QUE_get(dev->todevice); /* done with atomic stuff */ TSK_enable(); /* * #define COPYBUFS to cause buffers to be copied through the pipe * instead of being exchanged. Doing so retains the semantics of * the ISSUERECLAIM model, but is slow. If COPYBUFS is *not* defined, * then one side reclaims buffers issued by the other side, thereby * not strictly retaining buffer ordering. */ #ifdef COPYBUFS if (dev->mode == DEV_INPUT) { dstframe = frame; srcframe = otherframe; } else { dstframe = otherframe; srcframe = frame; } memcpy(dstframe->addr, srcframe->addr, srcframe->size); dstframe->size = srcframe->size; dstframe->arg = srcframe->arg; QUE_put(dev->fromdevice, frame); QUE_put(otherdev->fromdevice, otherframe); /* * frames reclaimed from an output device must have size 0. */ if (dev->mode != DEV_INPUT) { frame->size = 0; } else { otherframe->size = 0; } #else QUE_put(dev->fromdevice, otherframe); QUE_put(otherdev->fromdevice, frame); /* * frames reclaimed from an output device must have size 0. */ if (dev->mode != DEV_INPUT) { otherframe->size = 0; } else { frame->size = 0; } #endif } else { /* done with atomic stuff */ TSK_enable(); } SEM_post(pipe->toSem); if (otherReady != NULL) { SEM_post(otherReady); } return SYS_OK; }