Linux的的DMA高速串口驱动的设计高速串口驱动的设计
在双核移动终端中进行验证,两芯片通过串口进行芯片间通信,实验结果证明了设计的高速串口驱动具有较好
的可靠性和可行性。
引言
本文讨论的双核终端硬件以AP(Application Processor,应用处理器)+CP(Cell phone Processor,基带处理器)的架构构
建,CP运行TD/GSM双模协议栈,AP运行Android软件。两个芯片间通过串口进行IPC(InterProcessor Communication,芯片间
通信)通信,像短信、电话等AT指令以及PS业务等均通过串口实现AP和CP的通信。当3G的网络环境对数据传输速率要求较高
时,普通串口驱动已经满足不了这样的要求,因此需要用基于DMA方式的串口驱动,来支持高波特率的数据传输。AP侧为
Android平台,CP的协议栈软件基于Nucleus平台[1]。AP与CP串口通信结构图如图1所示。
图1 AP与CP通信的UART通道
2 高速串口驱动设计原则
2.1 DMA的工作原理
目前应用比较广泛的串口驱动都是采用普通传输方式,在实现发送功能时,是CPU将发送缓冲区(上层应用将要发送的数据
写到circ_buf中)中的数据逐个送入串口的发送FIFO,从而将数据发送出去。在接收时,将接收FIFO中的数据送入TTY层,供
上层的应用读取。在串口的传输速度较低时,这种方式可以很稳定地工作;而当波特率设置得很高时,将会导致CPU来不及
取走数据,导致串口的FIFO溢出,从而造成丢数,针对上述问题,提出了基于DMA(Direct Memory Access)方式的串口传
输方式。
DMA是一种无需CPU参与就可以让外设与系统内存之间进行双向数据传输的硬件机制。使用DMA可以使系统CPU从实际的
I/O数据传输过程中摆脱出来,从而大大提高系统的吞吐率。DMA方式的数据传输由DMA控制器(DMAC)控制,在传输期
间,CPU可以并发地执行其他任务。当DMA传输结束后,DMAC通过中断通知CPU数据传输已经结束,然后由CPU执行相应
的中断服务程序进行后处理。内存中用于与外设交互数据的一块区域被称作DMA缓冲区,DMA缓冲区必须是物理上连续的
[23]。
将DMA用于串口驱动时,在接收时需要申请一片和外设接收FIFO进行直接交互的缓冲区,通过void
*dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)来实现,DMA负责将接收FIFO中的数据
送到申请的缓冲区中,然后CPU负责将缓冲区中的数据推至TTY层。发送时需要将发送缓冲区映射出其总线地址才能和外设发
送FIFO进行交互,通过dma_addr_t dma_map_single(struct device *dev ,void *buffer,size_t size,enum dma_data_dircetion
direction)来实现。
1.2 申请的DMA缓冲区交替接收机制
在用DMA方式接收时,并不直接将接收FIFO中的数据送到TTY层,而是申请了一片2 KB大小的DMA缓冲区,并将其分成两个
1 KB的缓冲区,用来交替从接收FIFO中接收数据,将2 KB大小的缓冲区分成为大小为1 KB的rx_buf[0]和rx_buf[1],在串口的设
备节点被打开时,把这两个缓冲区排队到DMA buf队列中。这里利用申请的两个缓冲区交替从FIFO中接收数据,以提高传输
效率。流程大致如下:
① 启动DMA,等待接收FIFO中的数据达到触发值,产生中断来进行DMA传输,将接收FIFO中的数据送到rx_buf中。
② 当其中一个rx_buf接收数据满时,将其数据送到上层之后排队到DMA buf队列中。
③ 而此时另外一块之前已经排队的rx_buf已经开始接收数据,等待接收满时,执行步骤②,两块rx_buf如此交替从接收FIFO中
接收数据,当接收满时排队到DMA buf队列中去,等待下次继续从接收FIFO中接收数据。
2 高速串口驱动设计流程
2.1 相应的数据结构
下面的结构体用来描述DMA来负责接收时,申请的一片DMA缓冲区的信息,此缓冲区用来暂存从接收FIFO中接收来的数据。
struct uart_dma_buffer{
unsigned char *area;//缓冲区的虚拟地址的首地址
unsigned char *pos;//缓冲区虚拟地址当前的位移
dma_addr_t dma_addr_rx; //缓冲区的物理地址size_t
bytes;//申请缓冲区的大小
unsigned int state;//缓冲区当前的状态