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的定义:
-
//出现两个ioremap
-
#ifndef __arch_ioremap
-
#define ioremap(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE)
-
#define ioremap_nocache(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE)
-
#define ioremap_cached(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE_CACHED)
-
#define ioremap_wc(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE_WC)
-
#define iounmap(cookie) __iounmap(cookie)
-
#else
-
#define ioremap(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE)
-
#define ioremap_nocache(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE)
-
#define ioremap_cached(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE_CACHED)
-
#define ioremap_wc(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE_WC)
-
#define iounmap(cookie) __arch_iounmap(cookie)
-
#endif
-
-
没有定义 #ifndef __arch_ioremap,所以是
-
#define MT_DEVICE 0
-
#define ioremap(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE)
3.在arch/arm/mm/ioremap.c中
-
-
__arm_ioremap(cookie, size, MT_DEVICE) 也有两个定义,一个是在nommu.c中,一个是在arch/arm/mm/ioremap.c中,所以很明显进入 arch/arm/mm/ioremap.c中:
-
//这个函数将物理地址phys_addr拆成两部分高20位的页帧号(Page Frame Number)pfn和低12位的页内偏移地址offset
-
void __iomem *
-
__arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
-
{
-
unsigned long last_addr;
-
unsigned long offset = phys_addr & ~PAGE_MASK;
-
unsigned long pfn = __phys_to_pfn(phys_addr);
-
-
/*
-
* Don't allow wraparound or zero size
-
*/
-
last_addr = phys_addr + size - 1;
-
if (!size || last_addr < phys_addr)
-
return NULL;
-
//此处打印值如下: last_addr=0x530fffff, size=0x100000, offset=0x0, pfn=0x53000
-
return __arm_ioremap_pfn(pfn, offset, size, mtype);
-
}
-
EXPORT_SYMBOL(__arm_ioremap);
-
-
/*
-
* Convert a physical address to a Page Frame Number and back
-
*/
-
#define PAGE_SHIFT 12
-
#define __phys_to_pfn(paddr) ((paddr) >> PAGE_SHIFT)
4. 在arch/arm/mm/ioremap.c中
-
-
/*
-
* Remap an arbitrary physical address space into the kernel virtual
-
* address space. Needed when the kernel wants to access high addresses
-
* directly.
-
*
-
* We need to allow non-page-aligned mappings too: we will obviously
-
* have to convert them into an offset in a page-aligned mapping, but the
-
* caller shouldn't need to know that small detail.
-
*
-
* 'flags' are the extra L_PTE_ flags that you want to specify for this
-
* mapping. See <asm/pgtable.h> for more information.
-
*/
-
void __iomem *
-
__arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
-
unsigned int mtype)
-
{
-
const struct mem_type *type;
-
int err;
-
unsigned long addr;
-
struct vm_struct * area;
-
-
/*
-
* High mappings must be supersection aligned
-
*/
-
if (pfn >= 0x100000 && (__pfn_to_phys(pfn) & ~SUPERSECTION_MASK))
-
return NULL;
-
-
type = get_mem_type(mtype);
-
if (!type)
-
return NULL;
-
-
/*
-
* Page align the mapping size, taking account of any offset.
-
*/
-
size = PAGE_ALIGN(offset + size);
-
-
area = get_vm_area(size, VM_IOREMAP); //分配虚拟地址空间
-
if (!area)
-
return NULL;
-
addr = (unsigned long)area->addr;
-
//此处打印出的地址: addr=0xc5400000
-
#ifndef CONFIG_SMP //不进入此处
-
if (DOMAIN_IO == 0 &&
-
(((cpu_architecture() >= CPU_ARCH_ARMv6) && (get_cr() & CR_XP)) ||
-
cpu_is_xsc3()) && pfn >= 0x100000 &&
-
!((__pfn_to_phys(pfn) | size | addr) & ~SUPERSECTION_MASK)) {
-
area->flags |= VM_ARM_SECTION_MAPPING;
-
err = remap_area_supersections(addr, pfn, size, type);
-
} else if (!((__pfn_to_phys(pfn) | size | addr) & ~PMD_MASK)) {
-
area->flags |= VM_ARM_SECTION_MAPPING;
-
err = remap_area_sections(addr, pfn, size, type);
-
} else
-
#endif
-
err = remap_area_pages(addr, pfn, size, type);
-
-
if (err) {
-
vunmap((void *)addr);
-
return NULL;
-
}
-
-
flush_cache_vmap(addr, addr + size);
-
return (void __iomem *) (offset + addr);
-
}
-
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中
-
static int
-
remap_area_sections(unsigned long virt, unsigned long pfn,
-
size_t size, const struct mem_type *type)
-
{
-
unsigned long addr = virt, end = virt + size;
-
pgd_t *pgd;
-
-
/*
-
* Remove and free any PTE-based mapping, and
-
* sync the current kernel mapping.
-
*/
-
unmap_area_sections(virt, size);
-
-
pgd = pgd_offset_k(addr);
-
do {
-
pmd_t *pmd = pmd_offset(pgd, addr);
-
-
pmd[0] = __pmd(__pfn_to_phys(pfn) | type->prot_sect);
-
pfn += SZ_1M >> PAGE_SHIFT;
-
pmd[1] = __pmd(__pfn_to_phys(pfn) | type->prot_sect);
-
pfn += SZ_1M >> PAGE_SHIFT;
-
flush_pmd_entry(pmd);
-
-
addr += PGDIR_SIZE;
-
pgd++;
-
} while (addr < end);
-
-
return 0;
-
}
阅读(593) | 评论(0) | 转发(0) |