OsdHardware.c revision 146734
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: head/sys/dev/acpica/Osd/OsdHardware.c 146734 2005-05-29 04:42:30Z nyan $
28 */
29
30/*
31 * 6.7 : Hardware Abstraction
32 */
33
34#include "acpi.h"
35
36#include <machine/bus.h>
37#include <machine/pci_cfgreg.h>
38#include <dev/pci/pcireg.h>
39
40/*
41 * ACPICA's rather gung-ho approach to hardware resource ownership is a little
42 * troublesome insofar as there is no easy way for us to know in advance
43 * exactly which I/O resources it's going to want to use.
44 *
45 * In order to deal with this, we ignore resource ownership entirely, and simply
46 * use the native I/O space accessor functionality.  This is Evil, but it works.
47 *
48 * XXX use an intermediate #define for the tag/handle
49 */
50
51#ifdef __i386__
52#define ACPI_BUS_SPACE_IO	I386_BUS_SPACE_IO
53#define ACPI_BUS_HANDLE		0
54#endif
55#ifdef __ia64__
56#define ACPI_BUS_SPACE_IO	IA64_BUS_SPACE_IO
57#define ACPI_BUS_HANDLE		0
58#endif
59#ifdef __amd64__
60#define ACPI_BUS_SPACE_IO	AMD64_BUS_SPACE_IO
61#define ACPI_BUS_HANDLE		0
62#endif
63
64ACPI_STATUS
65AcpiOsReadPort(ACPI_IO_ADDRESS InPort, UINT32 *Value, UINT32 Width)
66{
67    switch (Width) {
68    case 8:
69        *(u_int8_t *)Value = bus_space_read_1(ACPI_BUS_SPACE_IO,
70	    ACPI_BUS_HANDLE, InPort);
71        break;
72    case 16:
73        *(u_int16_t *)Value = bus_space_read_2(ACPI_BUS_SPACE_IO,
74	    ACPI_BUS_HANDLE, InPort);
75        break;
76    case 32:
77        *(u_int32_t *)Value = bus_space_read_4(ACPI_BUS_SPACE_IO,
78	    ACPI_BUS_HANDLE, InPort);
79        break;
80    default:
81        /* debug trap goes here */
82	break;
83    }
84
85    return (AE_OK);
86}
87
88ACPI_STATUS
89AcpiOsWritePort(ACPI_IO_ADDRESS OutPort, UINT32	Value, UINT32 Width)
90{
91    switch (Width) {
92    case 8:
93        bus_space_write_1(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, OutPort, Value);
94        break;
95    case 16:
96        bus_space_write_2(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, OutPort, Value);
97        break;
98    case 32:
99        bus_space_write_4(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, OutPort, Value);
100        break;
101    default:
102        /* debug trap goes here */
103	break;
104    }
105
106    return (AE_OK);
107}
108
109ACPI_STATUS
110AcpiOsReadPciConfiguration(ACPI_PCI_ID *PciId, UINT32 Register, void *Value,
111    UINT32 Width)
112{
113    u_int32_t	byte_width = Width / 8;
114    u_int32_t	val;
115
116    if (!pci_cfgregopen())
117        return (AE_NOT_EXIST);
118
119    val = pci_cfgregread(PciId->Bus, PciId->Device, PciId->Function, Register,
120	byte_width);
121    switch (Width) {
122    case 8:
123	*(u_int8_t *)Value = val & 0xff;
124	break;
125    case 16:
126	*(u_int16_t *)Value = val & 0xffff;
127	break;
128    case 32:
129	*(u_int32_t *)Value = val;
130	break;
131    default:
132	/* debug trap goes here */
133	break;
134    }
135
136    return (AE_OK);
137}
138
139
140ACPI_STATUS
141AcpiOsWritePciConfiguration (ACPI_PCI_ID *PciId, UINT32 Register,
142    ACPI_INTEGER Value, UINT32 Width)
143{
144    u_int32_t	byte_width = Width / 8;
145
146    if (!pci_cfgregopen())
147    	return (AE_NOT_EXIST);
148
149    pci_cfgregwrite(PciId->Bus, PciId->Device, PciId->Function, Register,
150	Value, byte_width);
151
152    return (AE_OK);
153}
154
155/* XXX should use acpivar.h but too many include dependencies */
156extern ACPI_STATUS acpi_GetInteger(ACPI_HANDLE handle, char *path, int
157    *number);
158
159/*
160 * Depth-first recursive case for finding the bus, given the slot/function.
161 */
162static int
163acpi_bus_number(ACPI_HANDLE root, ACPI_HANDLE curr, ACPI_PCI_ID *PciId)
164{
165    ACPI_HANDLE parent;
166    ACPI_STATUS status;
167    ACPI_OBJECT_TYPE type;
168    UINT32 adr;
169    int bus, slot, func, class, subclass, header;
170
171    /* Try to get the _BBN object of the root, otherwise assume it is 0. */
172    bus = 0;
173    if (root == curr) {
174	status = acpi_GetInteger(root, "_BBN", &bus);
175	if (ACPI_FAILURE(status) && bootverbose)
176	    printf("acpi_bus_number: root bus has no _BBN, assuming 0\n");
177	return (bus);
178    }
179    status = AcpiGetParent(curr, &parent);
180    if (ACPI_FAILURE(status))
181	return (bus);
182
183    /* First, recurse up the tree until we find the host bus. */
184    bus = acpi_bus_number(root, parent, PciId);
185
186    /* Validate parent bus device type. */
187    if (ACPI_FAILURE(AcpiGetType(parent, &type)) || type != ACPI_TYPE_DEVICE) {
188	printf("acpi_bus_number: not a device, type %d\n", type);
189	return (bus);
190    }
191
192    /* Get the parent's slot and function. */
193    status = acpi_GetInteger(parent, "_ADR", &adr);
194    if (ACPI_FAILURE(status)) {
195	printf("acpi_bus_number: can't get _ADR\n");
196	return (bus);
197    }
198    slot = ACPI_HIWORD(adr);
199    func = ACPI_LOWORD(adr);
200
201    /* Is this a PCI-PCI or Cardbus-PCI bridge? */
202    class = pci_cfgregread(bus, slot, func, PCIR_CLASS, 1);
203    if (class != PCIC_BRIDGE)
204	return (bus);
205    subclass = pci_cfgregread(bus, slot, func, PCIR_SUBCLASS, 1);
206
207    /* Find the header type, masking off the multifunction bit. */
208    header = pci_cfgregread(bus, slot, func, PCIR_HDRTYPE, 1) & PCIM_HDRTYPE;
209    if (header == PCIM_HDRTYPE_BRIDGE && subclass == PCIS_BRIDGE_PCI)
210	bus = pci_cfgregread(bus, slot, func, PCIR_SECBUS_1, 1);
211    if (header == PCIM_HDRTYPE_CARDBUS && subclass == PCIS_BRIDGE_CARDBUS)
212	bus = pci_cfgregread(bus, slot, func, PCIR_SECBUS_2, 1);
213    return (bus);
214}
215
216/*
217 * Find the bus number for a device
218 *
219 * rhandle: handle for the root bus
220 * chandle: handle for the device
221 * PciId: pointer to device slot and function, we fill out bus
222 */
223void
224AcpiOsDerivePciId(ACPI_HANDLE rhandle, ACPI_HANDLE chandle, ACPI_PCI_ID **PciId)
225{
226    ACPI_HANDLE parent;
227    ACPI_STATUS status;
228    int bus;
229
230    if (pci_cfgregopen() == 0)
231	panic("AcpiOsDerivePciId unable to initialize pci bus");
232
233    /* Try to read _BBN for bus number if we're at the root */
234    bus = 0;
235    if (rhandle == chandle) {
236	status = acpi_GetInteger(rhandle, "_BBN", &bus);
237	if (ACPI_FAILURE(status) && bootverbose)
238	    printf("AcpiOsDerivePciId: root bus has no _BBN, assuming 0\n");
239    }
240
241    /*
242     * Get the parent handle and call the recursive case.  It is not
243     * clear why we seem to be getting a chandle that points to a child
244     * of the desired slot/function but passing in the parent handle
245     * here works.
246     */
247    if (ACPI_SUCCESS(AcpiGetParent(chandle, &parent)))
248	bus = acpi_bus_number(rhandle, parent, *PciId);
249    (*PciId)->Bus = bus;
250    if (bootverbose) {
251	printf("AcpiOsDerivePciId: bus %d dev %d func %d\n",
252	    (*PciId)->Bus, (*PciId)->Device, (*PciId)->Function);
253    }
254}
255