Chinaunix首页 | 论坛 | 博客
  • 博客访问: 154031
  • 博文数量: 49
  • 博客积分: 45
  • 博客等级: 民兵
  • 技术积分: 545
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-23 13:22
文章分类
文章存档

2017年(5)

2016年(18)

2015年(18)

2014年(8)

我的朋友

分类: Android平台

2015-03-17 13:57:13

一、4412 spec 11章, Direct Memory Access Controller (DMAC) 

DMAC 分两部分:DMA_mem 和 DMA_peri 。前者有一个PL330组成,后者由两个PL330组成。

这两部分的特点如下:

1DMA_peri: You should set all the peripherals as non-secure in TrustZone Protection Controller (TZPC) module since DMA_peri operates only as non-secure. 只在非安全模式下运行。

2DMA_mem: The attributes that the DMA_mem DMA Controllers have:

·  DMA_mem accesses memory through the AXI_IMGX bus and is located in IMG block.

·  DMA_mem supports only the secured AXI transaction.

AXI_IMG 模块执行,只在安全模式下执行。(所以,普通模式下kernel没有这个控制器的注册,参考文件Dma.c (arch\arm\mach-exynos) 末尾

关于PL330的具体细节,可以在在ARM官网下载PL330的datasheet 阅读:DDI0424D_dma330_r1p2_trm 
附录:相关杂记:

1,下面博客记录了一个PL330 probe 的时候失败的案例,是因为时钟没打开导致读ID 失败。

http://blog.chinaunix.net/uid-122754-id-3182046.html

二、串口DMA 研究

/kernel/drivers/tty/serial$ 目录中有Samsung.c make menuconfig打开CONFIG_SERIAL_SAMSUNG_DMA 宏, 串口DMA就被启动了。

 

DMAC的驱动Pl330.c (drivers\dma) 中的pl330_filter函数中添加dump_stack 即可看到调度流程如下:

[    3.865000] liucong pl330_filter 

[    3.865000] [] (unwind_backtrace+0x0/0xf0) from [] (pl330_filter+0x18/0x58)

[    3.865000] [] (pl330_filter+0x18/0x58) from [] (__dma_request_channel+0xdc/0x1d4)

[    3.865000] [] (__dma_request_channel+0xdc/0x1d4) from [] (samsung_dmadev_request+0x40/0x4c)

[    3.865000] [] (samsung_dmadev_request+0x40/0x4c) from [] (s3c64xx_serial_startup+0x168/0x1a0)

[    3.865000] [] (s3c64xx_serial_startup+0x168/0x1a0) from [] (uart_startup+0x58/0x1ac)

[    3.865000] [] (uart_startup+0x58/0x1ac) from [] (uart_open+0xd4/0x124)

[    3.865000] [] (uart_open+0xd4/0x124) from [] (tty_open+0x1e4/0x4d4)

[    3.865000] [] (tty_open+0x1e4/0x4d4) from [] (chrdev_open+0x94/0x158)

[    3.865000] [] (chrdev_open+0x94/0x158) from [] (do_dentry_open.clone.15+0x1d8/0x254)

[    3.865000] [] (do_dentry_open.clone.15+0x1d8/0x254) from [] (nameidata_to_filp+0x40/0x7c)

[    3.865000] [] (nameidata_to_filp+0x40/0x7c) from [] (do_last.clone.24+0xdc/0x7f0)

[    3.865000] [] (do_last.clone.24+0xdc/0x7f0) from [] (path_openat+0xb8/0x3d0)

[    3.865000] [] (path_openat+0xb8/0x3d0) from [] (do_filp_open+0x30/0x84)

[    3.865000] [] (do_filp_open+0x30/0x84) from [] (do_sys_open+0xdc/0x174)

[    3.865000] [] (do_sys_open+0xdc/0x174) from [] (ret_fast_syscall+0x0/0x30)

 

又在DMAC的驱动Pl330.c (drivers\dma) 中的pl330_alloc_chan_resources函数中添加dump_stack 即可看到调度流程如下:

 

[    3.865000] liucong pl330_alloc_chan_resources 

[    3.865000] [] (unwind_backtrace+0x0/0xf0) from [] (pl330_alloc_chan_resources+0x28/0x210)

[    3.865000] [] (pl330_alloc_chan_resources+0x28/0x210) from [] (dma_chan_get+0x5c/0xfc)

[    3.865000] [] (dma_chan_get+0x5c/0xfc) from [] (__dma_request_channel+0x110/0x1d4)

[    3.865000] [] (__dma_request_channel+0x110/0x1d4) from [] (samsung_dmadev_request+0x40/0x4c)

[    3.865000] [] (samsung_dmadev_request+0x40/0x4c) from [] (s3c64xx_serial_startup+0x168/0x1a0)

[    3.865000] [] (s3c64xx_serial_startup+0x168/0x1a0) from [] (uart_startup+0x58/0x1ac)

[    3.865000] [] (uart_startup+0x58/0x1ac) from [] (uart_open+0xd4/0x124)

[    3.865000] [] (uart_open+0xd4/0x124) from [] (tty_open+0x1e4/0x4d4)

[    3.865000] [] (tty_open+0x1e4/0x4d4) from [] (chrdev_open+0x94/0x158)

[    3.865000] [] (chrdev_open+0x94/0x158) from [] (do_dentry_open.clone.15+0x1d8/0x254)

[    3.865000] [] (do_dentry_open.clone.15+0x1d8/0x254) from [] (nameidata_to_filp+0x40/0x7c)

[    3.865000] [] (nameidata_to_filp+0x40/0x7c) from [] (do_last.clone.24+0xdc/0x7f0)

[    3.865000] [] (do_last.clone.24+0xdc/0x7f0) from [] (path_openat+0xb8/0x3d0)

[    3.865000] [] (path_openat+0xb8/0x3d0) from [] (do_filp_open+0x30/0x84)

[    3.865000] [] (do_filp_open+0x30/0x84) from [] (do_sys_open+0xdc/0x174)

[    3.865000] [] (do_sys_open+0xdc/0x174) from [] (ret_fast_syscall+0x0/0x30)

 

其中在文件Samsung.c (drivers\tty\serial) 的 s3c64xx_serial_startup函数中有关于DMA的初始化和申请的一段:

 

#ifdef CONFIG_SERIAL_SAMSUNG_DMA

if (uart_dma->use_dma) {

/* initialize err_occurred */

ourport->err_occurred = 0;

 

/* Acquire DMA channels */

while (!acquire_dma(uart_dma))

msleep(20);

 

/* Alloc buffer for dma */

uart_dma->rx_buff = kmalloc(RX_BUFFER_SIZE, GFP_KERNEL);

uart_dma->rx.req_size = RX_BUFFER_SIZE;

 

/* uart_rx_dma_request */

uart_rx_dma_request(ourport);

 

/* UnMask Err interrupt */

uintm = rd_regl(port, S3C64XX_UINTM);

uintm &= ~(S3C64XX_UINTM_ERR_MSK);

wr_regl(port, S3C64XX_UINTM, uintm);

 

/* enable rx dma mode */

enable_rx_dma(port);

}

#endif

 

三、MMC DMA研究

 

static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)

{

int ret;

struct mmc_data *data = host->data;

 

ret = mmci_dma_prep_data(host, host->data, NULL);

if (ret)

return ret;

 

/* Okay, go for it. */

dev_vdbg(mmc_dev(host->mmc),

 "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n",

 data->sg_len, data->blksz, data->blocks, data->flags);

dmaengine_submit(host->dma_desc_current);

dma_async_issue_pending(host->dma_current);

 

datactrl |= MCI_DPSM_DMAENABLE;

 

/* Trigger the DMA transfer */

writel(datactrl, host->base + MMCIDATACTRL);

 

/*

 * Let the MMCI say when the data is ended and it's time

 * to fire next DMA request. When that happens, MMCI will

 * call mmci_data_end()

 */

writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK,

       host->base + MMCIMASK0);

return 0;

}

  蓝色标记的即是触发DMAC的开关,而USB 并没有这样的开关,那么USB 的DMA 是怎么回事呢?相信我,接下来更精彩!

参考链接:

http://blog.csdn.net/qq405180763/article/details/14524675

 


四、USB DMA的调查:

Usb dma 使用:

首先看一个USB 结构体:

struct usb_bus {

struct device *controller; /* host/master side hardware */

int busnum; /* Bus number (in order of reg) */

const char *bus_name; /* stable id (PCI slot_name etc) */

u8 uses_dma; /* Does the host controller use DMA? */

u8 uses_pio_for_control; /*

 * Does the host controller use PIO

 * for control transfers?

 */

u8 otg_port; /* 0, or number of OTG/HNP port */

    ... ...

标蓝的字就指明了这个USB 设备是否使用DMA 

然后在函数int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urbgfp_t mem_flags)中会判断这个值。

if (hcd->self.uses_dma) {//判断是否DMA 传输

urb->setup_dma = dma_map_single( //返回一个设备可以识别的总线地址

hcd->self.controller,

urb->setup_packet,

sizeof(struct usb_ctrlrequest),//urb 结构类型的请求结构体

DMA_TO_DEVICE);//从内存到设备

========================研究结论=================

USB 应该只是用了DMA 的接口来获取一个总线地址,并没有真正使用DMA 控制器,USB 的ehci 控制器应该自己具有类似DMA 的功能

在内核里面通过 dma_map_single返回一个地址,这个地址是内存的物理地址,这个地址是IOMMU 能识别的。

所以接下来调查uboot 里面的给ehci的地址也应该是物理地址。   

我采取的方法是,把所有变量编译链接的地址改成跟物理内存实际范围一样的状况,物理内存的实际地址范围是4000000-8000000 ,而我们的链接地址是C000000-1000000,所以我们要改链接地址,
使得他们的范围对应,这里涉及到了一点编译链接的知识。

这里涉及到要改链接地址:

要修改两个地方:

1,./board/samsung/smdk4412/config.mk:13:CONFIG_SYS_TEXT_BASE = 0xc3e00000 

2,Tiny4412.h (include\configs)

#define CONFIG_ENABLE_MMU

/*

#ifdef CONFIG_ENABLE_MMU

#define CONFIG_SYS_MAPPED_RAM_BASE 0xc0000000

#define virt_to_phys(x) virt_to_phy_s5pv310(x)

#else

#define CONFIG_SYS_MAPPED_RAM_BASE CONFIG_SYS_SDRAM_BASE

#define virt_to_phys(x) (x)

#endif*/

#ifdef CONFIG_ENABLE_MMU

#define CONFIG_SYS_MAPPED_RAM_BASE 0x40000000

#define virt_to_phys(x) (x)

#else

#define CONFIG_SYS_MAPPED_RAM_BASE CONFIG_SYS_SDRAM_BASE

#define virt_to_phys(x) (x)

#endif


阅读(3118) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~