acpi_pci.c revision 1.7 1 /* $NetBSD: acpi_pci.c,v 1.7 2010/04/22 15:14:24 jruoho Exp $ */
2
3 /*
4 * Copyright (c) 2009, 2010 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christoph Egger and Gregoire Sutre.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 /*
32 * ACPI PCI Bus
33 */
34
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: acpi_pci.c,v 1.7 2010/04/22 15:14:24 jruoho Exp $");
37
38 #include <sys/param.h>
39 #include <sys/device.h>
40 #include <sys/kmem.h>
41 #include <sys/systm.h>
42
43 #include <dev/pci/pcireg.h>
44 #include <dev/pci/pcidevs.h>
45 #include <dev/pci/ppbreg.h>
46
47 #include <dev/acpi/acpireg.h>
48 #include <dev/acpi/acpivar.h>
49 #include <dev/acpi/acpi_pci.h>
50
51 #define _COMPONENT ACPI_BUS_COMPONENT
52 ACPI_MODULE_NAME ("acpi_pci")
53
54 #define ACPI_HILODWORD(x) ACPI_HIWORD(ACPI_LODWORD((x)))
55 #define ACPI_LOLODWORD(x) ACPI_LOWORD(ACPI_LODWORD((x)))
56
57 static ACPI_STATUS acpi_pcidev_pciroot_bus(ACPI_HANDLE, uint16_t *);
58 static ACPI_STATUS acpi_pcidev_pciroot_bus_callback(ACPI_RESOURCE *,
59 void *);
60 static ACPI_STATUS acpi_pcidev_scan_rec(struct acpi_devnode *);
61
62
63 /*
64 * Regarding PCI Segment Groups, the ACPI spec says (cf. ACPI 4.0, p. 277):
65 *
66 * "The optional _SEG object is located under a PCI host bridge and
67 * evaluates to an integer that describes the PCI Segment Group (see PCI
68 * Firmware Specification v3.0)."
69 *
70 * "PCI Segment Group supports more than 256 buses in a system by allowing
71 * the reuse of the PCI bus numbers. Within each PCI Segment Group, the bus
72 * numbers for the PCI buses must be unique. PCI buses in different PCI
73 * Segment Group are permitted to have the same bus number."
74 *
75 * "If _SEG does not exist, OSPM assumes that all PCI bus segments are in
76 * PCI Segment Group 0."
77 *
78 * "The lower 16 bits of _SEG returned integer is the PCI Segment Group
79 * number. Other bits are reserved."
80 */
81
82 /*
83 * Regarding PCI Base Bus Numbers, the ACPI spec says (cf. ACPI 4.0, p. 277):
84 *
85 * "For multi-root PCI platforms, the _BBN object evaluates to the PCI bus
86 * number that the BIOS assigns. This is needed to access a PCI_Config
87 * operation region for the specified bus. The _BBN object is located under
88 * a PCI host bridge and must be unique for every host bridge within a
89 * segment since it is the PCI bus number."
90 *
91 * Moreover, the ACPI FAQ (http://www.acpi.info/acpi_faq.htm) says:
92 *
93 * "For a multiple root bus machine, _BBN is required for each bus. _BBN
94 * should provide the bus number assigned to this bus by the BIOS at boot
95 * time."
96 */
97
98
99 /*
100 * acpi_pcidev_pciroot_bus:
101 *
102 * Derive the PCI bus number of a PCI root bridge from its resources.
103 * If successful, return AE_OK and fill *busp. Otherwise, return an
104 * exception code and leave *busp unchanged.
105 *
106 * XXX Use ACPI resource parsing functions (acpi_resource.c) once bus number
107 * ranges are implemented there.
108 */
109 static ACPI_STATUS
110 acpi_pcidev_pciroot_bus(ACPI_HANDLE handle, uint16_t *busp)
111 {
112 ACPI_STATUS rv;
113 int32_t bus;
114
115 bus = -1;
116 rv = AcpiWalkResources(handle, METHOD_NAME__CRS,
117 acpi_pcidev_pciroot_bus_callback, &bus);
118
119 if (ACPI_FAILURE(rv))
120 return rv;
121
122 if (bus < 0 || bus > 0xFFFF)
123 return AE_NOT_EXIST;
124
125 *busp = (uint16_t)bus;
126 return rv;
127 }
128
129 static ACPI_STATUS
130 acpi_pcidev_pciroot_bus_callback(ACPI_RESOURCE *res, void *context)
131 {
132 int32_t *bus = context;
133 ACPI_RESOURCE_ADDRESS64 addr64;
134
135 if ((res->Type != ACPI_RESOURCE_TYPE_ADDRESS16) &&
136 (res->Type != ACPI_RESOURCE_TYPE_ADDRESS32) &&
137 (res->Type != ACPI_RESOURCE_TYPE_ADDRESS64))
138 return AE_OK; /* continue the walk */
139
140 if (ACPI_FAILURE(AcpiResourceToAddress64(res, &addr64)))
141 return AE_OK; /* continue the walk */
142
143 if (addr64.ResourceType != ACPI_BUS_NUMBER_RANGE)
144 return AE_OK; /* continue the walk */
145
146 if (*bus != -1)
147 return AE_ALREADY_EXISTS;
148
149 *bus = addr64.Minimum;
150 return AE_OK; /* continue the walk */
151 }
152
153 /*
154 * acpi_pcidev_scan_rec:
155 *
156 * Scan the ACPI device tree for PCI devices. A node is detected as a
157 * PCI device if it has an ancestor that is a PCI root bridge and such
158 * that all intermediate nodes are PCI-to-PCI bridges. Depth-first
159 * recursive implementation.
160 */
161 static ACPI_STATUS
162 acpi_pcidev_scan_rec(struct acpi_devnode *ad)
163 {
164 struct acpi_devnode *child;
165 struct acpi_pci_info *ap;
166 ACPI_INTEGER val;
167 ACPI_STATUS rv;
168
169 if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE ||
170 !(ad->ad_devinfo->Valid & ACPI_VALID_ADR)) {
171 ad->ad_pciinfo = NULL;
172 goto rec;
173 }
174
175 if (ad->ad_devinfo->Flags & ACPI_PCI_ROOT_BRIDGE) {
176 ap = kmem_zalloc(sizeof(*ap), KM_SLEEP);
177 if (ap == NULL)
178 return AE_NO_MEMORY;
179
180 rv = acpi_eval_integer(ad->ad_handle, METHOD_NAME__SEG, &val);
181 if (ACPI_SUCCESS(rv))
182 ap->ap_segment = ACPI_LOWORD(val);
183 else
184 ap->ap_segment = 0;
185
186 /* try to get bus number using _CRS first */
187 rv = acpi_pcidev_pciroot_bus(ad->ad_handle, &ap->ap_bus);
188 if (ACPI_FAILURE(rv)) {
189 rv = acpi_eval_integer(ad->ad_handle, METHOD_NAME__BBN, &val);
190 if (ACPI_SUCCESS(rv))
191 ap->ap_bus = ACPI_LOWORD(val);
192 else
193 ap->ap_bus = 0;
194 }
195
196 ap->ap_device = ACPI_HILODWORD(ad->ad_devinfo->Address);
197 ap->ap_function = ACPI_LOLODWORD(ad->ad_devinfo->Address);
198
199 ap->ap_bridge = true;
200 ap->ap_downbus = ap->ap_bus;
201
202 ad->ad_pciinfo = ap;
203 goto rec;
204 }
205
206 if ((ad->ad_parent != NULL) &&
207 (ad->ad_parent->ad_pciinfo != NULL) &&
208 (ad->ad_parent->ad_pciinfo->ap_bridge)) {
209 /*
210 * Our parent is a PCI root bridge or a PCI-to-PCI bridge. We
211 * have the same PCI segment#, and our bus# is its downstream
212 * bus number.
213 */
214 ap = kmem_zalloc(sizeof(*ap), KM_SLEEP);
215 if (ap == NULL)
216 return AE_NO_MEMORY;
217
218 ap->ap_segment = ad->ad_parent->ad_pciinfo->ap_segment;
219 ap->ap_bus = ad->ad_parent->ad_pciinfo->ap_downbus;
220
221 ap->ap_device = ACPI_HILODWORD(ad->ad_devinfo->Address);
222 ap->ap_function = ACPI_LOLODWORD(ad->ad_devinfo->Address);
223
224 /*
225 * Check whether this device is a PCI-to-PCI bridge and get its
226 * secondary bus#.
227 */
228 rv = acpi_pcidev_ppb_downbus(ap->ap_segment, ap->ap_bus,
229 ap->ap_device, ap->ap_function, &ap->ap_downbus);
230 if (ACPI_SUCCESS(rv))
231 ap->ap_bridge = true;
232 else
233 ap->ap_bridge = false;
234
235 ad->ad_pciinfo = ap;
236 goto rec;
237 }
238 rec:
239 SIMPLEQ_FOREACH(child, &ad->ad_child_head, ad_child_list) {
240 rv = acpi_pcidev_scan_rec(child);
241 if (ACPI_FAILURE(rv))
242 return rv;
243 }
244
245 return AE_OK;
246 }
247
248 /*
249 * acpi_pcidev_ppb_downbus:
250 *
251 * Retrieve the secondary bus number of the PCI-to-PCI bridge having the
252 * given PCI id. If successful, return AE_OK and fill *busp. Otherwise,
253 * return an exception code and leave *busp unchanged.
254 *
255 * XXX Need to deal with PCI segment groups (see also acpica/OsdHardware.c).
256 */
257 ACPI_STATUS
258 acpi_pcidev_ppb_downbus(uint16_t segment, uint16_t bus, uint16_t device,
259 uint16_t function, uint16_t *downbus)
260 {
261 struct acpi_softc *sc = acpi_softc;
262 pci_chipset_tag_t pc;
263 pcitag_t tag;
264 pcireg_t val;
265
266 if (bus > 255 || device > 31 || function > 7)
267 return AE_BAD_PARAMETER;
268
269 if (sc == NULL)
270 pc = NULL;
271 else
272 pc = sc->sc_pc;
273
274 tag = pci_make_tag(pc, bus, device, function);
275
276 /* Check that this device exists. */
277 val = pci_conf_read(pc, tag, PCI_ID_REG);
278 if (PCI_VENDOR(val) == PCI_VENDOR_INVALID ||
279 PCI_VENDOR(val) == 0)
280 return AE_NOT_EXIST;
281
282 /* Check that this device is a PCI-to-PCI bridge. */
283 val = pci_conf_read(pc, tag, PCI_BHLC_REG);
284 if (PCI_HDRTYPE_TYPE(val) != PCI_HDRTYPE_PPB)
285 return AE_TYPE;
286
287 /* This is a PCI-to-PCI bridge. Get its secondary bus#. */
288 val = pci_conf_read(pc, tag, PPB_REG_BUSINFO);
289 *downbus = PPB_BUSINFO_SECONDARY(val);
290 return AE_OK;
291 }
292
293 static void
294 acpi_pcidev_print(struct acpi_devnode *ad)
295 {
296 aprint_debug(" ");
297 if (ad->ad_devinfo->Flags & ACPI_PCI_ROOT_BRIDGE)
298 aprint_debug("*");
299 aprint_debug("%s@%"PRIx16":%"PRIx16":%"PRIx16":%"PRIx16,
300 ad->ad_name,
301 ad->ad_pciinfo->ap_segment,
302 ad->ad_pciinfo->ap_bus,
303 ad->ad_pciinfo->ap_device,
304 ad->ad_pciinfo->ap_function);
305 if (ad->ad_pciinfo->ap_bridge)
306 aprint_debug(">%"PRIx16, ad->ad_pciinfo->ap_downbus);
307 }
308
309 void
310 acpi_pcidev_scan(struct acpi_softc *sc)
311 {
312 struct acpi_devnode *ad;
313
314 acpi_pcidev_scan_rec(sc->sc_root);
315 aprint_debug_dev(sc->sc_dev, "pci devices:");
316 SIMPLEQ_FOREACH(ad, &sc->ad_head, ad_list) {
317 if (ad->ad_pciinfo != NULL)
318 acpi_pcidev_print(ad);
319 }
320 aprint_debug("\n");
321 }
322
323 /*
324 * acpi_pcidev_find:
325 *
326 * Finds a PCI device in the ACPI name space.
327 * The return status is either:
328 * - AE_NOT_FOUND if no such device was found.
329 * - AE_OK if one and only one such device was found.
330 */
331 ACPI_STATUS
332 acpi_pcidev_find(uint16_t segment, uint16_t bus, uint16_t device,
333 uint16_t function, struct acpi_devnode **devnodep)
334 {
335 struct acpi_softc *sc = acpi_softc;
336 struct acpi_devnode *ad;
337
338 if (sc == NULL)
339 return AE_NOT_FOUND;
340
341 SIMPLEQ_FOREACH(ad, &sc->ad_head, ad_list) {
342 if ((ad->ad_pciinfo != NULL) &&
343 (ad->ad_pciinfo->ap_segment == segment) &&
344 (ad->ad_pciinfo->ap_bus == bus) &&
345 (ad->ad_pciinfo->ap_device == device) &&
346 (ad->ad_pciinfo->ap_function == function)) {
347 *devnodep = ad;
348 return AE_OK;
349 }
350 }
351 return AE_NOT_FOUND;
352 }
353