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