Skip to content

Commit f964333

Browse files
committed
Merge tag 'acpi-6.3-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull ACPI fix from Rafael Wysocki: "Fix a recent regression related to the handling of ACPI notifications that made it more likely for ACPI driver callbacks to be invoked in an unexpected order and NULL pointers can be dereferenced as a result or similar. The fix is to modify the global ACPI notification handler so it does not invoke driver callbacks at all and allow the device-level notification handlers to receive "system" notifications (for the drivers that want to receive them)" * tag 'acpi-6.3-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: ACPI: bus: Rework system-level device notification handling
2 parents 39f6921 + c56610a commit f964333

File tree

1 file changed

+37
-46
lines changed

1 file changed

+37
-46
lines changed

drivers/acpi/bus.c

Lines changed: 37 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -459,85 +459,67 @@ static void acpi_bus_osc_negotiate_usb_control(void)
459459
Notification Handling
460460
-------------------------------------------------------------------------- */
461461

462-
/*
463-
* acpi_bus_notify
464-
* ---------------
465-
* Callback for all 'system-level' device notifications (values 0x00-0x7F).
462+
/**
463+
* acpi_bus_notify - Global system-level (0x00-0x7F) notifications handler
464+
* @handle: Target ACPI object.
465+
* @type: Notification type.
466+
* @data: Ignored.
467+
*
468+
* This only handles notifications related to device hotplug.
466469
*/
467470
static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
468471
{
469472
struct acpi_device *adev;
470-
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
471-
bool hotplug_event = false;
472473

473474
switch (type) {
474475
case ACPI_NOTIFY_BUS_CHECK:
475476
acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
476-
hotplug_event = true;
477477
break;
478478

479479
case ACPI_NOTIFY_DEVICE_CHECK:
480480
acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
481-
hotplug_event = true;
482481
break;
483482

484483
case ACPI_NOTIFY_DEVICE_WAKE:
485484
acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_WAKE event\n");
486-
break;
485+
return;
487486

488487
case ACPI_NOTIFY_EJECT_REQUEST:
489488
acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
490-
hotplug_event = true;
491489
break;
492490

493491
case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
494492
acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK_LIGHT event\n");
495493
/* TBD: Exactly what does 'light' mean? */
496-
break;
494+
return;
497495

498496
case ACPI_NOTIFY_FREQUENCY_MISMATCH:
499497
acpi_handle_err(handle, "Device cannot be configured due "
500498
"to a frequency mismatch\n");
501-
break;
499+
return;
502500

503501
case ACPI_NOTIFY_BUS_MODE_MISMATCH:
504502
acpi_handle_err(handle, "Device cannot be configured due "
505503
"to a bus mode mismatch\n");
506-
break;
504+
return;
507505

508506
case ACPI_NOTIFY_POWER_FAULT:
509507
acpi_handle_err(handle, "Device has suffered a power fault\n");
510-
break;
508+
return;
511509

512510
default:
513511
acpi_handle_debug(handle, "Unknown event type 0x%x\n", type);
514-
break;
512+
return;
515513
}
516514

517515
adev = acpi_get_acpi_dev(handle);
518-
if (!adev)
519-
goto err;
520-
521-
if (adev->dev.driver) {
522-
struct acpi_driver *driver = to_acpi_driver(adev->dev.driver);
523-
524-
if (driver && driver->ops.notify &&
525-
(driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
526-
driver->ops.notify(adev, type);
527-
}
528-
529-
if (!hotplug_event) {
530-
acpi_put_acpi_dev(adev);
531-
return;
532-
}
533516

534-
if (ACPI_SUCCESS(acpi_hotplug_schedule(adev, type)))
517+
if (adev && ACPI_SUCCESS(acpi_hotplug_schedule(adev, type)))
535518
return;
536519

537520
acpi_put_acpi_dev(adev);
538521

539-
err:
540-
acpi_evaluate_ost(handle, type, ost_code, NULL);
522+
acpi_evaluate_ost(handle, type, ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
541523
}
542524

543525
static void acpi_notify_device(acpi_handle handle, u32 event, void *data)
@@ -562,42 +544,51 @@ static u32 acpi_device_fixed_event(void *data)
562544
return ACPI_INTERRUPT_HANDLED;
563545
}
564546

565-
static int acpi_device_install_notify_handler(struct acpi_device *device)
547+
static int acpi_device_install_notify_handler(struct acpi_device *device,
548+
struct acpi_driver *acpi_drv)
566549
{
567550
acpi_status status;
568551

569-
if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
552+
if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) {
570553
status =
571554
acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
572555
acpi_device_fixed_event,
573556
device);
574-
else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
557+
} else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) {
575558
status =
576559
acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
577560
acpi_device_fixed_event,
578561
device);
579-
else
580-
status = acpi_install_notify_handler(device->handle,
581-
ACPI_DEVICE_NOTIFY,
562+
} else {
563+
u32 type = acpi_drv->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS ?
564+
ACPI_ALL_NOTIFY : ACPI_DEVICE_NOTIFY;
565+
566+
status = acpi_install_notify_handler(device->handle, type,
582567
acpi_notify_device,
583568
device);
569+
}
584570

585571
if (ACPI_FAILURE(status))
586572
return -EINVAL;
587573
return 0;
588574
}
589575

590-
static void acpi_device_remove_notify_handler(struct acpi_device *device)
576+
static void acpi_device_remove_notify_handler(struct acpi_device *device,
577+
struct acpi_driver *acpi_drv)
591578
{
592-
if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
579+
if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) {
593580
acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
594581
acpi_device_fixed_event);
595-
else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
582+
} else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) {
596583
acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
597584
acpi_device_fixed_event);
598-
else
599-
acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
585+
} else {
586+
u32 type = acpi_drv->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS ?
587+
ACPI_ALL_NOTIFY : ACPI_DEVICE_NOTIFY;
588+
589+
acpi_remove_notify_handler(device->handle, type,
600590
acpi_notify_device);
591+
}
601592
}
602593

603594
/* Handle events targeting \_SB device (at present only graceful shutdown) */
@@ -1039,7 +1030,7 @@ static int acpi_device_probe(struct device *dev)
10391030
acpi_drv->name, acpi_dev->pnp.bus_id);
10401031

10411032
if (acpi_drv->ops.notify) {
1042-
ret = acpi_device_install_notify_handler(acpi_dev);
1033+
ret = acpi_device_install_notify_handler(acpi_dev, acpi_drv);
10431034
if (ret) {
10441035
if (acpi_drv->ops.remove)
10451036
acpi_drv->ops.remove(acpi_dev);
@@ -1062,7 +1053,7 @@ static void acpi_device_remove(struct device *dev)
10621053
struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
10631054

10641055
if (acpi_drv->ops.notify)
1065-
acpi_device_remove_notify_handler(acpi_dev);
1056+
acpi_device_remove_notify_handler(acpi_dev, acpi_drv);
10661057

10671058
if (acpi_drv->ops.remove)
10681059
acpi_drv->ops.remove(acpi_dev);

0 commit comments

Comments
 (0)