📄 tmdma.c
字号:
/*
* +-------------------------------------------------------------------+
* | Copyright (c) 1995,2000 TriMedia Technologies Inc. |
* | |
* | This software is furnished under a license and may only be used |
* | and copied in accordance with the terms and conditions of such a |
* | license and with the inclusion of this copyright notice. This |
* | software or any other copies of this software may not be provided |
* | or otherwise made available to any other person. The ownership |
* | and title of this software is not transferred. |
* | |
* | The information in this software is subject to change without |
* | any prior notice and should not be construed as a commitment by |
* | TriMedia Technologies. |
* | |
* | This code and information is provided "as is" without any |
* | warranty of any kind, either expressed or implied, including but |
* | not limited to the implied warranties of merchantability and/or |
* | fitness for any particular purpose. |
* +-------------------------------------------------------------------+
*
* Module name : tmDMA.c 1.36
*
* Module type : IMPLEMENTATION
*
* Title : DMA service library
*
* Last update : 10:39:16 - 00/06/20
*
* Description :
*
*/
/*----------------------------includes----------------------------------------*/
#include <stdio.h>
#include <tm1/tmAssert.h>
#include <tmlib/AppModel.h>
#include <tm1/mmio.h>
#include <tm1/tmDMA.h>
#include <tm1/tmInterrupts.h>
/*------------------------- local definitions -------------------------------*/
#define WORDSIZE sizeof(Pointer)
#define DMA_INTERRUPT intINT_16
#define ALIGNED4(x) (!(((int)(x))&3))
/*----------------------------functions---------------------------------------*/
static pdmaRequest_t dma_queue_first;
static pdmaRequest_t dma_current;
static Int next_instance;
static dmaCapabilities_t capabilities =
{
/* version */ {MAJOR_VERSION, MINOR_VERSION, BUILD_VERSION},
/* numSupportedInstances */ -1,
/* numCurrentInstances */ 0
};
static dmaSetup_t cur_setup = {intPRIO_0};
/*
* The following macro sets up the next DMA transfer.
* Although it is not currently done, this macro could
* inspect the request, and find out if it could cause
* the completion function or the AppModel resume function
* to be called. If not, then it could temporarily patch
* a simpler and cheaper version of the interrupt handler
* into the exception vector:
*/
#define START_NEXT_TRANSFER() \
{ \
pdmaDescription_t current; \
\
current= &(dma_current->descriptions[dma_current->current_description]);\
\
MMIO(SRC_ADR) = (UInt)current->source; \
MMIO(DEST_ADR)= (UInt)current->destination; \
\
MMIO(DMA_CTL) = current->length \
| ( current->direction << 26 ) \
| ( current->write_and_invalidate ? (1<<27) : 0 ); \
}
#define INSERT_REQUEST(x) \
if (dma_queue_first == NULL) { \
x->link = NULL; \
dma_queue_first = x; \
\
} else { \
pdmaRequest_t *pnext = &dma_queue_first; \
UInt priority = x->priority; \
\
while ( (*pnext) != NULL \
&& (*pnext)->priority <= priority \
) { \
pnext= &(*pnext)->link; \
} \
\
x->link = *pnext; \
*pnext = x; \
}
static void
dma_handler(void)
{
#pragma TCS_handler
if (MMIO(BIU_STATUS) & 0xc00) {
/*
* Target- or Master abort; clear the status, and retry the
* current DMA description
*/
MMIO(BIU_STATUS) = (0xc00 | 0x20); /* plus handshake to PCI
* interface */
dma_current->nrof_retries++;
}
else {
/* else: DMA done; */
pdmaDescription_t current;
MMIO(BIU_STATUS) = 0x20; /* handshake to PCI interface */
current = &(dma_current->descriptions[dma_current->current_description]);
if (--(current->nr_of_transfers) == 0) {
dma_current->current_description++;
}
else {
current->source =
(Pointer) (((Address) current->source)
+ current->source_stride);
current->destination =
(Pointer) (((Address) current->destination)
+ current->destination_stride);
}
}
/* -- . -- */
if (dma_current->current_description >= dma_current->nr_of_descriptions) {
pdmaRequest_t current = dma_current;
dmaFunc_t completion_function = current->completion_function;
AppModel_AppId requester = current->requester;
Bool synchronous = current->mode == dmaSynchronous;
current->done = True;
dma_current = dma_queue_first;
if (dma_queue_first != NULL) {
dma_queue_first = dma_queue_first->link;
START_NEXT_TRANSFER();
}
/*
* These functions should be called at the very end, because
* they might schedule a higher priority task in, and we
* can't have that while we are fiddling with the global
* queue:
*/
if (synchronous)
AppModel_resume(requester);
if (completion_function) {
AppModel_suspend_scheduling();
AppModel_run_on_sstack( (Pointer)completion_function, (Pointer)current );
AppModel_resume_scheduling();
}
}
else if (dma_queue_first != NULL
&& dma_current->priority > dma_queue_first->priority ) {
INSERT_REQUEST(dma_current);
dma_current = dma_queue_first;
dma_queue_first = dma_queue_first->link;
START_NEXT_TRANSFER();
}
else {
START_NEXT_TRANSFER();
}
}
/*
* Function : DMA dispatch function.
* Parameters : dma_request (I) description of required
* dma actions to be taken
* Function Result : True iff a synchronous dma request was
* suspended in order to wait for completion.
*/
tmLibdevErr_t
dmaDispatch(
Int instance,
pdmaRequest_t dma_request
)
{
UInt ien;
tmAssert(dma_request != Null, TMLIBDEV_ERR_NULL_PARAMETER);
tmAssert(capabilities.numCurrentInstances != 0, TMLIBDEV_ERR_NOT_OWNER);
if (dma_request->nr_of_descriptions == 0)
return TMLIBDEV_OK;
#ifndef NDEBUG
{
UInt i;
for (i= 0; i< dma_request->nr_of_descriptions; i++) {
pdmaDescription_t p= &dma_request->descriptions[i];
tmAssert(ALIGNED4(p->source), DMA_ERR_SOURCE_NOT_ALIGNED );
tmAssert(ALIGNED4(p->destination), DMA_ERR_DEST_NOT_ALIGNED );
tmAssert(ALIGNED4(p->length), DMA_ERR_LENGTH_NOT_ALIGNED );
if (p->nr_of_transfers > 1) {
tmAssert(ALIGNED4(p->source_stride), DMA_ERR_SOURCE_STRIDE_NOT_ALIGNED );
tmAssert(ALIGNED4(p->destination_stride), DMA_ERR_DEST_STRIDE_NOT_ALIGNED );
}
}
}
#endif
/*
* set current thread, and insert into dma queue:
*/
dma_request->requester = AppModel_current_thread;
dma_request->current_description = 0;
dma_request->nrof_retries = 0;
dma_request->done = False;
ien = intCLEAR_IEN();
if (dma_current == NULL) {
dma_current = dma_request;
START_NEXT_TRANSFER();
}
else {
INSERT_REQUEST(dma_request);
}
intRESTORE_IEN(ien);
/* -- . -- */
/*
* Call slack function, when specified:
*/
if (dma_request->slack_function) {
dma_request->slack_function(dma_request);
}
/* -- . -- */
/*
* Await completion, as specified:
*/
switch (dma_request->mode) {
case dmaAsynchronous:
return TMLIBDEV_OK;
case dmaSynchronous_By_Polling:
do {} while (!dma_request->done);
return TMLIBDEV_OK;
case dmaSynchronous:
AppModel_suspend_self();
return TMLIBDEV_OK;
default:
return TMLIBDEV_OK; /* keep apcc happy */
}
}
/*----------------------------functions---------------------------------------*/
/*
* Function : Fills in the capabilities structure.
* Parameters : cap (O) returned pointer to
* internal capabilities structure
* Function Result : resulting error condition
*/
tmLibdevErr_t
dmaGetCapabilities(pdmaCapabilities_t * cap)
{
tmAssert(cap != Null, TMLIBDEV_ERR_NULL_PARAMETER);
*cap = &capabilities;
return TMLIBDEV_OK;
}
/*
* Function : Changes parameters of DMA interface,
* like speed and priority.
* Use is optional.
* Parameters : setup (O) pointer to buffer holding new capabilities
* Function Result : resulting error condition
*/
tmLibdevErr_t
dmaSetup(dmaSetup_t * setup)
{
UInt ien;
tmAssert(setup != Null, TMLIBDEV_ERR_NULL_PARAMETER);
ien= intCLEAR_IEN();
cur_setup= *setup;
if (capabilities.numCurrentInstances != 0) {
intInstanceSetup_t int_setup;
intGetInstanceSetup(DMA_INTERRUPT, &int_setup);
int_setup.priority = cur_setup.priority;
intInstanceSetup(DMA_INTERRUPT, &int_setup);
}
intRESTORE_IEN(ien);
return TMLIBDEV_OK;
}
/*
* Function : Retrieve global parameters.
* Parameters : setup (O) pointer to buffer
* receiving returned parameters
* Function Result : resulting error condition
*/
extern tmLibdevErr_t
dmaGetSetup(dmaSetup_t * setup)
{
UInt ien;
tmAssert(setup != Null, TMLIBDEV_ERR_NULL_PARAMETER);
ien = intCLEAR_IEN();
*setup = cur_setup;
intRESTORE_IEN(ien);
return TMLIBDEV_OK;
}
/*
* Function : Assigns a unique instance for the caller.
* Parameters : instance (O) pointer to result variable
* Function Result : resulting error condition
*/
tmLibdevErr_t
dmaOpen(Int * instance)
{
UInt ien;
tmLibdevErr_t err;
tmAssert(instance != Null, TMLIBDEV_ERR_NULL_PARAMETER);
/*
* Setup DMA handling:
*/
ien= intCLEAR_IEN();
if (capabilities.numCurrentInstances == 0) {
if (err = intOpen(DMA_INTERRUPT)) {
intRESTORE_IEN(ien);
return err;
}
else {
intInstanceSetup_t int_setup;
tmAssert(sizeof (int_setup) == 4 * WORDSIZE, DMA_ERR_STRUCT_CHANGED);
int_setup.handler = dma_handler;
int_setup.priority = cur_setup.priority;
int_setup.level_triggered = True;
int_setup.enabled = True;
intInstanceSetup(DMA_INTERRUPT, &int_setup);
MMIO(BIU_CTL) |= 0x10; /* enable DMA interrupt */
}
}
++capabilities.numCurrentInstances;
*instance = ++next_instance;
intRESTORE_IEN(ien);
return TMLIBDEV_OK;
}
/*
* Function : Deallocates the instance.
* Parameters : instance (O) instance to give up
* Function Result : resulting error condition
*/
tmLibdevErr_t
dmaClose(Int instance)
{
UInt ien;
tmAssert(capabilities.numCurrentInstances != 0, TMLIBDEV_ERR_NOT_OWNER);
ien= intCLEAR_IEN();
if (--capabilities.numCurrentInstances == 0) {
intClose(DMA_INTERRUPT);
}
intRESTORE_IEN(ien);
return TMLIBDEV_OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -