当前位置:嗨网首页>书籍在线阅读

15-IO内存静态映射

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

11.5 I/O内存静态映射

在将Linux移植到目标电路板的过程中,通常会建立外设I/O内存物理地址到虚拟地址的静态映射,这个映射通过在电路板对应的map_desc结构体数组中添加新的成员来完成,map_desc结构体的定义如代码清单11.11所示。

代码清单11.11 map_desc结构体

1 struct map_desc {

2 unsigned long virtual;/ 虚拟地址 /

3 unsigned long pfn ; / __phys_to_pfn(phy_addr) /

4 unsigned long length; / 大小 /

5 unsigned int type;/ 类型 /

6 };

例如,在内核arch/arm/mach-ixp2000/ixdp2x01.c文件对应的Intel IXDP2401和IXDP2801平台上包含一个CPLD,该文件中就进行了CPLD物理地址到虚拟地址的静态映射,如代码清单11.12所示。

代码清单11.12 在板文件中增加物理地址到虚拟地址的静态映射

1 static struct map_desc ixdp2x01_iodesc _initdata = {

2 .virtual = IXDP2X01_VIRT_CPLD_BASE,

3 .pfn = _ _phys_to_pfn(IXDP2X01_PHYS_CPLD_BASE),

4 .length = IXDP2X01_CPLD_REGION_SIZE,

5 .type = MT_DEVICE

6 };

7

8 static void _ _init ixdp2x01_map_io(void)

9 {

10 ixp2000_map_io();

11 iotable_init(&ixdp2x01_io_desc, 1);

12 }

代码清单11.12中的第11行iotableinit()是最终建立页映射的函数,它被通过MACHINE START、MACHINE_END宏赋值给板的map_io()函数。Linux操作系统移植到特定平台上,MACHINE_START、MACHINE_END宏之间的定义针对特定电路板而设计,其中的map_io()成员函数完成I/O内存的静态映射,代码清单11.13给出了IXDP2401电路板的MACHINE_START、MACHINE_END宏的例子。

代码清单11.13 IXDP2401电路板的MACHINE_START、MACHINE_END宏

1 MACHINE_START(IXDP2401, "Intel IXDP2401 Development Platform")

2 / Maintainer: MontaVista Software, Inc. /

3 .phys_io = IXP2000_UART_PHYS_BASE,

4 .io_pg_offst = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,

5 .boot_params = 0x00000100,

6 .map_io = ixdp2x01_map_io,

7 .init_irq = ixdp2x01_init_irq,

8 .timer = &ixdp2x01_timer,

9 .init_machine = ixdp2x01_init_machine,

10 MACHINE_END

在一个已经移植好OS的内核中,驱动工程师完全可以对非常规内存区域的I/O内存(外设控制器寄存器、MCU内部集成的外设控制器寄存器等)依照电路板的资源使用情况添加到map_ desc数组中,代码清单11.14的例子给出了内存空间资源的使用情况(注释部分)与map_desc数组的对应关系。

代码清单11.14 根据电路板内存资源情况定义map_desc

1 /*

2 * 逻辑地址 物理地址

3 * e8000000 40000000 PCI memory PHYS_PCI_MEM_BASE (max 512M)

4 * ec000000 61000000 PCI 配置空间 PHYS_PCI_CONFIG_BASE (max 16M)

5 * ed000000 62000000 PCI V3 regs PHYS_PCI_V3_BASE (max 64k)

6 * ee000000 60000000 PCI IO PHYS_PCI_IO_BASE (max 16M)

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 * f1a00000 1a000000 调试用LEDs

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_16M,

69 .type = MT_DEVICE

70 }, {

71 .virtual = PCI_CONFIG_VADDR,

72 .pfn = __phys_to_pfn(PHYS_PCI_CONFIG_BASE),

73 .length = SZ_16M,

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()。

我们若要在LDD6410开发板的板文件中添加新的物理地址到虚拟地址的映射,只需要修改文件/arch/arm/mach-s3c6410/mach-ldd6410.c中的map_desc数组(目前该数组为空):

struct map_desc ldd6410_iodesc[] = {};