4 * Copyright (c) 2009 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: acpi_pci.c,v 1.1 2009/12/03 21:04:29 cegger Exp $");
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/device.h>
45 #include <dev/pci/pcivar.h>
47 #include <dev/acpi/acpica.h>
48 #include <dev/acpi/acpireg.h>
49 #include <dev/acpi/acpivar.h>
50 #include <dev/acpi/acpi_pci.h>
54 static TAILQ_HEAD(, acpi_pcidev
) acpi_pcidevlist
=
55 TAILQ_HEAD_INITIALIZER(acpi_pcidevlist
);
58 struct acpi_devnode
*ap_node
;
64 TAILQ_ENTRY(acpi_pcidev
) ap_list
;
68 static const char * const acpi_pcidev_ids
[] = {
69 "PNP0A??", /* ACPI PCI host controllers */
74 acpi_pcidev_add(struct acpi_softc
*sc
, struct acpi_devnode
*ad
)
76 struct acpi_pcidev
*ap
;
78 ACPI_INTEGER seg
, bus
, addr
;
81 * ACPI spec: "The _BBN object is located under a
82 * PCI host bridge and must be unique for every
83 * host bridge within a segment since it is the PCI bus number."
85 rv
= acpi_eval_integer(ad
->ad_handle
, "_BBN", &bus
);
89 * The ACPI address (_ADR) is equal to: (device << 16) | function.
91 rv
= acpi_eval_integer(ad
->ad_handle
, "_ADR", &addr
);
96 * ACPI spec: "The optional _SEG object is located under a PCI host
97 * bridge and evaluates to an integer that describes the
98 * PCI Segment Group (see PCI Firmware Specification v3.0)."
100 * "PCI Segment Group supports more than 256 buses
101 * in a system by allowing the reuse of the PCI bus numbers.
102 * Within each PCI Segment Group, the bus numbers for the PCI
103 * buses must be unique. PCI buses in different PCI Segment
104 * Group are permitted to have the same bus number."
106 rv
= acpi_eval_integer(ad
->ad_handle
, "_SEG", &seg
);
107 if (ACPI_FAILURE(rv
)) {
109 * ACPI spec: "If _SEG does not exist, OSPM assumes that all
110 * PCI bus segments are in PCI Segment Group 0."
115 ap
= kmem_alloc(sizeof(*ap
), KM_SLEEP
);
117 aprint_error("%s: kmem_alloc failed\n", __func__
);
121 if (acpi_match_hid(ad
->ad_devinfo
, acpi_pcidev_ids
))
122 ap
->ap_pcihost
= true;
124 ap
->ap_pcihost
= false;
129 ap
->ap_pcidev
= addr
>> 16;
130 ap
->ap_pcifunc
= addr
& 0xffff;
132 TAILQ_INSERT_TAIL(&acpi_pcidevlist
, ap
, ap_list
);
138 acpi_pcidev_print(struct acpi_pcidev
*ap
)
140 aprint_debug(" %s", ap
->ap_node
->ad_name
);
144 acpi_pcidev_scan(struct acpi_softc
*sc
)
146 struct acpi_scope
*as
;
147 struct acpi_devnode
*ad
;
148 struct acpi_pcidev
*ap
;
149 ACPI_DEVICE_INFO
*di
;
152 #define ACPI_STA_DEV_VALID \
153 (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED|ACPI_STA_DEV_OK)
155 TAILQ_FOREACH(as
, &sc
->sc_scopes
, as_list
) {
156 TAILQ_FOREACH(ad
, &as
->as_devnodes
, ad_list
) {
158 if (di
->Type
!= ACPI_TYPE_DEVICE
)
160 if ((di
->Valid
& ACPI_VALID_STA
) != 0 &&
161 (di
->CurrentStatus
& ACPI_STA_DEV_VALID
) !=
164 if (acpi_pcidev_add(sc
, ad
) == true)
169 #undef ACPI_STA_DEV_VALID
174 aprint_debug_dev(sc
->sc_dev
, "pci devices:");
175 TAILQ_FOREACH(ap
, &acpi_pcidevlist
, ap_list
)
176 acpi_pcidev_print(ap
);
185 * Finds a PCI device in the ACPI name space.
186 * The return status is either:
187 * - AE_NOT_FOUND if no such device was found.
188 * - AE_OK if one and only one such device was found.
191 acpi_pcidev_find(u_int segment
, u_int bus
, u_int device
, u_int function
,
192 ACPI_HANDLE
*handlep
)
194 struct acpi_pcidev
*ap
;
198 TAILQ_FOREACH(ap
, &acpi_pcidevlist
, ap_list
) {
199 if (ap
->ap_pciseg
!= segment
)
201 if (ap
->ap_pcibus
!= bus
)
203 if (ap
->ap_pcidev
!= device
)
205 if (ap
->ap_pcifunc
!= function
)
208 hdl
= ap
->ap_node
->ad_handle
;
213 return (hdl
!= NULL
) ? AE_OK
: AE_NOT_FOUND
;