分类: LINUX
2008-09-24 16:52:07
在将Linux移植到目标电路板的过程中,通常会建立外设I/O内存物理地址到虚拟地址的静态映射,这个映射通过在电路板对应的map_desc结构体数组中添加新的成员来完成,map_desc结构体的定义如代码清单11.12所示。
代码清单11.12 map_desc结构体
1 struct map_desc
2 {
3 unsigned long virtual;//虚拟地址
4 unsigned long pfn ;// __phys_to_pfn(phy_addr)
5 unsigned long length; //大小
6 unsigned int type;//类型
7 };
例如,S
代码清单11.13 SMDK2440评估板的map_desc数组
1 static struct map_desc smdk2440_iodesc[] __initdata = {
2 /* ISA IO空间映射 */
3 {
4 .virtual = (u32)S
5 .pfn = __phys_to_pfn(S
6 .length = 0x10000,
7 .type = MT_DEVICE,
8 }, {
9 .virtual = (u32)S
10 .pfn = __phys_to_pfn(S
11 .length = SZ_
12 .type = MT_DEVICE,
13 }, {
14 .virtual = (u32)S
15 .pfn = __phys_to_pfn(S
16 .length = 0x10000,
17 .type = MT_DEVICE,
18 }, {
19 .virtual = (u32)S
20 .pfn = __phys_to_pfn(S
21 .length = SZ_
22 .type = MT_DEVICE,
23 }
24 };
Linux操作系统移植到特定平台上MACHINE_START到MACHINE_END宏之间的定义针对特定电路板而设计,其中的map_io()成员函数完成I/O内存的静态映射,代码清单11.14给出了SMDK2440电路板的MACHINE_START、MACHINE_END宏的例子。
代码清单11.14 SMDK2440 MACHINE_START、MACHINE_END宏
1 MACHINE_START(S
2 /* Maintainer: Ben Dooks
3 .phys_io = S
4 .io_pg_offst = (((u32)S
5 .boot_params = S
6
7 .init_irq = s
8 .map_io = smdk2440_map_io,
9 .init_machine = smdk2440_machine_init,
10 .timer = &s
11 MACHINE_END
第8行赋值给map_io的smdk2440_map_io()函数完成SMDK2440电路板I/O内存的静态映射,最终调用的是cpu->map_io()建立map_desc数组中物理内存和虚拟内存的静态映射关系。
在一个已经移植好OS的内核中,驱动工程师完全可以对非常规内存区域的I/O内存(外设控制器寄存器、MCU内部集成的外设控制器寄存器等)依照电路板的资源使用情况添加到map_desc数组中,代码清单11.15的例子给出了内存空间资源的使用情况(注释部分)与map_desc数组的对应关系。
代码清单11.15 根据电路板内存资源情况定义map_desc
1 /*
2 * 逻辑地址 物理地址
3 * e8000000 40000000 PCI memory PHYS_PCI_MEM_BASE (max
4 * ec000000 61000000 PCI 配置空间 PHYS_PCI_CONFIG_BASE (max
5 * ed000000 62000000 PCI V3 regs PHYS_PCI_V3_BASE (max 64k)
6 * ee000000 60000000 PCI IO PHYS_PCI_IO_BASE (max
7 * ef000000 Cache flush
8 * f1000000 10000000 核心模块寄存器
9 * f1100000 11000000 系统控制寄存器
10 * f1200000 12000000 EBI寄存器
11 * f1300000 13000000 计数器/定时器
12 * f1400000 14000000 中断控制器
13 * f1600000 16000000 UART 0
14 * f1700000 17000000 UART 1
15 * f
16 * f1b00000 1b000000 GPIO
17 */
18
19 static struct map_desc ap_io_desc[] __initdata = {
20 {
21 .virtual = IO_ADDRESS(INTEGRATOR_HDR_BASE),
22 .pfn = __phys_to_pfn(INTEGRATOR_HDR_BASE),
23 .length = SZ_4K,
24 .type = MT_DEVICE
25 }, {
26 .virtual = IO_ADDRESS(INTEGRATOR_SC_BASE),
27 .pfn = __phys_to_pfn(INTEGRATOR_SC_BASE),
28 .length = SZ_4K,
29 .type = MT_DEVICE
30 }, {
31 .virtual = IO_ADDRESS(INTEGRATOR_EBI_BASE),
32 .pfn = __phys_to_pfn(INTEGRATOR_EBI_BASE),
33 .length = SZ_4K,
34 .type = MT_DEVICE
35 }, {
36 .virtual = IO_ADDRESS(INTEGRATOR_CT_BASE),
37 .pfn = __phys_to_pfn(INTEGRATOR_CT_BASE),
38 .length = SZ_4K,
39 .type = MT_DEVICE
40 }, {
41 .virtual = IO_ADDRESS(INTEGRATOR_IC_BASE),
42 .pfn = __phys_to_pfn(INTEGRATOR_IC_BASE),
43 .length = SZ_4K,
44 .type = MT_DEVICE
45 }, {
46 .virtual = IO_ADDRESS(INTEGRATOR_UART0_BASE),
47 .pfn = __phys_to_pfn(INTEGRATOR_UART0_BASE),
48 .length = SZ_4K,
49 .type = MT_DEVICE
50 }, {
51 .virtual = IO_ADDRESS(INTEGRATOR_UART1_BASE),
52 .pfn = __phys_to_pfn(INTEGRATOR_UART1_BASE),
53 .length = SZ_4K,
54 .type = MT_DEVICE
55 }, {
56 .virtual = IO_ADDRESS(INTEGRATOR_DBG_BASE),
57 .pfn = __phys_to_pfn(INTEGRATOR_DBG_BASE),
58 .length = SZ_4K,
59 .type = MT_DEVICE
60 }, {
61 .virtual = IO_ADDRESS(INTEGRATOR_GPIO_BASE),
62 .pfn = __phys_to_pfn(INTEGRATOR_GPIO_BASE),
63 .length = SZ_4K,
64 .type = MT_DEVICE
65 }, {
66 .virtual = PCI_MEMORY_VADDR,
67 .pfn = __phys_to_pfn(PHYS_PCI_MEM_BASE),
68 .length = SZ_
69 .type = MT_DEVICE
70 }, {
71 .virtual = PCI_CONFIG_VADDR,
72 .pfn = __phys_to_pfn(PHYS_PCI_CONFIG_BASE),
73 .length = SZ_
74 .type = MT_DEVICE
75 }, {
76 .virtual = PCI_V3_VADDR,
77 .pfn = __phys_to_pfn(PHYS_PCI_V3_BASE),
78 .length = SZ_64K,
79 .type = MT_DEVICE
80 }, {
81 .virtual = PCI_IO_VADDR,
82 .pfn = __phys_to_pfn(PHYS_PCI_IO_BASE),
83 .length = SZ_64K,
84 .type = MT_DEVICE
85 }
86 };
此后,在设备驱动中访问经过map_desc数组映射后的I/O内存时,直接在map_desc中该段的虚拟地址上加上相应的偏移即可,不再需要使用ioremap()。