PCI: Difference between revisions

1,027 bytes added ,  29 days ago
m
Bot: Replace deprecated source tag with syntaxhighlight
[unchecked revision][unchecked revision]
(Fix confusing wording in IRQ handling section)
m (Bot: Replace deprecated source tag with syntaxhighlight)
 
(10 intermediate revisions by 6 users not shown)
Line 41:
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.
 
<sourcesyntaxhighlight lang="c">
uint16_t pciConfigReadWord(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) {
uint32_t address;
Line 60:
return tmp;
}
</syntaxhighlight>
</source>
 
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.
 
<sourcesyntaxhighlight lang="c">
uint16_t pciCheckVendor(uint8_t bus, uint8_t slot) {
uint16_t vendor, device;
Line 74:
} return (vendor);
}
</syntaxhighlight>
</source>
 
=== Configuration Space Access Mechanism #2 ===
Line 141:
 
The following field descriptions are common to all Header Types:
 
{| {{wikitable}}
|-
! Register !! Offset !! Bits 31-24 !! Bits 23-16 !! Bits 15-8 !! Bits 7-0
|-
| 0x0
| 0x0
| colspan="2" | Device ID
| colspan="2" | Vendor ID
|-
| 0x1
| 0x4
| colspan="2" | Status
| colspan="2" | Command
|-
| 0x2
| 0x8
| Class code || Subclass || Prog IF || Revision 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.
* ''Vendor ID:'' Identifies the manufacturer of the device. Where valid IDs are allocated by PCI-SIG (the list is [https://pcisig.com/membership/member-companies here]) to ensure uniqueness and <code>0xFFFF</code> is an invalid value that will be returned on read accesses to Configuration Space registers of non-existent devices.
* ''[[#Status_Register|Status]]:'' A register used to record status information for PCI bus related events.
* ''[[#Command_Register|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.
* ''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.
Line 151 ⟶ 179:
* ''Revision ID:'' Specifies a revision identifier for a particular device. Where valid IDs are allocated by the vendor.
* ''BIST:'' Represents that status and allows control of a devices BIST (built-in self test).
* ''Header Type:'' Identifies the layout of the rest of the header beginning at byte <code>0x10</code> of the header and also specifies whether or not the device has multiple functions. Where a value of <code>0x0</code> specifies a general device, a value of <code>0x1</code> specifies a PCI-to-PCI bridge, and a value of <code>0x2</code> specifies a CardBus bridge. If bit 7 of this register is set, the device has multiple functions; otherwise, it is a single function device. Types:
** <code>0x0</code>: [[#Header_Type_0x0|a general device]]
** <code>0x1</code>: [[#Header Type_0x1_(PCI-to-PCI_bridge)|a PCI-to-PCI bridge]]
** <code>0x2</code>: [[#Header_Type_0x2_(PCI-to-CardBus_bridge)|a PCI-to-CardBus bridge]].
* ''Latency Timer:'' Specifies the latency timer in units of PCI bus clocks.
* ''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.
 
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.
 
===== Command Register =====
 
Here is the layout of the Command register:
 
{| {{wikitable}}
|-
! Bits 11-15 !! Bit 10 !! Bit 9 !! Bit 8 !! Bit 7 !! Bit 6 !! Bit 5 !! Bit 4 !! Bit 3 !! Bit 2 !! Bit 1 !! Bit 0
|-
| Reserved
| Interrupt Disable
| Fast Back-to-Back Enable
| SERR# Enable
| Reserved
| Parity Error Response
| VGA Palette Snoop
| 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.
* ''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.
* ''SERR# Enable'' - If set to 1 the SERR# driver is enabled; otherwise, the driver is disabled.
* ''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.
* ''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.
* ''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.
* ''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.
* ''Special Cycles'' - If set to 1 the device can monitor Special Cycle operations; otherwise, the device will ignore them.
* ''Bus Master'' - If set to 1 the device can behave as a bus master; otherwise, the device can not generate PCI accesses.
* ''Memory Space'' - If set to 1 the device can respond to Memory Space accesses; otherwise, the device's response is disabled.
* ''I/O Space'' - If set to 1 the device can respond to I/O Space accesses; otherwise, the device's response is disabled.
 
If the kernel configures the BARs of the devices, the kernel also have to enable bits 0 and 1 for it to activate.
 
===== Status Register =====
 
Here is the layout of the Status register:
 
{| {{wikitable}}
|-
! Bit 15 !! Bit 14 !! Bit 13 !! Bit 12 !! Bit 11 !! Bits 9-10 !! Bit 8 !! Bit 7 !! Bit 6 !! Bit 5 !! Bit 4 !! Bit 3 !! Bits 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
| 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.
* ''Signalled System Error'' - This bit will be set to 1 whenever the device asserts SERR#.
* ''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.
* ''Received Target Abort'' - This bit will be set to 1, by a master device, whenever its transaction is terminated with Target-Abort.
* ''Signalled Target Abort'' - This bit will be set to 1 whenever a target device terminates a transaction with Target-Abort.
* ''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 <code>0x0</code> represents fast timing, a value of <code>0x1</code> represents medium timing, and a value of <code>0x2</code> represents slow timing.
* ''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.
* ''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.
* ''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.
* ''66 MHz Capable'' - If set to 1 the device is capable of running at 66 MHz; otherwise, the device runs at 33 MHz.
* ''Capabilities List'' - If set to 1 the device implements the pointer for a New Capabilities Linked list at offset <code>0x34</code>; otherwise, the linked list is not available.
* ''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.
 
==== Header Type 0x0 ====
Line 458 ⟶ 590:
| colspan="4" | 16-bit PC Card legacy mode base address
|}
 
===== Command Register =====
 
Here is the layout of the Command register:
 
{| {{wikitable}}
|-
! Bits 11-15 !! Bit 10 !! Bit 9 !! Bit 8 !! Bit 7 !! Bit 6 !! Bit 5 !! Bit 4 !! Bit 3 !! Bit 2 !! Bit 1 !! Bit 0
|-
| Reserved
| Interrupt Disable
| Fast Back-to-Back Enable
| SERR# Enable
| Reserved
| Parity Error Response
| VGA Palette Snoop
| Memory Write and Invalidate Enable
| Special Cycles
| Bus Master
| Memory Space
| I/O Space
|}
 
* ''Interrupt Disable'' - If set to 1 the assertion of the devices INTx# signal is disabled; otherwise, assertion of the signal is enabled.
* ''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.
* ''SERR# Enable'' - If set to 1 the SERR# driver is enabled; otherwise, the driver is disabled.
* ''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.
* ''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.
* ''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.
* ''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.
* ''Special Cycles'' - If set to 1 the device can monitor Special Cycle operations; otherwise, the device will ignore them.
* ''Bus Master'' - If set to 1 the device can behave as a bus master; otherwise, the device can not generate PCI accesses.
* ''Memory Space'' - If set to 1 the device can respond to Memory Space accesses; otherwise, the device's response is disabled.
* ''I/O Space'' - If set to 1 the device can respond to I/O Space accesses; otherwise, the device's response is disabled.
 
If the kernel configures the BARs of the devices, the kernel also have to enable bits 0 and 1 for it to activate.
 
===== Status Register =====
 
Here is the layout of the Status register:
 
{| {{wikitable}}
|-
! Bit 15 !! Bit 14 !! Bit 13 !! Bit 12 !! Bit 11 !! Bits 9-10 !! Bit 8 !! Bit 7 !! Bit 6 !! Bit 5 !! Bit 4 !! Bit 3 !! Bits 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
| Capabilities List
| Interrupt Status
| Reserved
|}
 
* ''Detected Parity Error'' - This bit will be set to 1 whenever the device detects a parity error, even if parity error handling is disabled.
* ''Signalled System Error'' - This bit will be set to 1 whenever the device asserts SERR#.
* ''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.
* ''Received Target Abort'' - This bit will be set to 1, by a master device, whenever its transaction is terminated with Target-Abort.
* ''Signalled Target Abort'' - This bit will be set to 1 whenever a target device terminates a transaction with Target-Abort.
* ''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 <code>0x0</code> represents fast timing, a value of <code>0x1</code> represents medium timing, and a value of <code>0x2</code> represents slow timing.
* ''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.
* ''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.
* ''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.
* ''66 MHz Capable'' - If set to 1 the device is capable of running at 66 MHz; otherwise, the device runs at 33 MHz.
* ''Capabilities List'' - If set to 1 the device implements the pointer for a New Capabilities Linked list at offset <code>0x34</code>; otherwise, the linked list is not available.
* ''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.
 
Recall 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.
 
=== Base Address Registers ===
Line 570 ⟶ 628:
 
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 <code>(BAR[x] & 0xFFF0)</code>. For 32-bit Memory Space BARs, you calculate <code>(BAR[x] & 0xFFFFFFF0)</code>. For 64-bit Memory Space BARs, you calculate <code>((BAR[x] & 0xFFFFFFF0) + ((BAR[x + 1] & 0xFFFFFFFF) << 32))</code> For I/O Space BARs, you calculate <code>(BAR[x] & 0xFFFFFFFC)</code>.
 
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.
 
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. [https://web.archive.org/web/20150101180929/https://www.pcisig.com/reflector/msg05233.html]
Line 958 ⟶ 1,018:
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:
 
<sourcesyntaxhighlight lang="c">
void checkDevice(uint8_t bus, uint8_t device) {
uint8_t function = 0;
Line 978 ⟶ 1,038:
void checkFunction(uint8_t bus, uint8_t device, uint8_t function) {
}
</syntaxhighlight>
</source>
 
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.
Line 986 ⟶ 1,046:
For the brute force method, the remaining code is relatively simple. Pseudo-code might look like this:
 
<sourcesyntaxhighlight lang="c">
void checkAllBuses(void) {
uint16_t bus;
Line 997 ⟶ 1,057:
}
}
</syntaxhighlight>
</source>
 
For this method, there are 32 devices per bus and 256 buses, so you call "checkDevice()" 8192 times.
Line 1,005 ⟶ 1,065:
The first step for the recursive scan is to implement a function that scans one bus. Pseudo-code might look like this:
 
<sourcesyntaxhighlight lang="c">
void checkBus(uint8_t bus) {
uint8_t device;
Line 1,013 ⟶ 1,073:
}
}
</syntaxhighlight>
</source>
 
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.
Line 1,019 ⟶ 1,079:
Pseudo-code might look like this:
 
<sourcesyntaxhighlight lang="c">
void checkFunction(uint8_t bus, uint8_t device, uint8_t function) {
uint8_t baseClass;
Line 1,032 ⟶ 1,092:
}
}
</syntaxhighlight>
</source>
 
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).
Line 1,038 ⟶ 1,098:
Pseudo-code might look like this:
 
<sourcesyntaxhighlight lang="c">
void checkAllBuses(void) {
uint8_t function;
Line 1,056 ⟶ 1,116:
}
}
</syntaxhighlight>
</source>
 
=== Recursive Scan With Bus Configuration ===
Line 1,082 ⟶ 1,142:
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.
 
If you plan to use the [[I/O APIC]], things aren't so easy. Basically the PCI bus specifies that theirthere 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.
 
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]].
Line 1,097 ⟶ 1,157:
=== Enabling 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 - <code>0x50x05</code> for MSI. The next 8 bits are the offset (in [[#Configuration Space|PCI Configuration Space]]) of the next capability.
 
The MSI capability is as follows:
Line 1,146 ⟶ 1,206:
 
The message address/data is architecture specific. On x86(-64), it is as follows:
<sourcesyntaxhighlight lang="c">
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));
}
</syntaxhighlight>
</source>
MSI interrupts seem to be invariably edge triggered high.
 
Line 1,292 ⟶ 1,352:
[[Category:Buses]]
[[Category:PCI]]
[[Category:Standards]]
[[de:Peripheral_Component_Interconnect]]