Skip to content

Commit 54f529a

Browse files
James Morsectmarinas
authored andcommitted
firmware: arm_sdei: Use cpus_read_lock() to avoid races with cpuhp
SDEI has private events that need registering and enabling on each CPU. CPUs can come and go while we are trying to do this. SDEI tries to avoid these problems by setting the reregister flag before the register call, so any CPUs that come online register the event too. Sticking plaster like this doesn't work, as if the register call fails, a CPU that subsequently comes online will register the event before reregister is cleared. Take cpus_read_lock() around the register and enable calls. We don't want surprise CPUs to do the wrong thing if they race with these calls failing. Signed-off-by: James Morse <[email protected]> Signed-off-by: Catalin Marinas <[email protected]>
1 parent c66d52b commit 54f529a

File tree

1 file changed

+14
-12
lines changed

1 file changed

+14
-12
lines changed

drivers/firmware/arm_sdei.c

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -418,14 +418,19 @@ int sdei_event_enable(u32 event_num)
418418
return -ENOENT;
419419
}
420420

421-
spin_lock(&sdei_list_lock);
422-
event->reenable = true;
423-
spin_unlock(&sdei_list_lock);
424421

422+
cpus_read_lock();
425423
if (event->type == SDEI_EVENT_TYPE_SHARED)
426424
err = sdei_api_event_enable(event->event_num);
427425
else
428426
err = sdei_do_cross_call(_local_event_enable, event);
427+
428+
if (!err) {
429+
spin_lock(&sdei_list_lock);
430+
event->reenable = true;
431+
spin_unlock(&sdei_list_lock);
432+
}
433+
cpus_read_unlock();
429434
mutex_unlock(&sdei_events_lock);
430435

431436
return err;
@@ -627,21 +632,18 @@ int sdei_event_register(u32 event_num, sdei_event_callback *cb, void *arg)
627632
break;
628633
}
629634

630-
spin_lock(&sdei_list_lock);
631-
event->reregister = true;
632-
spin_unlock(&sdei_list_lock);
633-
635+
cpus_read_lock();
634636
err = _sdei_event_register(event);
635637
if (err) {
636-
spin_lock(&sdei_list_lock);
637-
event->reregister = false;
638-
event->reenable = false;
639-
spin_unlock(&sdei_list_lock);
640-
641638
sdei_event_destroy(event);
642639
pr_warn("Failed to register event %u: %d\n", event_num,
643640
err);
641+
} else {
642+
spin_lock(&sdei_list_lock);
643+
event->reregister = true;
644+
spin_unlock(&sdei_list_lock);
644645
}
646+
cpus_read_unlock();
645647
} while (0);
646648
mutex_unlock(&sdei_events_lock);
647649

0 commit comments

Comments
 (0)