diff options
| author | Takashi Iwai <tiwai@suse.de> | 2013-08-01 05:12:10 -0400 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2013-08-01 05:12:10 -0400 |
| commit | 209fb1b7e298c5f5a93a9450bc9e9e7923f745d9 (patch) | |
| tree | 27cbfa78e5eeaceb2aae1c165f7f0e24f6fee286 /arch/powerpc/kernel/eeh_driver.c | |
| parent | a8d30608eaed6cc759b8e2e8a8bbbb42591f797f (diff) | |
| parent | 3fef7f795fff7ccc58d55a28315ca73305515884 (diff) | |
Merge tag 'asoc-v3.11-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: Fixes for v3.11
A fix to make sure userspace knows when control writes have caused a
change in value, fixing some UIs, plus a few few driver fixes mainly
cleaning up issues from recent refactorings on less mainstream platforms.
Diffstat (limited to 'arch/powerpc/kernel/eeh_driver.c')
| -rw-r--r-- | arch/powerpc/kernel/eeh_driver.c | 77 |
1 files changed, 74 insertions, 3 deletions
diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index 2b1ce17cae50..36bed5a12750 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c | |||
| @@ -143,10 +143,14 @@ static void eeh_disable_irq(struct pci_dev *dev) | |||
| 143 | static void eeh_enable_irq(struct pci_dev *dev) | 143 | static void eeh_enable_irq(struct pci_dev *dev) |
| 144 | { | 144 | { |
| 145 | struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); | 145 | struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); |
| 146 | struct irq_desc *desc; | ||
| 146 | 147 | ||
| 147 | if ((edev->mode) & EEH_DEV_IRQ_DISABLED) { | 148 | if ((edev->mode) & EEH_DEV_IRQ_DISABLED) { |
| 148 | edev->mode &= ~EEH_DEV_IRQ_DISABLED; | 149 | edev->mode &= ~EEH_DEV_IRQ_DISABLED; |
| 149 | enable_irq(dev->irq); | 150 | |
| 151 | desc = irq_to_desc(dev->irq); | ||
| 152 | if (desc && desc->depth > 0) | ||
| 153 | enable_irq(dev->irq); | ||
| 150 | } | 154 | } |
| 151 | } | 155 | } |
| 152 | 156 | ||
| @@ -338,6 +342,54 @@ static void *eeh_report_failure(void *data, void *userdata) | |||
| 338 | return NULL; | 342 | return NULL; |
| 339 | } | 343 | } |
| 340 | 344 | ||
| 345 | static void *eeh_rmv_device(void *data, void *userdata) | ||
| 346 | { | ||
| 347 | struct pci_driver *driver; | ||
| 348 | struct eeh_dev *edev = (struct eeh_dev *)data; | ||
| 349 | struct pci_dev *dev = eeh_dev_to_pci_dev(edev); | ||
| 350 | int *removed = (int *)userdata; | ||
| 351 | |||
| 352 | /* | ||
| 353 | * Actually, we should remove the PCI bridges as well. | ||
| 354 | * However, that's lots of complexity to do that, | ||
| 355 | * particularly some of devices under the bridge might | ||
| 356 | * support EEH. So we just care about PCI devices for | ||
| 357 | * simplicity here. | ||
| 358 | */ | ||
| 359 | if (!dev || (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)) | ||
| 360 | return NULL; | ||
| 361 | driver = eeh_pcid_get(dev); | ||
| 362 | if (driver && driver->err_handler) | ||
| 363 | return NULL; | ||
| 364 | |||
| 365 | /* Remove it from PCI subsystem */ | ||
| 366 | pr_debug("EEH: Removing %s without EEH sensitive driver\n", | ||
| 367 | pci_name(dev)); | ||
| 368 | edev->bus = dev->bus; | ||
| 369 | edev->mode |= EEH_DEV_DISCONNECTED; | ||
| 370 | (*removed)++; | ||
| 371 | |||
| 372 | pci_stop_and_remove_bus_device(dev); | ||
| 373 | |||
| 374 | return NULL; | ||
| 375 | } | ||
| 376 | |||
| 377 | static void *eeh_pe_detach_dev(void *data, void *userdata) | ||
| 378 | { | ||
| 379 | struct eeh_pe *pe = (struct eeh_pe *)data; | ||
| 380 | struct eeh_dev *edev, *tmp; | ||
| 381 | |||
| 382 | eeh_pe_for_each_dev(pe, edev, tmp) { | ||
| 383 | if (!(edev->mode & EEH_DEV_DISCONNECTED)) | ||
| 384 | continue; | ||
| 385 | |||
| 386 | edev->mode &= ~(EEH_DEV_DISCONNECTED | EEH_DEV_IRQ_DISABLED); | ||
| 387 | eeh_rmv_from_parent_pe(edev); | ||
| 388 | } | ||
| 389 | |||
| 390 | return NULL; | ||
| 391 | } | ||
| 392 | |||
| 341 | /** | 393 | /** |
| 342 | * eeh_reset_device - Perform actual reset of a pci slot | 394 | * eeh_reset_device - Perform actual reset of a pci slot |
| 343 | * @pe: EEH PE | 395 | * @pe: EEH PE |
| @@ -349,8 +401,9 @@ static void *eeh_report_failure(void *data, void *userdata) | |||
| 349 | */ | 401 | */ |
| 350 | static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) | 402 | static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) |
| 351 | { | 403 | { |
| 404 | struct pci_bus *frozen_bus = eeh_pe_bus_get(pe); | ||
| 352 | struct timeval tstamp; | 405 | struct timeval tstamp; |
| 353 | int cnt, rc; | 406 | int cnt, rc, removed = 0; |
| 354 | 407 | ||
| 355 | /* pcibios will clear the counter; save the value */ | 408 | /* pcibios will clear the counter; save the value */ |
| 356 | cnt = pe->freeze_count; | 409 | cnt = pe->freeze_count; |
| @@ -362,8 +415,11 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) | |||
| 362 | * devices are expected to be attached soon when calling | 415 | * devices are expected to be attached soon when calling |
| 363 | * into pcibios_add_pci_devices(). | 416 | * into pcibios_add_pci_devices(). |
| 364 | */ | 417 | */ |
| 418 | eeh_pe_state_mark(pe, EEH_PE_KEEP); | ||
| 365 | if (bus) | 419 | if (bus) |
| 366 | __pcibios_remove_pci_devices(bus, 0); | 420 | pcibios_remove_pci_devices(bus); |
| 421 | else if (frozen_bus) | ||
| 422 | eeh_pe_dev_traverse(pe, eeh_rmv_device, &removed); | ||
| 367 | 423 | ||
| 368 | /* Reset the pci controller. (Asserts RST#; resets config space). | 424 | /* Reset the pci controller. (Asserts RST#; resets config space). |
| 369 | * Reconfigure bridges and devices. Don't try to bring the system | 425 | * Reconfigure bridges and devices. Don't try to bring the system |
| @@ -384,9 +440,24 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) | |||
| 384 | * potentially weird things happen. | 440 | * potentially weird things happen. |
| 385 | */ | 441 | */ |
| 386 | if (bus) { | 442 | if (bus) { |
| 443 | pr_info("EEH: Sleep 5s ahead of complete hotplug\n"); | ||
| 387 | ssleep(5); | 444 | ssleep(5); |
| 445 | |||
| 446 | /* | ||
| 447 | * The EEH device is still connected with its parent | ||
| 448 | * PE. We should disconnect it so the binding can be | ||
| 449 | * rebuilt when adding PCI devices. | ||
| 450 | */ | ||
| 451 | eeh_pe_traverse(pe, eeh_pe_detach_dev, NULL); | ||
| 388 | pcibios_add_pci_devices(bus); | 452 | pcibios_add_pci_devices(bus); |
| 453 | } else if (frozen_bus && removed) { | ||
| 454 | pr_info("EEH: Sleep 5s ahead of partial hotplug\n"); | ||
| 455 | ssleep(5); | ||
| 456 | |||
| 457 | eeh_pe_traverse(pe, eeh_pe_detach_dev, NULL); | ||
| 458 | pcibios_add_pci_devices(frozen_bus); | ||
| 389 | } | 459 | } |
| 460 | eeh_pe_state_clear(pe, EEH_PE_KEEP); | ||
| 390 | 461 | ||
| 391 | pe->tstamp = tstamp; | 462 | pe->tstamp = tstamp; |
| 392 | pe->freeze_count = cnt; | 463 | pe->freeze_count = cnt; |
