Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2704595
  • 博文数量: 505
  • 博客积分: 1552
  • 博客等级: 上尉
  • 技术积分: 2514
  • 用 户 组: 普通用户
  • 注册时间: 2007-09-23 18:24
文章分类

全部博文(505)

文章存档

2019年(12)

2018年(15)

2017年(1)

2016年(17)

2015年(14)

2014年(93)

2013年(233)

2012年(108)

2011年(1)

2009年(11)

分类: LINUX

2013-02-23 12:03:21

原文地址:linux驱动2--ioremap过程 作者:wangcong02345

TQ2440的watchdog linux驱动在内核源码linux-2.6.30.4的:  ./drivers/watchdog/s3c2410_wdt.c下
1. watchdog ioremap的过程:
res->start=0x53000000   //物理地址
wdt_base=0xc5400000 //虚拟地址
wdt_base = ioremap(res->start, size);
将物理地址res->start映射到了虚拟地址0xc5400000处,映射大小为:size=0x100000.
注: 不知道为什么刚开始这个size=8,后来就成了0x100000(1M)。

2. arch/arm/include/asm/io.h中,找到ioremap的定义:

点击(此处)折叠或打开

  1. //出现两个ioremap
  2. #ifndef __arch_ioremap
  3. #define ioremap(cookie,size)        __arm_ioremap(cookie, size, MT_DEVICE)
  4. #define ioremap_nocache(cookie,size)    __arm_ioremap(cookie, size, MT_DEVICE)
  5. #define ioremap_cached(cookie,size)    __arm_ioremap(cookie, size, MT_DEVICE_CACHED)
  6. #define ioremap_wc(cookie,size)        __arm_ioremap(cookie, size, MT_DEVICE_WC)
  7. #define iounmap(cookie)            __iounmap(cookie)
  8. #else
  9. #define ioremap(cookie,size)        __arch_ioremap((cookie), (size), MT_DEVICE)
  10. #define ioremap_nocache(cookie,size)    __arch_ioremap((cookie), (size), MT_DEVICE)
  11. #define ioremap_cached(cookie,size)    __arch_ioremap((cookie), (size), MT_DEVICE_CACHED)
  12. #define ioremap_wc(cookie,size)        __arch_ioremap((cookie), (size), MT_DEVICE_WC)
  13. #define iounmap(cookie)            __arch_iounmap(cookie)
  14. #endif

  15. 没有定义 #ifndef __arch_ioremap,所以是
  16. #define MT_DEVICE        0
  17. #define ioremap(cookie,size)        __arm_ioremap(cookie, size, MT_DEVICE)
3.在arch/arm/mm/ioremap.c中

点击(此处)折叠或打开

  1.  
  2. __arm_ioremap(cookie, size, MT_DEVICE) 也有两个定义,一个是在nommu.c中,一个是在arch/arm/mm/ioremap.c中,所以很明显进入 arch/arm/mm/ioremap.c中:
  3. //这个函数将物理地址phys_addr拆成两部分高20位的页帧号(Page Frame Number)pfn和低12位的页内偏移地址offset
  4. void __iomem *
  5. __arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
  6. {
  7.     unsigned long last_addr;
  8.      unsigned long offset = phys_addr & ~PAGE_MASK;
  9.      unsigned long pfn = __phys_to_pfn(phys_addr);

  10.      /*
  11.       * Don't allow wraparound or zero size
  12.      */
  13.     last_addr = phys_addr + size - 1;
  14.     if (!size || last_addr < phys_addr)
  15.         return NULL;
  16.      //此处打印值如下: last_addr=0x530fffff, size=0x100000, offset=0x0, pfn=0x53000
  17.      return __arm_ioremap_pfn(pfn, offset, size, mtype);
  18. }
  19. EXPORT_SYMBOL(__arm_ioremap);

  20. /*
  21.  * Convert a physical address to a Page Frame Number and back
  22.  */
  23. #define PAGE_SHIFT        12
  24. #define    __phys_to_pfn(paddr)    ((paddr) >> PAGE_SHIFT)

4. 在arch/arm/mm/ioremap.c中

点击(此处)折叠或打开


  1. /*
  2.  * Remap an arbitrary physical address space into the kernel virtual
  3.  * address space. Needed when the kernel wants to access high addresses
  4.  * directly.
  5.  *
  6.  * We need to allow non-page-aligned mappings too: we will obviously
  7.  * have to convert them into an offset in a page-aligned mapping, but the
  8.  * caller shouldn't need to know that small detail.
  9.  *
  10.  * 'flags' are the extra L_PTE_ flags that you want to specify for this
  11.  * mapping. See <asm/pgtable.h> for more information.
  12.  */
  13. void __iomem *
  14. __arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
  15.          unsigned int mtype)
  16. {
  17.     const struct mem_type *type;
  18.     int err;
  19.     unsigned long addr;
  20.      struct vm_struct * area;

  21.     /*
  22.      * High mappings must be supersection aligned
  23.      */
  24.     if (pfn >= 0x100000 && (__pfn_to_phys(pfn) & ~SUPERSECTION_MASK))
  25.         return NULL;

  26.     type = get_mem_type(mtype);
  27.     if (!type)
  28.         return NULL;

  29.     /*
  30.      * Page align the mapping size, taking account of any offset.
  31.      */
  32.     size = PAGE_ALIGN(offset + size);

  33.      area = get_vm_area(size, VM_IOREMAP); //分配虚拟地址空间
  34.      if (!area)
  35.          return NULL;
  36.      addr = (unsigned long)area->addr;
  37.      //此处打印出的地址: addr=0xc5400000
  38. #ifndef CONFIG_SMP //不进入此处
  39.     if (DOMAIN_IO == 0 &&
  40.      (((cpu_architecture() >= CPU_ARCH_ARMv6) && (get_cr() & CR_XP)) ||
  41.      cpu_is_xsc3()) && pfn >= 0x100000 &&
  42.      !((__pfn_to_phys(pfn) | size | addr) & ~SUPERSECTION_MASK)) {
  43.         area->flags |= VM_ARM_SECTION_MAPPING;
  44.         err = remap_area_supersections(addr, pfn, size, type);
  45.     } else if (!((__pfn_to_phys(pfn) | size | addr) & ~PMD_MASK)) {
  46.         area->flags |= VM_ARM_SECTION_MAPPING;
  47.         err = remap_area_sections(addr, pfn, size, type);
  48.     } else
  49. #endif
  50.         err = remap_area_pages(addr, pfn, size, type);

  51.     if (err) {
  52.          vunmap((void *)addr);
  53.          return NULL;
  54.      }

  55.     flush_cache_vmap(addr, addr + size);
  56.     return (void __iomem *) (offset + addr);
  57. }
  58. EXPORT_SYMBOL(__arm_ioremap_pfn);
area = get_vm_area(size, VM_IOREMAP); //分配虚拟地址空间
err = remap_area_pages(addr, pfn, size, type);
这两个函数。

5. 在arch/arm/mm/ioremap.c中

点击(此处)折叠或打开

  1. static int
  2. remap_area_sections(unsigned long virt, unsigned long pfn,
  3.          size_t size, const struct mem_type *type)
  4. {
  5.     unsigned long addr = virt, end = virt + size;
  6.     pgd_t *pgd;

  7.     /*
  8.      * Remove and free any PTE-based mapping, and
  9.      * sync the current kernel mapping.
  10.      */
  11.     unmap_area_sections(virt, size);

  12.     pgd = pgd_offset_k(addr);
  13.     do {
  14.         pmd_t *pmd = pmd_offset(pgd, addr);

  15.         pmd[0] = __pmd(__pfn_to_phys(pfn) | type->prot_sect);
  16.         pfn += SZ_1M >> PAGE_SHIFT;
  17.         pmd[1] = __pmd(__pfn_to_phys(pfn) | type->prot_sect);
  18.         pfn += SZ_1M >> PAGE_SHIFT;
  19.         flush_pmd_entry(pmd);

  20.         addr += PGDIR_SIZE;
  21.         pgd++;
  22.     } while (addr < end);

  23.     return 0;
  24. }



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