OsdHardware.c revision 119539
167760Smsmith/*-
280071Smsmith * Copyright (c) 2000, 2001 Michael Smith
367760Smsmith * Copyright (c) 2000 BSDi
467760Smsmith * All rights reserved.
567760Smsmith *
667760Smsmith * Redistribution and use in source and binary forms, with or without
767760Smsmith * modification, are permitted provided that the following conditions
867760Smsmith * are met:
967760Smsmith * 1. Redistributions of source code must retain the above copyright
1067760Smsmith *    notice, this list of conditions and the following disclaimer.
1167760Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1267760Smsmith *    notice, this list of conditions and the following disclaimer in the
1367760Smsmith *    documentation and/or other materials provided with the distribution.
1467760Smsmith *
1567760Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1667760Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1767760Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1867760Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1967760Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2067760Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2167760Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2267760Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2367760Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2467760Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2567760Smsmith * SUCH DAMAGE.
2667760Smsmith *
2767760Smsmith *	$FreeBSD: head/sys/dev/acpica/Osd/OsdHardware.c 119539 2003-08-28 21:22:25Z jhb $
2867760Smsmith */
2967760Smsmith
3067760Smsmith/*
3167760Smsmith * 6.7 : Hardware Abstraction
3267760Smsmith */
3367760Smsmith
3467760Smsmith#include "acpi.h"
3567760Smsmith
3667760Smsmith#include <machine/bus_pio.h>
3767760Smsmith#include <machine/bus.h>
3867760Smsmith#include <machine/pci_cfgreg.h>
39114977Sjhb#if __FreeBSD_version >= 500000
40114246Snjl#include <dev/pci/pcireg.h>
41114977Sjhb#else
42114977Sjhb#include <pci/pcireg.h>
43114977Sjhb#endif
4467760Smsmith
4567760Smsmith/*
4667760Smsmith * ACPICA's rather gung-ho approach to hardware resource ownership is a little
4767760Smsmith * troublesome insofar as there is no easy way for us to know in advance
4867760Smsmith * exactly which I/O resources it's going to want to use.
4967760Smsmith *
5067760Smsmith * In order to deal with this, we ignore resource ownership entirely, and simply
5167760Smsmith * use the native I/O space accessor functionality.  This is Evil, but it works.
5267760Smsmith *
5367760Smsmith * XXX use an intermediate #define for the tag/handle
5467760Smsmith */
5567760Smsmith
5684446Sdfr#ifdef __i386__
5767760Smsmith#define ACPI_BUS_SPACE_IO	I386_BUS_SPACE_IO
5867760Smsmith#define ACPI_BUS_HANDLE		0
5984446Sdfr#endif
6084446Sdfr#ifdef __ia64__
6184446Sdfr#define ACPI_BUS_SPACE_IO	IA64_BUS_SPACE_IO
6284446Sdfr#define ACPI_BUS_HANDLE		0
6384446Sdfr#endif
64115427Speter#ifdef __amd64__
65115427Speter#define ACPI_BUS_SPACE_IO	AMD64_BUS_SPACE_IO
66115427Speter#define ACPI_BUS_HANDLE		0
67115427Speter#endif
6867760Smsmith
6980071SmsmithACPI_STATUS
7080071SmsmithAcpiOsReadPort (
7180071Smsmith    ACPI_IO_ADDRESS	InPort,
72117530Snjl    UINT32		*Value,
7380071Smsmith    UINT32		Width)
7467760Smsmith{
7580071Smsmith    switch (Width) {
7680071Smsmith    case 8:
7780071Smsmith        *(u_int8_t *)Value = bus_space_read_1(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, InPort);
7880071Smsmith        break;
7980071Smsmith    case 16:
8080071Smsmith        *(u_int16_t *)Value = bus_space_read_2(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, InPort);
8180071Smsmith        break;
8280071Smsmith    case 32:
8380071Smsmith        *(u_int32_t *)Value = bus_space_read_4(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, InPort);
8480071Smsmith        break;
8580071Smsmith    default:
8680071Smsmith        /* debug trap goes here */
8792666Speter	break;
8880071Smsmith    }
8967760Smsmith
9080071Smsmith    return(AE_OK);
9167760Smsmith}
9267760Smsmith
9367760SmsmithACPI_STATUS
9480071SmsmithAcpiOsWritePort (
9580071Smsmith    ACPI_IO_ADDRESS	OutPort,
96117530Snjl    UINT32		Value,
9780071Smsmith    UINT32		Width)
9867760Smsmith{
9980071Smsmith    switch (Width) {
10080071Smsmith    case 8:
10180071Smsmith        bus_space_write_1(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, OutPort, Value);
10280071Smsmith        break;
10380071Smsmith    case 16:
10480071Smsmith        bus_space_write_2(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, OutPort, Value);
10580071Smsmith        break;
10680071Smsmith    case 32:
10780071Smsmith        bus_space_write_4(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, OutPort, Value);
10880071Smsmith        break;
10980071Smsmith    default:
11080071Smsmith        /* debug trap goes here */
11192666Speter	break;
11280071Smsmith    }
11367760Smsmith
11467760Smsmith    return(AE_OK);
11567760Smsmith}
11667760Smsmith
11767760SmsmithACPI_STATUS
11880071SmsmithAcpiOsReadPciConfiguration (
11980071Smsmith    ACPI_PCI_ID		*PciId,
12080071Smsmith    UINT32		Register,
12180071Smsmith    void		*Value,
12280071Smsmith    UINT32		Width)
12367760Smsmith{
12480071Smsmith    u_int32_t	byte_width = Width / 8;
12580071Smsmith    u_int32_t	val;
12667760Smsmith
12767760Smsmith    if (!pci_cfgregopen())
12880071Smsmith        return(AE_NOT_EXIST);
12967760Smsmith
13080071Smsmith    val = pci_cfgregread(PciId->Bus, PciId->Device, PciId->Function, Register, byte_width);
13180071Smsmith    switch (Width) {
13280071Smsmith    case 8:
13380071Smsmith	*(u_int8_t *)Value = val & 0xff;
13480071Smsmith	break;
13580071Smsmith    case 16:
13680071Smsmith	*(u_int16_t *)Value = val & 0xffff;
13780071Smsmith	break;
13880071Smsmith    case 32:
13980071Smsmith	*(u_int32_t *)Value = val;
14080071Smsmith	break;
14180071Smsmith    default:
14280071Smsmith	/* debug trap goes here */
14392666Speter	break;
14480071Smsmith    }
14580071Smsmith
14680071Smsmith
14767760Smsmith    return(AE_OK);
14867760Smsmith}
14967760Smsmith
15080071Smsmith
15167760SmsmithACPI_STATUS
15280071SmsmithAcpiOsWritePciConfiguration (
15380071Smsmith    ACPI_PCI_ID		*PciId,
15480071Smsmith    UINT32		Register,
15587036Smsmith    ACPI_INTEGER	Value,
15680071Smsmith    UINT32		Width)
15767760Smsmith{
15880071Smsmith    u_int32_t	byte_width = Width / 8;
15967760Smsmith
16067760Smsmith    if (!pci_cfgregopen())
16180071Smsmith    	return(AE_NOT_EXIST);
16267760Smsmith
16380071Smsmith    pci_cfgregwrite(PciId->Bus, PciId->Device, PciId->Function, Register, Value, byte_width);
16480071Smsmith
16567760Smsmith    return(AE_OK);
16667760Smsmith}
167114246Snjl
168114246Snjl/* XXX should use acpivar.h but too many include dependencies */
169114246Snjlextern ACPI_STATUS acpi_EvaluateInteger(ACPI_HANDLE handle, char *path, int
170114246Snjl    *number);
171114246Snjl
172114246Snjl/*
173114246Snjl * Depth-first recursive case for finding the bus, given the slot/function.
174114246Snjl */
175114246Snjlstatic int
176114246Snjlacpi_bus_number(ACPI_HANDLE root, ACPI_HANDLE curr, ACPI_PCI_ID *PciId)
177114246Snjl{
178114246Snjl    ACPI_HANDLE parent;
179114246Snjl    ACPI_OBJECT_TYPE type;
180114246Snjl    UINT32 adr;
181114246Snjl    int bus, slot, func, class, subclass, header;
182114246Snjl
183114246Snjl    /* Try to get the _BBN object of the root, otherwise assume it is 0 */
184114246Snjl    bus = 0;
185114246Snjl    if (root == curr) {
186114949Snjl        if (ACPI_FAILURE(acpi_EvaluateInteger(root, "_BBN", &bus)) &&
187114949Snjl          bootverbose)
188114246Snjl            printf("acpi_bus_number: root bus has no _BBN, assuming 0\n");
189114246Snjl	return (bus);
190114246Snjl    }
191114246Snjl    if (ACPI_FAILURE(AcpiGetParent(curr, &parent)))
192114246Snjl        return (bus);
193114246Snjl
194114246Snjl    /* First, recurse up the tree until we find the host bus */
195114246Snjl    bus = acpi_bus_number(root, parent, PciId);
196114246Snjl
197114246Snjl    /* Validate parent bus device type */
198114246Snjl    if (ACPI_FAILURE(AcpiGetType(parent, &type)) || type != ACPI_TYPE_DEVICE) {
199114246Snjl        printf("acpi_bus_number: not a device, type %d\n", type);
200114246Snjl        return (bus);
201114246Snjl    }
202114246Snjl    /* Get the parent's slot and function */
203114246Snjl    if (ACPI_FAILURE(acpi_EvaluateInteger(parent, "_ADR", &adr))) {
204114246Snjl        printf("acpi_bus_number: can't get _ADR\n");
205114246Snjl        return (bus);
206114246Snjl    }
207114246Snjl    slot = ACPI_HIWORD(adr);
208114246Snjl    func = ACPI_LOWORD(adr);
209114246Snjl
210114246Snjl    /* Is this a PCI-PCI or Cardbus-PCI bridge? */
211114246Snjl    class = pci_cfgregread(bus, slot, func, PCIR_CLASS, 1);
212114246Snjl    if (class != PCIC_BRIDGE)
213114246Snjl        return (bus);
214114246Snjl    subclass = pci_cfgregread(bus, slot, func, PCIR_SUBCLASS, 1);
215114246Snjl    /* Find the header type, masking off the multifunction bit */
216119539Sjhb    header = pci_cfgregread(bus, slot, func, PCIR_HDRTYPE, 1) & PCIM_HDRTYPE;
217119539Sjhb    if (header == PCIM_HDRTYPE_BRIDGE && subclass == PCIS_BRIDGE_PCI)
218114246Snjl        bus = pci_cfgregread(bus, slot, func, PCIR_SECBUS_1, 1);
219119539Sjhb    if (header == PCIM_HDRTYPE_CARDBUS && subclass == PCIS_BRIDGE_CARDBUS)
220114246Snjl        bus = pci_cfgregread(bus, slot, func, PCIR_SECBUS_2, 1);
221114246Snjl    return (bus);
222114246Snjl}
223114246Snjl
224114246Snjl/*
225114246Snjl * Find the bus number for a device
226114246Snjl *
227114246Snjl * rhandle: handle for the root bus
228114246Snjl * chandle: handle for the device
229114246Snjl * PciId: pointer to device slot and function, we fill out bus
230114246Snjl */
231114246Snjlvoid
232114246SnjlAcpiOsDerivePciId (
233114246Snjl    ACPI_HANDLE		rhandle,
234114246Snjl    ACPI_HANDLE		chandle,
235114246Snjl    ACPI_PCI_ID		**PciId)
236114246Snjl{
237114246Snjl    ACPI_HANDLE parent;
238114246Snjl    int bus;
239114246Snjl
240114246Snjl    if (pci_cfgregopen() == 0)
241114246Snjl        panic("AcpiOsDerivePciId unable to initialize pci bus");
242114246Snjl
243114246Snjl    /* Try to read _BBN for bus number if we're at the root */
244114246Snjl    bus = 0;
245114246Snjl    if (rhandle == chandle) {
246114949Snjl        if (ACPI_FAILURE(acpi_EvaluateInteger(rhandle, "_BBN", &bus)) &&
247114949Snjl          bootverbose)
248114246Snjl            printf("AcpiOsDerivePciId: root bus has no _BBN, assuming 0\n");
249114246Snjl    }
250114246Snjl    /*
251114246Snjl     * Get the parent handle and call the recursive case.  It is not
252114246Snjl     * clear why we seem to be getting a chandle that points to a child
253114246Snjl     * of the desired slot/function but passing in the parent handle
254114246Snjl     * here works.
255114246Snjl     */
256114246Snjl    if (ACPI_SUCCESS(AcpiGetParent(chandle, &parent)))
257114246Snjl        bus = acpi_bus_number(rhandle, parent, *PciId);
258114246Snjl    (*PciId)->Bus = bus;
259114246Snjl    if (bootverbose) {
260114246Snjl        printf("AcpiOsDerivePciId: bus %d dev %d func %d\n",
261114246Snjl            (*PciId)->Bus, (*PciId)->Device, (*PciId)->Function);
262114246Snjl    }
263114246Snjl}
264