1 /*
2 * Copyright (c) 2009 Corey Tabaka
3 * Copyright (c) 2020 Travis Geiselbrecht
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 #include <dev/bus/pci.h>
10
11 #include <lk/debug.h>
12 #include <lk/err.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <kernel/thread.h>
16 #include <kernel/spinlock.h>
17 #include <lk/trace.h>
18
19 #include "pci_priv.h"
20
21 #define LOCAL_TRACE 0
22
23 // Largely C level api for the PCI bus manager
24
25 namespace {
26 SpinLock lock;
27 pci_backend *pcib = nullptr;
28 } // namespace
29
pci_get_last_bus()30 int pci_get_last_bus() {
31 if (!pcib) {
32 return ERR_NOT_CONFIGURED;
33 }
34
35 return pcib->get_last_bus();
36 }
37
38 /* user facing routines */
pci_find_pci_device(pci_location_t * state,uint16_t device_id,uint16_t vendor_id,uint16_t index)39 status_t pci_find_pci_device(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index) {
40 LTRACEF("device_id dev %#hx vendor %#hx index %#hx\n", device_id, vendor_id, index);
41
42 if (!pcib) return ERR_NOT_CONFIGURED;
43
44 AutoSpinLock guard(&lock);
45
46 int res = pcib->find_pci_device(state, device_id, vendor_id, index);
47
48 return res;
49 }
50
pci_find_pci_class_code(pci_location_t * state,uint32_t class_code,uint16_t index)51 status_t pci_find_pci_class_code(pci_location_t *state, uint32_t class_code, uint16_t index) {
52 LTRACEF("device_id class %#x index %#hx\n", class_code, index);
53
54 if (!pcib) return ERR_NOT_CONFIGURED;
55
56 AutoSpinLock guard(&lock);
57
58 int res = pcib->find_pci_class_code(state, class_code, index);
59
60 return res;
61 }
62
pci_read_config_byte(const pci_location_t * state,uint32_t reg,uint8_t * value)63 status_t pci_read_config_byte(const pci_location_t *state, uint32_t reg, uint8_t *value) {
64 if (!pcib) return ERR_NOT_CONFIGURED;
65
66 AutoSpinLock guard(&lock);
67
68 int res = pcib->read_config_byte(state, reg, value);
69
70 return res;
71 }
pci_read_config_half(const pci_location_t * state,uint32_t reg,uint16_t * value)72 status_t pci_read_config_half(const pci_location_t *state, uint32_t reg, uint16_t *value) {
73 if (!pcib) return ERR_NOT_CONFIGURED;
74
75 AutoSpinLock guard(&lock);
76
77 int res = pcib->read_config_half(state, reg, value);
78
79 return res;
80 }
81
pci_read_config_word(const pci_location_t * state,uint32_t reg,uint32_t * value)82 status_t pci_read_config_word(const pci_location_t *state, uint32_t reg, uint32_t *value) {
83 if (!pcib) return ERR_NOT_CONFIGURED;
84
85 AutoSpinLock guard(&lock);
86
87 int res = pcib->read_config_word(state, reg, value);
88
89 return res;
90 }
91
pci_write_config_byte(const pci_location_t * state,uint32_t reg,uint8_t value)92 status_t pci_write_config_byte(const pci_location_t *state, uint32_t reg, uint8_t value) {
93 if (!pcib) return ERR_NOT_CONFIGURED;
94
95 AutoSpinLock guard(&lock);
96
97 int res = pcib->write_config_byte(state, reg, value);
98
99 return res;
100 }
101
pci_write_config_half(const pci_location_t * state,uint32_t reg,uint16_t value)102 status_t pci_write_config_half(const pci_location_t *state, uint32_t reg, uint16_t value) {
103 if (!pcib) return ERR_NOT_CONFIGURED;
104
105 AutoSpinLock guard(&lock);
106
107 int res = pcib->write_config_half(state, reg, value);
108
109 return res;
110 }
111
pci_write_config_word(const pci_location_t * state,uint32_t reg,uint32_t value)112 status_t pci_write_config_word(const pci_location_t *state, uint32_t reg, uint32_t value) {
113 if (!pcib) return ERR_NOT_CONFIGURED;
114
115 AutoSpinLock guard(&lock);
116
117 int res = pcib->write_config_word(state, reg, value);
118
119 return res;
120 }
121
pci_get_irq_routing_options(irq_routing_entry * entries,uint16_t * count,uint16_t * pci_irqs)122 status_t pci_get_irq_routing_options(irq_routing_entry *entries, uint16_t *count, uint16_t *pci_irqs) {
123 if (!pcib) return ERR_NOT_CONFIGURED;
124
125 // TODO: highly bios32 specific, abstract this differently
126 pci_backend::irq_routing_options_t options;
127 options.size = sizeof(irq_routing_entry) * *count;
128 options.selector = 0x10; // XXX actually DATA_SELECTOR
129 options.offset = entries;
130
131 int res;
132 {
133 AutoSpinLock guard(&lock);
134
135 res = pcib->get_irq_routing_options(&options, pci_irqs);
136 }
137
138 *count = options.size / sizeof(irq_routing_entry);
139
140 return res;
141 }
142
pci_set_irq_hw_int(const pci_location_t * state,uint8_t int_pin,uint8_t irq)143 status_t pci_set_irq_hw_int(const pci_location_t *state, uint8_t int_pin, uint8_t irq) {
144 if (!pcib) return ERR_NOT_CONFIGURED;
145
146 AutoSpinLock guard(&lock);
147
148 int res = pcib->set_irq_hw_int(state, int_pin, irq);
149
150 return res;
151 }
152
pci_init_legacy()153 status_t pci_init_legacy() {
154 LTRACE_ENTRY;
155
156 DEBUG_ASSERT(pcib == nullptr);
157
158 // try a series of detection mechanisms based on legacy PCI access on x86 PCs
159
160 // try to BIOS32 access first, if present
161 if ((pcib = pci_bios32::detect())) {
162 dprintf(INFO, "PCI: pci bios functions installed\n");
163 dprintf(INFO, "PCI: last pci bus is %d\n", pcib->get_last_bus());
164 return NO_ERROR;
165 }
166
167 // try type 1 access
168 if ((pcib = pci_type1::detect())) {
169 dprintf(INFO, "PCI: pci type1 functions installed\n");
170 dprintf(INFO, "PCI: last pci bus is %d\n", pcib->get_last_bus());
171 return NO_ERROR;
172 }
173
174 // if we couldn't find anything, leave pcib null
175 return ERR_NOT_FOUND;
176 }
177
pci_init_ecam(paddr_t ecam_base,uint16_t segment,uint8_t start_bus,uint8_t end_bus)178 status_t pci_init_ecam(paddr_t ecam_base, uint16_t segment, uint8_t start_bus, uint8_t end_bus) {
179 LTRACEF("base %#lx, segment %hu, bus [%hhu...%hhu]\n", ecam_base, segment, start_bus, end_bus);
180
181 DEBUG_ASSERT(pcib == nullptr);
182
183 if ((pcib = pci_ecam::detect(ecam_base, segment, start_bus, end_bus))) {
184 dprintf(INFO, "PCI: pci ecam functions installed\n");
185 dprintf(INFO, "PCI: last pci bus is %d\n", pcib->get_last_bus());
186 return NO_ERROR;
187 }
188
189 // if we couldn't find anything, leave pcib null
190 return ERR_NOT_FOUND;
191 }
192
193