PCI 外围组件互连
The PCI Bus 源文本:The PCI Bus 翻译文本:PCI 总线
The PCI (Peripheral Component Interconnect) bus was defined to establish a high performance and low cost local bus that would remain through several generations of products. By combining a transparent upgrade path from 132 MB/s (32-bit at 33 MHz) to 528 MB/s (64-bit at 66 MHz) and both 5 volt and 3.3 volt signalling environments, the PCI bus meets the needs of both low end desktop systems and high-end LAN servers. The PCI bus component and add-in card interface is processor independent, enabling an efficient transition to future processors, as well as use with multiple processor architectures. The disadvantage of the PCI bus is the limited number of electrical loads it can drive. A single PCI bus can drive a maximum of 10 loads. (Remember when counting the number of loads on the bus, a connector counts as one load and the PCI device counts as another, and sometimes two.)
PCI(外围组件互连)总线旨在建立一种高性能且低成本的局部总线,该总线能够贯穿多个产品代。通过提供从 132MB/s(32 位 33MHz)到 528MB/s(64 位 66MHz)的透明升级路径,并兼容 5 伏和 3.3 伏信号环境,PCI 总线满足了低端桌面系统与高端局域网服务器的不同需求。PCI 总线组件及扩展卡接口与处理器无关,便于向未来处理器平滑过渡,并可用于多种处理器架构。然而,PCI 总线的局限在于其驱动电气负载的数量有限,单个 PCI 总线最多可驱动 10 个负载。(计算总线上的负载数时,一个连接器算作一个负载,PCI 设备也算作一个,有时甚至算作两个。)
Configuration Space 配置空间
The PCI specification provides for totally software driven initialization and configuration of each device (or target) on the PCI Bus via a separate Configuration Address Space. All PCI devices, except host bus bridges, are required to provide 256 bytes of configuration registers for this purpose.
PCI 规范通过独立的配置地址空间,实现了对 PCI 总线上每个设备(或目标)完全由软件驱动的初始化和配置。除主机总线桥接器外,所有 PCI 设备均需为此提供 256 字节的配置寄存器。
Configuration read/write cycles are used to access the Configuration Space of each target device. A target is selected during a configuration access when its IDSEL signal is asserted. The IDSEL acts as the classic "chip select" signal. During the address phase of the configuration cycle, the processor can address one of 64 32-bit registers within the configuration space by placing the required register number on address lines 2 through 7 (AD[7..2]) and the byte enable lines.
配置读写周期用于访问每个目标设备的配置空间。在配置访问期间,当目标设备的 IDSEL 信号被激活时,即选定该目标。IDSEL 充当传统的“芯片选择”信号。在配置周期的地址阶段,处理器可以通过将所需的寄存器编号放置在地址线 2 至 7(AD[7..2])和字节使能线上,来寻址配置空间内 64 个 32 位寄存器中的一个。
PCI devices are inherently little-endian, meaning all multiple byte fields have the least significant values at the lower addresses. This requires a big-endian processor, such as a Power PC, to perform the proper byte-swapping of data read from or written to the PCI device, including any accesses to the Configuration Address Space.
PCI 设备本质上采用小端序,意味着所有多字节字段在较低地址处存放最不重要的值。这要求大端序处理器,如 Power PC,在从 PCI 设备读取或写入数据时,包括对配置地址空间的任何访问,执行适当的字节交换。
Systems must provide a mechanism that allows access to the PCI configuration space, as most CPUs do not have any such mechanism. This task is usually performed by the Host to PCI Bridge (Host Bridge). Two distinct mechanisms are defined to allow the software to generate the required configuration accesses. Configuration mechanism #1 is the preferred method, while mechanism #2 is provided for backwards compatibility. Only configuration mechanism #1 will be described here, as it is the only access mechanism that will be used in the future.
系统必须提供一种机制,允许访问 PCI 配置空间,因为大多数 CPU 不具备此类机制。此任务通常由主机到 PCI 桥接器(主机桥)执行。为使软件能够生成所需的配置访问,定义了两种不同的机制。配置机制#1 是首选方法,而机制#2 则是为了向后兼容而提供。此处仅描述配置机制#1,因为它是未来唯一将使用的访问机制。
Configuration Space Access Mechanism #1
配置空间访问机制 #1
Two 32-bit I/O locations are used, the first location (0xCF8
) is named CONFIG_ADDRESS, and the second (0xCFC
) is called CONFIG_DATA. CONFIG_ADDRESS specifies the configuration address that is required to be accesses, while accesses to CONFIG_DATA will actually generate the configuration access and will transfer the data to or from the CONFIG_DATA register.
使用两个 32 位 I/O 位置,第一个位置( 0xCF8
)命名为 CONFIG_ADDRESS,第二个( 0xCFC
)称为 CONFIG_DATA。CONFIG_ADDRESS 指定需要访问的配置地址,而访问 CONFIG_DATA 实际上会生成配置访问,并将数据传输到或从 CONFIG_DATA 寄存器传出。
The CONFIG_ADDRESS is a 32-bit register with the format shown in following figure. Bit 31 is an enable flag for determining when accesses to CONFIG_DATA should be translated to configuration cycles. Bits 23 through 16 allow the configuration software to choose a specific PCI bus in the system. Bits 15 through 11 select the specific device on the PCI Bus. Bits 10 through 8 choose a specific function in a device (if the device supports multiple functions).
CONFIG_ADDRESS 是一个 32 位寄存器,其格式如下图所示。第 31 位是用于确定何时将访问 CONFIG_DATA 转换为配置周期的使能标志。第 23 至 16 位允许配置软件选择系统中的特定 PCI 总线。第 15 至 11 位用于在 PCI 总线上选择特定的设备。第 10 至 8 位用于在设备中选择特定功能(如果设备支持多个功能)。
The least significant byte selects the offset into the 256-byte configuration space available through this method. Since all reads and writes must be both 32-bits and aligned to work on all implementations, the two lowest bits of CONFIG_ADDRESS must always be zero, with the remaining six bits allowing you to choose each of the 64 32-bit words. If you don't need all 32 bits, you'll have to perform the unaligned access in software by aligning the address, followed by masking and shifting the answer.
最低有效字节通过此方法选择进入 256 字节配置空间的偏移量。由于所有读写操作必须在所有实现上均为 32 位且对齐,因此 CONFIG_ADDRESS 的最低两位必须始终为零,剩余的六位允许您选择 64 个 32 位字中的每一个。如果您不需要全部 32 位,则必须在软件中通过对齐地址、随后进行掩码和移位操作来执行未对齐访问。
Bit 31 第 31 位 | Bits 30-24 位 30-24 | Bits 23-16 位 23-16 | Bits 15-11 位 15-11 | Bits 10-8 位 10-8 | Bits 7-0 位 7-0 |
---|---|---|---|---|---|
Enable Bit 启用位 | Reserved 已保留 | Bus Number 公交编号 | Device Number 设备编号 | Function Number 功能编号 | Register Offset1 寄存器偏移 1 |
1 Register Offset has to point to consecutive DWORDs, ie. bits 1:0 are always 0b00 (they are still part of the Register Offset).
1 寄存器偏移量必须指向连续的双字(DWORD),即位 1:0 始终为 0b00(它们仍属于寄存器偏移量的一部分)。
The following code segment illustrates the use of configuration mechanism #1 to read 16-bit fields from configuration space. Note that this segment, the outl(port, value) and inl(port) functions refer to the OUTL and INL Pentium assembly language instructions.
以下代码段展示了使用配置机制#1 从配置空间读取 16 位字段的方法。请注意,此段代码中的 outl(port, value)和 inl(port)函数对应于 Pentium 汇编语言中的 OUTL 和 INL 指令。
uint16_t pciConfigReadWord(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { uint32_t address; uint32_t lbus = (uint32_t)bus; uint32_t lslot = (uint32_t)slot; uint32_t lfunc = (uint32_t)func; uint16_t tmp = 0; // Create configuration address as per Figure 1 address = (uint32_t)((lbus << 16) | (lslot << 11) | (lfunc << 8) | (offset & 0xFC) | ((uint32_t)0x80000000)); // Write out the address outl(0xCF8, address); // Read in the data // (offset & 2) * 8) = 0 will choose the first word of the 32-bit register tmp = (uint16_t)((inl(0xCFC) >> ((offset & 2) * 8)) & 0xFFFF); return tmp; }
When a configuration access attempts to select a device that does not exist, the host bridge will complete the access without error, dropping all data on writes and returning all ones on reads. The following code segment illustrates the read of a non-existent device.
当配置访问尝试选择一个不存在的设备时,主机桥将无错误地完成访问,写入时丢弃所有数据,读取时返回全 1。以下代码段演示了对不存在设备的读取操作。
uint16_t pciCheckVendor(uint8_t bus, uint8_t slot) { uint16_t vendor, device; /* Try and read the first configuration register. Since there are no * vendors that == 0xFFFF, it must be a non-existent device. */ if ((vendor = pciConfigReadWord(bus, slot, 0, 0)) != 0xFFFF) { device = pciConfigReadWord(bus, slot, 0, 2); . . . } return (vendor); }
Configuration Space Access Mechanism #2
配置空间访问机制 #2
This configuration space access mechanism was deprecated in PCI version 2.0. This means it's only likely to exist on hardware from around 1992 (when PCI 1.0 was introduced) to 1993 (when PCI 2.0 was introduced), which limits it to 80486 and early Pentium motherboards.
此配置空间访问机制在 PCI 版本 2.0 中已被弃用。这意味着它仅可能存在于 1992 年(PCI 1.0 引入时)至 1993 年(PCI 2.0 引入时)期间的硬件上,因此局限于 80486 及早期奔腾主板。
For access mechanism #2, the IO port at 0xCF8
is an 8-bit port and is used to enable/disable the access mechanism and set the function number. It has the following format:
对于访问机制#2,位于 0xCF8
的 IO 端口是一个 8 位端口,用于启用/禁用访问机制并设置功能号。其格式如下:
Bits 7-4 位 7-4 | Bits 3-1 位 3-1 | Bit 0 第 0 位 |
---|---|---|
Key (0 = access mechanism disabled, non-zero = access mechanism enabled)
关键(0 = 访问机制禁用,非零 = 访问机制启用) |
Function number 功能编号 | Special cycle enabled if set
若设置则启用特殊循环 |
The IO port at 0xCFA
(the "Forwarding Register") is also an 8-bit port, and is used to set the bus number for subsequent PCI configuration space accesses.
0xCFA
处的 IO 端口(即“转发寄存器”)同样是一个 8 位端口,用于设定后续 PCI 配置空间访问的总线号。
Once the access mechanism has been enabled; accesses to IO ports 0xC000
to 0xCFFF
are used to access PCI configuration space. The IO port number has the following format:
一旦访问机制被启用,对 IO 端口 0xC000
至 0xCFFF
的访问将用于访问 PCI 配置空间。IO 端口号具有以下格式:
Bits 15-12 位 15-12 | Bits 11-8 位 11-8 | Bits 7-2 位 7-2 | Bits 1-0 位 1-0 |
---|---|---|---|
Must be 1100b 必须是 1100b | Device number 设备编号 | Register index 寄存器索引 | Must be zero 必须为零 |
Note that this limits the system to 16 devices per PCI bus.
请注意,这限制了系统每条 PCI 总线最多可连接 16 个设备。
Memory Mapped PCI Configuration Space Access
内存映射 PCI 配置空间访问
PCI Express introduced a new way to access PCI configuration space, where it's simply memory mapped and no IO ports are used. This access mechanism is described in PCI Express.
PCI Express 引入了一种访问 PCI 配置空间的新方式,其中配置空间被简单地内存映射,无需使用 IO 端口。这种访问机制在 PCI Express 规范中有详细描述。
Note that systems that do provide the memory mapped access mechanism are also required to support PCI access mechanism #1 for backwards compatibility.
请注意,提供内存映射访问机制的系统也必须支持 PCI 访问机制#1,以确保向后兼容性。
Detecting Configuration Space Access Mechanism/s
检测配置空间访问机制/s
In general there are 4 cases:
通常有四种情况:
- Computer doesn't support PCI (either the computer is too old, or your OS is being run at some time in the future after PCI has been superseded)
计算机不支持 PCI(要么是计算机太旧,要么是您的操作系统在未来某个时间点运行,此时 PCI 已被取代) - Computer supports mechanism #2
计算机支持机制#2 - Computer supports mechanism #1 but doesn't support the memory mapped access mechanism
计算机支持机制#1,但不支持内存映射访问机制 - Computer supports both mechanism #1 and the memory mapped access mechanism
计算机同时支持机制#1 和内存映射访问机制
For BIOS systems, int 0x1A, AX=0xB101
will tell you if the system uses mechanism #1 or mechanism #2. If this function doesn't exist you can't be sure if the computer supports PCI or not. If it says mechanism #1 is supported you won't know if the memory mapped access mechanism is also supported or not.
对于 BIOS 系统, int 0x1A, AX=0xB101
将告知您系统采用机制#1 还是机制#2。如果此功能不存在,则无法确定计算机是否支持 PCI。若显示支持机制#1,则无法得知是否也支持内存映射访问机制。
For UEFI systems, it's extremely safe to assume that mechanism #2 is not supported; and you can test to see if the computer supports PCI or not by checking to see if the "PCI bus support" protocol exists. If PCI is supported, there's no easy way to determine if (e.g.) the computer supports mechanism #1 or not.
对于 UEFI 系统,可以非常安全地假设不支持机制#2;您可以通过检查是否存在“PCI 总线支持”协议来测试计算机是否支持 PCI。如果支持 PCI,则没有简单的方法来确定计算机是否支持机制#1(例如)。
For both BIOS and UEFI systems, you can check the ACPI tables to determine if the memory mapped access mechanism is supported.
对于 BIOS 和 UEFI 系统,您都可以检查 ACPI 表来确定是否支持内存映射访问机制。
This leaves a few cases uncovered (e.g. where you don't know if whether mechanism #1 or #2 are supported despite trying all of the above). For these cases the only option left is manual probing. This means 2 specific tests - whether mechanism #1 is supported, and if not whether mechanism #2 is supported. Please note that manual probing has risks; in that if there is no PCI (e.g. the system only has ISA) the IO port accesses might cause undefined behaviour (especially on systems where the ISA bus ignores highest 6 bits of the IO port address, where accessing IO port 0xCF8
is the same as accessing IO port 0xF8
).
这导致少数情况未被覆盖(例如,尽管尝试了上述所有方法,仍无法确定是否支持机制#1 或#2)。对于这些情况,唯一的选择是手动探测。这意味着要进行两项具体测试——检查是否支持机制#1,若不支持,则检查是否支持机制#2。请注意,手动探测存在风险;如果系统不支持 PCI(例如,系统仅有 ISA 总线),则 IO 端口访问可能导致未定义行为(特别是在 ISA 总线忽略 IO 端口地址最高 6 位的系统中,访问 IO 端口 0xCF8
等同于访问 IO 端口 0xF8
)。
PCI Device Structure PCI 设备结构
The PCI Specification defines the organization of the 256-byte Configuration Space registers and imposes a specific template for the space. Figures 2 & 3 show the layout of the 256-byte Configuration space. All PCI compliant devices must support the Vendor ID, Device ID, Command and Status, Revision ID, Class Code and Header Type fields. Implementation of the other registers is optional, depending upon the devices functionality.
PCI 规范定义了 256 字节配置空间寄存器的组织方式,并为该空间规定了特定的模板。图 2 和图 3 展示了 256 字节配置空间的布局。所有符合 PCI 标准的设备都必须支持供应商 ID、设备 ID、命令和状态、修订 ID、类代码以及头类型字段。其他寄存器的实现则根据设备功能可选。
Common Header Fields 常见头部字段
The following field descriptions are common to all Header Types:
以下字段描述适用于所有标题类型:
Register 注册 | Offset 偏移量 | Bits 31-24 位 31-24 | Bits 23-16 位 23-16 | Bits 15-8 位 15-8 | Bits 7-0 位 7-0 |
---|---|---|---|---|---|
0x0 | 0x0 | Device ID 设备 ID | Vendor ID 供应商 ID | ||
0x1 | 0x4 0x4 Step 1: Identify the source text as a hexadecimal number. Step 2: Translate the hexadecimal number into Simplified Chinese. Step 3: Output the translated text without any additional text | Status 状态 | Command 命令 | ||
0x2 | 0x8 | Class code 类代码 | Subclass 子类 | Prog IF 程序 IF | Revision ID 修订 ID |
0x3 | 0xC | BIST | Header type 标题类型 | Latency Timer 延迟计时器 | Cache Line Size 缓存行大小 |
... |
- Device ID: Identifies the particular device. Where valid IDs are allocated by the vendor.
设备 ID:标识特定设备。有效 ID 由供应商分配。 - Vendor ID: Identifies the manufacturer of the device. Where valid IDs are allocated by PCI-SIG (the list is here) to ensure uniqueness and
0xFFFF
is an invalid value that will be returned on read accesses to Configuration Space registers of non-existent devices.
供应商 ID:标识设备制造商。有效 ID 由 PCI-SIG 分配(列表见此)以确保唯一性,而0xFFFF
是一个无效值,在读取不存在设备的配置空间寄存器时将返回该值。 - Status: A register used to record status information for PCI bus related events.
状态:用于记录与 PCI 总线相关事件状态信息的寄存器。 - Command: Provides control over a device's ability to generate and respond to PCI cycles. Where the only functionality guaranteed to be supported by all devices is, when a 0 is written to this register, the device is disconnected from the PCI bus for all accesses except Configuration Space access.
命令:提供对设备生成和响应 PCI 周期能力的控制。所有设备保证支持的唯一功能是,当向此寄存器写入 0 时,设备将从 PCI 总线断开,所有访问除外配置空间访问。 - Class Code: A read-only register that specifies the type of function the device performs.
类别代码:一个只读寄存器,用于指定设备执行的功能类型。 - Subclass: A read-only register that specifies the specific function the device performs.
子类:一个只读寄存器,用于指定设备执行的具体功能。 - Prog IF(Programming Interface Byte): A read-only register that specifies a register-level programming interface the device has, if it has any at all.
Prog IF(编程接口字节):一个只读寄存器,用于指定设备是否具有任何寄存器级别的编程接口。 - Revision ID: Specifies a revision identifier for a particular device. Where valid IDs are allocated by the vendor.
修订 ID:指定特定设备的修订标识符,有效 ID 由供应商分配。 - BIST: Represents that status and allows control of a devices BIST (built-in self test).
BIST:表示设备自检(BIST)的状态并允许对其进行控制。 - Header Type: Identifies the layout of the rest of the header beginning at byte
0x10
of the header. If bit 7 of this register is set, the device has multiple functions; otherwise, it is a single function device. Types:
头部类型:标识从头部字节0x10
开始其余头部的布局。如果此寄存器的第 7 位被设置,则设备具有多种功能;否则,它是一个单功能设备。类型:-
0x0
: a general device
0x0
: 通用设备 -
0x1
: a PCI-to-PCI bridge
0x1
: 一个 PCI 到 PCI 的桥接器 -
0x2
: a PCI-to-CardBus bridge.
0x2
:一种 PCI 到 CardBus 的桥接器。
-
- Latency Timer: Specifies the latency timer in units of PCI bus clocks.
延迟计时器:以 PCI 总线时钟为单位指定延迟计时器。 - Cache Line Size: Specifies the system cache line size in 32-bit units. A device can limit the number of cacheline sizes it can support, if a unsupported value is written to this field, the device will behave as if a value of 0 was written.
缓存行大小:以 32 位单位指定系统缓存行大小。设备可以限制其支持的缓存行大小数量,如果向此字段写入不支持的值,设备将表现得如同写入了 0 值。
Remember that the PCI devices follow little ENDIAN ordering. The lower addresses contain the least significant portions of the field. Software to manipulate this structure must take particular care that the endian-ordering follows the PCI devices, not the CPUs.
请记住,PCI 设备遵循小端字节序排列。较低的地址包含字段的最不重要部分。操作此结构的软件必须特别注意,字节序排列应遵循 PCI 设备,而非 CPU。
Command Register 命令寄存器
Here is the layout of the Command register:
这里是命令寄存器的布局:
Bits 11-15 位 11-15 | Bit 10 第 10 位 | Bit 9 第 9 位 | Bit 8 第 8 位 | Bit 7 第 7 位 | Bit 6 位 6 | Bit 5 位 5 | Bit 4 第 4 位 | Bit 3 第 3 位 | Bit 2 第 2 位 | Bit 1 位 1 | Bit 0 第 0 位 |
---|---|---|---|---|---|---|---|---|---|---|---|
Reserved 已保留 | Interrupt Disable 中断禁用 | Fast Back-to-Back Enable
快速连续使能 |
SERR# Enable SERR# 启用 | Reserved 已保留 | Parity Error Response 奇偶校验错误响应 | VGA Palette Snoop VGA 调色板窥探 | Memory Write and Invalidate Enable
内存写入与无效化使能 |
Special Cycles 特殊周期 | Bus Master 总线主控器 | Memory Space 内存空间 | I/O Space 输入/输出空间 |
RW | RO | RW | RO | RW | RO | RO | RO | RW | RW | RW |
- Interrupt Disable - If set to 1 the assertion of the devices INTx# signal is disabled; otherwise, assertion of the signal is enabled.
中断禁用 - 若设置为 1,则设备的 INTx#信号断言被禁用;否则,信号断言被启用。 - Fast Back-Back Enable - If set to 1 indicates a device is allowed to generate fast back-to-back transactions; otherwise, fast back-to-back transactions are only allowed to the same agent.
快速连续启用 - 若设置为 1,表示允许设备生成快速连续交易;否则,快速连续交易仅允许针对同一代理。 - SERR# Enable - If set to 1 the SERR# driver is enabled; otherwise, the driver is disabled.
SERR# 启用 - 若设置为 1,则 SERR#驱动程序启用;否则,驱动程序禁用。 - Bit 7 - As of revision 3.0 of the PCI local bus specification this bit is hardwired to 0. In earlier versions of the specification this bit was used by devices and may have been hardwired to 0, 1, or implemented as a read/write bit.
第 7 位 - 自 PCI 本地总线规范 3.0 版起,此位被硬编码为 0。在早期版本的规范中,此位由设备使用,可能被硬编码为 0、1,或实现为可读写位。 - Parity Error Response - If set to 1 the device will take its normal action when a parity error is detected; otherwise, when an error is detected, the device will set bit 15 of the Status register (Detected Parity Error Status Bit), but will not assert the PERR# (Parity Error) pin and will continue operation as normal.
奇偶错误响应 - 若设置为 1,设备在检测到奇偶错误时将采取正常动作;否则,当检测到错误时,设备将设置状态寄存器第 15 位(检测到的奇偶错误状态位),但不激活 PERR#(奇偶错误)引脚,并继续正常操作。 - VGA Palette Snoop - If set to 1 the device does not respond to palette register writes and will snoop the data; otherwise, the device will trate palette write accesses like all other accesses.
VGA 调色板窥探 - 若设置为 1,设备不会响应调色板寄存器写入操作,而是会窥探数据;否则,设备将像对待其他访问一样处理调色板写入访问。 - Memory Write and Invalidate Enable - If set to 1 the device can generate the Memory Write and Invalidate command; otherwise, the Memory Write command must be used.
内存写入与无效化使能 - 若设置为 1,设备可生成内存写入与无效化命令;否则,必须使用内存写入命令。 - Special Cycles - If set to 1 the device can monitor Special Cycle operations; otherwise, the device will ignore them.
特殊循环 - 若设置为 1,设备可监控特殊循环操作;否则,设备将忽略这些操作。 - Bus Master - If set to 1 the device can behave as a bus master; otherwise, the device can not generate PCI accesses.
总线主控 - 若设置为 1,设备可作为总线主控;否则,设备无法发起 PCI 访问。 - Memory Space - If set to 1 the device can respond to Memory Space accesses; otherwise, the device's response is disabled.
内存空间 - 若设置为 1,设备可响应内存空间访问;否则,设备响应功能将被禁用。 - I/O Space - If set to 1 the device can respond to I/O Space accesses; otherwise, the device's response is disabled.
I/O 空间 - 若设置为 1,设备可响应 I/O 空间访问;否则,设备的响应功能将被禁用。
If the kernel configures the BARs of the devices, the kernel also have to enable bits 0 and 1 for it to activate.
若内核配置了设备的基地址寄存器(BARs),则还需启用位 0 和位 1 以激活设备。
Status Register 状态寄存器
Here is the layout of the Status register:
这里是状态寄存器的布局:
Bit 15 第 15 位 | Bit 14 第 14 位 | Bit 13 第 13 位 | Bit 12 第 12 位 | Bit 11 第 11 位 | Bits 9-10 位 9-10 | Bit 8 第 8 位 | Bit 7 第 7 位 | Bit 6 第 6 位 | Bit 5 第 5 位 | Bit 4 第 4 位 | Bit 3 第 3 位 | Bits 0-2 位 0-2 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Detected Parity Error 检测到奇偶校验错误 | Signaled System Error 信号系统错误 | Received Master Abort 收到主中止 | Received Target Abort 收到目标中止 | Signaled Target Abort 信号目标中止 | DEVSEL Timing 设备选择时序 | Master Data Parity Error
主数据奇偶校验错误 |
Fast Back-to-Back Capable
快速连续处理能力 |
Reserved 已保留 | 66 MHz Capable 66 MHz 兼容 | Capabilities List 功能列表 | Interrupt Status 中断状态 | Reserved 已保留 |
RW1C | RW1C | RW1C | RW1C | RW1C | RO | RW1C | RO | RO | RO | RO | RO |
- Detected Parity Error - This bit will be set to 1 whenever the device detects a parity error, even if parity error handling is disabled.
检测到奇偶校验错误 - 每当设备检测到奇偶校验错误时,无论奇偶校验错误处理是否被禁用,此位都将被设置为 1。 - Signalled System Error - This bit will be set to 1 whenever the device asserts SERR#.
信号系统错误 - 每当设备断言 SERR#时,此位将设置为 1。 - Received Master Abort - This bit will be set to 1, by a master device, whenever its transaction (except for Special Cycle transactions) is terminated with Master-Abort.
收到主设备中止 - 每当主设备的事务(特殊周期事务除外)因主设备中止而终止时,此位将被设置为 1。 - Received Target Abort - This bit will be set to 1, by a master device, whenever its transaction is terminated with Target-Abort.
收到目标中止 - 此位将由主设备设置为 1,每当其事务因目标中止而终止时。 - Signalled Target Abort - This bit will be set to 1 whenever a target device terminates a transaction with Target-Abort.
信号化目标中止 - 每当目标设备以目标中止方式终止交易时,此位将被设置为 1。 - DEVSEL Timing - Read only bits that represent the slowest time that a device will assert DEVSEL# for any bus command except Configuration Space read and writes. Where a value of
0x0
represents fast timing, a value of0x1
represents medium timing, and a value of0x2
represents slow timing.
DEVSEL 时序 - 只读位,表示设备在除配置空间读写外的任何总线命令下,最慢的 DEVSEL# 信号确认时间。其中,0x0
值代表快速时序,0x1
值代表中速时序,0x2
值代表慢速时序。 - Master Data Parity Error - This bit is only set when the following conditions are met. The bus agent asserted PERR# on a read or observed an assertion of PERR# on a write, the agent setting the bit acted as the bus master for the operation in which the error occurred, and bit 6 of the Command register (Parity Error Response bit) is set to 1.
主数据奇偶校验错误 - 仅当满足以下条件时,此位才会被设置。总线代理在读取时断言 PERR#或在写入时观察到 PERR#的断言,设置该位的代理作为发生错误操作的总线主控,并且命令寄存器(奇偶校验错误响应位)的第 6 位设置为 1。 - Fast Back-to-Back Capable - If set to 1 the device can accept fast back-to-back transactions that are not from the same agent; otherwise, transactions can only be accepted from the same agent.
快速连续处理能力 - 若设置为 1,设备可接受来自不同代理的快速连续交易;否则,仅能接受来自同一代理的交易。 - Bit 6 - As of revision 3.0 of the PCI Local Bus specification this bit is reserved. In revision 2.1 of the specification this bit was used to indicate whether or not a device supported User Definable Features.
第 6 位 - 自 PCI 局部总线规范 3.0 修订版起,此位被保留。在 2.1 修订版中,此位用于指示设备是否支持用户自定义特性。 - 66 MHz Capable - If set to 1 the device is capable of running at 66 MHz; otherwise, the device runs at 33 MHz.
66 MHz 兼容 - 若设置为 1,设备可运行于 66 MHz;否则,设备运行于 33 MHz。 - Capabilities List - If set to 1 the device implements the pointer for a New Capabilities Linked list at offset
0x34
; otherwise, the linked list is not available.
功能列表 - 若设置为 1,设备将在偏移量0x34
处实现新功能链接列表的指针;否则,链接列表不可用。 - Interrupt Status - Represents the state of the device's INTx# signal. If set to 1 and bit 10 of the Command register (Interrupt Disable bit) is set to 0 the signal will be asserted; otherwise, the signal will be ignored.
中断状态 - 表示设备的 INTx#信号状态。如果设置为 1 且命令寄存器(中断禁用位)的第 10 位设置为 0,则信号将被断言;否则,信号将被忽略。
Header Type 0x0 报头类型 0x0
This table is applicable if the Header Type is 0x0
. (Figure 2)
该表适用于标题类型为 0x0
的情况。(图 2)
Register 注册 | Offset 偏移量 | Bits 31-24 位 31-24 | Bits 23-16 位 23-16 | Bits 15-8 位 15-8 | Bits 7-0 位 7-0 |
---|---|---|---|---|---|
0x0 | 0x0 | Device ID 设备 ID | Vendor ID 供应商 ID | ||
0x1 | 0x4 | Status 状态 | Command 命令 | ||
0x2 | 0x8 0x8 Translated Text: 0x8 | Class code 类代码 | Subclass 子类 | Prog IF 程序 IF | Revision ID 修订 ID |
0x3 | 0xC | BIST | Header type 标题类型 | Latency Timer 延迟计时器 | Cache Line Size 缓存行大小 |
0x4 | 0x10 | Base address #0 (BAR0) 基地址 #0 (BAR0) | |||
0x5 | 0x14 | Base address #1 (BAR1) 基地址 #1 (BAR1) | |||
0x6 | 0x18 | Base address #2 (BAR2) 基地址 #2 (BAR2) | |||
0x7 | 0x1C | Base address #3 (BAR3) 基地址 #3 (BAR3) | |||
0x8 | 0x20 | Base address #4 (BAR4) 基地址 #4 (BAR4) | |||
0x9 | 0x24 | Base address #5 (BAR5) 基地址 #5 (BAR5) | |||
0xA | 0x28 | Cardbus CIS Pointer Cardbus CIS 指针 | |||
0xB | 0x2C | Subsystem ID 子系统 ID | Subsystem Vendor ID 子系统供应商 ID | ||
0xC | 0x30 | Expansion ROM base address
扩展 ROM 基地址 | |||
0xD | 0x34 | Reserved 已保留 | Capabilities Pointer 功能指针 | ||
0xE | 0x38 | Reserved 已保留 | |||
0xF 十六进制数 0xF | 0x3C | Max latency 最大延迟 | Min Grant 最小授权 | Interrupt PIN 中断 PIN 码 | Interrupt Line 中断线 |
The following field descriptions apply if the Header Type is 0x0
:
以下字段描述适用于标题类型为 0x0
时:
- CardBus CIS Pointer: Points to the Card Information Structure and is used by devices that share silicon between CardBus and PCI.
CardBus CIS 指针:指向卡信息结构,供共享 CardBus 和 PCI 之间硅片的设备使用。
- Interrupt Line: Specifies which input of the system interrupt controllers the device's interrupt pin is connected to and is implemented by any device that makes use of an interrupt pin. For the x86 architecture this register corresponds to the PIC IRQ numbers 0-15 (and not I/O APIC IRQ numbers) and a value of
0xFF
defines no connection.
中断线:指定设备的硬件中断引脚连接到系统中断控制器的哪个输入,任何使用中断引脚的设备都会实现这一点。对于 x86 架构,此寄存器对应于 PIC IRQ 编号 0-15(而非 I/O APIC IRQ 编号),值为0xFF
表示无连接。
- Interrupt Pin: Specifies which interrupt pin the device uses. Where a value of
0x1
is INTA#,0x2
is INTB#,0x3
is INTC#,0x4
is INTD#, and0x0
means the device does not use an interrupt pin.
中断引脚:指定设备使用哪个中断引脚。其中,0x1
表示 INTA#,0x2
表示 INTB#,0x3
表示 INTC#,0x4
表示 INTD#,而0x0
表示设备不使用中断引脚。
- Max Latency: A read-only register that specifies how often the device needs access to the PCI bus (in 1/4 microsecond units).
最大延迟:一个只读寄存器,指定设备需要访问 PCI 总线的频率(以 1/4 微秒为单位)。
- Min Grant: A read-only register that specifies the burst period length, in 1/4 microsecond units, that the device needs (assuming a 33 MHz clock rate).
Min Grant:一个只读寄存器,以 1/4 微秒为单位指定设备所需的突发周期长度(假设时钟频率为 33MHz)。
- Capabilities Pointer: Points (i.e. an offset into this function's configuration space) to a linked list of new capabilities implemented by the device. Used if bit 4 of the status register (Capabilities List bit) is set to 1. The bottom two bits are reserved and should be masked before the Pointer is used to access the Configuration Space.
能力指针:指向(即此函数配置空间的偏移量)设备实现的新能力链表。当状态寄存器(能力列表位)的第 4 位设置为 1 时使用。最低两位保留,使用指针访问配置空间前应先屏蔽这两位。
Header Type 0x1 (PCI-to-PCI bridge)
头部类型 0x1(PCI 到 PCI 桥接器)
This table is applicable if the Header Type is 0x1
(PCI-to-PCI bridge) (Figure 3)
此表适用于当头部类型为 0x1
(PCI-至-PCI 桥接器)(图 3)
Register 注册 | Offset 偏移量 | Bits 31-24 位 31-24 | Bits 23-16 位 23-16 | Bits 15-8 位 15-8 | Bits 7-0 位 7-0 |
---|---|---|---|---|---|
0x0 | 0x0 | Device ID 设备 ID | Vendor ID 供应商 ID | ||
0x1 | 0x4 | Status 状态 | Command 命令 | ||
0x2 | 0x8 | Class code 类代码 | Subclass 子类 | Prog IF 程序 IF | Revision ID 修订 ID |
0x3 | 0xC | BIST | Header type 标题类型 | Latency Timer 延迟计时器 | Cache Line Size 缓存行大小 |
0x4 0x4 Here is the translation: 0x4 | 0x10 | Base address #0 (BAR0) 基地址 #0 (BAR0) | |||
0x5 | 0x14 | Base address #1 (BAR1) 基地址 #1 (BAR1) | |||
0x6 | 0x18 | Secondary Latency Timer 次级延迟计时器 | Subordinate Bus Number 从属总线编号 | Secondary Bus Number 辅助总线编号 | Primary Bus Number 主总线编号 |
0x7 | 0x1C | Secondary Status 次要状态 | I/O Limit 输入/输出限制 | I/O Base 输入/输出基地址 | |
0x8 | 0x20 | Memory Limit 内存限制 | Memory Base 内存库 | ||
0x9 | 0x24 | Prefetchable Memory Limit
预取内存限制 |
Prefetchable Memory Base 预取内存基址 | ||
0xA | 0x28 | Prefetchable Base Upper 32 Bits
可预取基址高 32 位 | |||
0xB | 0x2C | Prefetchable Limit Upper 32 Bits
预取上限高 32 位 | |||
0xC | 0x30 | I/O Limit Upper 16 Bits
输入/输出限制高 16 位 |
I/O Base Upper 16 Bits
输入/输出基址高 16 位 | ||
0xD | 0x34 | Reserved 已保留 | Capability Pointer 能力指针 | ||
0xE | 0x38 | Expansion ROM base address
扩展 ROM 基地址 | |||
0xF 十六进制数:0xF | 0x3C | Bridge Control 桥梁控制 | Interrupt PIN 中断个人识别码 | Interrupt Line 中断线 |
Header Type Register 头部类型寄存器
Here is the layout of the Header Type register:
这里是头部类型寄存器的布局:
Bit 7 第 7 位 | Bits 6-0 位 6-0 |
---|---|
MF | Header Type 头部类型 |
- MF - If MF = 1 Then this device has multiple functions.
多功 - 若 MF = 1,则此设备具备多功能。 - Header Type -
0x0
Standard Header -0x1
PCI-to-PCI Bridge -0x2
CardBus Bridge
头部类型 -0x0
标准头部 -0x1
PCI 至 PCI 桥接器 -0x2
CardBus 桥接器
BIST Register 内置自检寄存器
Here is the layout of the BIST register:
这里是 BIST 寄存器的布局:
Bit 7 第 7 位 | Bit 6 第 6 位 | Bits 4-5 位 4-5 | Bits 0-3 位 0-3 |
---|---|---|---|
BIST Capable 内置自检功能 | Start BIST 启动 BIST | Reserved 已保留 | Completion Code 完成码 |
- BIST Capable - Will return 1 the device supports BIST.
BIST 支持 - 若设备支持 BIST,则返回 1。 - Start BIST - When set to 1 the BIST is invoked. This bit is reset when BIST completes. If BIST does not complete after 2 seconds the device should be failed by system software.
启动 BIST - 当设置为 1 时,将调用 BIST。此位在 BIST 完成后重置。如果 BIST 在 2 秒后仍未完成,系统软件应判定设备故障。 - Completion Code - Will return 0, after BIST execution, if the test completed successfully.
完成代码 - 在 BIST 执行后,如果测试成功完成,将返回 0。
Header Type 0x2 (PCI-to-CardBus bridge)
头部类型 0x2(PCI 至 CardBus 桥接器)
This table is applicable if the Header Type is 0x2
(PCI-to-CardBus bridge)
此表适用于当头部类型为 0x2
(PCI 到 CardBus 桥接器)的情况
Register 注册 | Offset 偏移 | Bits 31-24 位 31-24 | Bits 23-16 位 23-16 | Bits 15-8 位 15-8 | Bits 7-0 位 7-0 |
---|---|---|---|---|---|
0x0 | 0x0 | Device ID 设备 ID | Vendor ID 供应商 ID | ||
0x1 | 0x4 | Status 状态 | Command 命令 | ||
0x2 | 0x8 | Class code 类代码 | Subclass 子类 | Prog IF 程序 IF | Revision ID 修订 ID |
0x3 | 0xC | BIST | Header type 标题类型 | Latency Timer 延迟计时器 | Cache Line Size 缓存行大小 |
0x4 | 0x10 | CardBus Socket/ExCa base address
CardBus 插槽/ExCa 基地址 | |||
0x5 | 0x14 | Secondary status 次要地位 | Reserved 已保留 | Offset of capabilities list
能力列表的偏移量 | |
0x6 | 0x18 | CardBus latency timer CardBus 延迟定时器 | Subordinate bus number 从属总线编号 | CardBus bus number CardBus 总线编号 | PCI bus number PCI 总线编号 |
0x7 | 0x1C | Memory Base Address 0 内存基地址 0 | |||
0x8 | 0x20 | Memory Limit 0 内存限制 0 | |||
0x9 | 0x24 | Memory Base Address 1 内存基地址 1 | |||
0xA | 0x28 | Memory Limit 1 内存限制 1 | |||
0xB | 0x2C | I/O Base Address 0 输入/输出基地址 0 | |||
0xC | 0x30 | I/O Limit 0 输入/输出限制 0 | |||
0xD | 0x34 | I/O Base Address 1 输入/输出基地址 1 | |||
0xE | 0x38 | I/O Limit 1 输入/输出限制 1 | |||
0xF 十六进制数 0xF | 0x3C | Bridge Control 桥梁控制 | Interrupt PIN 中断个人识别码 | Interrupt Line 中断线 | |
0x10 | 0x40 | Subsystem Vendor ID 子系统供应商 ID | Subsystem Device ID 子系统设备标识符 | ||
0x11 | 0x44 | 16-bit PC Card legacy mode base address
16 位 PC 卡传统模式基地址 |
Base Address Registers 基地址寄存器
Base Address Registers (or BARs) can be used to hold memory addresses used by the device, or offsets for port addresses. Typically, memory address BARs need to be located in physical ram while I/O space BARs can reside at any memory address (even beyond physical memory). To distinguish between them, you can check the value of the lowest bit. The following tables describe the two types of BARs:
基地址寄存器(或 BARs)可用于保存设备使用的内存地址或端口地址的偏移量。通常,内存地址 BARs 需要位于物理 RAM 中,而 I/O 空间 BARs 可以位于任何内存地址(甚至超出物理内存范围)。为区分它们,可检查最低位值。以下表格描述了两种类型的 BARs:
Bits 31-4 位 31-4 | Bit 3 第 3 位 | Bits 2-1 位 2-1 | Bit 0 第 0 位 |
---|---|---|---|
16-Byte Aligned Base Address
16 字节对齐基地址 |
Prefetchable 可预取的 | Type 类型 | Always 0 始终为 0 |
Bits 31-2 位 31-2 | Bit 1 位 1 | Bit 0 第 0 位 |
---|---|---|
4-Byte Aligned Base Address
四字节对齐基地址 |
Reserved 已保留 | Always 1 始终 1 |
The Type field of the Memory Space BAR Layout specifies the size of the base register and where in memory it can be mapped. If it has a value of 0x0
then the base register is 32-bits wide and can be mapped anywhere in the 32-bit Memory Space. A value of 0x2
means the base register is 64-bits wide and can be mapped anywhere in the 64-bit Memory Space (A 64-bit base address register consumes 2 of the base address registers available). A value of 0x1
is reserved as of revision 3.0 of the PCI Local Bus Specification. In earlier versions it was used to support memory space below 1MB (16-bit wide base register that can be mapped anywhere in the 16-bit Memory Space).
Memory 空间 BAR 布局中的 Type 字段指定了基址寄存器的大小及其在内存中的映射位置。若其值为 0x0
,则基址寄存器为 32 位宽,可映射至 32 位内存空间的任意位置。值为 0x2
表示基址寄存器为 64 位宽,可映射至 64 位内存空间的任意位置(64 位基地址寄存器占用两个可用基地址寄存器)。修订版 3.0 的 PCI 本地总线规范中,值 0x1
被保留。在早期版本中,它用于支持低于 1MB 的内存空间(16 位宽的基址寄存器,可映射至 16 位内存空间的任意位置)。
When a base address register is marked as Prefetchable, it means that the region does not have read side effects (reading from that memory range doesn't change any state), and it is allowed for the CPU to cache loads from that memory region and read it in bursts (typically cache line sized). Hardware is also allowed to merge repeated stores to the same address into one store of the latest value. If you are using paging and want maximum performance, you should map prefetchable MMIO regions as WT (write-through) instead of UC (uncacheable). On x86, frame buffers are the exception, they should be almost always be mapped WC (write-combining).
当基地址寄存器被标记为可预取时,意味着该区域不存在读取副作用(从该内存范围读取不会改变任何状态),并允许 CPU 对该内存区域进行缓存加载并以突发方式读取(通常为缓存行大小)。硬件还可以将重复存储到同一地址的操作合并为最新值的一次存储。若使用分页并追求最高性能,应将可预取的 MMIO 区域映射为 WT(直写式)而非 UC(不可缓存)。在 x86 架构中,帧缓冲区为例外,它们几乎总是应被映射为 WC(写组合)。
Address and size of the BAR
基地址和 BAR 大小
When you want to retrieve the actual base address of a BAR, be sure to mask the lower bits. For 16-bit Memory Space BARs, you calculate (BAR[x] & 0xFFF0)
. For 32-bit Memory Space BARs, you calculate (BAR[x] & 0xFFFFFFF0)
. For 64-bit Memory Space BARs, you calculate ((BAR[x] & 0xFFFFFFF0) + ((BAR[x + 1] & 0xFFFFFFFF) << 32))
For I/O Space BARs, you calculate (BAR[x] & 0xFFFFFFFC)
.
当您需要获取基地址寄存器(BAR)的实际基地址时,务必屏蔽低位。对于 16 位内存空间 BAR,计算方式为 (BAR[x] & 0xFFF0)
。对于 32 位内存空间 BAR,计算方式为 (BAR[x] & 0xFFFFFFF0)
。对于 64 位内存空间 BAR,计算方式为 ((BAR[x] & 0xFFFFFFF0) + ((BAR[x + 1] & 0xFFFFFFFF) << 32))
。对于 I/O 空间 BAR,计算方式为 (BAR[x] & 0xFFFFFFFC)
。
Before attempting to read the information about the BAR, make sure to disable both I/O and memory decode in the command byte. You can restore the original value after completing the BAR info read. This is needed as some devices are known to decode the write of all ones to the register as an (unintended) access.
在尝试读取 BAR 信息之前,请确保在命令字节中禁用 I/O 和内存解码。读取 BAR 信息后,您可以恢复原始值。这是因为某些设备已知将向寄存器写入全 1 的操作用作(非预期的)访问。
To determine the amount of address space needed by a PCI device, you must save the original value of the BAR, write a value of all 1's to the register, then read it back. The amount of memory can then be determined by masking the information bits, performing a bitwise NOT ('~' in C), and incrementing the value by 1. The original value of the BAR should then be restored. The BAR register is naturally aligned and as such you can only modify the bits that are set. For example, if a device utilizes 16 MB it will have BAR0 filled with 0xFF000000 (0x1000000 after decoding) and you can only modify the upper 8-bits. [1]
要确定 PCI 设备所需的地址空间大小,必须先保存基地址寄存器(BAR)的原始值,向该寄存器写入全 1 的值,然后读回。通过屏蔽信息位,执行按位取反(C 语言中的'~'),并将结果加 1,即可计算出所需内存量。之后应恢复 BAR 的原始值。BAR 寄存器自然对齐,因此只能修改已设置的位。例如,若设备使用 16MB 空间,BAR0 将填充为 0xFF000000(解码后为 0x1000000),此时仅能修改高 8 位。
Class Codes 类别代码
The Class Code, Subclass, and Prog IF registers are used to identify the device's type, the device's function, and the device's register-level programming interface, respectively.
类代码、子类和程序接口寄存器分别用于标识设备的类型、设备的功能以及设备的寄存器级编程接口。
The following table details most of the known device types and functions:
下表详细列出了大多数已知设备类型及其功能:
Class Code 类别代码 | Subclass 子类 | Prog IF 程序 IF |
---|---|---|
0x0 - Unclassified 0x0 - 未分类 | 0x0 - Non-VGA-Compatible Unclassified Device 0x0 - 非 VGA 兼容未分类设备 |
-- |
0x1 - VGA-Compatible Unclassified Device 0x1 - 兼容 VGA 的未分类设备 |
-- | |
0x1 - Mass Storage Controller
0x1 - 大容量存储控制器 |
0x0 - SCSI Bus Controller 0x0 - SCSI 总线控制器 |
-- |
0x1 - IDE Controller
0x1 - IDE 控制器 |
0x0 - ISA Compatibility mode-only controller
0x0 - 仅支持 ISA 兼容模式的控制器 | |
0x5 - PCI native mode-only controller
0x5 - 仅支持 PCI 原生模式的控制器 | ||
0xA - ISA Compatibility mode controller, supports both channels switched to PCI native mode
0xA - ISA 兼容模式控制器,支持两个通道切换至 PCI 原生模式 | ||
0xF - PCI native mode controller, supports both channels switched to ISA compatibility mode
0xF - PCI 原生模式控制器,支持两个通道切换至 ISA 兼容模式 | ||
0x80 - ISA Compatibility mode-only controller, supports bus mastering
0x80 - 仅支持 ISA 兼容模式的控制器,支持总线主控 | ||
0x85 - PCI native mode-only controller, supports bus mastering
0x85 - 仅支持 PCI 原生模式的控制器,支持总线主控 | ||
0x8A - ISA Compatibility mode controller, supports both channels switched to PCI native mode, supports bus mastering
0x8A - ISA 兼容模式控制器,支持双通道切换至 PCI 原生模式,支持总线主控 | ||
0x8F - PCI native mode controller, supports both channels switched to ISA compatibility mode, supports bus mastering
0x8F - PCI 本机模式控制器,支持两个通道切换至 ISA 兼容模式,支持总线主控 | ||
0x2 - Floppy Disk Controller 0x2 - 软盘控制器 |
-- | |
0x3 - IPI Bus Controller 0x3 - IPI 总线控制器 |
-- | |
0x4 - RAID Controller 0x4 - RAID 控制器 |
-- | |
0x5 - ATA Controller
0x5 - ATA 控制器 |
0x20 - Single DMA 0x20 - 单通道 DMA | |
0x30 - Chained DMA 0x30 - 链式 DMA | ||
0x6 - Serial ATA Controller
0x6 - 串行 ATA 控制器 |
0x0 - Vendor Specific Interface
0x0 - 供应商特定接口 | |
0x1 - AHCI 1.0 | ||
0x2 - Serial Storage Bus
0x2 - 串行存储总线 | ||
0x7 - Serial Attached SCSI Controller
0x7 - 串行连接 SCSI 控制器 |
0x0 - SAS | |
0x1 - Serial Storage Bus
0x1 - 串行存储总线 | ||
0x8 - Non-Volatile Memory Controller
0x8 - 非易失性内存控制器 |
0x1 - NVMHCI | |
0x2 - NVM Express | ||
0x80 - Other 0x80 - 其他 | -- | |
0x2 - Network Controller
0x2 - 网络控制器 |
0x0 - Ethernet Controller 0x0 - 以太网控制器 |
-- |
0x1 - Token Ring Controller 0x1 - 令牌环控制器 |
-- | |
0x2 - FDDI Controller 0x2 - FDDI 控制器 |
-- | |
0x3 - ATM Controller 0x3 - ATM 控制器 |
-- | |
0x4 - ISDN Controller 0x4 - ISDN 控制器 |
-- | |
0x5 - WorldFip Controller 0x5 - 世界菲普控制器 |
-- | |
0x6 - PICMG 2.14 Multi Computing Controller 0x6 - PICMG 2.14 多计算控制器 |
-- | |
0x7 - Infiniband Controller 0x7 - Infiniband 控制器 |
-- | |
0x8 - Fabric Controller 0x8 - 结构控制器 |
-- | |
0x80 - Other 0x80 - 其他 | -- | |
0x3 - Display Controller
0x3 - 显示控制器 |
0x0 - VGA Compatible Controller
0x0 - VGA 兼容控制器 |
0x0 - VGA Controller 0x0 - VGA 控制器 |
0x1 - 8514-Compatible Controller
0x1 - 8514 兼容控制器 | ||
0x1 - XGA Controller 0x1 - XGA 控制器 |
-- | |
0x2 - 3D Controller (Not VGA-Compatible) 0x2 - 3D 控制器(非 VGA 兼容) |
-- | |
0x80 - Other 0x80 - 其他 | -- | |
0x4 - Multimedia Controller
0x4 - 多媒体控制器 |
0x0 - Multimedia Video Controller 0x0 - 多媒体视频控制器 |
-- |
0x1 - Multimedia Audio Controller 0x1 - 多媒体音频控制器 |
-- | |
0x2 - Computer Telephony Device 0x2 - 计算机电话设备 |
-- | |
0x3 - Audio Device 0x3 - 音频设备 |
-- | |
0x80 - Other 0x80 - 其他 | -- | |
0x5 - Memory Controller
0x5 - 内存控制器 |
0x0 - RAM Controller 0x0 - 内存控制器 |
-- |
0x1 - Flash Controller 0x1 - 闪存控制器 |
-- | |
0x80 - Other 0x80 - 其他 | -- | |
0x6 - Bridge 0x6 - 桥接 | 0x0 - Host Bridge 0x0 - 主机桥接器 |
-- |
0x1 - ISA Bridge 0x1 - ISA 桥接器 |
-- | |
0x2 - EISA Bridge 0x2 - EISA 桥接器 |
-- | |
0x3 - MCA Bridge 0x3 - MCA 桥接器 |
-- | |
0x4 - PCI-to-PCI Bridge
0x4 - PCI 至 PCI 桥接器 |
0x0 - Normal Decode 0x0 - 正常解码 | |
0x1 - Subtractive Decode 0x1 - 减法解码 | ||
0x5 - PCMCIA Bridge 0x5 - PCMCIA 桥接器 |
-- | |
0x6 - NuBus Bridge 0x6 - NuBus 桥接器 |
-- | |
0x7 - CardBus Bridge 0x7 - CardBus 桥接器 |
-- | |
0x8 - RACEway Bridge
0x8 - RACEway 桥接器 |
0x0 - Transparent Mode 0x0 - 透明模式 | |
0x1 - Endpoint Mode 0x1 - 端点模式 | ||
0x9 - PCI-to-PCI Bridge
0x9 - PCI 至 PCI 桥接器 |
0x40 - Semi-Transparent, Primary bus towards host CPU
0x40 - 半透明,主总线朝向主机 CPU | |
0x80 - Semi-Transparent, Secondary bus towards host CPU
0x80 - 半透明,通往主机 CPU 的辅助总线 | ||
0x0A - InfiniBand-to-PCI Host Bridge 0x0A - InfiniBand 到 PCI 主机桥接器 |
-- | |
0x80 - Other 0x80 - 其他 | -- | |
0x7 - Simple Communication Controller
0x7 - 简易通信控制器 |
0x0 - Serial Controller
0x0 - 串行控制器 |
0x0 - 8250-Compatible (Generic XT)
0x0 - 兼容 8250(通用 XT) |
0x1 - 16450-Compatible 0x1 - 兼容 16450 | ||
0x2 - 16550-Compatible 0x2 - 兼容 16550 | ||
0x3 - 16650-Compatible 0x3 - 兼容 16650 | ||
0x4 - 16750-Compatible 0x4 - 兼容 16750 | ||
0x5 - 16850-Compatible 0x5 - 兼容 16850 | ||
0x6 - 16950-Compatible 0x6 - 兼容 16950 | ||
0x1 - Parallel Controller
0x1 - 并行控制器 |
0x0 - Standard Parallel Port
0x0 - 标准并行端口 | |
0x1 - Bi-Directional Parallel Port
0x1 - 双向并行端口 | ||
0x2 - ECP 1.X Compliant Parallel Port
0x2 - ECP 1.X 兼容并行端口 | ||
0x3 - IEEE 1284 Controller
0x3 - IEEE 1284 控制器 | ||
0xFE - IEEE 1284 Target Device
0xFE - IEEE 1284 目标设备 | ||
0x2 - Multiport Serial Controller 0x2 - 多端口串行控制器 |
-- | |
0x3 - Modem 0x3 - 调制解调器 | 0x0 - Generic Modem 0x0 - 通用调制解调器 | |
0x1 - Hayes 16450-Compatible Interface
0x1 - 海斯 16450 兼容接口 | ||
0x2 - Hayes 16550-Compatible Interface
0x2 - 海斯 16550 兼容接口 | ||
0x3 - Hayes 16650-Compatible Interface
0x3 - 海斯 16650 兼容接口 | ||
0x4 - Hayes 16750-Compatible Interface
0x4 - 海斯 16750 兼容接口 | ||
0x4 - IEEE 488.1/2 (GPIB) Controller 0x4 - IEEE 488.1/2 (GPIB) 控制器 |
-- | |
0x5 - Smart Card Controller 0x5 - 智能卡控制器 |
-- | |
0x80 - Other 0x80 - 其他 | -- | |
0x8 - Base System Peripheral
0x8 - 基础系统外设 |
0x0 - PIC 0x0 - 外围接口控制器 | 0x0 - Generic 8259-Compatible
0x0 - 通用 8259 兼容型 |
0x1 - ISA-Compatible 0x1 - 兼容 ISA | ||
0x2 - EISA-Compatible 0x2 - EISA 兼容 | ||
0x10 - I/O APIC Interrupt Controller
0x10 - I/O APIC 中断控制器 | ||
0x20 - I/O(x) APIC Interrupt Controller
0x20 - I/O(x) APIC 中断控制器 | ||
0x01 - DMA Controller
0x01 - DMA 控制器 |
0x00 - Generic 8237-Compatible
0x00 - 通用 8237 兼容型 | |
0x01 - ISA-Compatible 0x01 - 兼容 ISA | ||
0x02 - EISA-Compatible 0x02 - EISA 兼容 | ||
0x02 - Timer 0x02 - 定时器 | 0x00 - Generic 8254-Compatible
0x00 - 通用 8254 兼容 | |
0x01 - ISA-Compatible 0x01 - 兼容 ISA | ||
0x02 - EISA-Compatible 0x02 - EISA 兼容 | ||
0x03 - HPET 0x03 - HPET 翻译:0x03 - 高精度事件定时器 | ||
0x3 - RTC Controller
0x3 - RTC 控制器 |
0x0 - Generic RTC 0x0 - 通用实时时钟 | |
0x1 - ISA-Compatible 0x1 - 兼容 ISA | ||
0x4 - PCI Hot-Plug Controller 0x4 - PCI 热插拔控制器 |
-- | |
0x5 - SD Host controller 0x5 - SD 主机控制器 |
-- | |
0x6 - IOMMU | -- | |
0x80 - Other 0x80 - 其他 | -- | |
0x9 - Input Device Controller
0x9 - 输入设备控制器 |
0x0 - Keyboard Controller 0x0 - 键盘控制器 |
-- |
0x1 - Digitizer Pen 0x1 - 数位笔 |
-- | |
0x2 - Mouse Controller 0x2 - 鼠标控制器 |
-- | |
0x3 - Scanner Controller 0x3 - 扫描控制器 |
-- | |
0x4 - Gameport Controller
0x4 - 游戏端口控制器 |
0x0 - Generic 0x0 - 通用 | |
0x10 - Extended 0x10 - 扩展 | ||
0x80 - Other 0x80 - 其他 | -- | |
0xA - Docking Station
0xA - 对接站 |
0x0 - Generic 0x0 - 通用 | -- |
0x80 - Other 0x80 - 其他 | -- | |
0xB - Processor 0xB - 处理器 | 0x0 - 386 | -- |
0x1 - 486 | -- | |
0x2 - Pentium 0x2 - 奔腾 | -- | |
0x3 - Pentium Pro 0x3 - 奔腾 Pro |
-- | |
0x10 - Alpha 0x10 - 阿尔法 | -- | |
0x20 - PowerPC 0x20 - PowerPC 翻译: 0x20 - 高性能计算平台 | -- | |
0x30 - MIPS 0x30 - MIPS 翻译:0x30 - MIPS | -- | |
0x40 - Co-Processor 0x40 - 协处理器 | -- | |
0x80 - Other 0x80 - 其他 | -- | |
0xC - Serial Bus Controller
0xC - 串行总线控制器 |
0x0 - FireWire (IEEE 1394) Controller
0x0 - 火线(IEEE 1394)控制器 |
0x0 - Generic 0x0 - 通用 |
0x10 - OHCI 0x10 - OHCI 翻译:0x10 - OHCI | ||
0x1 - ACCESS Bus Controller 0x1 - 访问总线控制器 |
-- | |
0x2 - SSA 0x2 - SSA 翻译:0x2 - 单一安全分析器 | -- | |
0x3 - USB Controller
0x3 - USB 控制器 |
0x0 - UHCI Controller 0x0 - UHCI 控制器 | |
0x10 - OHCI Controller 0x10 - OHCI 控制器 | ||
0x20 - EHCI (USB2) Controller
0x20 - EHCI(USB2)控制器 | ||
0x30 - XHCI (USB3) Controller
0x30 - XHCI(USB3)控制器 | ||
0x80 - Unspecified 0x80 - 未指定 | ||
0xFE - USB Device (Not a host controller)
0xFE - USB 设备(非主机控制器) | ||
0x4 - Fibre Channel 0x4 - 光纤通道 |
-- | |
0x5 - SMBus Controller 0x5 - SMBus 控制器 |
-- | |
0x6 - InfiniBand Controller 0x6 - InfiniBand 控制器 |
-- | |
0x7 - IPMI Interface
0x7 - IPMI 接口 |
0x0 - SMIC 0x0 - 中芯国际 | |
0x1 - Keyboard Controller Style
0x1 - 键盘控制器样式 | ||
0x2 - Block Transfer 0x2 - 块传输 | ||
0x8 - SERCOS Interface (IEC 61491) 0x8 - SERCOS 接口(IEC 61491) |
-- | |
0x9 - CANbus Controller 0x9 - CAN 总线控制器 |
-- | |
0x80 - Other 0x80 - 其他 | -- | |
0xD - Wireless Controller
0xD - 无线控制器 |
0x0 - iRDA Compatible Controller 0x0 - iRDA 兼容控制器 |
-- |
0x1 - Consumer IR Controller 0x1 - 消费红外控制器 |
-- | |
0x10 - RF Controller 0x10 - 射频控制器 |
-- | |
0x11 - Bluetooth Controller 0x11 - 蓝牙控制器 |
-- | |
0x12 - Broadband Controller 0x12 - 宽带控制器 |
-- | |
0x20 - Ethernet Controller (802.1a) 0x20 - 以太网控制器(802.1a) |
-- | |
0x21 - Ethernet Controller (802.1b) 0x21 - 以太网控制器(802.1b) |
-- | |
0x80 - Other 0x80 - 其他 | -- | |
0xE - Intelligent Controller 0xE - 智能控制器 |
0x0 - I20 0x0 - I20 翻译:0x0 - I20 | -- |
0xF - Satellite Communication Controller
0xF - 卫星通信控制器 |
0x1 - Satellite TV Controller 0x1 - 卫星电视控制器 |
-- |
0x2 - Satellite Audio Controller 0x2 - 卫星音频控制器 |
-- | |
0x3 - Satellite Voice Controller 0x3 - 卫星语音控制器 |
-- | |
0x4 - Satellite Data Controller 0x4 - 卫星数据控制器 |
-- | |
0x10 - Encryption Controller
0x10 - 加密控制器 |
0x0 - Network and Computing Encrpytion/Decryption 0x0 - 网络与计算加密/解密 |
-- |
0x10 - Entertainment Encryption/Decryption 0x10 - 娱乐加密/解密 |
-- | |
0x80 - Other 0x80 - 其他 | -- | |
0x11 - Signal Processing Controller
0x11 - 信号处理控制器 |
0x0 - DPIO Modules 0x0 - DPIO 模块 |
-- |
0x1 - Performance Counters 0x1 - 性能计数器 |
-- | |
0x10 - Communication Synchronizer 0x10 - 通信同步器 |
-- | |
0x20 - Signal Processing Management 0x20 - 信号处理管理 |
-- | |
0x80 - Other 0x80 - 其他 | -- | |
0x12 - Processing Accelerator 0x12 - 处理加速器 |
-- | -- |
0x13 - Non-Essential Instrumentation 0x13 - 非必要仪表设备 |
-- | -- |
0x14 - 0x3F (Reserved) 0x14 - 0x3F (保留) |
-- | -- |
0x40 - Co-Processor 0x40 - 协处理器 | -- | -- |
0x41 - 0xFE (Reserved) 0x41 - 0xFE(保留) |
-- | -- |
0xFF - Unassigned Class (Vendor specific) 0xFF - 未分配类(厂商特定) |
-- | -- |
Enumerating PCI Buses 枚举 PCI 总线
There are 3 ways to enumerate devices on PCI buses. The first way is "brute force", checking every device on every PCI bus (regardless of whether the PCI bus exists or not). The second way avoids a lot of work by figuring out valid bus numbers while it scans, and is a little more complex as it involves recursion. For both of these methods you rely on something (firmware) to have configured PCI buses properly (setting up PCI to PCI bridges to forward request from one bus to another). The third method is like the second method, except that you configure PCI bridges while you're doing it.
枚举 PCI 总线上的设备有三种方法。第一种是“暴力法”,即检查每个 PCI 总线上的每个设备(无论该 PCI 总线是否存在)。第二种方法通过在扫描过程中确定有效总线号来避免大量工作,这种方法稍微复杂一些,因为它涉及递归。对于这两种方法,你都依赖于(固件)已经正确配置了 PCI 总线(设置 PCI 到 PCI 桥接器以将请求从一个总线转发到另一个总线)。第三种方法类似于第二种,不同之处在于你在执行过程中配置 PCI 桥接器。
For all 3 methods, you need to be able to check if a specific device on a specific bus is present and if it is multi-function or not. Pseudo-code might look like this:
对于所有 3 种方法,您需要能够检查特定总线上的特定设备是否存在,以及它是否为多功能设备。伪代码可能如下所示:
void checkDevice(uint8_t bus, uint8_t device) { uint8_t function = 0; vendorID = getVendorID(bus, device, function); if (vendorID == 0xFFFF) return; // Device doesn't exist checkFunction(bus, device, function); headerType = getHeaderType(bus, device, function); if( (headerType & 0x80) != 0) { // It's a multi-function device, so check remaining functions for (function = 1; function < 8; function++) { if (getVendorID(bus, device, function) != 0xFFFF) { checkFunction(bus, device, function); } } } } void checkFunction(uint8_t bus, uint8_t device, uint8_t function) { }
Please note that if you don't check bit 7 of the header type and scan all functions, then some single-function devices will report details for "function 0" for every function.
请注意,若未检查头部类型中的第 7 位且遍历所有功能,则某些单功能设备将对每个功能报告“功能 0”的详细信息。
"Brute Force" Scan "暴力破解"扫描
For the brute force method, the remaining code is relatively simple. Pseudo-code might look like this:
对于暴力破解方法,剩余的代码相对简单。伪代码可能如下所示:
void checkAllBuses(void) { uint16_t bus; uint8_t device; for (bus = 0; bus < 256; bus++) { for (device = 0; device < 32; device++) { checkDevice(bus, device); } } }
For this method, there are 32 devices per bus and 256 buses, so you call "checkDevice()" 8192 times.
对于此方法,每条总线上有 32 个设备,共有 256 条总线,因此您需要调用"checkDevice()"8192 次。
Recursive Scan 递归扫描
The first step for the recursive scan is to implement a function that scans one bus. Pseudo-code might look like this:
递归扫描的第一步是实现一个函数,该函数扫描一条总线。伪代码可能如下所示:
void checkBus(uint8_t bus) { uint8_t device; for (device = 0; device < 32; device++) { checkDevice(bus, device); } }
The next step is to add code in "checkFunction()" that detects if the function is a PCI to PCI bridge. If the device is a PCI to PCI bridge then you want to extract the "secondary bus number" from the bridge's configuration space and call "checkBus()" with the number of the bus on the other side of the bridge.
下一步是在"checkFunction()"中添加代码,以检测该功能是否为 PCI 到 PCI 桥接器。如果设备是 PCI 到 PCI 桥接器,则需要从桥接器的配置空间中提取“辅助总线号”,并使用桥另一侧的总线号调用“checkBus()”。
Pseudo-code might look like this:
伪代码可能看起来像这样:
void checkFunction(uint8_t bus, uint8_t device, uint8_t function) { uint8_t baseClass; uint8_t subClass; uint8_t secondaryBus; baseClass = getBaseClass(bus, device, function); subClass = getSubClass(bus, device, function); if ((baseClass == 0x6) && (subClass == 0x4)) { secondaryBus = getSecondaryBus(bus, device, function); checkBus(secondaryBus); } }
The final step is to handle systems with multiple PCI host controllers correctly. Start by checking if the device at bus 0, device 0 is a multi-function device. If it's not a multi-function device, then there is only one PCI host controller and bus 0, device 0, function 0 will be the PCI host controller responsible for bus 0. If it's a multi-function device, then bus 0, device 0, function 0 will be the PCI host controller responsible for bus 0; bus 0, device 0, function 1 will be the PCI host controller responsible for bus 1, etc (up to the number of functions supported).
最后一步是正确处理具有多个 PCI 主机控制器的系统。首先检查总线 0、设备 0 处的设备是否为多功能设备。如果不是多功能设备,则只有一个 PCI 主机控制器,总线 0、设备 0、功能 0 将是负责总线 0 的 PCI 主机控制器。如果是多功能设备,则总线 0、设备 0、功能 0 将是负责总线 0 的 PCI 主机控制器;总线 0、设备 0、功能 1 将是负责总线 1 的 PCI 主机控制器,以此类推(直至支持的功能数上限)。
Pseudo-code might look like this:
伪代码可能看起来像这样:
void checkAllBuses(void) { uint8_t function; uint8_t bus; headerType = getHeaderType(0, 0, 0); if ((headerType & 0x80) == 0) { // Single PCI host controller checkBus(0); } else { // Multiple PCI host controllers for (function = 0; function < 8; function++) { if (getVendorID(0, 0, function) != 0xFFFF) break; bus = function; checkBus(bus); } } }
Recursive Scan With Bus Configuration
递归扫描与总线配置
This is similar to the recursive scan above; except that you set the "secondary bus" field in PCI to PCI bridges (using something like setSecondaryBus(bus, device, function, nextBusNumber++);
instead of the getSecondaryBus();
). However; if you are configuring PCI buses you are also responsible for configuring the memory areas/BARs in PCI functions, and ensuring that PCI bridges forward requests from their primary bus to their secondary buses.
这与上述递归扫描类似;区别在于你在 PCI 中将“辅助总线”字段设置为 PCI 桥接器(使用类似 setSecondaryBus(bus, device, function, nextBusNumber++);
而非 getSecondaryBus();
)。但若你在配置 PCI 总线,还需负责配置 PCI 功能中的内存区域/基地址寄存器(BARs),并确保 PCI 桥接器将其主总线的请求转发至辅助总线。
Writing code to support this without a deep understanding of PCI specifications is not recommended; and if you have a deep understanding of PCI specifications you have no need for pseudo code. For this reason there will be no example code for this method here.
不深入理解 PCI 规范而编写支持代码并不推荐;若你已深入理解 PCI 规范,则无需伪代码。因此,此处不会提供此方法的示例代码。
Configuring PCI-to-PCI bridges
配置 PCI 到 PCI 桥接器
To configure this the kernel has to forget about BIOS for a moment, first scan the root PCI device, (check if it is multi-function to scan multiple buses). Root bus is always 0.
要配置此功能,内核需暂时忽略 BIOS,首先扫描根 PCI 设备,(检查其是否为多功能的以扫描多个总线)。根总线始终为 0。
Secondary and subordinate bus acts as a range start-end of what buses the PCI-to-PCI bridge will manage.
次级和从属总线充当 PCI-to-PCI 桥接器管理总线的范围起止点。
Then, after this step it's up to implementation: Scan each device, then if a bridge is found, allocate a bus number to it (note: PCI-to-PCI bridges can have multiple bridges within them). Scan that bus and find more devices, once you find more bridges add 1 to the subordinate bus for each bridge found, because PCI-to-PCI bridges can manage multiple bridges.
随后,此步骤之后取决于实施细节:逐一扫描每个设备,若发现桥接器,则为其分配一个总线号(注意:PCI 到 PCI 桥接器内部可能包含多个桥接器)。接着扫描该总线并寻找更多设备,一旦找到更多桥接器,每发现一个桥接器,就将从属总线数加 1,因为 PCI 到 PCI 桥接器能够管理多个桥接器。
And this is just the beginning: After allocating bus numbers, you need to allocate MMIO, it would be trivial if it wasn't for the fact that PCI has 3 areas the kernel manages: IO, Prefetch and Memory.
而这仅仅是开始:分配完总线编号后,还需分配 MMIO,若非 PCI 有内核管理的三个区域——IO、预取和内存,这一过程本应轻而易举。
A bridge can manage multiple buses, but that means it spans all the memory of these buses, if device 1 is behind bridge 2, which is behind bridge 1, then bridge 2 will contain the memory area of device 1 + any other device's areas, supposing IO is 4M, Memory is 16M and Prefetch is 5MB (supposing there are 3 devices in bridge's 2 bus), bridge 2 would contain those, take in reference table for Header type 0x1
. However, bridge 1 will contain the areas of bridge 2 + any other devices in bridge's 1 bus.
一个桥接器可以管理多个总线,但这意味着它涵盖了这些总线的所有内存。如果设备 1 位于桥接器 2 之后,而桥接器 2 又位于桥接器 1 之后,那么桥接器 2 将包含设备 1 的内存区域以及任何其他设备的区域。假设 IO 为 4M,内存为 16M,预取为 5MB(假设桥接器 2 的总线上有 3 个设备),桥接器 2 将包含这些内容,并参考表头类型 0x1
。然而,桥接器 1 将包含桥接器 2 的区域以及桥接器 1 总线上的任何其他设备区域。
Once all memory areas are allocated, the devices can be used. Note that PCI-to-PCI bridges also have BAR's.
一旦所有内存区域分配完毕,设备即可使用。请注意,PCI 到 PCI 桥接器也具有基地址寄存器(BAR)。
If the kernel does not configure a PCI-to-PCI bridge, the BIOS will probably do, however on environments without BIOS, this method is mandatory otherwise devices behind that bridge won't show up.
如果内核未配置 PCI 到 PCI 桥接器,BIOS 可能会代为处理,但在无 BIOS 的环境中,此方法必不可少,否则桥接器后的设备将无法显示。
IRQ Handling 中断请求处理
If you're using the old PIC, your life is really easy. You have the Interrupt Line field of the header, which is read/write (you can change it's value!) and it says which interrupt will the PCI device fire when it needs attention.
如果你使用的是旧的 PIC,你的生活真的很轻松。你拥有头部的中断线字段,它是可读写的(你可以更改其值!),它指明了 PCI 设备在需要关注时将触发哪个中断。
If you plan to use the I/O APIC, things aren't so easy. Basically the PCI bus specifies that there are 4 interrupt pins. They are labeled INTA#, INTB#, INTC#, and INTD#. You find out what pin a device is using by reading the Interrupt Pin field of the header. So far, so good.
若计划使用 I/O APIC,事情就不那么简单了。基本上,PCI 总线规定有 4 个中断引脚,分别标记为 INTA#、INTB#、INTC#和 INTD#。要了解设备使用哪个引脚,需通过读取头部的“中断引脚”字段来确定。到目前为止,一切顺利。
The only problem is that the PCI pins correspond to an arbitrary I/O APIC pin. It's up to the programmer to find the mapping. How is that done? You must parse the MP Tables or the ACPI tables. The MP tables are easy, only they aren't supported on newer hardware. The ACPI tables, however, involve parsing AML, which is not an easy task. If one wants to take a shortcut, you can use ACPICA.
唯一的问题是 PCI 引脚对应于一个任意的 I/O APIC 引脚。这需要程序员去查找映射关系。如何实现呢?必须解析 MP 表或 ACPI 表。MP 表较为简单,但新硬件上不支持。而 ACPI 表则涉及解析 AML,这并非易事。若想走捷径,可使用 ACPICA。
Once you've found the I/O APIC pin, all you do is map that to an IRQ using the I/O APIC redirection table. See the I/O APIC article for more information on this.
一旦找到 I/O APIC 引脚,只需将其映射到 I/O APIC 重定向表中的 IRQ 即可。更多信息请参阅 I/O APIC 相关文章。
Alternatively, you could just use MSI or MSI-X, and skip complicated ACPI.
或者,您也可以直接使用 MSI 或 MSI-X,跳过复杂的 ACPI。
Message Signaled Interrupts
消息信号中断
Message Signaled Interrupts, or MSI, have been supported since PCI 2.2. However, support for them is mandatory in PCIe devices, so you can be sure that they're usable on modern hardware.
消息信号中断(MSI)自 PCI 2.2 起得到支持。然而,在 PCIe 设备中对其支持是强制性的,因此您可以确信它们在现代硬件上是可用的。
Use of MSI and MSI-X are mutually exclusive.
MSI 和 MSI-X 的使用是互斥的。
Enabling MSI 启用 MSI
First, check that the device has a pointer to the capabilities list (status register bit 4 set to 1).
Then, traverse the capabilities list. The low 8 bits of a capability register are the ID - 0x05
for MSI. The next 8 bits are the offset (in PCI Configuration Space) of the next capability.
首先,确认设备具有指向能力列表的指针(状态寄存器位 4 设为 1)。接着,遍历能力列表。能力寄存器的低 8 位是 ID—— 0x05
代表 MSI。接下来的 8 位是下一个能力的偏移量(在 PCI 配置空间中)。
The MSI capability is as follows:
MSI 功能如下:
Register 注册 | Offset 偏移量 | Bits 31-24 位 31-24 | Bits 23-16 位 23-16 | Bits 15-8 位 15-8 | Bits 7-0 位 7-0 |
---|---|---|---|---|---|
Cap + 0x0 帽 + 0x0 | Cap + 0x0 帽 + 0x0 | Message Control 消息控制 | Next pointer 下一指针 | Capability ID = 05 能力 ID = 05 | |
Cap + 0x1 帽 + 0x1 | Cap + 0x4 帽 + 0x4 | Message Address [Low] 消息地址 [低] | |||
Cap + 0x2 帽 + 0x2 | Cap + 0x8 帽 + 0x8 | [Message Address High] 消息地址高位 | |||
Cap + 0x2/0x3 帽 + 0x2/0x3 | Cap + 0x8/0xC | Reserved 已保留 | Message Data 消息数据 | ||
Cap + 0x4 帽 + 0x4 | Cap + 0x10 帽 + 0x10 | [Mask] 翻译文本:[面具] | |||
Cap + 0x5 帽 + 0x5 | Cap + 0x14 帽 + 0x14 | [Pending] 待定 |
Here is the layout of the message control register:
消息控制寄存器的布局如下:
Bits 15-9 位 15-9 | Bit 8 第 8 位 | Bit 7 第 7 位 | Bits 6-4 位 6-4 | Bits 3-1 位 3-1 | Bit 0 第 0 位 |
---|---|---|---|---|---|
Reserved 已保留 | Per-vector masking 逐向量掩码 | 64-bit 64 位 | Multiple Message Enable 多消息启用 | Multiple Message Capable
多消息能力 |
Enable 启用 |
The message address/data is architecture specific. On x86(-64), it is as follows:
消息地址/数据与架构相关。在 x86(-64)上,情况如下:
uint64_t arch_msi_address(uint64_t *data, size_t vector, uint32_t processor, uint8_t edgetrigger, uint8_t deassert) { *data = (vector & 0xFF) | (edgetrigger == 1 ? 0 : (1 << 15)) | (deassert == 1 ? 0 : (1 << 14)); return (0xFEE00000 | (processor << 12)); }
MSI interrupts seem to be invariably edge triggered high.
MSI 中断似乎总是高电平边沿触发。
Multiple messages: 多条消息:
MME / MMI | Interrupts 中断 |
---|---|
000 | 1 |
001 | 2 |
010 | 4 |
011 | 8 |
100 | 16 |
101 | 32 |
In MME, specifies the number of low bits of Message Data that may be modified by the device.
在 MME 中,指定设备可以修改的消息数据低位的位数。
Therefore, the interrupt vector block allocated must be aligned accordingly.
因此,分配的中断向量块必须相应地对齐。
Interrupt masking 中断屏蔽
If capable, you can mask individual messages by setting the corresponding bit (1 << n), in the mask register.
若具备此功能,您可通过设置掩码寄存器中对应的位(1 << n)来屏蔽单个消息。
If a message is pending, then the corresponding bit in the pending register is set.
若消息处于待处理状态,则待处理寄存器中对应的位将被置位。
Note that the PCI specification doesn't specify the location of these registers if the message address is 32-bit. This is because a function that supports masking is required to implement 64-bit addressing!
请注意,如果消息地址为 32 位,PCI 规范并未指定这些寄存器的位置。这是因为需要支持掩码功能的函数来实现 64 位寻址!
Enabling MSI-X 启用 MSI-X
Like for MSI, you have to find the MSI-X capability, but the ID for MSI-X is 0x11
与 MSI 类似,您需要找到 MSI-X 功能,但 MSI-X 的 ID 是 0x11
The structure is as follows:
结构如下:
Register 注册 | Offset 偏移 | Bits 31-24 位 31-24 | Bits 23-16 位 23-16 | Bits 15-8 位 15-8 | Bits 7-3 位 7-3 | Bits 2-0 位 2-0 |
---|---|---|---|---|---|---|
Cap + 0x0 帽 + 0x0 | Cap + 0x0 帽 + 0x0 | Message Control 消息控制 | Next Pointer 下一指针 | Capability ID = 11 能力 ID = 11 | ||
Cap + 0x1 帽 + 0x1 | Cap + 0x4 帽 + 0x4 | Table Offset 表偏移 | BIR | |||
Cap + 0x2 帽 + 0x2 | Cap + 0x8 帽 + 0x8 | Pending Bit Offset 待定位偏移 | Pending Bit BIR 待定位 BIR |
Unlike MSI, MSI-X supports 2048 interrupts. This is achieved by maintaining a table of interrupts in the PCI device's address space. The wording of the PCI 3.0 specification indicates that this must be via a Memory BAR.
与 MSI 不同,MSI-X 支持 2048 个中断。这是通过在 PCI 设备的地址空间中维护一个中断表来实现的。PCI 3.0 规范的措辞表明,这必须通过内存基址寄存器(Memory BAR)来完成。
BIR specifies which BAR is used for the Message Table. This may be a 64-bit BAR, and is zero-indexed (so BIR=0, BAR0, offset 0x10
into the header).
BIR 指定用于消息表的 BAR。这可能是一个 64 位 BAR,并且是零索引的(因此 BIR=0,BAR0,偏移量 0x10
进入头部)。
Table Offset is an offset into that BAR where the Message Table lives. Note that it is 8-byte aligned - so simply mask BIR.
表偏移是指消息表所在 BAR 中的偏移量。请注意,它是 8 字节对齐的——因此只需屏蔽 BIR 即可。
The format of Message Control is as follows:
消息控制格式如下:
Bit 15 第 15 位 | Bit 14 位 14 | Bits 13-11 位 13-11 | Bits 10-0 位 10-0 |
---|---|---|---|
Enable 启用 | Function Mask 功能掩码 | Reserved 已保留 | Table Size 表格大小 |
Table Size is N - 1 encoded, and is the number of entries in the MSI-X table. This field is Read-Only.
表大小为 N-1 编码,表示 MSI-X 表中的条目数。此字段为只读。
Now you have all the information you need to find the MSI-X table:
现在你已掌握寻找 MSI-X 表所需的所有信息:
Bits 127-96 位 127-96 | Bits 95-64 位 95-64 | Bits 63-32 位 63-32 | Bits 31-0 位 31-0 |
---|---|---|---|
Vector Control (0) 矢量控制(0) | Message Data (0) 消息数据 (0) | Message Address High (0)
消息地址高位(0) |
Message Address Low (0) 消息地址低(0) |
Vector Control (1) 矢量控制(1) | Message Data (1) 消息数据 (1) | Message Address High (1)
消息地址高位(1) |
Message Address Low (1) 消息地址低位(1) |
... | ... | ... | ... |
Vector Control (N - 1)
矢量控制(N - 1) |
Message Data (N - 1)
消息数据(N - 1) |
Message Address High (N - 1)
消息地址高位(N - 1) |
Message Address Low (N - 1)
消息地址低位(N - 1) |
Vector Control is as follows:
矢量控制如下:
Bits 31-1 位 31-1 | Bit 0 第 0 位 |
---|---|
Reserved 已保留 | Masked 已屏蔽 |
Note that Message Address is is 4-byte aligned, so, again, mask the low bits. The interrupt is masked if Masked is set to 1.
注意,消息地址是 4 字节对齐的,因此再次需要屏蔽低位。如果 Masked 设置为 1,则中断被屏蔽。
Message Address and Data are as they were for MSI - architecture specific. However, unlike with MSI, you can specify independent vectors for all the interrupts, only limited by having the same upper 32-bit message address.
消息地址和数据与 MSI 时相同——特定于架构。然而,与 MSI 不同的是,您可以为所有中断指定独立向量,仅受限于拥有相同的 32 位高位消息地址。
Multi-function Devices 多功能设备
Multi-function devices behave in the same manner as normal PCI devices. The easiest way to detect a multi-function device is bit 7 of the header type field. If it is set (value = 0x80
), the device is multi-function -- else it is not. Make sure you mask this bit when you determine header type. To detect the number of functions you need to scan the PCI configuration space for every function - unused functions have vendor 0xFFFF
. Device IDs and Class codes vary between functions. Functions are not necessarily in order - you can have function 0x0
, 0x1
and 0x7
in use.
多功能设备的行为与普通 PCI 设备相同。检测多功能设备最简单的方法是检查头部类型字段的第 7 位。如果该位被设置(值为 0x80
),则设备为多功能设备——否则不是。在确定头部类型时,务必屏蔽此位。要检测功能数量,需要扫描 PCI 配置空间中的每个功能——未使用的功能具有供应商 0xFFFF
。设备 ID 和类代码在不同功能之间可能不同。功能不一定按顺序排列——可能正在使用功能 0x0
、 0x1
和 0x7
。
Disclaimer 免责声明
This text originates from "Pentium on VME", unknown author, md5sum d292807a3c56881c6faba7a1ecfd4c79. The original document is apparently no longer present on the Web ...
此文本源自“Pentium on VME”,作者未知,md5sum 值为 d292807a3c56881c6faba7a1ecfd4c79。原文件显然已无法在网络上找到...
Closest match: [2] 最接近匹配:[2]
References 参考文献
- PCI Local Bus Specification, revision 3.0, PCI Special Interest Group, August 12, 2002
PCI 本地总线规范,修订版 3.0,PCI 特别兴趣小组,2002 年 8 月 12 日
See Also 相关内容
Articles 文章
External Links 外部链接
- Very useful page about VendorID and DeviceID
关于 VendorID 和 DeviceID 的非常有用的页面 - Very detailed PCI-to-PCI architecture specification
非常详细的 PCI 到 PCI 架构规范 - How PCI Express devices talk
PCI Express 设备通信方式 - PCI Local Bus (Solaris documentation)
PCI 本地总线(Solaris 文档) - PCI in the Linux kernel
Linux 内核中的 PCI - More up to date PCI vendor and device numbers
更新的 PCI 厂商和设备编号 - Structure describes that PCI configuration space for PCI devices
结构描述了 PCI 设备的 PCI 配置空间