Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.30-rc2 359 lines 9.6 kB view raw
1/* 2 * pci_bind.c - ACPI PCI Device Binding ($Revision: 2 $) 3 * 4 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> 5 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 6 * 7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or (at 12 * your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, but 15 * WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License along 20 * with this program; if not, write to the Free Software Foundation, Inc., 21 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 22 * 23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 24 */ 25 26#include <linux/kernel.h> 27#include <linux/module.h> 28#include <linux/init.h> 29#include <linux/types.h> 30#include <linux/proc_fs.h> 31#include <linux/spinlock.h> 32#include <linux/pm.h> 33#include <linux/pci.h> 34#include <linux/acpi.h> 35#include <acpi/acpi_bus.h> 36#include <acpi/acpi_drivers.h> 37 38#define _COMPONENT ACPI_PCI_COMPONENT 39ACPI_MODULE_NAME("pci_bind"); 40 41struct acpi_pci_data { 42 struct acpi_pci_id id; 43 struct pci_bus *bus; 44 struct pci_dev *dev; 45}; 46 47static int acpi_pci_unbind(struct acpi_device *device); 48 49static void acpi_pci_data_handler(acpi_handle handle, u32 function, 50 void *context) 51{ 52 53 /* TBD: Anything we need to do here? */ 54 55 return; 56} 57 58/** 59 * acpi_get_pci_id 60 * ------------------ 61 * This function is used by the ACPI Interpreter (a.k.a. Core Subsystem) 62 * to resolve PCI information for ACPI-PCI devices defined in the namespace. 63 * This typically occurs when resolving PCI operation region information. 64 */ 65acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id) 66{ 67 int result = 0; 68 acpi_status status = AE_OK; 69 struct acpi_device *device = NULL; 70 struct acpi_pci_data *data = NULL; 71 72 73 if (!id) 74 return AE_BAD_PARAMETER; 75 76 result = acpi_bus_get_device(handle, &device); 77 if (result) { 78 printk(KERN_ERR PREFIX 79 "Invalid ACPI Bus context for device %s\n", 80 acpi_device_bid(device)); 81 return AE_NOT_EXIST; 82 } 83 84 status = acpi_get_data(handle, acpi_pci_data_handler, (void **)&data); 85 if (ACPI_FAILURE(status) || !data) { 86 ACPI_EXCEPTION((AE_INFO, status, 87 "Invalid ACPI-PCI context for device %s", 88 acpi_device_bid(device))); 89 return status; 90 } 91 92 *id = data->id; 93 94 /* 95 id->segment = data->id.segment; 96 id->bus = data->id.bus; 97 id->device = data->id.device; 98 id->function = data->id.function; 99 */ 100 101 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 102 "Device %s has PCI address %04x:%02x:%02x.%d\n", 103 acpi_device_bid(device), id->segment, id->bus, 104 id->device, id->function)); 105 106 return AE_OK; 107} 108 109EXPORT_SYMBOL(acpi_get_pci_id); 110 111int acpi_pci_bind(struct acpi_device *device) 112{ 113 int result = 0; 114 acpi_status status; 115 struct acpi_pci_data *data; 116 struct acpi_pci_data *pdata; 117 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 118 acpi_handle handle; 119 struct pci_dev *dev; 120 struct pci_bus *bus; 121 122 123 if (!device || !device->parent) 124 return -EINVAL; 125 126 data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); 127 if (!data) 128 return -ENOMEM; 129 130 status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); 131 if (ACPI_FAILURE(status)) { 132 kfree(data); 133 return -ENODEV; 134 } 135 136 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI device [%s]...\n", 137 (char *)buffer.pointer)); 138 139 /* 140 * Segment & Bus 141 * ------------- 142 * These are obtained via the parent device's ACPI-PCI context. 143 */ 144 status = acpi_get_data(device->parent->handle, acpi_pci_data_handler, 145 (void **)&pdata); 146 if (ACPI_FAILURE(status) || !pdata || !pdata->bus) { 147 ACPI_EXCEPTION((AE_INFO, status, 148 "Invalid ACPI-PCI context for parent device %s", 149 acpi_device_bid(device->parent))); 150 result = -ENODEV; 151 goto end; 152 } 153 data->id.segment = pdata->id.segment; 154 data->id.bus = pdata->bus->number; 155 156 /* 157 * Device & Function 158 * ----------------- 159 * These are simply obtained from the device's _ADR method. Note 160 * that a value of zero is valid. 161 */ 162 data->id.device = device->pnp.bus_address >> 16; 163 data->id.function = device->pnp.bus_address & 0xFFFF; 164 165 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "...to %04x:%02x:%02x.%d\n", 166 data->id.segment, data->id.bus, data->id.device, 167 data->id.function)); 168 169 /* 170 * TBD: Support slot devices (e.g. function=0xFFFF). 171 */ 172 173 /* 174 * Locate PCI Device 175 * ----------------- 176 * Locate matching device in PCI namespace. If it doesn't exist 177 * this typically means that the device isn't currently inserted 178 * (e.g. docking station, port replicator, etc.). 179 * We cannot simply search the global pci device list, since 180 * PCI devices are added to the global pci list when the root 181 * bridge start ops are run, which may not have happened yet. 182 */ 183 bus = pci_find_bus(data->id.segment, data->id.bus); 184 if (bus) { 185 list_for_each_entry(dev, &bus->devices, bus_list) { 186 if (dev->devfn == PCI_DEVFN(data->id.device, 187 data->id.function)) { 188 data->dev = dev; 189 break; 190 } 191 } 192 } 193 if (!data->dev) { 194 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 195 "Device %04x:%02x:%02x.%d not present in PCI namespace\n", 196 data->id.segment, data->id.bus, 197 data->id.device, data->id.function)); 198 result = -ENODEV; 199 goto end; 200 } 201 if (!data->dev->bus) { 202 printk(KERN_ERR PREFIX 203 "Device %04x:%02x:%02x.%d has invalid 'bus' field\n", 204 data->id.segment, data->id.bus, 205 data->id.device, data->id.function); 206 result = -ENODEV; 207 goto end; 208 } 209 210 /* 211 * PCI Bridge? 212 * ----------- 213 * If so, set the 'bus' field and install the 'bind' function to 214 * facilitate callbacks for all of its children. 215 */ 216 if (data->dev->subordinate) { 217 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 218 "Device %04x:%02x:%02x.%d is a PCI bridge\n", 219 data->id.segment, data->id.bus, 220 data->id.device, data->id.function)); 221 data->bus = data->dev->subordinate; 222 device->ops.bind = acpi_pci_bind; 223 device->ops.unbind = acpi_pci_unbind; 224 } 225 226 /* 227 * Attach ACPI-PCI Context 228 * ----------------------- 229 * Thus binding the ACPI and PCI devices. 230 */ 231 status = acpi_attach_data(device->handle, acpi_pci_data_handler, data); 232 if (ACPI_FAILURE(status)) { 233 ACPI_EXCEPTION((AE_INFO, status, 234 "Unable to attach ACPI-PCI context to device %s", 235 acpi_device_bid(device))); 236 result = -ENODEV; 237 goto end; 238 } 239 240 /* 241 * PCI Routing Table 242 * ----------------- 243 * Evaluate and parse _PRT, if exists. This code is independent of 244 * PCI bridges (above) to allow parsing of _PRT objects within the 245 * scope of non-bridge devices. Note that _PRTs within the scope of 246 * a PCI bridge assume the bridge's subordinate bus number. 247 * 248 * TBD: Can _PRTs exist within the scope of non-bridge PCI devices? 249 */ 250 status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); 251 if (ACPI_SUCCESS(status)) { 252 if (data->bus) /* PCI-PCI bridge */ 253 acpi_pci_irq_add_prt(device->handle, data->id.segment, 254 data->bus->number); 255 else /* non-bridge PCI device */ 256 acpi_pci_irq_add_prt(device->handle, data->id.segment, 257 data->id.bus); 258 } 259 260 end: 261 kfree(buffer.pointer); 262 if (result) 263 kfree(data); 264 265 return result; 266} 267 268static int acpi_pci_unbind(struct acpi_device *device) 269{ 270 int result = 0; 271 acpi_status status; 272 struct acpi_pci_data *data; 273 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 274 275 276 if (!device || !device->parent) 277 return -EINVAL; 278 279 status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); 280 if (ACPI_FAILURE(status)) 281 return -ENODEV; 282 283 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unbinding PCI device [%s]...\n", 284 (char *) buffer.pointer)); 285 kfree(buffer.pointer); 286 287 status = 288 acpi_get_data(device->handle, acpi_pci_data_handler, 289 (void **)&data); 290 if (ACPI_FAILURE(status)) { 291 result = -ENODEV; 292 goto end; 293 } 294 295 status = acpi_detach_data(device->handle, acpi_pci_data_handler); 296 if (ACPI_FAILURE(status)) { 297 ACPI_EXCEPTION((AE_INFO, status, 298 "Unable to detach data from device %s", 299 acpi_device_bid(device))); 300 result = -ENODEV; 301 goto end; 302 } 303 if (data->dev->subordinate) { 304 acpi_pci_irq_del_prt(data->id.segment, data->bus->number); 305 } 306 kfree(data); 307 308 end: 309 return result; 310} 311 312int 313acpi_pci_bind_root(struct acpi_device *device, 314 struct acpi_pci_id *id, struct pci_bus *bus) 315{ 316 int result = 0; 317 acpi_status status; 318 struct acpi_pci_data *data = NULL; 319 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 320 321 if (!device || !id || !bus) { 322 return -EINVAL; 323 } 324 325 data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); 326 if (!data) 327 return -ENOMEM; 328 329 data->id = *id; 330 data->bus = bus; 331 device->ops.bind = acpi_pci_bind; 332 device->ops.unbind = acpi_pci_unbind; 333 334 status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); 335 if (ACPI_FAILURE(status)) { 336 kfree (data); 337 return -ENODEV; 338 } 339 340 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI root bridge [%s] to " 341 "%04x:%02x\n", (char *)buffer.pointer, 342 id->segment, id->bus)); 343 344 status = acpi_attach_data(device->handle, acpi_pci_data_handler, data); 345 if (ACPI_FAILURE(status)) { 346 ACPI_EXCEPTION((AE_INFO, status, 347 "Unable to attach ACPI-PCI context to device %s", 348 (char *)buffer.pointer)); 349 result = -ENODEV; 350 goto end; 351 } 352 353 end: 354 kfree(buffer.pointer); 355 if (result != 0) 356 kfree(data); 357 358 return result; 359}