1 /*
2 * Copyright (c) 2009 Corey Tabaka
3 * Copyright (c) 2020 Travis Geiseblrecht
4 *
5 * Use of this source code is governed by a MIT-style
6 * license that can be found in the LICENSE file or at
7 * https://opensource.org/licenses/MIT
8 */
9 #pragma once
10
11 #include <assert.h>
12 #include <sys/types.h>
13 #include <lk/compiler.h>
14
15 // pci level structures and defines
16 #include <hw/pci.h>
17
18 __BEGIN_CDECLS
19
20 /*
21 * PCI address structure
22 */
23 typedef struct {
24 uint16_t segment;
25 uint8_t bus;
26 uint8_t dev;
27 uint8_t fn;
28 } pci_location_t;
29
30 typedef struct {
31 uint64_t addr;
32 size_t size;
33 bool io;
34 bool prefetchable;
35 bool size_64;
36 bool valid;
37 } pci_bar_t;
38
39 // only use one of these two:
40 // try to detect PCI based on legacy PC PCI accessor methods
41 status_t pci_init_legacy(void);
42
43 // try to detect PCI based on a known ecam base.
44 status_t pci_init_ecam(paddr_t ecam_base, uint16_t segment, uint8_t start_bus, uint8_t end_bus);
45
46 // user facing C api
47 int pci_get_last_bus(void);
48 int pci_get_last_segment(void);
49
50 status_t pci_read_config(pci_location_t loc, pci_config_t *config);
51
52 status_t pci_read_config_byte(pci_location_t state, uint32_t reg, uint8_t *value);
53 status_t pci_read_config_half(pci_location_t state, uint32_t reg, uint16_t *value);
54 status_t pci_read_config_word(pci_location_t state, uint32_t reg, uint32_t *value);
55
56 status_t pci_write_config_byte(pci_location_t state, uint32_t reg, uint8_t value);
57 status_t pci_write_config_half(pci_location_t state, uint32_t reg, uint16_t value);
58 status_t pci_write_config_word(pci_location_t state, uint32_t reg, uint32_t value);
59
60 // pci bus manager
61 // builds a list of devices and allows for various operations on the list
62
63 // C level visitor routine
64 typedef void(*pci_visit_routine)(pci_location_t loc, void *cookie);
65 status_t pci_bus_mgr_visit_devices(pci_visit_routine routine, void *cookie);
66
67 // must be called before pci_bus_mgr_init if available
68 enum pci_resource_type {
69 PCI_RESOURCE_IO_RANGE = 0,
70 PCI_RESOURCE_MMIO_RANGE,
71 PCI_RESOURCE_MMIO64_RANGE,
72 };
73 status_t pci_bus_mgr_add_resource(enum pci_resource_type, uint64_t mmio_base, uint64_t len);
74
75 status_t pci_bus_mgr_assign_resources(void);
76
77 // must be called after pci_init_*();
78 status_t pci_bus_mgr_init(void);
79
80 // Look for the Nth match of device id and vendor id.
81 // Either device or vendor is skipped if set to 0xffff.
82 // Error if both is set to 0xffff.
83 status_t pci_bus_mgr_find_device(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, size_t index);
84
85 // Look for the Nth match of combination of base, subclass, and interface.
86 // interface and subclass may be set to 0xff in which case it will skip.
87 status_t pci_bus_mgr_find_device_by_class(pci_location_t *state, uint8_t base_class, uint8_t subclass, uint8_t interface, size_t index);
88
89 // set io and mem enable on the device
90 status_t pci_bus_mgr_enable_device(const pci_location_t loc);
91
92 // read a list of up to 6 bars out of the device. each is marked with a valid bit
93 status_t pci_bus_mgr_read_bars(const pci_location_t loc, pci_bar_t bar[6]);
94
95 // try to allocate one or more msi vectors for this device
96 status_t pci_bus_mgr_allocate_msi(const pci_location_t loc, size_t num_requested, uint *irqbase);
97
98 // allocate a regular irq for this device and return it in irqbase
99 status_t pci_bus_mgr_allocate_irq(const pci_location_t loc, uint *irqbase);
100
101 // return a pointer to a formatted string
102 const char *pci_loc_string(pci_location_t loc, char out_str[14]);
103
104 // debug printing routines
105 void pci_dump_bar(const pci_bar_t *bar, int index);
106 void pci_dump_bars(pci_bar_t bar[6], size_t count);
107 const char *pci_resource_type_to_str(enum pci_resource_type);
108
109 __END_CDECLS
110
111 #if __cplusplus
112
113 // C++ helper routine for pci_bus_mgr_visit_devices
114 // Wrapper to convert lambdas and other function like things to the C api
115 template <typename T>
pci_bus_mgr_visit_devices(T routine)116 void pci_bus_mgr_visit_devices(T routine) {
117 struct vdata {
118 T &routine;
119 };
120
121 auto v = [](pci_location_t loc, void *cookie) {
122 vdata *data = static_cast<vdata *>(cookie);
123 data->routine(loc);
124 };
125
126 vdata data = { routine };
127 pci_bus_mgr_visit_devices(v, &data);
128 }
129
130 inline bool operator==(pci_location_t a, pci_location_t b) {
131 return a.segment == b.segment &&
132 a.bus == b.bus &&
133 a.dev == b.dev &&
134 a.fn == b.fn;
135 }
136
137 #endif // __cplusplus
138
139