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