📄 dma_ep93xx.c
字号:
case NFB: dma_m2m_next_frame_buffer(dma); break; /* * Done interrupt generated, indicating that the transfer is complete. */ case DONE: dma_m2m_transfer_done(dma); break; default: break; } if ((dma_int != UNDEF_INT) && dma->callback) dma->callback(dma_int, dma->device, dma->user_data);}/***************************************************************************** * * dma_m2p_irq_handler * * * ****************************************************************************/static voiddma_m2p_irq_handler(int irq, void *dev_id, struct pt_regs *regs){ ep93xx_dma_t *dma = (ep93xx_dma_t *) dev_id; unsigned int M2P_reg_base = dma->reg_base; unsigned int read_back; ep93xx_dma_dev_t dma_int = UNDEF_INT; unsigned int loop, uiCONTROL, uiINTERRUPT; /* * Determine what kind of dma interrupt this is. */ if ( inl(M2P_reg_base+M2P_OFFSET_INTERRUPT) & INTERRUPT_M2P_STALLINT ) dma_int = STALL; else if ( inl(M2P_reg_base+M2P_OFFSET_INTERRUPT) & INTERRUPT_M2P_NFBINT ) dma_int = NFB; else if ( inl(M2P_reg_base+M2P_OFFSET_INTERRUPT) & INTERRUPT_M2P_CHERRORINT ) dma_int = CHERROR; /* * Stall Interrupt: The Channel is stalled, meaning nothing is * programmed to transfer right now. So, we're back to the * beginnning. If there's a buffer to transfer, program it into * max and base 0 registers. */ if (dma_int == STALL) { DPRINTK("1 "); if (dma->total_buffers) { /* * The current_buffer has already been tranfered, so * add the byte count to the total_bytes field. */ dma->total_bytes = dma->total_bytes + dma->buffer_queue[dma->current_buffer].size; /* * Mark the current_buffer as used. */ dma->buffer_queue[dma->current_buffer].used = TRUE; /* * Increment the used buffer counter */ dma->used_buffers++; DPRINTK("#%d", dma->current_buffer); /* * Increment the current_buffer */ dma->current_buffer = (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS; /* * check if there's a new buffer to transfer. */ if (dma->new_buffers && dma->xfer_enable) { /* * We have a new buffer to transfer so program * in the buffer values. Since a STALL * interrupt was triggered, we program the * base0 and maxcnt0 * * Set the MAXCNT0 register with the buffer * size */ outl( dma->buffer_queue[dma->current_buffer].size, M2P_reg_base+M2P_OFFSET_MAXCNT0 ); /* * Set the BASE0 register with the buffer base * address */ outl( dma->buffer_queue[dma->current_buffer].source, M2P_reg_base+M2P_OFFSET_BASE0 ); /* * Decrement the new buffer counter */ dma->new_buffers--; if (dma->new_buffers) { DPRINTK("A "); /* * Set the MAXCNT1 register with the * buffer size */ outl( dma->buffer_queue[(dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].size, M2P_reg_base+M2P_OFFSET_MAXCNT1 ); /* * Set the BASE1 register with the * buffer base address */ outl( dma->buffer_queue[dma->current_buffer + 1 % MAX_EP93XX_DMA_BUFFERS].source, M2P_reg_base+M2P_OFFSET_BASE1 ); /* * Decrement the new buffer counter */ dma->new_buffers--; /* * Enable the NFB Interrupt. */ uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL); uiCONTROL |= CONTROL_M2P_NFBINTEN; outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL ); } } else { /* * No new buffers. */ DPRINTK("2 \n"); /* * There's a chance we setup both buffer descriptors, but * didn't service the NFB quickly enough, causing the channel * to transfer both buffers, then enter the stall state. * So, we need to be able to process the second buffer. */ if ((dma->used_buffers + dma->new_buffers) < dma->total_buffers) { DPRINTK("3 "); /* * The current_buffer has already been tranfered, so add the * byte count to the total_bytes field. */ dma->total_bytes = dma->total_bytes + dma->buffer_queue[dma->current_buffer].size; /* * Mark the current_buffer as used. */ dma->buffer_queue[dma->current_buffer].used = TRUE; /* * Increment the used buffer counter */ dma->used_buffers++; DPRINTK("#%d", dma->current_buffer); /* * Increment the current buffer pointer. */ dma->current_buffer = (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS; } /* * No new buffers to transfer, so disable the channel. */ uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL); uiCONTROL &= ~CONTROL_M2P_ENABLE; outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL ); /* * Indicate that this channel is in the pause by starvation * state by setting the pause bit to true. */ dma->pause = TRUE; DPRINTK("STATUS - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_STATUS) ); DPRINTK("CONTROL - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CONTROL) ); DPRINTK("REMAIN - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_REMAIN) ); DPRINTK("PPALLOC - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_PPALLOC) ); DPRINTK("BASE0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_BASE0) ); DPRINTK("MAXCNT0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_MAXCNT0) ); DPRINTK("CURRENT0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CURRENT0) ); DPRINTK("BASE1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_BASE1) ); DPRINTK("MAXCNT1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_MAXCNT1) ); DPRINTK("CURRENT1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CURRENT1) ); DPRINTK("Buffer buf_id source size last used \n"); for (loop = 0; loop < 32; loop ++) DPRINTK("%d 0x%x 0x%x 0x%x %d %d \n", loop, dma->buffer_queue[loop].buf_id, dma->buffer_queue[loop].source, dma->buffer_queue[loop].size, dma->buffer_queue[loop].last, dma->buffer_queue[loop].used); DPRINTK("pause 0x%x 0x%x 0x%x %d %d \n", dma->pause_buf.buf_id, dma->pause_buf.source, dma->pause_buf.size, dma->pause_buf.last, dma->pause_buf.used); DPRINTK("Pause - %d \n", dma->pause); DPRINTK("xfer_enable - %d \n", dma->xfer_enable); DPRINTK("total bytes - 0x%x \n", dma->total_bytes); DPRINTK("total buffer - %d \n", dma->total_buffers); DPRINTK("new buffers - %d \n", dma->new_buffers); DPRINTK("current buffer - %d \n", dma->current_buffer); DPRINTK("last buffer - %d \n", dma->last_buffer); DPRINTK("used buffers - %d \n", dma->used_buffers); DPRINTK("callback addr - 0x%p \n", dma->callback); } } else { /* * No buffers to transfer, or old buffers to mark as used, * so Disable the channel */ uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL); uiCONTROL &= ~CONTROL_M2P_ENABLE; outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL ); /* * Must read the control register back after a write. */ read_back = inl(M2P_reg_base+M2P_OFFSET_CONTROL); /* * Indicate that this channel is in the pause by * starvation state by setting the pause bit to true. */ dma->pause = TRUE; } } /* * Next Frame Buffer Interrupt. If there's a new buffer program it * Check if this is the last buffer in the transfer, * and if it is, disable the NFB int to prevent being * interrupted for another buffer when we know there won't be * another. */ if (dma_int == NFB) { DPRINTK("5 "); if (dma->total_buffers) { DPRINTK("6 "); /* * The iCurrentBuffer has already been transfered. so add the * byte count from the current buffer to the total byte count. */ dma->total_bytes = dma->total_bytes + dma->buffer_queue[dma->current_buffer].size; /* * Mark the Current Buffer as used. */ dma->buffer_queue[dma->current_buffer].used = TRUE; /* * Increment the used buffer counter */ dma->used_buffers++; DPRINTK("#%d", dma->current_buffer); if ((dma->buffer_queue[ (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].last) || (dma->new_buffers == 0) || (dma->xfer_enable == FALSE)) { DPRINTK("7 "); /* * This is the last Buffer in this transaction, so disable * the NFB interrupt. We shouldn't get an NFB int when the * FSM moves to the ON state where it would typically get the * NFB int indicating a new buffer can be programmed. * Instead, once in the ON state, the DMA will just proceed * to complet the transfer of the current buffer, move the * FSB directly to the STALL state where a STALL interrupt * will be generated. */ uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL); uiCONTROL &= ~CONTROL_M2P_NFBINTEN; outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL ); /* * The current buffer has been transferred, so increment * the current buffer counter to reflect this. */ dma->current_buffer = (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS; DPRINTK("End of NFB handling. \n"); DPRINTK("STATUS - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_STATUS) ); DPRINTK("CONTROL - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CONTROL) ); DPRINTK("REMAIN - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_REMAIN) ); DPRINTK("PPALLOC - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_PPALLOC) ); DPRINTK("BASE0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_BASE0) ); DPRINTK("MAXCNT0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_MAXCNT0) ); DPRINTK("CURRENT0 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CURRENT0) ); DPRINTK("BASE1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_BASE1) ); DPRINTK("MAXCNT1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_MAXCNT1) ); DPRINTK("CURRENT1 - 0x%x \n", inl(M2P_reg_base+M2P_OFFSET_CURRENT1) ); DPRINTK("Buffer buf_id source size last used \n"); for (loop = 0; loop < 32; loop ++) DPRINTK("%d 0x%x 0x%x 0x%x %d %d \n", loop, dma->buffer_queue[loop].buf_id, dma->buffer_queue[loop].source, dma->buffer_queue[loop].size, dma->buffer_queue[loop].last, dma->buffer_queue[loop].used); DPRINTK("pause 0x%x 0x%x 0x%x %d %d \n", dma->pause_buf.buf_id, dma->pause_buf.source, dma->pause_buf.size, dma->pause_buf.last, dma->pause_buf.used); DPRINTK("Pause - %d \n", dma->pause); DPRINTK("xfer_enable - %d \n", dma->xfer_enable); DPRINTK("total bytes - 0x%x \n", dma->total_bytes); DPRINTK("total buffer - %d \n", dma->total_buffers); DPRINTK("new buffers - %d \n", dma->new_buffers); DPRINTK("current buffer - %d \n", dma->current_buffer); DPRINTK("last buffer - %d \n", dma->last_buffer); DPRINTK("used buffers - %d \n", dma->used_buffers); DPRINTK("callback addr - 0x%p \n", dma->callback); } else if (dma->new_buffers) { DPRINTK("8 "); /* * we have a new buffer, so increment the current buffer to * point to the next buffer, which is already programmed into * the DMA. Next time around, it'll be pointing to the * current buffer. */ dma->current_buffer = (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS; /* * we know we have a new buffer to program as the next * buffer, so check which set of MAXCNT and BASE registers * to program. */ if ( inl(M2P_reg_base+M2P_OFFSET_STATUS) & STATUS_M2P_NEXTBUFFER ) { /* * Set the MAXCNT1 register with the buffer size */ outl( dma->buffer_queue[ (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].size, M2P_reg_base+M2P_OFFSET_MAXCNT1 ); /* * Set the BASE1 register with the buffer base address */ outl( dma->buffer_queue[ (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].source, M2P_reg_base+M2P_OFFSET_BASE1 ); } else { /* * Set the MAXCNT0 register with the buffer size */ outl( dma->buffer_queue[ (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].size, M2P_reg_base+M2P_OFFSET_MAXCNT0 ); /* * Set the BASE0 register with the buffer base address */ outl( dma->buffer_queue[ (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].source, M2P_reg_base+M2P_OFFSET_BASE0 ); } /* * Decrement the new buffers counter */ dma->new_buffers--; } } else { /* * Total number of buffers is 0 - really we should never get here, * but just in case. */ DPRINTK("9 \n"); /* * No new buffers to transfer, so Disable the channel */ uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL); uiCONTROL &= ~CONTROL_M2P_ENABLE; outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL ); } } /* * Channel Error Interrupt, or perhipheral interrupt, specific to the * memory to/from peripheral channels. */ if (dma_int == CHERROR) { /* * just clear the interrupt, it's really up to the peripheral * driver to determine if any further action is necessary. */ uiINTERRUPT = inl(M2P_reg_base+M2P_OFFSET_INTERRUPT); uiINTERRUPT &= ~INTERRUPT_M2P_CHERRORINT; outl( uiINTERRUPT, M2P_reg_base+M2P_OFFSET_INTERRUPT ); } /* * Make sure the interrupt was valid, and if it was, then check * if a callback function was installed for this DMA channel. If a * callback was installed call it. */ if ((dma_int != UNDEF_INT) && dma->callback) dma->callback(dma_int, dma->device, dma->user_data);}/***************************************************************************** * * ep9312_dma_open_m2p(int device) * * Description: This function will attempt to open a M2P/P2M DMA channel. * If the open is successful, the channel number is returned, * otherwise a negative number is returned. * * Parameters: * device: device for which the dma channel is requested. * ****************************************************************************/static intdma_open_m2p(int device){ int channel = -1; unsigned int loop; unsigned int M2P_reg_base; unsigned int uiPWRCNT; unsigned long flags; DPRINTK("DMA Open M2P with hw dev %d\n", device); /* * Lock the dma channel list. */ spin_lock_irqsave(&dma_list_lock, flags); DPRINTK("1\n"); /* * Verify that the device requesting DMA isn't already using a DMA channel */ if (device >= 10) loop = 1; // Rx transfer requested else loop = 0; // Tx transfer requested for (; loop < 10; loop = loop + 2) /* * Before checking for a matching device, check that the * channel is in use, otherwise the device field is * invalid. */ if (dma_chan[loop].ref_count) if (device == dma_chan[loop].device) { DPRINTK("DMA Open M2P - Error\n"); return(-1); } /* * Get a DMA channel instance for the given hardware device. * If this is a TX look for even numbered channels, else look for * odd numbered channels */ if (device >= 10) loop = 1; /* Rx transfer requested */ else loop = 0; /* Tx transfer requested */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -