/* * MPC5200 BestComm interrupt handlers */ static void pcmcia_ide_recv_dmairq_hdl(rtems_irq_hdl_param unused) { SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend,IDE_RX_TASK_NO); /*Disable receive ints*/ bestcomm_glue_irq_disable(IDE_RX_TASK_NO); pcmcia_ide_rxInterrupts++; /* Rx int has occurred */ if (pcmcia_ide_hdl_task != 0) { rtems_event_send(pcmcia_ide_hdl_task,PCMCIA_IDE_INTERRUPT_EVENT); } }
/*! * \brief Clear the interrupt for a given BestComm task. * \param taskId Task handle passed back from a successful TaskSetup() * \returns 0 on success or negative on failure * \returns TASK_ERR_NO_ERR (which is not really an error) for success * or TASK_ERR_INVALID_ARG for an invalid taskId. */ int TaskIntClear( TaskId taskId ) { if( ((taskId >= 0) && (taskId < MAX_TASKS)) || (taskId == DEBUG_INTR_ID) || (taskId == TEA_INTR_ID) ) { SDMA_CLEAR_IEVENT( SDMA_INT_PEND, taskId ); return TASK_ERR_NO_ERR; /* success */ } else { return TASK_ERR_INVALID_ARG; } }
void mpc5200_pcmciaide_dma_blockop(bool is_write, int minor, uint16_t block_size, rtems_blkdev_sg_buffer *bufs, uint32_t *cbuf, uint32_t *pos) { #if IDE_USE_DMA /* * Nameing: * - a block is one unit of data on disk (multiple sectors) * - a buffer is a contignuous chunk of data in memory * a block on disk may be filled with data from several buffers */ uint32_t buf_idx,bufs_from_dma, bufs_to_dma,bufs_total; uint32_t bds_free; uint32_t llength; rtems_status_code rc = RTEMS_SUCCESSFUL; rtems_event_set events; BDIdx nxt_bd_idx; bool use_irq = (_System_state_Current == SYSTEM_STATE_UP); /* * determine number of blocks */ llength = 0; buf_idx = 0; bufs += *cbuf; /* *cbuf is the index of the next buffer to send in this transaction */ while (llength < block_size) { llength += bufs[buf_idx++].length; } bufs_from_dma = 0; bufs_to_dma = 0; bufs_total = buf_idx; /* * here all BDs should be unused */ bds_free = is_write ? PCMCIA_IDE_DMA_WR_BD_CNT : PCMCIA_IDE_DMA_RD_BD_CNT; /* * repeat, until all bufs are transferred */ while ((rc == RTEMS_SUCCESSFUL) && (bufs_from_dma < bufs_total)) { while ((rc == RTEMS_SUCCESSFUL) && (bufs_to_dma < bufs_total) && (bds_free > 0)) { /* * fill in BD, set interrupt if needed */ SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend,(is_write ? IDE_TX_TASK_NO : IDE_RX_TASK_NO)); if (is_write) { TaskBDAssign(pcmcia_ide_txTaskId , (void *)bufs[bufs_to_dma].buffer, (void *)mpc5200_ata_drive_regs[IDE_REGISTER_DATA_WORD], bufs[bufs_to_dma].length, 0/* flags */); #if IDE_USE_STATISTICS mpc5200_pcmciaide_write_block_block_cnt++; #endif } else { TaskBDAssign(pcmcia_ide_rxTaskId , (void *)mpc5200_ata_drive_regs[IDE_REGISTER_DATA_WORD], (void *)bufs[bufs_to_dma].buffer, bufs[bufs_to_dma].length, 0/* flags */); #if IDE_USE_STATISTICS mpc5200_pcmciaide_read_block_block_cnt++; #endif } bufs_to_dma ++; bds_free --; } if (is_write) { TaskStart( pcmcia_ide_txTaskId, TASK_AUTOSTART_DISABLE, pcmcia_ide_txTaskId, TASK_INTERRUPT_DISABLE ); } else { TaskStart( pcmcia_ide_rxTaskId, TASK_AUTOSTART_DISABLE, pcmcia_ide_rxTaskId, TASK_INTERRUPT_DISABLE ); } if (use_irq) { /* * enable interrupts, wait for interrupt event */ pcmcia_ide_hdl_task = rtems_task_self(); bestcomm_glue_irq_enable((is_write ? IDE_TX_TASK_NO : IDE_RX_TASK_NO)); rtems_event_receive(PCMCIA_IDE_INTERRUPT_EVENT, RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &events); pcmcia_ide_hdl_task = 0; } else { /* * HACK: just wait some time... */ /* * FIXME: poll, until SDMA is finished */ volatile int32_t i; for (i = 0;i < 10000;i++) {}; } do { nxt_bd_idx = TaskBDRelease(is_write ? pcmcia_ide_txTaskId : pcmcia_ide_rxTaskId); if ((nxt_bd_idx != TASK_ERR_BD_RING_EMPTY) && (nxt_bd_idx != TASK_ERR_BD_BUSY)) { (*cbuf)++; (*pos) += bufs[bufs_from_dma].length; bufs_from_dma++; bds_free++; } } while ((nxt_bd_idx != TASK_ERR_BD_RING_EMPTY) && (nxt_bd_idx != TASK_ERR_BD_BUSY) && (bufs_from_dma < bufs_to_dma)); } #endif /* IDE_USE_DMA */ }