-
Notifications
You must be signed in to change notification settings - Fork 0
PCI Capability Structure
Optional extended features that PCI devices advertise and use, such as MSI interrupts, power management, and hot-swap.
PCI devices can implement optional capability structures that extend the base PCI feature set. These capabilities are exposed through a linked-list chain in the device's configuration space. Each capability has a unique ID, an offset to the next capability, and capability-specific registers. The PCI base specification defines several well-known capability IDs, and vendors can implement vendor-specific capabilities.
Capability discovery happens during PCI device enumeration. The configuration header's CAP_POINTER (offset 0x34, lower 8 bits, bit 4 = 1 indicates capabilities list present) points to the first capability. Subsequent capabilities are linked via the NEXT pointer. JNode's Capability.createCapability() factory method dispatches on the capability ID to instantiate the appropriate concrete subclass.
The capability structure enables a clean extension mechanism: base PCI provides the discovery and access infrastructure, while each capability defines its own register layout and behavior. This allows drivers to query which capabilities a device supports and configure them accordingly.
| Class / File | Role |
|---|---|
core/src/driver/org/jnode/driver/bus/pci/Capability.java |
Abstract base class for all capabilities; defines id, offset, device access, and factory method |
core/src/driver/org/jnode/driver/bus/pci/MSICapability.java |
Message Signaled Interrupts capability |
core/src/driver/org/jnode/driver/bus/pci/PMCapability.java |
Power Management capability (PCI PM) |
core/src/driver/org/jnode/driver/bus/pci/AGPCapability.java |
Accelerated Graphics Port capability |
core/src/driver/org/jnode/driver/bus/pci/VPDCapability.java |
Vital Product Data capability |
core/src/driver/org/jnode/driver/bus/pci/SlotIDCapability.java |
Slot Identification capability |
core/src/driver/org/jnode/driver/bus/pci/CompactHotSwapCapability.java |
CompactPCI HotSwap capability |
core/src/driver/org/jnode/driver/bus/pci/PCIDevice.java |
PCI device; provides configuration space read/write via readConfigByte/Word/Dword
|
The PCI capability chain lives in configuration space. Each capability is at least 4 bytes:
| Offset | Field | Description |
|---|---|---|
| +0 | CAP_LIST_ID |
Capability ID (0x01-0xFF) |
| +1 | CAP_LIST_NEXT |
Offset to next capability (0x00 = end of list) |
| +2 | CAP_FLAGS |
Capability-specific flags (16 bits) |
Header (type 0 device) at 0x34: CAP_POINTER = 0xDC (capabilities list present)
Capability at 0xDC:
+0x00: ID (e.g., 0x05 = MSI)
+0x01: NEXT pointer
+0x02: flags
+0x04: capability-specific data...
Next capability at [NEXT]:
+0x00: ID
+0x01: NEXT
+0x02: flags
...
During PCI device initialization, PCIDeviceConfig reads the capabilities pointer and traverses the chain:
// Capability.java:93-97 — constructor reads the ID at the capability offset
Capability(PCIDevice device, int offset) {
this.device = device;
this.offset = offset;
this.id = device.readConfigByte(offset + PCI_CAP_LIST_ID);
}
// Capability.java:107-126 — factory dispatches on capability ID
static final Capability createCapability(PCIDevice device, int offset) {
final int id = device.readConfigByte(offset + PCI_CAP_LIST_ID);
switch (id) {
case Id.PM: return new PMCapability(device, offset);
case Id.AGP: return new AGPCapability(device, offset);
case Id.VPD: return new VPDCapability(device, offset);
case Id.SLOTID: return new SlotIDCapability(device, offset);
case Id.MSI: return new MSICapability(device, offset);
case Id.CHSWP: return new CompactHotSwapCapability(device, offset);
default: return new Capability(device, offset) {}; // generic
}
}Message Signaled Interrupts (MSI) allows a device to write a message (effectively a memory write) to trigger an interrupt rather than using a traditional wire-based IRQ line. This is advantageous because it supports multiple messages, enables more flexible interrupt routing (especially in multi-core systems), and reduces hardware complexity.
JNode's MSICapability currently provides the base class structure. The capability ID is 0x05. MSI capability registers include address low, address high (for 64-bit), data (for multi-message), and control fields.
Power Management (PMCapability, ID 0x01) extends PCI devices with standardized power state control:
- Capabilities register (offset +0x02, 16-bit): Specifies supported power management features (D0-D3 hot, D1/D2 support, aux current)
- PMC register (offset +0x04, 16-bit): Power Management Capabilities
- PMCSR register (offset +0x06, 16-bit): Power Management Control/Status — controls current power state
- Data register (offset +0x07, 8-bit): Provides power consumption data for the current state
// PMCapability.java — accessor methods read from capability-specific offsets
public final int getCapabilities() { return readConfigWord(0x02); }
public final int getStatus() { return readConfigWord(0x04); }
public final int getData() { return readConfigByte(0x07); }
public final int getBridgeSupportExtensions() { return readConfigByte(0x06); }-
AGPCapability (ID
0x02): Graphics port capability for AGP video cards -
VPDCapability (ID
0x03): Vital Product Data for device identification and configuration storage -
SlotIDCapability (ID
0x04): Slot identification for add-in cards -
CompactHotSwapCapability (ID
0x06): Hot-swap support for CompactPCI
Capabilities use their parent PCIDevice's configuration space access methods with an offset shift to account for the capability's position:
// Capability.java:150-169 — device configuration access with offset translation
protected final int readConfigDword(int offset) {
return device.readConfigDword(this.offset + offset);
}
protected final void writeConfigWord(int offset, int value) {
device.writeConfigWord(this.offset + offset, value);
}
// ... readConfigByte, readConfigWord, writeConfigByte, writeConfigDwordThe this.offset translation means capabilities work correctly regardless of their position in configuration space.
-
Capabilities are optional: Not all PCI devices have a capabilities list. The
CAP_POINTERbit in the status register (bit 4) indicates whether the list exists. Attempting to traverse a non-existent list will read garbage. - Link order is device-specific: The linked list order does not indicate importance or priority. A device may place MSI before PM or vice versa.
-
Unknown capability IDs return a generic anonymous subclass: When
createCapability()encounters an unknown ID, it returns an anonymousCapabilitysubclass that provides the base capability structure without specialized behavior. - MSI requires platform support: MSI capability being present does not guarantee the platform APIC or OS can route MSI messages. The capability must be enabled explicitly.
- Power management state transitions: PM capability state transitions (D0→D3) have implications for device availability. Transitioning to D3 may clear configuration.
- 64-bit MSI requires address high: When enabling 64-bit MSI, both address low and address high registers must be written. 32-bit MSI uses only address low.
-
Multi-message MSI: The MSI control register contains a
MME(Multi-Message Enable) field that controls how many message vectors are allocated (1, 2, 4, 8, 16, or 32).
- Bus-Drivers — PCI bus enumeration which discovers capability chains
- Interrupt-Handling — MSI as an interrupt delivery mechanism
- Resource-Management — IRQ resource allocation, which may be affected by MSI capability
- PCIDeviceToDriverMapper — Driver binding that may consider capability support
- Driver-Framework — Parent hub for device driver architecture