1 // Copyright 2016 The Fuchsia Authors 2 // Copyright (c) 2016, Google, Inc. All rights reserved 3 // 4 // Use of this source code is governed by a MIT-style 5 // license that can be found in the LICENSE file or at 6 // https://opensource.org/licenses/MIT 7 8 9 #pragma once 10 11 #include <assert.h> 12 #include <zircon/compiler.h> 13 #include <zircon/errors.h> 14 #include <dev/pcie_bus_driver.h> 15 #include <dev/pcie_caps.h> 16 #include <dev/pci_common.h> 17 #include <dev/pcie_irqs.h> 18 #include <dev/pcie_ref_counted.h> 19 #include <dev/pci_config.h> 20 #include <kernel/spinlock.h> 21 #include <fbl/algorithm.h> 22 #include <fbl/macros.h> 23 #include <fbl/mutex.h> 24 #include <fbl/ref_ptr.h> 25 #include <ktl/unique_ptr.h> 26 #include <sys/types.h> 27 28 /* Fwd decls */ 29 class PcieBusDriver; 30 class PcieUpstreamNode; 31 32 /* 33 * struct used to fetch information about a config 34 */ 35 struct pci_config_info_t { 36 uint64_t size = 0; 37 uint64_t base_addr = 0; 38 bool is_mmio; 39 }; 40 41 /* 42 * struct used to fetch information about a configured base address register 43 */ 44 struct pcie_bar_info_t { 45 uint64_t size = 0; 46 uint64_t bus_addr = 0; 47 bool is_mmio; 48 bool is_64bit; 49 bool is_prefetchable; 50 uint first_bar_reg; 51 RegionAllocator::Region::UPtr allocation; 52 }; 53 54 /* 55 * Base used to manage the relationship between a PCIe device/function and its 56 * associated driver. During a bus scan/probe operation, all drivers will have 57 * their registered probe methods called until a driver claims a device. A 58 * driver may claim a device by returning a pointer to a driver-managed 59 * pcie_device_state struct, with the driver owned fields filled out. 60 */ 61 class PcieDevice { 62 public: 63 using CapabilityList = fbl::SinglyLinkedList<ktl::unique_ptr<PciStdCapability>>; 64 static fbl::RefPtr<PcieDevice> Create(PcieUpstreamNode& upstream, uint dev_id, uint func_id); 65 virtual ~PcieDevice(); 66 67 // Disallow copying, assigning and moving. 68 DISALLOW_COPY_ASSIGN_AND_MOVE(PcieDevice); 69 70 // Require that derived classes implement ref counting. 71 PCIE_REQUIRE_REFCOUNTED; 72 73 fbl::RefPtr<PcieUpstreamNode> GetUpstream(); 74 75 zx_status_t Claim(); 76 void Unclaim(); 77 virtual void Unplug(); 78 79 /* 80 * Trigger a function level reset (if possible) 81 */ 82 zx_status_t DoFunctionLevelReset(); 83 84 /* 85 * Modify bits in the device's command register (in the device config space), 86 * clearing the bits specified by clr_bits and setting the bits specified by set 87 * bits. Specifically, the operation will be applied as... 88 * 89 * WR(cmd, (RD(cmd) & ~clr) | set) 90 * 91 * @param clr_bits The mask of bits to be cleared. 92 * @param clr_bits The mask of bits to be set. 93 * @return A zx_status_t indicating success or failure of the operation. 94 */ 95 zx_status_t ModifyCmd(uint16_t clr_bits, uint16_t set_bits); 96 97 /* 98 * Enable or disable bus mastering in a device's configuration. 99 * 100 * @param enable If true, allow the device to access main system memory as a bus 101 * master. 102 * @return A zx_status_t indicating success or failure of the operation. 103 */ EnableBusMaster(bool enabled)104 inline zx_status_t EnableBusMaster(bool enabled) { 105 if (enabled && disabled_) 106 return ZX_ERR_BAD_STATE; 107 108 return ModifyCmd(enabled ? 0 : PCI_COMMAND_BUS_MASTER_EN, 109 enabled ? PCI_COMMAND_BUS_MASTER_EN : 0); 110 } 111 112 /* 113 * Enable or disable PIO access in a device's configuration. 114 * 115 * @param enable If true, allow the device to access its PIO mapped registers. 116 * @return A zx_status_t indicating success or failure of the operation. 117 */ EnablePio(bool enabled)118 inline zx_status_t EnablePio(bool enabled) { 119 if (enabled && disabled_) 120 return ZX_ERR_BAD_STATE; 121 122 return ModifyCmd(enabled ? 0 : PCI_COMMAND_IO_EN, 123 enabled ? PCI_COMMAND_IO_EN : 0); 124 } 125 126 /* 127 * Enable or disable MMIO access in a device's configuration. 128 * 129 * @param enable If true, allow the device to access its MMIO mapped registers. 130 * @return A zx_status_t indicating success or failure of the operation. 131 */ EnableMmio(bool enabled)132 inline zx_status_t EnableMmio(bool enabled) { 133 if (enabled && disabled_) 134 return ZX_ERR_BAD_STATE; 135 136 return ModifyCmd(enabled ? 0 : PCI_COMMAND_MEM_EN, 137 enabled ? PCI_COMMAND_MEM_EN : 0); 138 } 139 140 141 /* 142 * Return information about the requested base address register, if it has been 143 * allocated. Otherwise, return NULL. 144 * 145 * @param bar_ndx The index of the BAR register to fetch info for. 146 * 147 * @return A pointer to the BAR info, including where in the bus address space 148 * the BAR window has been mapped, or NULL if the BAR window does not exist or 149 * has not been allocated. 150 */ GetBarInfo(uint bar_ndx)151 const pcie_bar_info_t* GetBarInfo(uint bar_ndx) const { 152 if (bar_ndx >= bar_count_) 153 return nullptr; 154 155 DEBUG_ASSERT(bar_ndx < fbl::count_of(bars_)); 156 157 const pcie_bar_info_t* ret = &bars_[bar_ndx]; 158 return (!disabled_ && (ret->allocation != nullptr)) ? ret : nullptr; 159 } 160 161 /** 162 * Query the number of IRQs which are supported for a given IRQ mode by a given 163 * device. 164 * 165 * @param mode The IRQ mode to query capabilities for. 166 * @param out_caps A pointer to structure which, upon success, will hold the 167 * capabilities of the selected IRQ mode. 168 * 169 * @return A zx_status_t indicating the success or failure of the operation. 170 */ 171 zx_status_t QueryIrqModeCapabilities(pcie_irq_mode_t mode, 172 pcie_irq_mode_caps_t* out_caps) const; 173 174 /** 175 * Fetch details about the currently configured IRQ mode. 176 * 177 * @param out_info A pointer to the structure which (upon success) will hold 178 * info about the currently configured IRQ mode. @see pcie_irq_mode_info_t for 179 * more details. 180 * 181 * @return A zx_status_t indicating the success or failure of the operation. 182 * Status codes may include (but are not limited to)... 183 * 184 * ++ ZX_ERR_UNAVAILABLE 185 * The device has become unplugged and is waiting to be released. 186 */ 187 zx_status_t GetIrqMode(pcie_irq_mode_info_t* out_info) const; 188 189 /** 190 * Configure the base IRQ mode, requesting a specific number of vectors and 191 * sharing mode in the process. 192 * 193 * Devices are not permitted to transition from an active mode (anything but 194 * DISABLED) to a different active mode. They must first transition to 195 * DISABLED, then request the new mode. 196 * 197 * Transitions to the DISABLED state will automatically mask and un-register all 198 * IRQ handlers, and return all allocated resources to the system pool. IRQ 199 * dispatch may continue to occur for unmasked IRQs during a transition to 200 * DISABLED, but is guaranteed not to occur after the call to pcie_set_irq_mode 201 * has completed. 202 * 203 * @param mode The requested mode. 204 * @param requested_irqs The number of individual IRQ vectors the device would 205 * like to use. 206 * 207 * @return A zx_status_t indicating the success or failure of the operation. 208 * Status codes may include (but are not limited to)... 209 * 210 * ++ ZX_ERR_UNAVAILABLE 211 * The device has become unplugged and is waiting to be released. 212 * ++ ZX_ERR_BAD_STATE 213 * The device cannot transition into the selected mode at this point in time 214 * due to the mode it is currently in. 215 * ++ ZX_ERR_NOT_SUPPORTED 216 * ++ The chosen mode is not supported by the device 217 * ++ The device supports the chosen mode, but does not support the number of 218 * IRQs requested. 219 * ++ ZX_ERR_NO_RESOURCES 220 * The system is unable to allocate sufficient system IRQs to satisfy the 221 * number of IRQs and exclusivity mode requested the device driver. 222 */ 223 zx_status_t SetIrqMode(pcie_irq_mode_t mode, uint requested_irqs); 224 225 /** 226 * Set the current IRQ mode to PCIE_IRQ_MODE_DISABLED 227 * 228 * Convenience function. @see SetIrqMode for details. 229 */ SetIrqModeDisabled()230 void SetIrqModeDisabled() { 231 /* It should be impossible to fail a transition to the DISABLED state, 232 * regardless of the state of the system. ASSERT this in debug builds */ 233 __UNUSED zx_status_t result; 234 235 result = SetIrqMode(PCIE_IRQ_MODE_DISABLED, 0); 236 237 DEBUG_ASSERT(result == ZX_OK); 238 } 239 240 /** 241 * Register an IRQ handler for the specified IRQ ID. 242 * 243 * @param irq_id The ID of the IRQ to register. 244 * @param handler A pointer to the handler function to call when the IRQ is 245 * received. Pass NULL to automatically mask the IRQ and unregister the 246 * handler. 247 * @param ctx A user supplied context pointer to pass to a registered handler. 248 * 249 * @return A zx_status_t indicating the success or failure of the operation. 250 * Status codes may include (but are not limited to)... 251 * 252 * ++ ZX_ERR_UNAVAILABLE 253 * The device has become unplugged and is waiting to be released. 254 * ++ ZX_ERR_BAD_STATE 255 * The device is in DISABLED IRQ mode. 256 * ++ ZX_ERR_INVALID_ARGS 257 * The irq_id parameter is out of range for the currently configured mode. 258 */ 259 zx_status_t RegisterIrqHandler(uint irq_id, pcie_irq_handler_fn_t handler, void* ctx); 260 261 /** 262 * Mask or unmask the specified IRQ for the given device. 263 * 264 * @param irq_id The ID of the IRQ to mask or unmask. 265 * @param mask If true, mask (disable) the IRQ. Otherwise, unmask it. 266 * 267 * @return A zx_status_t indicating the success or failure of the operation. 268 * Status codes may include (but are not limited to)... 269 * 270 * ++ ZX_ERR_UNAVAILABLE 271 * The device has become unplugged and is waiting to be released. 272 * ++ ZX_ERR_BAD_STATE 273 * Attempting to mask or unmask an IRQ while in the DISABLED mode or with no 274 * handler registered. 275 * ++ ZX_ERR_INVALID_ARGS 276 * The irq_id parameter is out of range for the currently configured mode. 277 * ++ ZX_ERR_NOT_SUPPORTED 278 * The device is operating in MSI mode, but neither the PCI device nor the 279 * platform interrupt controller support masking the MSI vector. 280 */ 281 zx_status_t MaskUnmaskIrq(uint irq_id, bool mask); 282 SetQuirksDone()283 void SetQuirksDone() { quirks_done_ = true; } 284 285 /** 286 * Convenience functions. @see MaskUnmaskIrq for details. 287 */ MaskIrq(uint irq_id)288 zx_status_t MaskIrq(uint irq_id) { return MaskUnmaskIrq(irq_id, true); } UnmaskIrq(uint irq_id)289 zx_status_t UnmaskIrq(uint irq_id) { return MaskUnmaskIrq(irq_id, false); } 290 config()291 const PciConfig* config() const { return cfg_; } config_phys()292 paddr_t config_phys() const { return cfg_phys_; } driver()293 PcieBusDriver& driver() { return bus_drv_; } 294 plugged_in()295 bool plugged_in() const { return plugged_in_; } disabled()296 bool disabled() const { return disabled_; } quirks_done()297 bool quirks_done() const { return quirks_done_; } 298 is_bridge()299 bool is_bridge() const { return is_bridge_; } is_pcie()300 bool is_pcie() const { return (pcie_ != nullptr); } vendor_id()301 uint16_t vendor_id() const { return vendor_id_; } device_id()302 uint16_t device_id() const { return device_id_; } class_id()303 uint8_t class_id() const { return class_id_; } subclass()304 uint8_t subclass() const { return subclass_; } prog_if()305 uint8_t prog_if() const { return prog_if_; } rev_id()306 uint8_t rev_id() const { return rev_id_; } bus_id()307 uint bus_id() const { return bus_id_; } dev_id()308 uint dev_id() const { return dev_id_; } func_id()309 uint func_id() const { return func_id_; } bar_count()310 uint bar_count() const { return bar_count_; } legacy_irq_pin()311 uint8_t legacy_irq_pin() const { return irq_.legacy.pin; } capabilities()312 const CapabilityList& capabilities() const { return caps_.detected; } 313 // TODO(cja): This doesn't really make sense in a pcie capability optional world. 314 // It is only used by bridge and debug code, so it might make sense to just have those check if 315 // the device is pcie first, then use dev->pcie()->devtype(). pcie_device_type()316 pcie_device_type_t pcie_device_type() const { 317 if (pcie_) 318 return pcie_->devtype(); 319 else 320 return PCIE_DEVTYPE_UNKNOWN; 321 } 322 323 // TODO(johngro) : make these protected. They are currently only visible 324 // because of debug code. dev_lock()325 fbl::Mutex* dev_lock() { return &dev_lock_; } 326 327 // Dump some information about the device 328 virtual void Dump() const; 329 330 protected: 331 friend class PcieUpstreamNode; 332 friend class PcieBusDriver; // TODO(johngro): remove this. Currently used for IRQ swizzle. 333 PcieDevice(PcieBusDriver& bus_drv, uint bus_id, uint dev_id, uint func_id, bool is_bridge); 334 335 void ModifyCmdLocked(uint16_t clr_bits, uint16_t set_bits); AssignCmdLocked(uint16_t value)336 void AssignCmdLocked(uint16_t value) { ModifyCmdLocked(0xFFFF, value); } 337 338 // Initialization and probing. 339 zx_status_t Init(PcieUpstreamNode& upstream); 340 zx_status_t InitLocked(PcieUpstreamNode& upstream); 341 zx_status_t ProbeBarsLocked(); 342 zx_status_t ProbeBarLocked(uint bar_id); 343 zx_status_t ProbeCapabilitiesLocked(); 344 zx_status_t ParseStdCapabilitiesLocked(); 345 zx_status_t ParseExtCapabilitiesLocked(); 346 zx_status_t MapPinToIrqLocked(fbl::RefPtr<PcieUpstreamNode>&& upstream); 347 zx_status_t InitLegacyIrqStateLocked(PcieUpstreamNode& upstream); 348 349 // BAR allocation 350 virtual zx_status_t AllocateBars(); 351 zx_status_t AllocateBarsLocked(); 352 zx_status_t AllocateBarLocked(pcie_bar_info_t& info); 353 354 // Disable a device, and anything downstream of it. The device will 355 // continue to enumerate, but users will only be able to access config (and 356 // only in a read only fashion). BAR windows, bus mastering, and interrupts 357 // will all be disabled. 358 virtual void Disable(); 359 void DisableLocked(); 360 361 PcieBusDriver& bus_drv_; // Reference to our bus driver state. 362 const PciConfig* cfg_ = nullptr; // Pointer to the memory mapped ECAM (kernel vaddr) 363 paddr_t cfg_phys_ = 0; // The physical address of the device's ECAM 364 SpinLock cmd_reg_lock_; // Protection for access to the command register. 365 const bool is_bridge_; // True if this device is also a bridge 366 const uint bus_id_; // The bus ID this bridge/device exists on 367 const uint dev_id_; // The device ID of this bridge/device 368 const uint func_id_; // The function ID of this bridge/device 369 uint16_t vendor_id_; // The device's vendor ID, as read from config 370 uint16_t device_id_; // The device's device ID, as read from config 371 uint8_t class_id_; // The device's class ID, as read from config. 372 uint8_t subclass_; // The device's subclass, as read from config. 373 uint8_t prog_if_; // The device's programming interface (from cfg) 374 uint8_t rev_id_; // The device's revision ID (from cfg) 375 376 fbl::RefPtr<PcieUpstreamNode> upstream_; // The upstream node in the device graph. 377 378 /* State related to lifetime management */ 379 mutable fbl::Mutex dev_lock_; 380 bool plugged_in_ = false; 381 bool disabled_ = false; 382 bool quirks_done_ = false; 383 384 /* Info about the BARs computed and cached during the initial setup/probe, 385 * indexed by starting BAR register index */ 386 pcie_bar_info_t bars_[PCIE_MAX_BAR_REGS]; 387 const uint bar_count_; 388 389 private: 390 friend class SharedLegacyIrqHandler; 391 392 // Top level internal IRQ support. 393 zx_status_t QueryIrqModeCapabilitiesLocked(pcie_irq_mode_t mode, 394 pcie_irq_mode_caps_t* out_caps) const; 395 zx_status_t GetIrqModeLocked(pcie_irq_mode_info_t* out_info) const; 396 zx_status_t SetIrqModeLocked(pcie_irq_mode_t mode, uint requested_irqs); 397 zx_status_t RegisterIrqHandlerLocked(uint irq_id, pcie_irq_handler_fn_t handler, void* ctx); 398 zx_status_t MaskUnmaskIrqLocked(uint irq_id, bool mask); 399 400 // Internal Legacy IRQ support. 401 zx_status_t MaskUnmaskLegacyIrq(bool mask); 402 zx_status_t EnterLegacyIrqMode(uint requested_irqs); 403 void LeaveLegacyIrqMode(); 404 405 // Internal MSI IRQ support. SetMsiEnb(bool enb)406 void SetMsiEnb(bool enb) { 407 DEBUG_ASSERT(irq_.msi); 408 DEBUG_ASSERT(irq_.msi->is_valid()); 409 cfg_->Write(irq_.msi->ctrl_reg(), 410 PCIE_CAP_MSI_CTRL_SET_ENB(enb, cfg_->Read(irq_.msi->ctrl_reg()))); 411 } 412 413 bool MaskUnmaskMsiIrqLocked(uint irq_id, bool mask); 414 zx_status_t MaskUnmaskMsiIrq(uint irq_id, bool mask); 415 void MaskAllMsiVectors(); 416 void SetMsiTarget(uint64_t tgt_addr, uint32_t tgt_data); 417 void FreeMsiBlock(); 418 void SetMsiMultiMessageEnb(uint requested_irqs); 419 void LeaveMsiIrqMode(); 420 zx_status_t EnterMsiIrqMode(uint requested_irqs); 421 422 void MsiIrqHandler(pcie_irq_handler_state_t& hstate); 423 static interrupt_eoi MsiIrqHandlerThunk(void *arg); 424 425 // Common Internal IRQ support. 426 void ResetCommonIrqBookkeeping(); 427 zx_status_t AllocIrqHandlers(uint requested_irqs, bool is_masked); 428 429 /* Capabilities */ 430 // TODO(cja): organize capabilities into their own structure 431 struct Capabilities { 432 CapabilityList detected; 433 } caps_; 434 /* PCI Express Capabilities (Standard Capability 0x10) if present */ 435 PciCapPcie* pcie_ = nullptr; 436 /* PCI Advanced Capabilities (Standard Capability 0x13) if present */ 437 PciCapAdvFeatures* pci_af_ = nullptr; 438 439 // IRQ configuration and handling state 440 struct { 441 /* Shared state */ 442 pcie_irq_mode_t mode = PCIE_IRQ_MODE_DISABLED; 443 pcie_irq_handler_state_t singleton_handler; 444 pcie_irq_handler_state_t* handlers = nullptr; 445 uint handler_count = 0; 446 uint registered_handler_count = 0; 447 448 /* Legacy IRQ state */ 449 struct { 450 // TODO(johngro): clean up the messy list_node initialization below 451 // by converting to fbl intrusive lists. 452 uint8_t pin = 0; 453 uint irq_id = static_cast<uint>(-1); 454 struct list_node shared_handler_node = { nullptr, nullptr}; 455 fbl::RefPtr<SharedLegacyIrqHandler> shared_handler; 456 } legacy; 457 458 PciCapMsi* msi = nullptr; 459 /* TODO(johngro) : Add MSI-X state */ 460 struct { } msi_x; 461 } irq_; 462 }; 463