2#ifndef PEDIGREE_PCI_EXPRESS_H
3#define PEDIGREE_PCI_EXPRESS_H
5#include "pedigree/kernel/processor/types.h"
8constexpr uint8_t CapabilityId = 0x10;
10enum class FindResult { Found, Absent, Unavailable, Malformed };
11enum class FlrResult { Complete, Unavailable, Unsupported, Busy, Unverified };
13enum class Type : uint8_t {
21 IntegratedEndpoint = 9,
28 Type type = Type::Endpoint;
29 uint8_t interruptMessage = 0;
30 uint32_t deviceCapabilities = 0;
31 uint16_t deviceControl = 0;
32 uint16_t deviceStatus = 0;
33 uint32_t linkCapabilities = 0;
34 uint16_t linkControl = 0;
35 uint16_t linkStatus = 0;
36 uint32_t slotCapabilities = 0;
37 uint16_t slotControl = 0;
38 uint16_t slotStatus = 0;
40 bool slotImplemented =
false;
42 bool supportsFlr()
const {
43 return (type == Type::Endpoint || type == Type::LegacyEndpoint ||
44 type == Type::IntegratedEndpoint) &&
45 (deviceCapabilities & (1U << 28));
47 uint8_t linkSpeed()
const {
48 return linkStatus & 0xfU;
50 uint8_t linkWidth()
const {
51 return (linkStatus >> 4) & 0x3fU;
53 bool linkTraining()
const {
54 return linkStatus & (1U << 11);
58inline bool validType(uint8_t type) {
59 return type <= 1 || (type >= 4 && type <= 10);
62template <
class Config>
63FindResult find(Config& config, State& result) {
66 uint8_t headerType = 0;
67 if (!config.read32(0,
identity) || !config.read16(6, status) || !config.read8(0x0e, headerType)) {
68 return FindResult::Unavailable;
70 if (!(
identity & 0xffffU) || (
identity & 0xffffU) == 0xffffU || (headerType & 0x7fU) > 1) {
71 return FindResult::Unavailable;
73 if (!(status & 0x10U)) {
74 return FindResult::Absent;
78 if (!config.read8(0x34, offset)) {
79 return FindResult::Unavailable;
81 uint64_t occupied = 0;
85 if (offset < 0x40 || (offset & 3U)) {
86 return FindResult::Malformed;
88 uint8_t
id = 0, next = 0;
89 if (!config.read8(offset,
id) || !config.read8(offset + 1, next)) {
90 return FindResult::Unavailable;
92 if (!
id ||
id == 0xffU || (next && (next < 0x40 || (next & 3U)))) {
93 return FindResult::Malformed;
100 uint16_t control = 0;
101 if (!config.read16(offset + 2, control)) {
102 return FindResult::Unavailable;
104 bytes = (control & 0x80U) ? 14 : 10;
105 if (control & 0x100U) {
108 }
else if (
id == 0x11) {
110 }
else if (
id == CapabilityId) {
112 return FindResult::Malformed;
115 if (!config.read16(offset + 2, flags)) {
116 return FindResult::Unavailable;
118 const uint8_t version = flags & 0xfU;
119 const uint8_t type = (flags >> 4) & 0xfU;
120 if ((version != 1 && version != 2) || !validType(type)) {
121 return FindResult::Malformed;
123 candidate.offset = offset;
124 candidate.version = version;
125 candidate.type =
static_cast<Type
>(type);
126 candidate.interruptMessage = (flags >> 9) & 0x1fU;
127 candidate.hasLink = type != 9 && type != 10;
128 candidate.slotImplemented = (flags & (1U << 8)) && (candidate.type == Type::RootPort ||
129 candidate.type == Type::DownstreamPort);
130 bytes = candidate.hasLink ? 0x14 : 0x0c;
131 if (candidate.type == Type::RootPort) {
133 }
else if (candidate.slotImplemented) {
137 if (
unsigned(offset) + bytes > 0x100) {
138 return FindResult::Malformed;
140 for (
unsigned slot = offset / 4; slot < (offset + bytes + 3) / 4; ++slot) {
141 const uint64_t bit = uint64_t{1} << slot;
142 if (occupied & bit) {
143 return FindResult::Malformed;
147 if (
id == CapabilityId) {
148 if (!config.read32(offset + 4, candidate.deviceCapabilities) ||
149 !config.read16(offset + 8, candidate.deviceControl) ||
150 !config.read16(offset + 0x0a, candidate.deviceStatus) ||
151 (candidate.hasLink && (!config.read32(offset + 0x0c, candidate.linkCapabilities) ||
152 !config.read16(offset + 0x10, candidate.linkControl) ||
153 !config.read16(offset + 0x12, candidate.linkStatus))) ||
154 (candidate.slotImplemented &&
155 (!config.read32(offset + 0x14, candidate.slotCapabilities) ||
156 !config.read16(offset + 0x18, candidate.slotControl) ||
157 !config.read16(offset + 0x1a, candidate.slotStatus)))) {
158 return FindResult::Unavailable;
165 return FindResult::Absent;
168 return FindResult::Found;
175template <
class Config,
class Wait>
176FlrResult resetFunction(Config& config, Wait wait) {
178 const FindResult found = find(config, state);
179 if (found != FindResult::Found) {
180 return found == FindResult::Absent ? FlrResult::Unsupported : FlrResult::Unavailable;
182 if (!state.supportsFlr()) {
183 return FlrResult::Unsupported;
186 uint16_t command = 0;
187 if (!config.read32(0,
identity) || !config.read16(4, command)) {
188 return FlrResult::Unavailable;
190 if ((command & 4U) || (state.deviceStatus & (1U << 5))) {
191 return FlrResult::Busy;
194 const bool wrote = config.write16(state.offset + 8, state.deviceControl | 0x8000U);
197 const bool waited = wait(100);
198 if (!wrote || !waited) {
199 return FlrResult::Unverified;
202 uint16_t afterCommand = 0;
203 if (!config.read32(0, actual) || actual !=
identity || !config.read16(4, afterCommand) ||
204 (afterCommand & 4U)) {
205 return FlrResult::Unverified;
207 return FlrResult::Complete;