pl330 dmac是基于arm amba的dma控制器,最多有8个操作通道,32个事件处理,并且有多个外设接口,有自己的命令集,详细信息看pl330 datesheet。
pl330驱动程序:
pl330驱动程序位于看kernel/driver/dma/pl330.c文件,该驱动程序由三星coder写的。
驱动的关键数据结构:
17 struct dma_pl330_platdata {
18 /*
19 * Number of valid peripherals connected to DMAC.
20 * This may be different from the value read from
21 * CR0, as the PL330 implementation might have 'holes'
22 * in the peri list or the peri could also be reached
23 * from another DMAC which the platform prefers.
24 */
25 u8 nr_valid_peri;
26 /* Array of valid peripherals */
27 u8 *peri_id;
28 /* Operational capabilities */
29 dma_cap_mask_t cap_mask;
30 /* Bytes to allocate for MC buffer */
31 unsigned mcbuf_sz; //dmac指令存储空间大小
32 };
该结构体是pl330的平台数据,用于声明具体soc上的pl330 dmac的配置,一般通过amba device的设备平台数据传入。
577 struct dma_pl330_dmac {
578 struct pl330_info pif;
579
580 /* DMA-Engine Device */
581 struct dma_device ddma;
582
583 /* Pool of descriptors available for the DMAC's channels */
584 struct list_head desc_pool;
585 /* To protect desc_pool manipulation */
586 spinlock_t pool_lock;
587
588 /* Peripheral channels connected to this DMAC */
589 struct dma_pl330_chan *peripherals; /* keep at end */
590 };
该结构体是pl330 dmac的抽象,封装了dma引擎结构体,是更高层的抽象,内部包含了 struct dma_device ddma (dma引擎对象),struct pl330_info pif(pl330的信息),struct list_head desc_pool(dmac通道的执行描述池链表)
/* Handle to the DMAC provided to the PL330 core */
308 struct pl330_info {
309 /* Owning device */
310 struct device *dev;
311 /* Size of MicroCode buffers for each channel. */
312 unsigned mcbufsz;
313 /* ioremap'ed address of PL330 registers. */
314 void __iomem *base;
315 /* Client can freely use it. */
316 void *client_data;
317 /* PL330 core data, Client must not touch it. */
318 void *pl330_data;
319 /* Populated by the PL330 core driver during pl330_add */
320 struct pl330_config pcfg;
321 /*
322 * If the DMAC has some reset mechanism, then the
323 * client may want to provide pointer to the method.
324 */
325 void (*dmac_reset)(struct pl330_info *pi);
326 };
该结构体是pl330中十分重要的数据,包含了pl330 dmac的硬件信息,包括unsigned mcbufsz(每个通道的指令集缓存大小), void __iomem *base(pl330 dmac寄存器基址),void *pl330_data(pl330 驱动使用数据),struct pl330_config pcfg(pl330 dmac配置信息,一般通过读dmac寄存器获取), void (*dmac_reset)(struct pl330_info *pi)(dmac复位操作函数,用来指定特定的复位操作)
292 /* Populated by the PL330 core driver for DMA API driver's info */
293 struct pl330_config {
294 u32 periph_id;
295 u32 pcell_id;
296 #define DMAC_MODE_NS (1 << 0)
297 unsigned int mode; //apb接口模式
298 unsigned int data_bus_width:10; /* In number of bits */ //axi总线宽度
299 unsigned int data_buf_dep:10; //dmac数据缓存深度
300 unsigned int num_chan:4; //dmac通道数量
301 unsigned int num_peri:6; //dmac支持外设数量
302 u32 peri_ns;
303 ; //事件数量
304 u32 irq_ns;
305 };
该结构体包含了pl330 dmac的硬件配置信息,通过读取dmac寄存器来填充。
538 struct dma_device {
539
540 unsigned int chancnt; //dmac 通道数量
541 unsigned int privatecnt; // 已经使用的通道数
542 struct list_head channels; //dma通道链表
543 struct list_head global_node; //dma设备链表
544 dma_cap_mask_t cap_mask; //dma设备能力掩码
545 unsigned short max_xor; //最大异或
546 unsigned short max_pq;
547 u8 copy_align;
548 u8 xor_align;
549 u8 pq_align;
550 u8 fill_align;
551 #define DMA_HAS_PQ_CONTINUE (1 << 15)
552
553 int dev_id; //设备id号
554 struct device *dev;
555
556 int (*device_alloc_chan_resources)(struct dma_chan *chan); //分配一个通道资源,是核心操作函数
557 void (*device_free_chan_resources)(struct dma_chan *chan);
558
559 struct dma_async_tx_descriptor *(*device_prep_dma_memcpy)(
560 struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
561 size_t len, unsigned long flags); //准备一次内存拷贝操作函数,返回一个操作描述结构体struct dma_async_tx_descriptor,核心操作函数。
562 struct dma_async_tx_descriptor *(*device_prep_dma_xor)(
563 struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
564 unsigned int src_cnt, size_t len, unsigned long flags);
565 struct dma_async_tx_descriptor *(*device_prep_dma_xor_val)(
566 struct dma_chan *chan, dma_addr_t *src, unsigned int src_cnt,
567 size_t len, enum sum_check_flags *result, unsigned long flags);
568 struct dma_async_tx_descriptor *(*device_prep_dma_pq)(
569 struct dma_chan *chan, dma_addr_t *dst, dma_addr_t *src,
570 unsigned int src_cnt, const unsigned char *scf,
571 size_t len, unsigned long flags);
572 struct dma_async_tx_descriptor *(*device_prep_dma_pq_val)(
573 struct dma_chan *chan, dma_addr_t *pq, dma_addr_t *src,
574 unsigned int src_cnt, const unsigned char *scf, size_t len,
575 enum sum_check_flags *pqres, unsigned long flags);
576 struct dma_async_tx_descriptor *(*device_prep_dma_memset)(
577 struct dma_chan *chan, dma_addr_t dest, int value, size_t len,
578 unsigned long flags);
579 struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)(
580 struct dma_chan *chan, unsigned long flags);
581 struct dma_async_tx_descriptor *(*device_prep_dma_sg)(
582 struct dma_chan *chan,
583 struct scatterlist *dst_sg, unsigned int dst_nents,
584 struct scatterlist *src_sg, unsigned int src_nents,
585 unsigned long flags);
586
587 struct dma_async_tx_descriptor *(*device_prep_slave_sg)(
588 struct dma_chan *chan, struct scatterlist *sgl,
589 unsigned int sg_len, enum dma_transfer_direction direction,
590 unsigned long flags, void *context);
591 struct dma_async_tx_descriptor *(*device_prep_dma_cyclic)(
592 struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
593 size_t period_len, enum dma_transfer_direction direction,
594 unsigned long flags, void *context);
595 struct dma_async_tx_descriptor *(*device_prep_interleaved_dma)(
596 struct dma_chan *chan, struct dma_interleaved_template *xt,
597 unsigned long flags);
598 int (*device_control)(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
599 unsigned long arg); //dma设备控制函数
600
601 enum dma_status (*device_tx_status)(struct dma_chan *chan,
602 dma_cookie_t cookie,
603 struct dma_tx_state *txstate); //dma操作状态查询函数
604 void (*device_issue_pending)(struct dma_chan *chan); //让dma通道执行传输操作,核心操作函数。
605 };
该结构体是dma引擎层的dma设备抽象,该结构体抽象了一个通用的dma设备,和具体的dmac无关,平时在kernel中调用dma设备时就只针对该结构体的操作。注意有的damc除了执行内存拷贝外还可以执行异或等其他操作。
412 struct dma_async_tx_descriptor {
413 dma_cookie_t cookie; //dma传输踪迹
414 enum dma_ctrl_flags flags; /* not a 'long' to pack with cookie */
415 dma_addr_t phys; //该描述符的物理地址
416 struct dma_chan *chan; //该传输使用的dma通道
417 dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx); //在相应的dma通道开始执行该描述符
418 dma_async_tx_callback callback; //执行完该描述符后的回调。
419 void *callback_param; //回调参数
420 #ifdef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH
421 struct dma_async_tx_descriptor *next;
422 struct dma_async_tx_descriptor *parent;
423 spinlock_t lock;
424 #endif
425 };
该结构体属于dma引擎层,为传输描述符结构体,每一次传输都有一个该描述符。
543 struct dma_pl330_chan {
544 /* Schedule desc completion */
545 struct tasklet_struct task; //传输描述符完成后调度
546
547 /* DMA-Engine Channel */
548 struct dma_chan chan;
549
550 /* List of to be xfered descriptors */
551 struct list_head work_list; //传输描述链表
552
553 /* Pointer to the DMAC that manages this channel,
554 * NULL if the channel is available to be acquired.
555 * As the parent, this DMAC also provides descriptors
556 * to the channel.
557 */
558 struct dma_pl330_dmac *dmac;
559
560 /* To protect channel manipulation */
561 spinlock_t lock;
562
563 /* Token of a hardware channel thread of PL330 DMAC
564 * NULL if the channel is available to be acquired.
565 */
566 void *pl330_chid;
567
568 /* For D-to-M and M-to-D channels */
569 int burst_sz; /* the peripheral fifo width */
570 int burst_len; /* the number of burst */
571 dma_addr_t fifo_addr; //fifo物理地址
572
573 /* for cyclic capability */
574 bool cyclic; //是否具有循环能力
575 };
该结构体是pl330 dma通道的抽象,封装了dma引擎结构,是更高层的抽象,struct tasklet_struct task (传输描述符完成后调度),struct dma_chan chan(dma引擎层数据,是通用dma通道抽象,一般kernel中调用的dma通道指的是该数据结构),
271 struct dma_chan {
272 struct dma_device *device;
273 dma_cookie_t cookie;
274 dma_cookie_t completed_cookie;
275
276 /* sysfs */
277 int chan_id;
278 struct dma_chan_dev *dev;
279
280 struct list_head device_node; //链接到dma device中
281 struct dma_chan_percpu __percpu *local;
282 int client_count; //多少用户在使用该dma通道
283 int table_count;
284 void *private;
285 };
dma引擎层数据结构,是通用dma通道抽象,struct dma_chan_dev *dev(在sysfs使用)
294 struct dma_chan_dev {
295 struct dma_chan *chan;
296 struct device device;
297 int dev_id; //所属dma device的id
298 atomic_t *idr_ref; //引用计数
299 };
dma通道在sysfs中的对象
592 struct dma_pl330_desc {
593 /* To attach to a queue as child */
594 struct list_head node; //描述符链表
595
596 /* Descriptor for the DMA Engine API */
597 struct dma_async_tx_descriptor txd;
598
599 /* Xfer for PL330 core */
600 struct pl330_xfer px; //pl330传输结构
601
602 struct pl330_reqcfg rqcfg; //pl330请求配置结构
603 struct pl330_req req; //pl330请求数据结构
604
605 enum desc_status status; //描述符状态
606
607 /* The channel which currently holds this desc */
608 struct dma_pl330_chan *pchan; //描述符所属pl330 dmac通道
609 };
该结构为pl330 dma的传输描述符, 封装了dma引擎结构,是更高层的抽象,struct dma_async_tx_descriptor txd(是dma引擎层的数据结构,是通用的dma传输描述符)
361 struct pl330_xfer {
362 u32 src_addr; //源物理地址
363 u32 dst_addr; //目的物理地址
364 /* Size to xfer */
365 u32 bytes; //传输字节数目
366 /*
367 * Pointer to next xfer in the list.
368 * The last xfer in the req must point to NULL.
369 */
370 struct pl330_xfer *next; //下一次传输信息
371 };
该结构是pl330的传输数据结构,包含者此次传输的信息。
336 struct pl330_reqcfg {
337 /* Address Incrementing */
338 unsigned dst_inc:1; //目的地址是否增加
339 unsigned src_inc:1; //源地址是否增加
340
341 /*
342 * For now, the SRC & DST protection levels
343 * and burst size/length are assumed same.
344 */
345 bool nonsecure; //是否安全模式
346 bool privileged; //权限
347 bool insnaccess;
348 unsigned brst_len:5; //传输突发
349 unsigned brst_size:3; /* in power of 2 */
350
351 enum pl330_dstcachectrl dcctl; //源缓存控制
352 enum pl330_srccachectrl scctl;
353 enum pl330_byteswap swap;
354 struct pl330_config *pcfg; //pl330 dmac的配置数据结构
355 };
该结构体是pl330 请求配置数据结构,pl330 dmac根据该配置执行请求操作、
383 /* A request defining Scatter-Gather List ending with NULL xfer. */
384 struct pl330_req {
385 enum pl330_reqtype rqtype; //pl330请求类型
386 /* Index of peripheral for the xfer. */
387 unsigned peri:5; //传输外设索引
388 /* Unique token for this xfer, set by the client. */
389 void *token; //传输令脾
390 /* Callback to be called after xfer. */
391 void (*xfer_cb)(void *token, enum pl330_op_err err); //传输完成回调
392 /* If NULL, req will be done at last set parameters. */
393 struct pl330_reqcfg *cfg; //请求配置
394 /* Pointer to first xfer in the request. */
395 struct pl330_xfer *x; //请求传输信息,是单项链表
396 /* Hook to attach to DMAC's list of reqs with due callback */
397 struct list_head rqd; //请求链表
398 };
该结构体是pl330传输请求数据结构
476 /* A DMAC Thread */
477 struct pl330_thread {
478 u8 id; //pl330 dmac处理线程id,即通道id
479 int ev; //pl330 dmac事件
480 /* If the channel is not yet acquired by any client */
481 bool free; //该线程是否被分配
482 /* Parent DMAC */
483 struct pl330_dmac *dmac; //pl330 dmac
484 /* Only two at a time */
485 struct _pl330_req req[2]; //pl330 请求
486 /* Index of the last enqueued request */
487 unsigned lstenq; //最后进入队列的请求索引
488 /* Index of the last submitted request or -1 if the DMA is stopped */
489 int req_running; //最后被执行的请求索引
490 };
该结构体是pl330 dmac处理线程的抽象
461 struct _pl330_req {
462 u32 mc_bus; //指令缓存物理地址
463 void *mc_cpu; //指令缓存虚拟地址
464 /* Number of bytes taken to setup MC for the req */
465 u32 mc_len; //指令缓存长度
466 struct pl330_req *r;
467 };
该结构体也是pl330 dmac请求数据结构,包括了指令缓存的物理和虚拟地址以及长度信息。
498 /* A DMAC */
499 struct pl330_dmac {
500 spinlock_t lock;
501 /* Holds list of reqs with due callbacks */
502 struct list_head req_done; //dmac请求完成链表
503 /* Pointer to platform specific stuff */
504 struct pl330_info *pinfo; //pl330信息
505 /* Maximum possible events/irqs */
506 int events[32]; //pl330 事件
507 /* BUS address of MicroCode buffer */
508 u32 mcode_bus; //指令缓存物理地址
509 /* CPU address of MicroCode buffer */
510 void *mcode_cpu; //指令缓存虚拟地址
511 /* List of all Channel threads */
512 struct pl330_thread *channels; //pl330处理线程指针数组
513 /* Pointer to the MANAGER thread */
514 struct pl330_thread *manager; //pl330管理线程
515 /* To handle bad news in interrupt */
516 struct tasklet_struct tasks;
517 struct _pl330_tbd dmac_tbd; //pl330 dmac将要进行的操作
518 /* State of DMAC operation */
519 enum pl330_dmac_state state; //pl330 dmac状态
520 };
该结构是pl330 dmac的抽象,是底层实现的抽象