Rev 1627 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1627 | Rev 1633 | ||
---|---|---|---|
Line 27... | Line 27... | ||
27 | return 'A' + pin - 1; |
27 | return 'A' + pin - 1; |
28 | } |
28 | } |
29 | 29 | ||
Line -... | Line 30... | ||
- | 30 | ||
- | 31 | /* -------------------------------------------------------------------------- |
|
- | 32 | PCI IRQ Routing Table (PRT) Support |
|
- | 33 | -------------------------------------------------------------------------- */ |
|
- | 34 | ||
- | 35 | static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(struct pci_dev *dev, |
|
- | 36 | int pin) |
|
- | 37 | { |
|
- | 38 | struct acpi_prt_entry *entry; |
|
- | 39 | int segment = pci_domain_nr(dev->bus); |
|
- | 40 | int bus = dev->bus->number; |
|
- | 41 | int device = PCI_SLOT(dev->devfn); |
|
- | 42 | ||
- | 43 | spin_lock(&acpi_prt_lock); |
|
- | 44 | list_for_each_entry(entry, &acpi_prt_list, list) { |
|
- | 45 | if ((segment == entry->id.Segment) |
|
- | 46 | && (bus == entry->id.Bus) |
|
- | 47 | && (device == entry->id.Device) |
|
- | 48 | && (pin == entry->pin)) { |
|
- | 49 | spin_unlock(&acpi_prt_lock); |
|
- | 50 | return entry; |
|
- | 51 | } |
|
- | 52 | } |
|
- | 53 | spin_unlock(&acpi_prt_lock); |
|
- | 54 | return NULL; |
|
- | 55 | } |
|
30 | 56 | ||
31 | static int acpi_pci_irq_add_entry(ACPI_HANDLE handle, struct pci_bus *bus, |
57 | static int acpi_pci_irq_add_entry(ACPI_HANDLE handle, struct pci_bus *bus, |
32 | struct acpi_pci_routing_table *prt) |
58 | struct acpi_pci_routing_table *prt) |
33 | { |
59 | { |
Line 127... | Line 153... | ||
127 | kfree(buffer.Pointer); |
153 | kfree(buffer.Pointer); |
128 | return 0; |
154 | return 0; |
129 | } |
155 | } |
Line -... | Line 156... | ||
- | 156 | ||
- | 157 | static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) |
|
- | 158 | { |
|
- | 159 | struct acpi_prt_entry *entry; |
|
- | 160 | struct pci_dev *bridge; |
|
- | 161 | u8 bridge_pin, orig_pin = pin; |
|
- | 162 | ||
- | 163 | entry = acpi_pci_irq_find_prt_entry(dev, pin); |
|
- | 164 | if (entry) { |
|
- | 165 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %s[%c] _PRT entry\n", |
|
- | 166 | pci_name(dev), pin_name(pin))); |
|
- | 167 | return entry; |
|
- | 168 | } |
|
- | 169 | ||
- | 170 | /* |
|
- | 171 | * Attempt to derive an IRQ for this device from a parent bridge's |
|
- | 172 | * PCI interrupt routing entry (eg. yenta bridge and add-in card bridge). |
|
- | 173 | */ |
|
- | 174 | bridge = dev->bus->self; |
|
- | 175 | while (bridge) |
|
- | 176 | { |
|
- | 177 | pin = pci_swizzle_interrupt_pin(dev, pin); |
|
- | 178 | ||
- | 179 | if ((bridge->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) { |
|
- | 180 | /* PC card has the same IRQ as its cardbridge */ |
|
- | 181 | bridge_pin = bridge->pin; |
|
- | 182 | if (!bridge_pin) { |
|
- | 183 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
|
- | 184 | "No interrupt pin configured for device %s\n", |
|
- | 185 | pci_name(bridge))); |
|
- | 186 | return NULL; |
|
- | 187 | } |
|
- | 188 | pin = bridge_pin; |
|
- | 189 | } |
|
- | 190 | ||
- | 191 | entry = acpi_pci_irq_find_prt_entry(bridge, pin); |
|
- | 192 | if (entry) { |
|
- | 193 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
|
- | 194 | "Derived GSI for %s INT %c from %s\n", |
|
- | 195 | pci_name(dev), pin_name(orig_pin), |
|
- | 196 | pci_name(bridge))); |
|
- | 197 | return entry; |
|
- | 198 | } |
|
- | 199 | ||
- | 200 | dev = bridge; |
|
- | 201 | bridge = dev->bus->self; |
|
- | 202 | } |
|
- | 203 | ||
- | 204 | dbgprintf("can't derive routing for PCI INT %c\n", |
|
- | 205 | pin_name(orig_pin)); |
|
- | 206 | return NULL; |
|
- | 207 | } |
|
- | 208 | ||
- | 209 | ||
- | 210 | int acpi_get_irq(struct pci_dev *dev) |
|
- | 211 | { |
|
- | 212 | struct acpi_prt_entry *entry; |
|
- | 213 | int gsi = -1; |
|
- | 214 | u8 pin; |
|
- | 215 | ||
- | 216 | int triggering = ACPI_LEVEL_SENSITIVE; |
|
- | 217 | int polarity = ACPI_ACTIVE_LOW; |
|
- | 218 | ||
- | 219 | char *link = NULL; |
|
- | 220 | char link_desc[16]; |
|
- | 221 | int rc; |
|
- | 222 | ||
- | 223 | pin = dev->pin; |
|
- | 224 | if (!pin) { |
|
- | 225 | dbgprintf(("No interrupt pin configured for device %s\n", |
|
- | 226 | pci_name(dev))); |
|
- | 227 | return 0; |
|
- | 228 | } |
|
- | 229 | ||
- | 230 | entry = acpi_pci_irq_lookup(dev, pin); |
|
- | 231 | if (!entry) { |
|
- | 232 | /* |
|
- | 233 | * IDE legacy mode controller IRQs are magic. Why do compat |
|
- | 234 | * extensions always make such a nasty mess. |
|
- | 235 | */ |
|
- | 236 | if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE && |
|
- | 237 | (dev->class & 0x05) == 0) |
|
- | 238 | return 0; |
|
- | 239 | } |
|
- | 240 | ||
- | 241 | if (entry) |
|
- | 242 | { |
|
- | 243 | if (entry->link) |
|
- | 244 | { |
|
- | 245 | gsi = acpi_pci_link_allocate_irq(entry->link, |
|
- | 246 | entry->index, |
|
- | 247 | &triggering, &polarity, |
|
- | 248 | &link); |
|
- | 249 | // dbgprintf("link not implemen\n"); |
|
- | 250 | } |
|
- | 251 | else |
|
- | 252 | gsi = entry->index; |
|
- | 253 | } else |
|
- | 254 | gsi = -1; |
|
- | 255 | ||
- | 256 | #if 0 |
|
- | 257 | ||
- | 258 | /* |
|
- | 259 | * No IRQ known to the ACPI subsystem - maybe the BIOS / |
|
- | 260 | * driver reported one, then use it. Exit in any case. |
|
- | 261 | */ |
|
- | 262 | if (gsi < 0) { |
|
- | 263 | u32 dev_gsi; |
|
- | 264 | dev_warn(&dev->dev, "PCI INT %c: no GSI", pin_name(pin)); |
|
- | 265 | /* Interrupt Line values above 0xF are forbidden */ |
|
- | 266 | if (dev->irq > 0 && (dev->irq <= 0xF) && |
|
- | 267 | (acpi_isa_irq_to_gsi(dev->irq, &dev_gsi) == 0)) { |
|
- | 268 | printk(" - using ISA IRQ %d\n", dev->irq); |
|
- | 269 | acpi_register_gsi(&dev->dev, dev_gsi, |
|
- | 270 | ACPI_LEVEL_SENSITIVE, |
|
- | 271 | ACPI_ACTIVE_LOW); |
|
- | 272 | return 0; |
|
- | 273 | } else { |
|
- | 274 | printk("\n"); |
|
- | 275 | return 0; |
|
- | 276 | } |
|
- | 277 | } |
|
- | 278 | ||
- | 279 | rc = acpi_register_gsi(&dev->dev, gsi, triggering, polarity); |
|
- | 280 | if (rc < 0) { |
|
- | 281 | dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n", |
|
- | 282 | pin_name(pin)); |
|
- | 283 | return rc; |
|
- | 284 | } |
|
- | 285 | dev->irq = rc; |
|
- | 286 | ||
- | 287 | if (link) |
|
- | 288 | snprintf(link_desc, sizeof(link_desc), " -> Link[%s]", link); |
|
- | 289 | else |
|
- | 290 | link_desc[0] = '\0'; |
|
- | 291 | ||
- | 292 | dev_info(&dev->dev, "PCI INT %c%s -> GSI %u (%s, %s) -> IRQ %d\n", |
|
- | 293 | pin_name(pin), link_desc, gsi, |
|
- | 294 | (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge", |
|
- | 295 | (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq); |
|
- | 296 | #endif |
|
- | 297 | ||
- | 298 | return gsi; |
|
- | 299 | } |
|
- | 300 | ||
- | 301 | ||
- | 302 | #define ACPI_PCI_LINK_MAX_POSSIBLE 16 |
|
- | 303 | ||
- | 304 | /* |
|
- | 305 | * If a link is initialized, we never change its active and initialized |
|
- | 306 | * later even the link is disable. Instead, we just repick the active irq |
|
- | 307 | */ |
|
- | 308 | struct acpi_pci_link_irq { |
|
- | 309 | u8 active; /* Current IRQ */ |
|
- | 310 | u8 triggering; /* All IRQs */ |
|
- | 311 | u8 polarity; /* All IRQs */ |
|
- | 312 | u8 resource_type; |
|
- | 313 | u8 possible_count; |
|
- | 314 | u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE]; |
|
- | 315 | u8 initialized:1; |
|
- | 316 | u8 reserved:7; |
|
- | 317 | }; |
|
- | 318 | ||
- | 319 | struct acpi_pci_link { |
|
- | 320 | struct list_head list; |
|
- | 321 | struct acpi_device *device; |
|
- | 322 | struct acpi_pci_link_irq irq; |
|
- | 323 | int refcnt; |
|
- | 324 | }; |
|
- | 325 | ||
- | 326 | static LIST_HEAD(acpi_link_list); |
|
- | 327 | static DEFINE_MUTEX(acpi_link_lock); |
|
- | 328 | ||
- | 329 | ||
- | 330 | static int acpi_pci_link_set(struct acpi_pci_link *link, int irq) |
|
- | 331 | { |
|
- | 332 | int result; |
|
- | 333 | ACPI_STATUS status; |
|
- | 334 | struct { |
|
- | 335 | struct acpi_resource res; |
|
- | 336 | struct acpi_resource end; |
|
- | 337 | } *resource; |
|
- | 338 | ||
- | 339 | ACPI_BUFFER buffer = { 0, NULL }; |
|
- | 340 | ||
- | 341 | if (!irq) |
|
- | 342 | return -EINVAL; |
|
- | 343 | ||
- | 344 | resource = kzalloc(sizeof(*resource) + 1, GFP_KERNEL); |
|
- | 345 | if (!resource) |
|
- | 346 | return -ENOMEM; |
|
- | 347 | ||
- | 348 | buffer.Length = sizeof(*resource) + 1; |
|
- | 349 | buffer.Pointer = resource; |
|
- | 350 | ||
- | 351 | switch (link->irq.resource_type) { |
|
- | 352 | case ACPI_RESOURCE_TYPE_IRQ: |
|
- | 353 | resource->res.Type = ACPI_RESOURCE_TYPE_IRQ; |
|
- | 354 | resource->res.Length = sizeof(struct acpi_resource); |
|
- | 355 | resource->res.Data.Irq.Triggering = link->irq.triggering; |
|
- | 356 | resource->res.Data.Irq.Polarity = |
|
- | 357 | link->irq.polarity; |
|
- | 358 | if (link->irq.triggering == ACPI_EDGE_SENSITIVE) |
|
- | 359 | resource->res.Data.Irq.Sharable = |
|
- | 360 | ACPI_EXCLUSIVE; |
|
- | 361 | else |
|
- | 362 | resource->res.Data.Irq.Sharable = ACPI_SHARED; |
|
- | 363 | resource->res.Data.Irq.InterruptCount = 1; |
|
- | 364 | resource->res.Data.Irq.Interrupts[0] = irq; |
|
- | 365 | break; |
|
- | 366 | ||
- | 367 | case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: |
|
- | 368 | resource->res.Type = ACPI_RESOURCE_TYPE_EXTENDED_IRQ; |
|
- | 369 | resource->res.Length = sizeof(struct acpi_resource); |
|
- | 370 | resource->res.Data.ExtendedIrq.ProducerConsumer = |
|
- | 371 | ACPI_CONSUMER; |
|
- | 372 | resource->res.Data.ExtendedIrq.Triggering = |
|
- | 373 | link->irq.triggering; |
|
- | 374 | resource->res.Data.ExtendedIrq.Polarity = |
|
- | 375 | link->irq.polarity; |
|
- | 376 | if (link->irq.triggering == ACPI_EDGE_SENSITIVE) |
|
- | 377 | resource->res.Data.Irq.Sharable = |
|
- | 378 | ACPI_EXCLUSIVE; |
|
- | 379 | else |
|
- | 380 | resource->res.Data.Irq.Sharable = ACPI_SHARED; |
|
- | 381 | resource->res.Data.ExtendedIrq.InterruptCount = 1; |
|
- | 382 | resource->res.Data.ExtendedIrq.Interrupts[0] = irq; |
|
- | 383 | /* ignore resource_source, it's optional */ |
|
- | 384 | break; |
|
- | 385 | default: |
|
- | 386 | printk(KERN_ERR PREFIX "Invalid Resource_type %d\n", link->irq.resource_type); |
|
- | 387 | result = -EINVAL; |
|
- | 388 | goto end; |
|
- | 389 | ||
- | 390 | } |
|
- | 391 | resource->end.Type = ACPI_RESOURCE_TYPE_END_TAG; |
|
- | 392 | ||
- | 393 | #if 0 |
|
- | 394 | /* Attempt to set the resource */ |
|
- | 395 | status = acpi_set_current_resources(link->device->handle, &buffer); |
|
- | 396 | ||
- | 397 | /* check for total failure */ |
|
- | 398 | if (ACPI_FAILURE(status)) { |
|
- | 399 | dbgprintf("%s failure Evaluating _SRS", __FUNCTION__); |
|
- | 400 | result = -ENODEV; |
|
- | 401 | goto end; |
|
- | 402 | } |
|
- | 403 | ||
- | 404 | /* Query _STA, set device->status */ |
|
- | 405 | result = acpi_bus_get_status(link->device); |
|
- | 406 | if (result) { |
|
- | 407 | printk(KERN_ERR PREFIX "Unable to read status\n"); |
|
- | 408 | goto end; |
|
- | 409 | } |
|
- | 410 | if (!link->device->status.enabled) { |
|
- | 411 | printk(KERN_WARNING PREFIX |
|
- | 412 | "%s [%s] disabled and referenced, BIOS bug\n", |
|
- | 413 | acpi_device_name(link->device), |
|
- | 414 | acpi_device_bid(link->device)); |
|
- | 415 | } |
|
- | 416 | ||
- | 417 | /* Query _CRS, set link->irq.active */ |
|
- | 418 | result = acpi_pci_link_get_current(link); |
|
- | 419 | if (result) { |
|
- | 420 | goto end; |
|
- | 421 | } |
|
- | 422 | ||
- | 423 | /* |
|
- | 424 | * Is current setting not what we set? |
|
- | 425 | * set link->irq.active |
|
- | 426 | */ |
|
- | 427 | if (link->irq.active != irq) { |
|
- | 428 | /* |
|
- | 429 | * policy: when _CRS doesn't return what we just _SRS |
|
- | 430 | * assume _SRS worked and override _CRS value. |
|
- | 431 | */ |
|
- | 432 | printk(KERN_WARNING PREFIX |
|
- | 433 | "%s [%s] BIOS reported IRQ %d, using IRQ %d\n", |
|
- | 434 | acpi_device_name(link->device), |
|
- | 435 | acpi_device_bid(link->device), link->irq.active, irq); |
|
- | 436 | link->irq.active = irq; |
|
- | 437 | } |
|
- | 438 | #endif |
|
- | 439 | ||
- | 440 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d\n", link->irq.active)); |
|
- | 441 | ||
- | 442 | end: |
|
- | 443 | kfree(resource); |
|
- | 444 | return result; |
|
- | 445 | } |
|
- | 446 | ||
- | 447 | ||
- | 448 | ||
- | 449 | #define ACPI_MAX_IRQS 256 |
|
- | 450 | #define ACPI_MAX_ISA_IRQ 16 |
|
- | 451 | ||
- | 452 | #define PIRQ_PENALTY_PCI_AVAILABLE (0) |
|
- | 453 | #define PIRQ_PENALTY_PCI_POSSIBLE (16*16) |
|
- | 454 | #define PIRQ_PENALTY_PCI_USING (16*16*16) |
|
- | 455 | #define PIRQ_PENALTY_ISA_TYPICAL (16*16*16*16) |
|
- | 456 | #define PIRQ_PENALTY_ISA_USED (16*16*16*16*16) |
|
- | 457 | #define PIRQ_PENALTY_ISA_ALWAYS (16*16*16*16*16*16) |
|
- | 458 | ||
- | 459 | static int acpi_irq_penalty[ACPI_MAX_IRQS] = { |
|
- | 460 | PIRQ_PENALTY_ISA_ALWAYS, /* IRQ0 timer */ |
|
- | 461 | PIRQ_PENALTY_ISA_ALWAYS, /* IRQ1 keyboard */ |
|
- | 462 | PIRQ_PENALTY_ISA_ALWAYS, /* IRQ2 cascade */ |
|
- | 463 | PIRQ_PENALTY_ISA_TYPICAL, /* IRQ3 serial */ |
|
- | 464 | PIRQ_PENALTY_ISA_TYPICAL, /* IRQ4 serial */ |
|
- | 465 | PIRQ_PENALTY_ISA_TYPICAL, /* IRQ5 sometimes SoundBlaster */ |
|
- | 466 | PIRQ_PENALTY_ISA_TYPICAL, /* IRQ6 */ |
|
- | 467 | PIRQ_PENALTY_ISA_TYPICAL, /* IRQ7 parallel, spurious */ |
|
- | 468 | PIRQ_PENALTY_ISA_TYPICAL, /* IRQ8 rtc, sometimes */ |
|
- | 469 | PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ9 PCI, often acpi */ |
|
- | 470 | PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ10 PCI */ |
|
- | 471 | PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ11 PCI */ |
|
- | 472 | PIRQ_PENALTY_ISA_USED, /* IRQ12 mouse */ |
|
- | 473 | PIRQ_PENALTY_ISA_USED, /* IRQ13 fpe, sometimes */ |
|
- | 474 | PIRQ_PENALTY_ISA_USED, /* IRQ14 ide0 */ |
|
- | 475 | PIRQ_PENALTY_ISA_USED, /* IRQ15 ide1 */ |
|
- | 476 | /* >IRQ15 */ |
|
- | 477 | }; |
|
- | 478 | ||
- | 479 | ||
- | 480 | ||
- | 481 | ||
- | 482 | static int acpi_irq_balance = 0; |
|
- | 483 | ||
- | 484 | static int acpi_pci_link_allocate(struct acpi_pci_link *link) |
|
- | 485 | { |
|
- | 486 | int irq; |
|
- | 487 | int i; |
|
- | 488 | ||
- | 489 | if (link->irq.initialized) { |
|
- | 490 | if (link->refcnt == 0) |
|
- | 491 | /* This means the link is disabled but initialized */ |
|
- | 492 | acpi_pci_link_set(link, link->irq.active); |
|
- | 493 | return 0; |
|
- | 494 | } |
|
- | 495 | ||
- | 496 | /* |
|
- | 497 | * search for active IRQ in list of possible IRQs. |
|
- | 498 | */ |
|
- | 499 | for (i = 0; i < link->irq.possible_count; ++i) { |
|
- | 500 | if (link->irq.active == link->irq.possible[i]) |
|
- | 501 | break; |
|
- | 502 | } |
|
- | 503 | /* |
|
- | 504 | * forget active IRQ that is not in possible list |
|
- | 505 | */ |
|
- | 506 | if (i == link->irq.possible_count) { |
|
- | 507 | printk(KERN_WARNING PREFIX "_CRS %d not found" |
|
- | 508 | " in _PRS\n", link->irq.active); |
|
- | 509 | link->irq.active = 0; |
|
- | 510 | } |
|
- | 511 | ||
- | 512 | /* |
|
- | 513 | * if active found, use it; else pick entry from end of possible list. |
|
- | 514 | */ |
|
- | 515 | if (link->irq.active) |
|
- | 516 | irq = link->irq.active; |
|
- | 517 | else |
|
- | 518 | irq = link->irq.possible[link->irq.possible_count - 1]; |
|
- | 519 | ||
- | 520 | if (acpi_irq_balance || !link->irq.active) { |
|
- | 521 | /* |
|
- | 522 | * Select the best IRQ. This is done in reverse to promote |
|
- | 523 | * the use of IRQs 9, 10, 11, and >15. |
|
- | 524 | */ |
|
- | 525 | for (i = (link->irq.possible_count - 1); i >= 0; i--) { |
|
- | 526 | if (acpi_irq_penalty[irq] > |
|
- | 527 | acpi_irq_penalty[link->irq.possible[i]]) |
|
- | 528 | irq = link->irq.possible[i]; |
|
- | 529 | } |
|
- | 530 | } |
|
- | 531 | ||
- | 532 | /* Attempt to enable the link device at this IRQ. */ |
|
- | 533 | if (acpi_pci_link_set(link, irq)) { |
|
- | 534 | printk(KERN_ERR PREFIX "Unable to set IRQ for %s [%s]. " |
|
- | 535 | "Try pci=noacpi or acpi=off\n", |
|
- | 536 | acpi_device_name(link->device), |
|
- | 537 | acpi_device_bid(link->device)); |
|
- | 538 | return -ENODEV; |
|
- | 539 | } else { |
|
- | 540 | acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING; |
|
- | 541 | printk(KERN_WARNING PREFIX "%s [%s] enabled at IRQ %d\n", |
|
- | 542 | acpi_device_name(link->device), |
|
- | 543 | acpi_device_bid(link->device), link->irq.active); |
|
- | 544 | } |
|
- | 545 | ||
- | 546 | link->irq.initialized = 1; |
|
- | 547 | return 0; |
|
- | 548 | } |
|
- | 549 | ||
- | 550 | ||
- | 551 | /* |
|
- | 552 | * acpi_pci_link_allocate_irq |
|
- | 553 | * success: return IRQ >= 0 |
|
- | 554 | * failure: return -1 |
|
- | 555 | */ |
|
- | 556 | int acpi_pci_link_allocate_irq(ACPI_HANDLE handle, int index, |
|
- | 557 | int *triggering, int *polarity, char **name) |
|
- | 558 | { |
|
- | 559 | int result; |
|
- | 560 | struct acpi_device *device; |
|
- | 561 | struct acpi_pci_link *link; |
|
- | 562 | ||
- | 563 | result = acpi_bus_get_device(handle, &device); |
|
- | 564 | if (result) { |
|
- | 565 | printk(KERN_ERR PREFIX "Invalid link device\n"); |
|
- | 566 | return -1; |
|
- | 567 | } |
|
- | 568 | ||
- | 569 | link = acpi_driver_data(device); |
|
- | 570 | if (!link) { |
|
- | 571 | printk(KERN_ERR PREFIX "Invalid link context\n"); |
|
- | 572 | return -1; |
|
- | 573 | } |
|
- | 574 | ||
- | 575 | /* TBD: Support multiple index (IRQ) entries per Link Device */ |
|
- | 576 | if (index) { |
|
- | 577 | printk(KERN_ERR PREFIX "Invalid index %d\n", index); |
|
- | 578 | return -1; |
|
- | 579 | } |
|
- | 580 | ||
- | 581 | mutex_lock(&acpi_link_lock); |
|
- | 582 | if (acpi_pci_link_allocate(link)) { |
|
- | 583 | mutex_unlock(&acpi_link_lock); |
|
- | 584 | return -1; |
|
- | 585 | } |
|
- | 586 | ||
- | 587 | if (!link->irq.active) { |
|
- | 588 | mutex_unlock(&acpi_link_lock); |
|
- | 589 | printk(KERN_ERR PREFIX "Link active IRQ is 0!\n"); |
|
- | 590 | return -1; |
|
- | 591 | } |
|
- | 592 | link->refcnt++; |
|
- | 593 | mutex_unlock(&acpi_link_lock); |
|
- | 594 | ||
- | 595 | if (triggering) |
|
- | 596 | *triggering = link->irq.triggering; |
|
- | 597 | if (polarity) |
|
- | 598 | *polarity = link->irq.polarity; |
|
- | 599 | if (name) |
|
- | 600 | *name = acpi_device_bid(link->device); |
|
- | 601 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
|
- | 602 | "Link %s is referenced\n", |
|
- | 603 | acpi_device_bid(link->device))); |
|
- | 604 | return (link->irq.active); |
|
- | 605 | }>>=>> |
|
- | 606 |