1 // Copyright 2017 The Fuchsia Authors 2 // 3 // Use of this source code is governed by a MIT-style 4 // license that can be found in the LICENSE file or at 5 // https://opensource.org/licenses/MIT 6 7 #pragma once 8 9 #include <debug.h> 10 #include <endian.h> 11 #include <fbl/ref_ptr.h> 12 #include <fbl/ref_counted.h> 13 #include <fbl/intrusive_single_list.h> 14 #include <dev/pci_common.h> 15 16 class PciReg8 { 17 public: PciReg8(uint16_t offset)18 constexpr explicit PciReg8(uint16_t offset) 19 : offset_(offset) {} PciReg8()20 constexpr PciReg8() 21 : offset_(0u) {} offset()22 constexpr uint16_t offset() const { return offset_; } 23 24 private: 25 uint16_t offset_; 26 }; 27 28 class PciReg16 { 29 public: PciReg16(uint16_t offset)30 constexpr explicit PciReg16(uint16_t offset) 31 : offset_(offset) {}; PciReg16()32 constexpr PciReg16() 33 : offset_(0u) {} offset()34 constexpr uint16_t offset() const { return offset_; } 35 36 private: 37 uint16_t offset_; 38 }; 39 40 class PciReg32 { 41 public: PciReg32(uint16_t offset)42 constexpr explicit PciReg32(uint16_t offset) 43 : offset_(offset) {}; PciReg32()44 constexpr PciReg32() 45 : offset_(0u) {} offset()46 constexpr uint16_t offset() const { return offset_; } 47 48 private: 49 uint16_t offset_; 50 }; 51 52 /* PciConfig supplies the factory for creating the appropriate pci config 53 * object based on the address space of the pci device. */ 54 class PciConfig : public fbl::SinglyLinkedListable<fbl::RefPtr<PciConfig>> 55 , public fbl::RefCounted<PciConfig> { 56 public: 57 // Standard PCI configuration space values. Offsets from PCI Firmware Spec ch 6. 58 static constexpr PciReg16 kVendorId = PciReg16(0x0); 59 static constexpr PciReg16 kDeviceId = PciReg16(0x2); 60 static constexpr PciReg16 kCommand = PciReg16(0x4); 61 static constexpr PciReg16 kStatus = PciReg16(0x6); 62 static constexpr PciReg8 kRevisionId = PciReg8(0x8); 63 static constexpr PciReg8 kProgramInterface = PciReg8(0x9); 64 static constexpr PciReg8 kSubClass = PciReg8(0xA); 65 static constexpr PciReg8 kBaseClass = PciReg8(0xB); 66 static constexpr PciReg8 kCacheLineSize = PciReg8(0xC); 67 static constexpr PciReg8 kLatencyTimer = PciReg8(0xD); 68 static constexpr PciReg8 kHeaderType = PciReg8(0xE); 69 static constexpr PciReg8 kBist = PciReg8(0xF); 70 /* 0x10 is the address of the first BAR in config space 71 * BAR rather than BaseAddress for space / sanity considerations */ kBAR(uint bar)72 static constexpr PciReg32 kBAR(uint bar) { 73 DEBUG_ASSERT(bar < PCIE_MAX_BAR_REGS); 74 return PciReg32(static_cast<uint16_t>(0x10 + (bar * sizeof(uint32_t)))); 75 } 76 static constexpr PciReg32 kCardbusCisPtr = PciReg32(0x28); 77 static constexpr PciReg16 kSubsystemVendorId = PciReg16(0x2C); 78 static constexpr PciReg16 kSubsystemId = PciReg16(0x2E); 79 static constexpr PciReg32 kExpansionRomAddress = PciReg32(0x30); 80 static constexpr PciReg8 kCapabilitiesPtr = PciReg8(0x34); 81 // 0x35 through 0x3B is reserved 82 static constexpr PciReg8 kInterruptLine = PciReg8(0x3C); 83 static constexpr PciReg8 kInterruptPin = PciReg8(0x3D); 84 static constexpr PciReg8 kMinGrant = PciReg8(0x3E); 85 static constexpr PciReg8 kMaxLatency = PciReg8(0x3F); 86 static constexpr uint8_t kStdCfgEnd = static_cast<uint8_t>(kMaxLatency.offset() + sizeof(uint8_t)); 87 88 /* pci to pci bridge config 89 * Unlike a normal PCI header, a bridge only has two BARs, but the BAR offset in config space 90 * is the same. */ 91 static constexpr PciReg8 kPrimaryBusId = PciReg8(0x18); 92 static constexpr PciReg8 kSecondaryBusId = PciReg8(0x19); 93 static constexpr PciReg8 kSubordinateBusId = PciReg8(0x1A); 94 static constexpr PciReg8 kSecondaryLatencyTimer = PciReg8(0x1B); 95 static constexpr PciReg8 kIoBase = PciReg8(0x1C); 96 static constexpr PciReg8 kIoLimit = PciReg8(0x1D); 97 static constexpr PciReg16 kSecondaryStatus = PciReg16(0x1E); 98 static constexpr PciReg16 kMemoryBase = PciReg16(0x20); 99 static constexpr PciReg16 kMemoryLimit = PciReg16(0x22); 100 static constexpr PciReg16 kPrefetchableMemoryBase = PciReg16(0x24); 101 static constexpr PciReg16 kPrefetchableMemoryLimit = PciReg16(0x26); 102 static constexpr PciReg32 kPrefetchableMemoryBaseUpper = PciReg32(0x28); 103 static constexpr PciReg32 kPrefetchableMemoryLimitUpper = PciReg32(0x2C); 104 static constexpr PciReg16 kIoBaseUpper = PciReg16(0x30); 105 static constexpr PciReg16 kIoLimitUpper = PciReg16(0x32); 106 // Capabilities Pointer for a bridge matches the standard 0x34 offset 107 // 0x35 through 0x38 is reserved 108 static constexpr PciReg32 kBridgeExpansionRomAddress = PciReg32(0x38); 109 // interrupt line for a bridge matches the standard 0x3C offset 110 // interrupt pin for a bridge matches the standard 0x3D offset 111 static constexpr PciReg16 kBridgeControl = PciReg16(0x3E); 112 113 /** Create a Pci Configuration object of the appropriate type. 114 * 115 * @param base The base address for the PCI configuration space. @param 116 * @param addr_type An enum value of PciAddrSpace to identify the time of address 117 * space the configuration object will use. 118 * 119 * @return a pointer to a new PciConfig instance on success, nullptr on failure. 120 */ 121 static fbl::RefPtr<PciConfig> Create(uintptr_t base, PciAddrSpace addr_type); base()122 inline uintptr_t base() const { return base_; } addr_space()123 inline PciAddrSpace addr_space() const { return addr_space_; } 124 125 // Virtuals 126 void DumpConfig(uint16_t len) const; 127 virtual uint8_t Read(const PciReg8 addr) const = 0; 128 virtual uint16_t Read(const PciReg16 addr) const = 0; 129 virtual uint32_t Read(const PciReg32 addr) const = 0; 130 virtual void Write(const PciReg8 addr, uint8_t val) const = 0; 131 virtual void Write(const PciReg16 addr, uint16_t val) const = 0; 132 virtual void Write(const PciReg32 addr, uint32_t val) const = 0; ~PciConfig()133 virtual ~PciConfig(){}; 134 135 protected: PciConfig(uintptr_t base,PciAddrSpace addr_space)136 PciConfig(uintptr_t base, PciAddrSpace addr_space) 137 : addr_space_(addr_space), base_(base) {} 138 const PciAddrSpace addr_space_; 139 const uintptr_t base_; 140 }; 141