xref: /freebsd/sys/dev/acpica/Osd/OsdHardware.c (revision 7660b554bc59a07be0431c17e0e33815818baa69)
1 /*-
2  * Copyright (c) 2000, 2001 Michael Smith
3  * Copyright (c) 2000 BSDi
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *	$FreeBSD$
28  */
29 
30 /*
31  * 6.7 : Hardware Abstraction
32  */
33 
34 #include "acpi.h"
35 
36 #include <machine/bus_pio.h>
37 #include <machine/bus.h>
38 #include <machine/pci_cfgreg.h>
39 #if __FreeBSD_version >= 500000
40 #include <dev/pci/pcireg.h>
41 #else
42 #include <pci/pcireg.h>
43 #endif
44 
45 /*
46  * ACPICA's rather gung-ho approach to hardware resource ownership is a little
47  * troublesome insofar as there is no easy way for us to know in advance
48  * exactly which I/O resources it's going to want to use.
49  *
50  * In order to deal with this, we ignore resource ownership entirely, and simply
51  * use the native I/O space accessor functionality.  This is Evil, but it works.
52  *
53  * XXX use an intermediate #define for the tag/handle
54  */
55 
56 #ifdef __i386__
57 #define ACPI_BUS_SPACE_IO	I386_BUS_SPACE_IO
58 #define ACPI_BUS_HANDLE		0
59 #endif
60 #ifdef __ia64__
61 #define ACPI_BUS_SPACE_IO	IA64_BUS_SPACE_IO
62 #define ACPI_BUS_HANDLE		0
63 #endif
64 #ifdef __amd64__
65 #define ACPI_BUS_SPACE_IO	AMD64_BUS_SPACE_IO
66 #define ACPI_BUS_HANDLE		0
67 #endif
68 
69 ACPI_STATUS
70 AcpiOsReadPort (
71     ACPI_IO_ADDRESS	InPort,
72     UINT32		*Value,
73     UINT32		Width)
74 {
75     switch (Width) {
76     case 8:
77         *(u_int8_t *)Value = bus_space_read_1(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, InPort);
78         break;
79     case 16:
80         *(u_int16_t *)Value = bus_space_read_2(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, InPort);
81         break;
82     case 32:
83         *(u_int32_t *)Value = bus_space_read_4(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, InPort);
84         break;
85     default:
86         /* debug trap goes here */
87 	break;
88     }
89 
90     return(AE_OK);
91 }
92 
93 ACPI_STATUS
94 AcpiOsWritePort (
95     ACPI_IO_ADDRESS	OutPort,
96     UINT32		Value,
97     UINT32		Width)
98 {
99     switch (Width) {
100     case 8:
101         bus_space_write_1(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, OutPort, Value);
102         break;
103     case 16:
104         bus_space_write_2(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, OutPort, Value);
105         break;
106     case 32:
107         bus_space_write_4(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, OutPort, Value);
108         break;
109     default:
110         /* debug trap goes here */
111 	break;
112     }
113 
114     return(AE_OK);
115 }
116 
117 ACPI_STATUS
118 AcpiOsReadPciConfiguration (
119     ACPI_PCI_ID		*PciId,
120     UINT32		Register,
121     void		*Value,
122     UINT32		Width)
123 {
124     u_int32_t	byte_width = Width / 8;
125     u_int32_t	val;
126 
127     if (!pci_cfgregopen())
128         return(AE_NOT_EXIST);
129 
130     val = pci_cfgregread(PciId->Bus, PciId->Device, PciId->Function, Register, byte_width);
131     switch (Width) {
132     case 8:
133 	*(u_int8_t *)Value = val & 0xff;
134 	break;
135     case 16:
136 	*(u_int16_t *)Value = val & 0xffff;
137 	break;
138     case 32:
139 	*(u_int32_t *)Value = val;
140 	break;
141     default:
142 	/* debug trap goes here */
143 	break;
144     }
145 
146 
147     return(AE_OK);
148 }
149 
150 
151 ACPI_STATUS
152 AcpiOsWritePciConfiguration (
153     ACPI_PCI_ID		*PciId,
154     UINT32		Register,
155     ACPI_INTEGER	Value,
156     UINT32		Width)
157 {
158     u_int32_t	byte_width = Width / 8;
159 
160     if (!pci_cfgregopen())
161     	return(AE_NOT_EXIST);
162 
163     pci_cfgregwrite(PciId->Bus, PciId->Device, PciId->Function, Register, Value, byte_width);
164 
165     return(AE_OK);
166 }
167 
168 /* XXX should use acpivar.h but too many include dependencies */
169 extern ACPI_STATUS acpi_EvaluateInteger(ACPI_HANDLE handle, char *path, int
170     *number);
171 
172 /*
173  * Depth-first recursive case for finding the bus, given the slot/function.
174  */
175 static int
176 acpi_bus_number(ACPI_HANDLE root, ACPI_HANDLE curr, ACPI_PCI_ID *PciId)
177 {
178     ACPI_HANDLE parent;
179     ACPI_OBJECT_TYPE type;
180     UINT32 adr;
181     int bus, slot, func, class, subclass, header;
182 
183     /* Try to get the _BBN object of the root, otherwise assume it is 0 */
184     bus = 0;
185     if (root == curr) {
186         if (ACPI_FAILURE(acpi_EvaluateInteger(root, "_BBN", &bus)) &&
187           bootverbose)
188             printf("acpi_bus_number: root bus has no _BBN, assuming 0\n");
189 	return (bus);
190     }
191     if (ACPI_FAILURE(AcpiGetParent(curr, &parent)))
192         return (bus);
193 
194     /* First, recurse up the tree until we find the host bus */
195     bus = acpi_bus_number(root, parent, PciId);
196 
197     /* Validate parent bus device type */
198     if (ACPI_FAILURE(AcpiGetType(parent, &type)) || type != ACPI_TYPE_DEVICE) {
199         printf("acpi_bus_number: not a device, type %d\n", type);
200         return (bus);
201     }
202     /* Get the parent's slot and function */
203     if (ACPI_FAILURE(acpi_EvaluateInteger(parent, "_ADR", &adr))) {
204         printf("acpi_bus_number: can't get _ADR\n");
205         return (bus);
206     }
207     slot = ACPI_HIWORD(adr);
208     func = ACPI_LOWORD(adr);
209 
210     /* Is this a PCI-PCI or Cardbus-PCI bridge? */
211     class = pci_cfgregread(bus, slot, func, PCIR_CLASS, 1);
212     if (class != PCIC_BRIDGE)
213         return (bus);
214     subclass = pci_cfgregread(bus, slot, func, PCIR_SUBCLASS, 1);
215     /* Find the header type, masking off the multifunction bit */
216     header = pci_cfgregread(bus, slot, func, PCIR_HDRTYPE, 1) & PCIM_HDRTYPE;
217     if (header == PCIM_HDRTYPE_BRIDGE && subclass == PCIS_BRIDGE_PCI)
218         bus = pci_cfgregread(bus, slot, func, PCIR_SECBUS_1, 1);
219     if (header == PCIM_HDRTYPE_CARDBUS && subclass == PCIS_BRIDGE_CARDBUS)
220         bus = pci_cfgregread(bus, slot, func, PCIR_SECBUS_2, 1);
221     return (bus);
222 }
223 
224 /*
225  * Find the bus number for a device
226  *
227  * rhandle: handle for the root bus
228  * chandle: handle for the device
229  * PciId: pointer to device slot and function, we fill out bus
230  */
231 void
232 AcpiOsDerivePciId (
233     ACPI_HANDLE		rhandle,
234     ACPI_HANDLE		chandle,
235     ACPI_PCI_ID		**PciId)
236 {
237     ACPI_HANDLE parent;
238     int bus;
239 
240     if (pci_cfgregopen() == 0)
241         panic("AcpiOsDerivePciId unable to initialize pci bus");
242 
243     /* Try to read _BBN for bus number if we're at the root */
244     bus = 0;
245     if (rhandle == chandle) {
246         if (ACPI_FAILURE(acpi_EvaluateInteger(rhandle, "_BBN", &bus)) &&
247           bootverbose)
248             printf("AcpiOsDerivePciId: root bus has no _BBN, assuming 0\n");
249     }
250     /*
251      * Get the parent handle and call the recursive case.  It is not
252      * clear why we seem to be getting a chandle that points to a child
253      * of the desired slot/function but passing in the parent handle
254      * here works.
255      */
256     if (ACPI_SUCCESS(AcpiGetParent(chandle, &parent)))
257         bus = acpi_bus_number(rhandle, parent, *PciId);
258     (*PciId)->Bus = bus;
259     if (bootverbose) {
260         printf("AcpiOsDerivePciId: bus %d dev %d func %d\n",
261             (*PciId)->Bus, (*PciId)->Device, (*PciId)->Function);
262     }
263 }
264