1 /* 2 * Copyright (c) 2021 Travis Geiseblrecht 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 #pragma once 9 10 #include <sys/types.h> 11 #include <dev/bus/pci.h> 12 #include <lk/cpp.h> 13 #include <lk/err.h> 14 #include <lk/list.h> 15 16 namespace pci { 17 18 class bus; 19 struct capability; 20 21 // generic pci device 22 class device { 23 public: 24 device(pci_location_t loc, bus *bus); 25 virtual ~device(); 26 27 DISALLOW_COPY_ASSIGN_AND_MOVE(device); 28 29 static status_t probe(pci_location_t loc, bus *bus, device **out_device); 30 31 status_t probe_capabilities(); 32 status_t init_msi_capability(capability *cap); 33 status_t init_msix_capability(capability *cap); 34 35 status_t allocate_irq(uint *irq); 36 status_t allocate_msi(size_t num_requested, uint *msi_base); 37 status_t load_config(); 38 status_t load_bars(); 39 40 status_t enable(); 41 42 // ask the device to add up the sizes of all its bars and return the sum 43 // bridges will be expected to recurse into sub-bridges 44 struct bar_sizes { 45 uint32_t io_size; 46 uint32_t mmio_size; 47 uint64_t mmio64_size; 48 uint64_t prefetchable_size; 49 uint64_t prefetchable64_size; 50 51 uint8_t io_align; 52 uint8_t mmio_align; 53 uint8_t mmio64_align; 54 uint8_t prefetchable_align; 55 uint8_t prefetchable64_align; 56 57 bar_sizes &operator+=(const bar_sizes &a); 58 }; 59 virtual status_t compute_bar_sizes(bar_sizes *sizes); 60 61 struct bar_alloc_request { 62 // linked list node 63 list_node node; 64 65 // requst for allocation of this type 66 pci_resource_type type; 67 uint64_t size; 68 uint8_t align; // power of 2 69 70 bool bridge; // either a bridge request or a bar 71 bool prefetchable; // prefetchable request (only makes sense for mmio or mmio64) 72 73 device *dev; 74 uint8_t bar_num; 75 76 void dump(); 77 }; 78 virtual status_t get_bar_alloc_requests(list_node *bar_alloc_requests); 79 virtual status_t assign_resource(bar_alloc_request *request, uint64_t address); assign_child_resources()80 virtual status_t assign_child_resources() { return NO_ERROR; } 81 loc()82 pci_location_t loc() const { return loc_; } get_bus()83 const bus *get_bus() const { return bus_; } 84 device_id()85 uint16_t device_id() const { return config_.device_id; } vendor_id()86 uint16_t vendor_id() const { return config_.vendor_id; } base_class()87 uint8_t base_class() const { return config_.base_class; } sub_class()88 uint8_t sub_class() const { return config_.sub_class; } interface()89 uint8_t interface() const { return config_.program_interface; } header_type()90 uint8_t header_type() const { return config_.header_type & PCI_HEADER_TYPE_MASK; } 91 92 status_t read_bars(pci_bar_t bar[6]); 93 has_msi()94 bool has_msi() const { return msi_cap_; } has_msix()95 bool has_msix() const { return msix_cap_; } 96 97 virtual void dump(size_t indent = 0); 98 99 protected: 100 // let the bus device directly manipulate our list node 101 friend class bus; 102 list_node node = LIST_INITIAL_CLEARED_VALUE; 103 104 pci_location_t loc_ = {}; 105 bus *bus_ = nullptr; 106 107 pci_config_t config_ = {}; 108 pci_bar_t bars_[6] = {}; 109 110 // capability list 111 list_node capability_list_ = LIST_INITIAL_VALUE(capability_list_); 112 capability *msi_cap_ = nullptr; 113 capability *msix_cap_ = nullptr; 114 }; 115 116 struct capability { 117 list_node node = LIST_INITIAL_CLEARED_VALUE; 118 uint16_t config_offset = 0; 119 uint16_t id = 0; 120 121 // simple accessors is_msicapability122 bool is_msi() const { return id == 0x5; } is_msixcapability123 bool is_msix() const { return id == 0x11; } 124 }; 125 126 inline device::bar_sizes operator+(const device::bar_sizes &a, const device::bar_sizes &b) { 127 device::bar_sizes result; 128 129 result.io_size = a.io_size + b.io_size; 130 result.mmio_size = a.mmio_size + b.mmio_size; 131 result.mmio64_size = a.mmio64_size + b.mmio64_size; 132 result.prefetchable_size = a.prefetchable_size + b.prefetchable_size; 133 result.prefetchable64_size = a.prefetchable64_size + b.prefetchable64_size; 134 135 result.io_align = (a.io_align > b.io_align) ? a.io_align : b.io_align; 136 result.mmio_align = (a.mmio_align > b.mmio_align) ? a.mmio_align : b.mmio_align; 137 result.mmio64_align = (a.mmio64_align > b.mmio64_align) ? a.mmio64_align : b.mmio64_align; 138 result.prefetchable_align = (a.prefetchable_align > b.prefetchable_align) ? a.prefetchable_align : b.prefetchable_align; 139 result.prefetchable64_align = (a.prefetchable64_align > b.prefetchable64_align) ? a.prefetchable64_align : b.prefetchable64_align; 140 141 return result; 142 } 143 144 inline device::bar_sizes &device::bar_sizes::operator+=(const device::bar_sizes &a) { 145 io_size += a.io_size; 146 mmio_size += a.mmio_size; 147 mmio64_size += a.mmio64_size; 148 prefetchable_size += a.prefetchable_size; 149 prefetchable64_size += a.prefetchable64_size; 150 151 io_align = (io_align > a.io_align) ? io_align : a.io_align; 152 mmio_align = (mmio_align > a.mmio_align) ? mmio_align : a.mmio_align; 153 mmio64_align = (mmio64_align > a.mmio64_align) ? mmio64_align : a.mmio64_align; 154 prefetchable_align = (prefetchable_align > a.prefetchable_align) ? prefetchable_align : a.prefetchable_align; 155 prefetchable64_align = (prefetchable64_align > a.prefetchable64_align) ? prefetchable64_align : a.prefetchable64_align; 156 157 return *this; 158 } 159 160 } // pci 161