1
2
3
4
5
6
7
8#include <acpi/acpi.h>
9#include "accommon.h"
10
11#define _COMPONENT ACPI_NAMESPACE
12ACPI_MODULE_NAME("hwpci")
13
14
15#define PCI_CFG_HEADER_TYPE_REG 0x0E
16#define PCI_CFG_PRIMARY_BUS_NUMBER_REG 0x18
17#define PCI_CFG_SECONDARY_BUS_NUMBER_REG 0x19
18
19#define PCI_HEADER_TYPE_MASK 0x7F
20#define PCI_TYPE_BRIDGE 0x01
21#define PCI_TYPE_CARDBUS_BRIDGE 0x02
22typedef struct acpi_pci_device {
23 acpi_handle device;
24 struct acpi_pci_device *next;
25
26} acpi_pci_device;
27
28
29
30static acpi_status
31acpi_hw_build_pci_list(acpi_handle root_pci_device,
32 acpi_handle pci_region,
33 struct acpi_pci_device **return_list_head);
34
35static acpi_status
36acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
37 struct acpi_pci_device *list_head);
38
39static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head);
40
41static acpi_status
42acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id,
43 acpi_handle pci_device,
44 u16 *bus_number, u8 *is_bridge);
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85acpi_status
86acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id,
87 acpi_handle root_pci_device, acpi_handle pci_region)
88{
89 acpi_status status;
90 struct acpi_pci_device *list_head;
91
92 ACPI_FUNCTION_TRACE(hw_derive_pci_id);
93
94 if (!pci_id) {
95 return_ACPI_STATUS(AE_BAD_PARAMETER);
96 }
97
98
99
100 status =
101 acpi_hw_build_pci_list(root_pci_device, pci_region, &list_head);
102 if (ACPI_SUCCESS(status)) {
103
104
105
106 status = acpi_hw_process_pci_list(pci_id, list_head);
107
108
109
110 acpi_hw_delete_pci_list(list_head);
111 }
112
113 return_ACPI_STATUS(status);
114}
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135static acpi_status
136acpi_hw_build_pci_list(acpi_handle root_pci_device,
137 acpi_handle pci_region,
138 struct acpi_pci_device **return_list_head)
139{
140 acpi_handle current_device;
141 acpi_handle parent_device;
142 acpi_status status;
143 struct acpi_pci_device *list_element;
144
145
146
147
148
149
150 *return_list_head = NULL;
151 current_device = pci_region;
152 while (1) {
153 status = acpi_get_parent(current_device, &parent_device);
154 if (ACPI_FAILURE(status)) {
155
156
157
158 acpi_hw_delete_pci_list(*return_list_head);
159 return (status);
160 }
161
162
163
164 if (parent_device == root_pci_device) {
165 return (AE_OK);
166 }
167
168 list_element = ACPI_ALLOCATE(sizeof(struct acpi_pci_device));
169 if (!list_element) {
170
171
172
173 acpi_hw_delete_pci_list(*return_list_head);
174 return (AE_NO_MEMORY);
175 }
176
177
178
179 list_element->next = *return_list_head;
180 list_element->device = parent_device;
181 *return_list_head = list_element;
182
183 current_device = parent_device;
184 }
185}
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204static acpi_status
205acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
206 struct acpi_pci_device *list_head)
207{
208 acpi_status status = AE_OK;
209 struct acpi_pci_device *info;
210 u16 bus_number;
211 u8 is_bridge = TRUE;
212
213 ACPI_FUNCTION_NAME(hw_process_pci_list);
214
215 ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
216 "Input PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n",
217 pci_id->segment, pci_id->bus, pci_id->device,
218 pci_id->function));
219
220 bus_number = pci_id->bus;
221
222
223
224
225
226
227
228
229 info = list_head;
230 while (info) {
231 status = acpi_hw_get_pci_device_info(pci_id, info->device,
232 &bus_number, &is_bridge);
233 if (ACPI_FAILURE(status)) {
234 return (status);
235 }
236
237 info = info->next;
238 }
239
240 ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
241 "Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X "
242 "Status %X BusNumber %X IsBridge %X\n",
243 pci_id->segment, pci_id->bus, pci_id->device,
244 pci_id->function, status, bus_number, is_bridge));
245
246 return (AE_OK);
247}
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head)
263{
264 struct acpi_pci_device *next;
265 struct acpi_pci_device *previous;
266
267 next = list_head;
268 while (next) {
269 previous = next;
270 next = previous->next;
271 ACPI_FREE(previous);
272 }
273}
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295static acpi_status
296acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id,
297 acpi_handle pci_device,
298 u16 *bus_number, u8 *is_bridge)
299{
300 acpi_status status;
301 acpi_object_type object_type;
302 u64 return_value;
303 u64 pci_value;
304
305
306
307 status = acpi_get_type(pci_device, &object_type);
308 if (ACPI_FAILURE(status)) {
309 return (status);
310 }
311
312 if (object_type != ACPI_TYPE_DEVICE) {
313 return (AE_OK);
314 }
315
316
317
318 status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR,
319 pci_device, &return_value);
320 if (ACPI_FAILURE(status)) {
321 return (AE_OK);
322 }
323
324
325
326
327
328 pci_id->device = ACPI_HIWORD(ACPI_LODWORD(return_value));
329 pci_id->function = ACPI_LOWORD(ACPI_LODWORD(return_value));
330
331
332
333
334
335 if (*is_bridge) {
336 pci_id->bus = *bus_number;
337 }
338
339
340
341
342
343
344 *is_bridge = FALSE;
345 status = acpi_os_read_pci_configuration(pci_id,
346 PCI_CFG_HEADER_TYPE_REG,
347 &pci_value, 8);
348 if (ACPI_FAILURE(status)) {
349 return (status);
350 }
351
352
353
354 pci_value &= PCI_HEADER_TYPE_MASK;
355
356 if ((pci_value != PCI_TYPE_BRIDGE) &&
357 (pci_value != PCI_TYPE_CARDBUS_BRIDGE)) {
358 return (AE_OK);
359 }
360
361
362
363 status = acpi_os_read_pci_configuration(pci_id,
364 PCI_CFG_PRIMARY_BUS_NUMBER_REG,
365 &pci_value, 8);
366 if (ACPI_FAILURE(status)) {
367 return (status);
368 }
369
370 *is_bridge = TRUE;
371 pci_id->bus = (u16)pci_value;
372
373
374
375 status = acpi_os_read_pci_configuration(pci_id,
376 PCI_CFG_SECONDARY_BUS_NUMBER_REG,
377 &pci_value, 8);
378 if (ACPI_FAILURE(status)) {
379 return (status);
380 }
381
382 *bus_number = (u16)pci_value;
383 return (AE_OK);
384}
385