diff options
Diffstat (limited to 'drivers/acpi/pci_bind.c')
| -rw-r--r-- | drivers/acpi/pci_bind.c | 313 |
1 files changed, 37 insertions, 276 deletions
diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c index bc46de3d967f..a5a77b78a723 100644 --- a/drivers/acpi/pci_bind.c +++ b/drivers/acpi/pci_bind.c | |||
| @@ -24,12 +24,7 @@ | |||
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
| 27 | #include <linux/module.h> | ||
| 28 | #include <linux/init.h> | ||
| 29 | #include <linux/types.h> | 27 | #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> | 28 | #include <linux/pci.h> |
| 34 | #include <linux/acpi.h> | 29 | #include <linux/acpi.h> |
| 35 | #include <acpi/acpi_bus.h> | 30 | #include <acpi/acpi_bus.h> |
| @@ -38,310 +33,76 @@ | |||
| 38 | #define _COMPONENT ACPI_PCI_COMPONENT | 33 | #define _COMPONENT ACPI_PCI_COMPONENT |
| 39 | ACPI_MODULE_NAME("pci_bind"); | 34 | ACPI_MODULE_NAME("pci_bind"); |
| 40 | 35 | ||
| 41 | struct acpi_pci_data { | 36 | static int acpi_pci_unbind(struct acpi_device *device) |
| 42 | struct acpi_pci_id id; | ||
| 43 | struct pci_bus *bus; | ||
| 44 | struct pci_dev *dev; | ||
| 45 | }; | ||
| 46 | |||
| 47 | static int acpi_pci_unbind(struct acpi_device *device); | ||
| 48 | |||
| 49 | static 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 | */ | ||
| 65 | acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id) | ||
| 66 | { | 37 | { |
| 67 | int result = 0; | 38 | struct pci_dev *dev; |
| 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 | 39 | ||
| 92 | *id = data->id; | 40 | dev = acpi_get_pci_dev(device->handle); |
| 41 | if (!dev || !dev->subordinate) | ||
| 42 | goto out; | ||
| 93 | 43 | ||
| 94 | /* | 44 | acpi_pci_irq_del_prt(dev->subordinate); |
| 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 | 45 | ||
| 101 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 46 | device->ops.bind = NULL; |
| 102 | "Device %s has PCI address %04x:%02x:%02x.%d\n", | 47 | device->ops.unbind = NULL; |
| 103 | acpi_device_bid(device), id->segment, id->bus, | ||
| 104 | id->device, id->function)); | ||
| 105 | 48 | ||
| 106 | return AE_OK; | 49 | out: |
| 50 | pci_dev_put(dev); | ||
| 51 | return 0; | ||
| 107 | } | 52 | } |
| 108 | 53 | ||
| 109 | EXPORT_SYMBOL(acpi_get_pci_id); | 54 | static int acpi_pci_bind(struct acpi_device *device) |
| 110 | |||
| 111 | int acpi_pci_bind(struct acpi_device *device) | ||
| 112 | { | 55 | { |
| 113 | int result = 0; | ||
| 114 | acpi_status status; | 56 | 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; | 57 | acpi_handle handle; |
| 58 | struct pci_bus *bus; | ||
| 59 | struct pci_dev *dev; | ||
| 119 | 60 | ||
| 120 | if (!device || !device->parent) | 61 | dev = acpi_get_pci_dev(device->handle); |
| 121 | return -EINVAL; | 62 | if (!dev) |
| 122 | 63 | return 0; | |
| 123 | data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); | ||
| 124 | if (!data) | ||
| 125 | return -ENOMEM; | ||
| 126 | |||
| 127 | status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); | ||
| 128 | if (ACPI_FAILURE(status)) { | ||
| 129 | kfree(data); | ||
| 130 | return -ENODEV; | ||
| 131 | } | ||
| 132 | |||
| 133 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI device [%s]...\n", | ||
| 134 | (char *)buffer.pointer)); | ||
| 135 | |||
| 136 | /* | ||
| 137 | * Segment & Bus | ||
| 138 | * ------------- | ||
| 139 | * These are obtained via the parent device's ACPI-PCI context. | ||
| 140 | */ | ||
| 141 | status = acpi_get_data(device->parent->handle, acpi_pci_data_handler, | ||
| 142 | (void **)&pdata); | ||
| 143 | if (ACPI_FAILURE(status) || !pdata || !pdata->bus) { | ||
| 144 | ACPI_EXCEPTION((AE_INFO, status, | ||
| 145 | "Invalid ACPI-PCI context for parent device %s", | ||
| 146 | acpi_device_bid(device->parent))); | ||
| 147 | result = -ENODEV; | ||
| 148 | goto end; | ||
| 149 | } | ||
| 150 | data->id.segment = pdata->id.segment; | ||
| 151 | data->id.bus = pdata->bus->number; | ||
| 152 | |||
| 153 | /* | ||
| 154 | * Device & Function | ||
| 155 | * ----------------- | ||
| 156 | * These are simply obtained from the device's _ADR method. Note | ||
| 157 | * that a value of zero is valid. | ||
| 158 | */ | ||
| 159 | data->id.device = device->pnp.bus_address >> 16; | ||
| 160 | data->id.function = device->pnp.bus_address & 0xFFFF; | ||
| 161 | |||
| 162 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "...to %04x:%02x:%02x.%d\n", | ||
| 163 | data->id.segment, data->id.bus, data->id.device, | ||
| 164 | data->id.function)); | ||
| 165 | |||
| 166 | /* | ||
| 167 | * TBD: Support slot devices (e.g. function=0xFFFF). | ||
| 168 | */ | ||
| 169 | |||
| 170 | /* | ||
| 171 | * Locate PCI Device | ||
| 172 | * ----------------- | ||
| 173 | * Locate matching device in PCI namespace. If it doesn't exist | ||
| 174 | * this typically means that the device isn't currently inserted | ||
| 175 | * (e.g. docking station, port replicator, etc.). | ||
| 176 | */ | ||
| 177 | data->dev = pci_get_slot(pdata->bus, | ||
| 178 | PCI_DEVFN(data->id.device, data->id.function)); | ||
| 179 | if (!data->dev) { | ||
| 180 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
| 181 | "Device %04x:%02x:%02x.%d not present in PCI namespace\n", | ||
| 182 | data->id.segment, data->id.bus, | ||
| 183 | data->id.device, data->id.function)); | ||
| 184 | result = -ENODEV; | ||
| 185 | goto end; | ||
| 186 | } | ||
| 187 | if (!data->dev->bus) { | ||
| 188 | printk(KERN_ERR PREFIX | ||
| 189 | "Device %04x:%02x:%02x.%d has invalid 'bus' field\n", | ||
| 190 | data->id.segment, data->id.bus, | ||
| 191 | data->id.device, data->id.function); | ||
| 192 | result = -ENODEV; | ||
| 193 | goto end; | ||
| 194 | } | ||
| 195 | 64 | ||
| 196 | /* | 65 | /* |
| 197 | * PCI Bridge? | 66 | * Install the 'bind' function to facilitate callbacks for |
| 198 | * ----------- | 67 | * children of the P2P bridge. |
| 199 | * If so, set the 'bus' field and install the 'bind' function to | ||
| 200 | * facilitate callbacks for all of its children. | ||
| 201 | */ | 68 | */ |
| 202 | if (data->dev->subordinate) { | 69 | if (dev->subordinate) { |
| 203 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 70 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
| 204 | "Device %04x:%02x:%02x.%d is a PCI bridge\n", | 71 | "Device %04x:%02x:%02x.%d is a PCI bridge\n", |
| 205 | data->id.segment, data->id.bus, | 72 | pci_domain_nr(dev->bus), dev->bus->number, |
| 206 | data->id.device, data->id.function)); | 73 | PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn))); |
| 207 | data->bus = data->dev->subordinate; | ||
| 208 | device->ops.bind = acpi_pci_bind; | 74 | device->ops.bind = acpi_pci_bind; |
| 209 | device->ops.unbind = acpi_pci_unbind; | 75 | device->ops.unbind = acpi_pci_unbind; |
| 210 | } | 76 | } |
| 211 | 77 | ||
| 212 | /* | 78 | /* |
| 213 | * Attach ACPI-PCI Context | 79 | * Evaluate and parse _PRT, if exists. This code allows parsing of |
| 214 | * ----------------------- | 80 | * _PRT objects within the scope of non-bridge devices. Note that |
| 215 | * Thus binding the ACPI and PCI devices. | 81 | * _PRTs within the scope of a PCI bridge assume the bridge's |
| 216 | */ | 82 | * subordinate bus number. |
| 217 | status = acpi_attach_data(device->handle, acpi_pci_data_handler, data); | ||
| 218 | if (ACPI_FAILURE(status)) { | ||
| 219 | ACPI_EXCEPTION((AE_INFO, status, | ||
| 220 | "Unable to attach ACPI-PCI context to device %s", | ||
| 221 | acpi_device_bid(device))); | ||
| 222 | result = -ENODEV; | ||
| 223 | goto end; | ||
| 224 | } | ||
| 225 | |||
| 226 | /* | ||
| 227 | * PCI Routing Table | ||
| 228 | * ----------------- | ||
| 229 | * Evaluate and parse _PRT, if exists. This code is independent of | ||
| 230 | * PCI bridges (above) to allow parsing of _PRT objects within the | ||
| 231 | * scope of non-bridge devices. Note that _PRTs within the scope of | ||
| 232 | * a PCI bridge assume the bridge's subordinate bus number. | ||
| 233 | * | 83 | * |
| 234 | * TBD: Can _PRTs exist within the scope of non-bridge PCI devices? | 84 | * TBD: Can _PRTs exist within the scope of non-bridge PCI devices? |
| 235 | */ | 85 | */ |
| 236 | status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); | 86 | status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); |
| 237 | if (ACPI_SUCCESS(status)) { | ||
| 238 | if (data->bus) /* PCI-PCI bridge */ | ||
| 239 | acpi_pci_irq_add_prt(device->handle, data->id.segment, | ||
| 240 | data->bus->number); | ||
| 241 | else /* non-bridge PCI device */ | ||
| 242 | acpi_pci_irq_add_prt(device->handle, data->id.segment, | ||
| 243 | data->id.bus); | ||
| 244 | } | ||
| 245 | |||
| 246 | end: | ||
| 247 | kfree(buffer.pointer); | ||
| 248 | if (result) { | ||
| 249 | pci_dev_put(data->dev); | ||
| 250 | kfree(data); | ||
| 251 | } | ||
| 252 | return result; | ||
| 253 | } | ||
| 254 | |||
| 255 | static int acpi_pci_unbind(struct acpi_device *device) | ||
| 256 | { | ||
| 257 | int result = 0; | ||
| 258 | acpi_status status; | ||
| 259 | struct acpi_pci_data *data; | ||
| 260 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 261 | |||
| 262 | |||
| 263 | if (!device || !device->parent) | ||
| 264 | return -EINVAL; | ||
| 265 | |||
| 266 | status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); | ||
| 267 | if (ACPI_FAILURE(status)) | 87 | if (ACPI_FAILURE(status)) |
| 268 | return -ENODEV; | 88 | goto out; |
| 269 | 89 | ||
| 270 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unbinding PCI device [%s]...\n", | 90 | if (dev->subordinate) |
| 271 | (char *) buffer.pointer)); | 91 | bus = dev->subordinate; |
| 272 | kfree(buffer.pointer); | 92 | else |
| 93 | bus = dev->bus; | ||
| 273 | 94 | ||
| 274 | status = | 95 | acpi_pci_irq_add_prt(device->handle, bus); |
| 275 | acpi_get_data(device->handle, acpi_pci_data_handler, | ||
| 276 | (void **)&data); | ||
| 277 | if (ACPI_FAILURE(status)) { | ||
| 278 | result = -ENODEV; | ||
| 279 | goto end; | ||
| 280 | } | ||
| 281 | 96 | ||
| 282 | status = acpi_detach_data(device->handle, acpi_pci_data_handler); | 97 | out: |
| 283 | if (ACPI_FAILURE(status)) { | 98 | pci_dev_put(dev); |
| 284 | ACPI_EXCEPTION((AE_INFO, status, | 99 | return 0; |
| 285 | "Unable to detach data from device %s", | ||
| 286 | acpi_device_bid(device))); | ||
| 287 | result = -ENODEV; | ||
| 288 | goto end; | ||
| 289 | } | ||
| 290 | if (data->dev->subordinate) { | ||
| 291 | acpi_pci_irq_del_prt(data->id.segment, data->bus->number); | ||
| 292 | } | ||
| 293 | pci_dev_put(data->dev); | ||
| 294 | kfree(data); | ||
| 295 | |||
| 296 | end: | ||
| 297 | return result; | ||
| 298 | } | 100 | } |
| 299 | 101 | ||
| 300 | int | 102 | int acpi_pci_bind_root(struct acpi_device *device) |
| 301 | acpi_pci_bind_root(struct acpi_device *device, | ||
| 302 | struct acpi_pci_id *id, struct pci_bus *bus) | ||
| 303 | { | 103 | { |
| 304 | int result = 0; | ||
| 305 | acpi_status status; | ||
| 306 | struct acpi_pci_data *data = NULL; | ||
| 307 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 308 | |||
| 309 | if (!device || !id || !bus) { | ||
| 310 | return -EINVAL; | ||
| 311 | } | ||
| 312 | |||
| 313 | data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); | ||
| 314 | if (!data) | ||
| 315 | return -ENOMEM; | ||
| 316 | |||
| 317 | data->id = *id; | ||
| 318 | data->bus = bus; | ||
| 319 | device->ops.bind = acpi_pci_bind; | 104 | device->ops.bind = acpi_pci_bind; |
| 320 | device->ops.unbind = acpi_pci_unbind; | 105 | device->ops.unbind = acpi_pci_unbind; |
| 321 | 106 | ||
| 322 | status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); | 107 | return 0; |
| 323 | if (ACPI_FAILURE(status)) { | ||
| 324 | kfree (data); | ||
| 325 | return -ENODEV; | ||
| 326 | } | ||
| 327 | |||
| 328 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI root bridge [%s] to " | ||
| 329 | "%04x:%02x\n", (char *)buffer.pointer, | ||
| 330 | id->segment, id->bus)); | ||
| 331 | |||
| 332 | status = acpi_attach_data(device->handle, acpi_pci_data_handler, data); | ||
| 333 | if (ACPI_FAILURE(status)) { | ||
| 334 | ACPI_EXCEPTION((AE_INFO, status, | ||
| 335 | "Unable to attach ACPI-PCI context to device %s", | ||
| 336 | (char *)buffer.pointer)); | ||
| 337 | result = -ENODEV; | ||
| 338 | goto end; | ||
| 339 | } | ||
| 340 | |||
| 341 | end: | ||
| 342 | kfree(buffer.pointer); | ||
| 343 | if (result != 0) | ||
| 344 | kfree(data); | ||
| 345 | |||
| 346 | return result; | ||
| 347 | } | 108 | } |
