acpi 学习笔记
更新时间:2024-05-21 00:58:01 阅读量: 综合文库 文档下载
ACPI学习笔记 - 不断修订中-last updated on Oct 15
刚起步, 3.0b规范还只看了一部分, 本文档对别人应该没什么意义,只是记录我的学习过程而已。 肯定有大量误解,欢迎BUG FIXING。 /**
* file : ACPI Notes with Linux.txt
* AUTHOR : albcamus * Copyright : GNU FDL(Free Documentation License) * XXX : continuously correcting and improving */
TERMINOLOGY: ===========
I.) TABLES OF ACPI
SDTH : System Description Table Header (注意这个不是Table,它是每个Table都包含的头) RSDP : Root System Description Pointer ('RSD PTR')
RSDT : Root System Description Table (signature is 'RSDT')
FADT : Fixed ACPI Description Table ('FACP')
FACS : Firmware ACPI Control Structure ('FACS')
DSDT : Differentiated System Description Table ('DSDT')
PSDT : Persistent System Description Table
('PSDT'). 注意它是ACPI Spec-1.0定义的,早已被移除。 SSDT : Secondary System Description Table ('SSDT')
MADT : Multipile ACPI Description Table ('APIC')
SBST : Smart Battery Table ('SBST')
XSDT : Extended System Description Table ('XSDT')
ECDT : Embedded Conroller Boot Resources Table ('ECDT')
SLIT : System Locality Distance Information Table ('SLIT')
SRAT : System Resource Affinity Table ('SRAT')
MCFG : PCI-Memory Mapped Configuration table and sub-table ('MCFG')
SPCR : Serial Port Console Redirection table ('SPCR')
BERT : Boot Error Record Table ('BERT')
SBFT : Simple Boot Flag Table ('BOOT')
CPET? : Corrected Platform Error Polling Table ('CPEP')
DBGT? : Debug Port Table
('DBGP')
DMAT? : DMA Remapping Table ('DMAR')
TCPT? : Trusted Computing Platform Alliance Table ('TCPA')
WDRT : Watchdog Resource Table ('WDRT')
ASFT? : Alert Standard Format Table ('ASF!')
具体见ACPI规范3.0b的Table 5-6. 这里只是一部分。
Note, ACPI定义的所有tables、blocks和structures,全都是little-endian。
II.) THE OTHER TERMINOLOGIES
ASL : ACPI Source Language AML : ACPI Machine Language DSL : Digital Simulation Language
E820 : a system memory map protocol, provided in ACPI spec, ch14 for 3.0b EFI : Enhanced Firmware Interface HPET : High Precision Event Timer GPE : General-Purpose Event GSI : Global System Interrupts OSL : OS Service Layer
OSPM : OS Power Management, 指Linux等OS中实现对ACPI支持的代码 PRT : PCI IRQ Routing Table
PXE : Preboot Execution Environment
SAPIC : Streamlined APIC, IA64上使用的APIC。其local SAPIC和I/O SAPIC分别对应着IA32
和x86-64上的Local APIC和I/O APIC SBF : Simple Boot Flag
SCI : System Control Interrupt
(OS-visible interrupts, triggered by ACPI events)
SMBIOS/DMI : System Management BIOS/Desktop Management Interface. PC的BIOS规范。
TOM : Top Of Memory
UUID : Universal Uniform IDentifiers
xface : Linux内核ACPI源文件的命名法,表示Interface。例如tbxface.c实现table的接口。
1, RSDP, RSDT and XSDT
RSDP是位于系统内存地址空间中的,它的值由firmware设置。
RSDP包含了两个指针(还有其他字段,见Linux的struct acpi_table_rsdp),分别保存着RSDT表的物理地址
(32位), 和XSDT表的物理地址(64位)。
Linux寻找RSDP的代码见acpi_os_get_root_pointer()函数。
从ACPI2.0+开始,XSDT就取代了RSDT。 RSDT是ACPI 1.0中的,现代的OEM厂商一般也还提供RSDT,但那只
是为了向后兼容ACPI-1.0而已。 或者用RSDT,或者用XSDT,不管选择用那个,它都包含了其他ACPI表数组 的地址。
Linux下这2者的定义是:
struct acpi_table_rsdt {
struct acpi_table_header header; /* Common ACPI table header */ u32 table_offset_entry[1]; /* Array of pointers to ACPI tables */ };
struct acpi_table_xsdt {
struct acpi_table_header header; /* Common ACPI table header */ u64 table_offset_entry[1]; /* Array of pointers to ACPI tables */ /* FIXME: 为什么数组大小是1? */ };
2, ACPI Table Header
ACPI所有的描述表(FACS表除外?Linux的acpi_table_facs结构不包含header,ACPI规范中也没有)都包含
着一个Header, 所有描述表的Header结构都是一样的。Linux把它定义为:
struct acpi_table_header {
char signature[ACPI_NAME_SIZE]; /* ASCII table signature */ u32 length; /* Length of table in bytes, including this header */ u8 revision; /* ACPI Specification minor version # */
u8 checksum; /* To make sum of entire table == 0 */ char oem_id[ACPI_OEM_ID_SIZE]; /* ASCII OEM identification */
char oem_table_id[ACPI_OEM_TABLE_ID_SIZE]; /* ASCII OEM table identification */
u32 oem_revision; /* OEM revision number */
char asl_compiler_id[ACPI_NAME_SIZE]; /* ASCII ASL compiler vendor ID */ u32 asl_compiler_revision; /* ASL compiler version */ };
3, (RSDT/XSDT之外的) ACPI描述表数组的第一个:FADT
这个数组的第一个元素由XSDT中的table_offset_entry[0]指定位置。
被指向的第一个表通常是FADT(Fixed ACPI Description Table),它的几个主要作用:
1) 保存着FACS和DSDT表的地址(64位也是)
2) 包含一些entries,每个entry有固定的length,描述一个硬件的ACPI feature(我的理解就是,
硬件对ACPI的支持程度)
Linux下FADT的定义见struct acpi_table_fadt结构。
4. DSDT表(Differentiated System Description Table)
由FADT中的字段指向,见上一条笔记。
//Thanks for wheelz!
DSDT表包含一个Definition Block,叫作'Differentiated Definition Block for the DSDT',它包含了
实现与配置信息(implementation and configuration information)。 OSPM用这些信息来实现:电源管理,
热量管理,以及(在ACPI硬件寄存器所描述的信息之外的)即插即用。
//FIXME: 奇怪的是,Linux没有提供一个struct acpi_table_dsdt 结构的定义,只提供了一个` acpi_system_read_dsdt()函数。
//FIXED: 注意,这个acpi_system_read_dsdt()函数不是内核用来load DSDT表的,而 是为了让用户程序(例如cp)通过/proc/acpi/dsdt来读取DSDT表的(in AML format),以便给内核开发者诊断 问题。
很多platform vendor提供的BIOS,特别是笔记本上,其DSDT表往往有BUG,导致Linux的电源管理出现问题。
Linux内核提供了CONFIG_ACPI_CUSTOM_DSDT和CONFIG_ACPI_CUSTOM_DSDT_FILE配置选项,允许用户自己提供
DSDT文件,替代BIOS中有BUG的那个。
这个用户自己提供的DSDT文件,其实就是一个AML语言描述的数据块。 可以用pmtools中的acpidump和
acpixtract程序把ACPI的表从BIOS中提取出来,再用iasl工具(Intel ACPICA中的ASL编译器、
AML反汇编器)
反汇编它,修正BUG,然后编译。
这个原理,参考Linux内核的acpi_os_table_override()函数。
5. SSDT表
它是DSDT表的扩展。如果有这个表,RSDT/XSDT中就有指向它的指针。 SSDT表可能有不止一个。 Definition Blocks, 都是定义在DSDT或者SSDT(s)表里的。其它的表没有 定义块。
6, FACS表(Firmware ACPI Control Structure)
跟DSDT表一样,FACS表也由FADT表中的字段指向。见笔记<3>。
7, CPU的Idle States (C-states)
从C0到C
n越大,CPU越省电,但从它转到C0的所需时间也越长。
Linux下,可以通过kernel parameter: processor.max_cstate来改变
8, CPU的Performance States (P-States), CPU频率管理
从P0到P
注意,只有C-State处于C0状态时,这些P-States才是有意义的。 如果CPU处于C
频率没有任何意义。
9, CPU的Throttling States (T-States)
Throttling是个什么意思呢?--CPU每秒多少个时钟周期s,我们称之为Cycles Per Seconds (CPS)。可以让
CPU在一个CPS中有一定比例的空闲时间。
T-States从T0到T
除了T0外的T-States,和“7, CPU的Performance States (P-States), CPU频率管理”不同,后者只是\让每
秒的周期数少一些\; 它也和CPU的空闲状态(例如C1状态)不同,后者是CPU在1秒钟里所有的周期都是空闲的。
Throttling不会降低电压,它只是让每秒钟都有几个时钟周期是空闲的。--注意,给定一个工作量, Throttling会导致CPU需要更长的时间来完成它,从而耗费更多的电。(电压不变,时间加长,自然耗电变多)
10. CPU的\
in ACPI there are 6 power state:
S0, S1, S2, S3, S4, and S5.
S0 : The Running state.
S1 : the suspend state. in this state, the CPU will suspend activity but remains its contexts.
S2 & S3 : sleep states. in these states,memory contexts are held but CPU contexts are lost.
the difference between S2 and S3 are in CPU re-initialization done by firmware and device reinitialization.
S4 : a sleep state in which contexts are saved to disk. the context will be restored
unpon the return to S0. This is identical to soft-off for hardware. This state can be implemented by either OS or firmware.
S5 : the soft-off state. All activity will stop and all contexts are lost.
ACPI规范说,还规定了另一个说法,叫作Global System State:
G0 == {S0} : Working.
G1 == {S1, S2, S3, S4} : Sleeeping. G2 == {S5} : Soft off G3 : Mechanical off
11, MADT表, Multiple APIC Description Table
ACPI规范认为,一共有3种中断模型: Dual-8259, APIC和SAPIC。 Firmware可以同时提供对它们的支持,
但OSPM只能选择一个。
1.) Linux的MADT表的结构定义为:
struct acpi_table_madt {
struct acpi_table_header header;
u32 address /* physical address of local APIC */ u32 flags; };
其中MADT表在44字节偏移处,有个APIC Structure[n]结构数组,每个元素的第一个字节是该Structure的
类型,第二个字节是该Structure的长度。Linux把这两个字节封装成了一个acpi_subtable_header结构:
struct acpi_subtable_header { u8 type; u8 length; };
2.) APIC Structure的类型有:
0 : Processor Local APIC 1 : I/O APIC
2 : interrupt Source Override
3 : Non-maskable Interrupt Source(NMI) 4 : Local APIC NMI Structure
5 : Local APIC Address Override Structure 6 : I/O SAPIC 7 : Local SAPIC
8 : Platform Interrupt Sources
9-127 : Reserved. OSPM skips structures of the reserved type 128-255 : Reserved for OEM use
从0到8的这九个结构,在Linux下分别是:
0, acpi_madt_local_apic,
1, acpi_madt_io_apic,
2, acpi_madt_interrupt_override,
对于同时支持APIC和dual-8259A两种中断模型的平台,GSI中断的0-15必须被映射到8259A的0-15
引脚上。如果不是这样,那么就必须提供Interrupt Override。
例如,如果你有一个ISA的PIT,连接到ISA IRQ 0;但是在APIC模式下,它连接到I/O APIC 的
IRQ 2。你就需要提供Interrupt Source Override,在source entry == 0处,指定其GSI为2。
3, acpi_madt_nmi_source,
该结构指定,I/O APIC的中断输入中,哪些应被当作NMI。
4, acpi_madt_local_apic_nmi,
该结构指定,每个CPU的Local APIC,其中断输入(LINT
5, acpi_madt_local_override,
MADT中的address是local APIC的地址,32位。为了提供对64位系统的支持,可以提供local
APIC Address Override Structure,这样local APIC的地址就可以被Override成64位。
6, acpi_madt_io_sapic, IA64的I/O SAPIC。
7, acpi_madt_local_sapic, IA64的Local SAPIC。
8, acpi_madt_interrupt_source.
用来管理PMI(Platform Management Interrupts)的. PMI是IA-64上的,跟IA32的SMI类似。
这几个结构,可以参考Linux找到它们时打印信息的代码来理解其结构:acpi_table_print_madt_entry() 函数。
3.) Local APIC/SAPIC的entry order:
为了POST以及其后的正确引导, 有两条规则应该遵守: 1). OSPM应该以 处理器在MADT表中出现的顺序来初始化它们 2). Firmware应该把MADT中的第一个Entry列为引导处理器BP
对于多线程处理器,道理是一样的:
1. OSPM应该以 逻辑处理器在MADT表中出现的顺序来初始化它们 2。 Firmware应该把每个处理器的第一个逻辑处理器,在MADT表中 列在任何2nd逻辑处理器之前。
4.) 参考9.1/9.2中的信息,看看Linux下对local APIC和I/O APIC的定义:
/* 0:Processor Local APIC */ struct acpi_madt_local_apic {
struct acpi_subtable_header header; u8 processor_id; /* ACPI processor ID */ u8 id; /* Processor's local APIC id */ u32 lapic_flags; };
/* 1: IO APIC */
struct acpi_madt_io_apic {
struct acpi_subtable_header header; u8 id; /* I/O APIC ID */
u8 reserved; /* reserved. must be zero */ u32 address; /* IO APIC physical address */
u32 global_irq_base; /* Global system interrupt where INIT lines start */ };
在Linux上,引导时通过acpi_parse_madt_lapic_entries()和acpi_parse_madt_ioapic_entries()
两个函数来获取BIOS中ACPI提供的Local APIC和I/O APIC的信息。
5.) 多个IO-APIC
I/O APIC有一或多个。在ACPI-enabled系统中,有两种中断模型:APIC模型和PC-AT的一对主从8259A 模型。
APIC模型下,每个IO APIC支持的irq输入数目,可以是不同的, OSPM读取每个IO APIC的Max
Redirection Register来获取这个数目.
参考acpi_madt_io_apic结构,如果一个io apic是系统中的第二个io apic,而第一个io apic的中断
数目是24, 那么第二个io apic的global_irq_base就是24 -- 亦即,第二个io apic的中断输入从第
24开始递增。
12. SRAT表(System Resource Affinity Table)
该表可选.
13, E820及其它(ACPI spec, CH14)
传统的PC使用INT 15H这个BIOS调用来获得内存布局; 用EFI的系统,则可以通过EFI的一个boot service:
GetMemoryMap()函数,来获取内存布局.
OS loader获取的memory map,然后把它传递给OSPM。
1). ACPI定义了5种类型的内存范围:
Value || Mnemonic Description
==================================================================================
1 || AddressRangeMemory 该范围是OS可用的RAM
==================================================================================
2 || AddressRangeReserved 由system使用或保留,OS不得使用
==================================================================================
3 || AddressRangeACPI ACPI占用的内存。当OS读取了ACPI Tables后,它就可
|| 以使用这块RAM了。
================================================================================== 4 || AddressRangeNVS ACPI NVS内存
==================================================================================
5 || AddressRangeUnusuable 该范围的内存有错误,OS不可使用。
==================================================================================
Other || Undefined 未定义,即保留给将来。OSPM应该象对待 AddressRangeReserved一样对待它。
2). INT 15H, E820H - 查询memory map
只能在real mode使用。 \的意思是,给EAX赋值e820h,然后int 0x15来调用BIOS的15号 调用。
PC机上一共有3中memmap探测方法,Linux采用的顺序是:先使用e820h,然后使用e801h,然后使用88h。
e820h : lets us assemble a memory map e801h : returns a 32-bit memory size 88h : returns 0-64m memory
见arch/i386/boot/setup.S
ACPI规定的是,要作出一个int 15h,e820h BIOS调用,要准备以下的输入:
EAX : E820h
EBX : 如果是第一次调用,为0。 如果不是,则存放上次调用之后的Continuation value。ACPI
规范说,EBX应该包含上一次调用的返回值,意思是每次调用后BIOS都自动把continuation value写入了ebx中。如果BIOS往ebx写的值为0,则说明EOF,不要进行下一次调用了。 ES:DI : Buffer地址,指向一个Address Range Descriptor结构,BIOS把信息写入这个结构。
ECX : Buffer size
EDX : 签名。应该是\这4个字母的ASCII值。 Linux写作#define SMAP 0x534d4150
而输出是:
CF : 为1表示出错
EAX : 签名。为\表示正确,可以判断ebx值进行下一次调用;否则为出错,应该放弃e820方法
ES:DI : 和输入一样
ECX : Buffer size. BIOS往ES:DI写了多少字节。 最小是20字节。 EBX : Continuation Value.
Address Range Descriptor Structure: ----------------------------------
0 BaseAddrLow Low 32 Bits of Base Address 4 BassAddrHigh High 32 Bits of Base Address 8 LengthLow Low 32 Bits of Length in Bytes 12 LengthHigh High 32 Bits of Length in Bytes 16 Type Address Type of this range 20 Extended Attributes see below
其中BassAddrLow和BaseAddrHigh一起组成了64位的Base Addr。 是该range的起始物理地址。
LengthLow和LengthHigh一起组成了64位的长度,即该range的size。 Type,就是1)中说的5种类型之一了:)
扩展属性我就不抄了,见ACPI Spec CH14。表14-5.
3). 如果是EFI enabled
OS loader使用GetMemoryMap()函数--它是EFI提供的Boot Services之一--来获取memmap,并且把它传递给
OSPM。
EFI没研究,暂且不说。
4). Linux对E820 memmap的实现
Linux定义了几个内存地址:
#define E820MAP 0x2d0 #define E820NR 0x1e8
和E820最多能有多少entries:
#define E820MAX 128
而在setup.S中:
设置ES:DI的值为E820MAP,以便调用int 15h,e820h时让BIOS把memmap写入这个地址:
movw $E820MAP, %di
在每次调用int 15h,e820h时,都增加(E820NR)的值:
incb (E820NR)
这样,当调用完毕,(E820NR)这块内存就保存了entries数目。
Linu引导时,设置memmap的调用路径是:
start_kernel() > setup_arch() > memory_setup() > sanitize_e820_map(E820_MAP, &E820_MAP_NR)
> copy_e820_map(E820_MAP, E820_MAP_NR)
其中E820_MAP和E820_MAP_NR的定义:
#define E820_MAP_NR (*(char*) (PARAM+E820NR))
#define E820_MAP ((struct e820entry *) (PARAM+E820MAP))
//FIXME:PARAM是什么意思? 猜测是Linux用来保存boot parameters的页面,见arch/i386/kernel/ head.S
其中E820NR和E820MAP是两个16位的内存地址,已经在setup.S中调用bios call时设置好了。见上边 的笔记。
/**
* 一个个range地添加从bios获得的内存布局信息 *
* 作者注释:
* =========
* 我们检查一下从BIOS获得的memmap是不是至少包含2个区间。 因为setup.S中的探测结果可能不
* 那么完美,而我们又知道大多数PC机有两个内存区域:一个从0到640k,另一个从1M往上。 *
* 如果BIOS得来的结果是正确的,那么我们就使用它给的memmap;如果不正确,我们就自己伪造
* 一个(案,即是在这里返回-1,让调用者machine_specific_memory_setup()去伪造。) */
int __init copy_e820_map(struct e820entry *biosmap, int nr_map) {
/* 只有一个,或者竟然是负的?那么就忽略它 */ if (nr_map < 2) return -1;
do {
unsigned long long start = biosmap->addr; unsigned long long size = bisomap->size; unsigned long long end = start + size; unsigned long type = biosmap->type; ...
if ( type = E820_RAM ) { //是ACPI中可用的RAM类型,那么我们就设置它 if (start < 0x100000ULL && end > 0xA0000ULL) { if (start < 0xA0000ULL)
add_memory_region(start, 0xA0000ULL-start, type); if (end <= 0x100000ULL) continue;
start = 0x100000ULL;
size = end - start; } }
/* 添加一个Memory Range。
* 注意! e820这个全局变量,就是在该函数中设置的值! */
add_memory_region(start, size, type);
} while (biosmap++, --nr_map);
return 0; }
这个copy_e820_map()函数执行完毕,则memory map就已经设置到全局变量e820中了。
14. ACPI Namespace 和 Definition Block
只有Unload一个Definition Block时,name才会从名空间中移除。
只有Load/Unload 定义块 时,Namespace中内容才可能改变。
Definition Block只可能出现在DSDT和SSDT(s)中。其它表没有。 Linux内核中加载namespace的
函数为acpi_tb_load_namespace(),其注释说:Load the namespace from the DSDT and all SSDTs/PSDTs found in the RSDT/XSDT.
(FIXME: 就Dell Optiplex 745机器用acpidump,acpixtract,iasl -d反汇编出来的.dsl 来看,一个DSDT或SSDT只有一个DefinitionBlock。 不知道这是否是ACPI规范了的)
Name的命名约定:
1. 每个Name都是固定的32bit(4字节)大小。
2. Name的第一个字符必须是'A'-'Z',或者下划线'_'
3. Name不足4个字节的,ASL编译器会对它进行填充。 惯用的填充方式就是在 结尾填充下划线'_'。
4. 以下划线'_'开头的Name是由ACPI规范预留的,也就是说,只有ACPI规范定义了 一个以'_'开头的Name, 供应商才能提供它。 不允许自己定义以'_'开头的Name
5. 以'\\'开头的Name,表示引用namespace的根。('\\'不算在4字节长度之内)
6. 以'^'开头的Name,表示引用本namespace的parent。('^'不算在4字节长 度之内)
预定义了的namespaces(见规范3.0之5.3.1部分)
\\_GPE : General events in GPE register block \\_PR : ACPI 1.0 Processor Namespace.
\\_SB : All Device/Bus Objects under this namespace \\_SI : System Indicator.
\\_TZ : ACPI 1.0 Thermal Zonen namespace.
15. Linux至少加载ACPI的3个Tables: FADT, FACS, DSDT (RSDT不算在内)
见acpi_tb_tables_loaded()函数:
if (acpi_gbl_root_table_list.count >= 3) { return (TRUE); else
return (FALSE);
其中DSDT和FACS在acpi_gbl_root_table_list数组中的索引是固定的,DSDT是0, FACS是1:
1). acpi_early_init()何时执行
2.6.22中,start_kernel() > acpi_early_init() > rest_init()
> kernel_init(KERNEL THREAD) > do_basic_setup() > do_initcalls()
可见,acpi_early_init()比带有__init属性的函数执行得要早。 另外,注释说:acpi_early_init() is before LAPIC and SMP init.
SMP和LAPIC的初试化在哪里呢?答曰:
start_kernel() > rest_init() > kernel_init() > smp_prepare_cpus() > smp_ops.smp_prepare_cpus() [这个即是native_smp_prepare_cpus()] > smp_boot_cpus() > setup_local_APIC() > smpboot_setup_io_apic()
2). acpi_early_init()都干了些什么 ...
status = acpi_reallocate_root_table(); /* 在dynamic memory中申请ACPI tables的空间
,然后从别处把它们copy过来 */
...
status = acpi_initialize_subsystem(); /* 初试化所有ACPI相关的全局变量 */ ...
status = acpi_load_tables(); /* 从DSDT/SSDTs/PSDT表获取数据,构建ACPI namespace */ ...
3). 看看acpi_reallocate_root_table()函数 ...
struct acpi_table_desc *tables; acpi_size new_size; ...
new_size = (acpi_gbl_root_table_list.count +
ACPI_ROOT_TABLE_SIZE_INCREMENT) * sizeof(struct acpi_table_desc);
tables = ACPI_ALLOCATE_ZEROED(new_size); /*在linux下该宏的功能相当于kzalloc()函数*/
ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables, new_size); /* memcpy */ ...
4). PCI设备的IRQ Routing
有个带__init属性的pci_acpi_init()函数,它有这么2句:
pcibios_enable_irq = acpi_pci_irq_enable;
pcibios_disable_irq = acpi_pci_irq_disable;
而这两个函数指针类型的变量,其原型为:
int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL; void (*pcibios_disable_irq)(struct pci_dev *dev) = NULL;
这两行赋值代码,其作用要等到PCI驱动程序调用pci_enable_device()和pci_disable_device()的 时候,才能真正发挥出来:
pci_enable_device() > pci_enable_device_bars() > do_pci_enable_device() > pcibios_enable_device() > pcibios_enable_irq() -- 在这里,调用的就是 acpi_pci_irq_enable()
Linux定义的PCI IRQ Routing Table:
struct acpi_prt_entry { struct list_head node; struct acpi_pci_id id; u8 pin; struct {
acpi_handle handle; u32 index; } link; u32 irq; };
struct acpi_prt_list { int count;
struct list_head entries; };
static struct acpi_prt_list acpi_prt;
struct acpi_pci_routing_table { u32 length; u32 pin;
acpi_integer address; u32 source_index; char source[4]; }; /*
* XXX *
* Type 1: Dynamic
* the 'source' field specifies the PCI interrupt link * device used to configure the IRQ assigned to this * slot|dev|pin. the 'source_index' field incicates which * resource descriptor in the resource templeate(of the * link device) this interrupt is allocated from. * *
* Type 2: Static
* The 'source' field is NULL, and the 'source_index' field * specifies the IRQ value, which is hardwired to specific * interrupt inputs on the interrupt controller.
*/
参考acpi_pci_irq_add_entry()函数。
/*}}}*/
51.1) ACPI和Linux设备驱动模型的集成//FIXME: 我还不理解!!
/*{{{*/
static struct acpi_driver acpi_pci_root_driver = { .name = \
.class = ACPI_PCI_ROOT_CLASS, .ids = ACPI_PCI_ROOT_HID, .ops = {
.add = acpi_pci_root_add, .remove = acpi_pci_root_remove, .start = acpi_pci_root_start, }, };
struct acpi_driver { char name[80]; char class[20];
char *ids; /* supported hardware IDs */ struct acpi_device_ops ops;
struct device_driver drv; /* XXX : struct device那层的 */ struct module *owner; };
struct acpi_device_ops { acpi_op_add add; acpi_op_remove remove; acpi_op_lock lock; acpi_op_start start; acpi_op_stop stop; acpi_op_suspend suspend; acpi_op_resume resume; acpi_op_scan scan; acpi_op_bind bind; acpi_op_unbind unbind; acpi_op_shutdown shutdown; };
struct acpi_bus_ops { ...; };
struct acpi_device {
acpi_handle handle;
struct acpi_device *parent; struct list_head children; struct list_head node; struct list_head wakeup_list; struct list_head g_list;
struct acpi_device_status status; ...;
void *driver_data; struct acpi_driver *driver; struct acpi_device_ops *ops;
struct device dev; //XXX: 注意,这就是和内核的驱动核心层的接口 struct acpi_bus_ops bus_ops; ...; };
ACPI的PRT表(PCI IRQ Routing Table)
struct acpi_prt_list {
int count; //number of entries struct list_head entries; }; /*}}}*/
52, ACPI中寻找一个Table,然后针对它运行handler
/*{{{*/
241 int __init acpi_table_parse(char *id, acpi_table_handler handler) 242 {
243 struct acpi_table_header *table = NULL; 244
245 if (!handler)
246 return -EINVAL; 247
/** 单独处理MADT表,是因为有些BIOS有多个MADT,这是硬件BUG。 * 见check_multipile_madt()函数的注释 */
248 if (strncmp(id, ACPI_SIG_MADT, 4) == 0)
249 acpi_get_table(id, acpi_apic_instance, &table); 250 else
251 acpi_get_table(id, 0, &table); 252
253 if (table) {
254 handler(table); 255 return 0; 256 } else
257 return 1; 258 }
好,再分析acpi_get_table()函数:
/*********************************************************************
********** *
* FUNCTION: acpi_get_table *
* PARAMETERS: Signature - ACPI signature of needed * table
* Instance - Which instance (for SSDTs)
* out_table - Where the pointer to the table is returned *
* RETURN: Status and pointer to table *
* DESCRIPTION: Finds and verifies an ACPI table. *
******************************************************************************/ acpi_status
acpi_get_table(char *signature,
acpi_native_uint instance, struct acpi_table_header **out_table) {
acpi_native_uint i; acpi_native_uint j; acpi_status status;
/* Parameter validation */
if (!signature || !out_table) { return (AE_BAD_PARAMETER); }
/**
* 遍历acpi_gbl_root_table_list表 */
for (i = 0, j = 0; i < acpi_gbl_root_table_list.count; i++) { if (!ACPI_COMPARE_NAME
(&(acpi_gbl_root_table_list.tables[i].signature), signature)) { continue; }
if (++j < instance) { continue; }
status = acpi_tb_verify_table(&acpi_gbl_root_table_list.tables[i]); if (ACPI_SUCCESS(status)) { /* 取得某Table的地址 */
*out_table = acpi_gbl_root_table_list.tables[i].pointer; }
if (!acpi_gbl_permanent_mmap) {
acpi_gbl_root_table_list.tables[i].pointer = NULL; }
return (status); }
return (AE_NOT_FOUND);
正在阅读:
acpi 学习笔记05-21
台州市2012年初级中学实验操作考查试题题目一览表12-23
地球概论作业习题01-17
2019年小学生描写国庆精彩的作文06-13
高中物理复习精讲易错题汇总04-06
DNA探针与基因诊断制剂IPO上市咨询(2014年最新政策+募投可研+细06-28
2020小学英语教师工作计划模板4篇03-20
2011年高三物理第一轮总复习及高中物理易错题归纳总结及答案分析(281页)第9专题_高中物理常见的物理模型208-13
省十一届人大五次会议06-12
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- 笔记
- 学习
- acpi
- 高级工题库汇总
- 9 泉城作业练习
- 应用文写作试题
- 名人八字.
- 福州市南台岛烟台山片区控制性详细规划 - 图文
- 小学五年级数学上册期末应用题天天练大全82
- 论坛
- 第二届佛山市中小学心理健康教育优秀成果评选入围名单
- 风力发电场岗位职责汇编 - 图文
- 2016通信专业监理继教试题及答案
- 2008年、2009年、2010年全国各省市中考数学试题分类汇编之函数与
- GIS基础应用技能考试题
- 土地增值税税率和扣除项目知识点
- 征信知识测试标准化试题
- 深冷制氮的工艺流程说明
- 特岗考试选择题(289道 含答案)
- 牛津释义3000词汇
- 040-双子塔项目底板钢筋工程施工方案 - 图文
- 网店和实体店发展优势比较
- 国民经济和社会发展第十二个五年规划基本思路