Skip to content

Commit 1edfaec

Browse files
James Morsegregkh
authored andcommitted
firmware: arm_sdei: Use cpus_read_lock() to avoid races with cpuhp
[ Upstream commit 54f529a ] 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 <james.morse@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 21e2f6b commit 1edfaec

1 file changed

Lines changed: 14 additions & 12 deletions

File tree

drivers/firmware/arm_sdei.c

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -412,14 +412,19 @@ int sdei_event_enable(u32 event_num)
412412
return -ENOENT;
413413
}
414414

415-
spin_lock(&sdei_list_lock);
416-
event->reenable = true;
417-
spin_unlock(&sdei_list_lock);
418415

416+
cpus_read_lock();
419417
if (event->type == SDEI_EVENT_TYPE_SHARED)
420418
err = sdei_api_event_enable(event->event_num);
421419
else
422420
err = sdei_do_cross_call(_local_event_enable, event);
421+
422+
if (!err) {
423+
spin_lock(&sdei_list_lock);
424+
event->reenable = true;
425+
spin_unlock(&sdei_list_lock);
426+
}
427+
cpus_read_unlock();
423428
mutex_unlock(&sdei_events_lock);
424429

425430
return err;
@@ -621,21 +626,18 @@ int sdei_event_register(u32 event_num, sdei_event_callback *cb, void *arg)
621626
break;
622627
}
623628

624-
spin_lock(&sdei_list_lock);
625-
event->reregister = true;
626-
spin_unlock(&sdei_list_lock);
627-
629+
cpus_read_lock();
628630
err = _sdei_event_register(event);
629631
if (err) {
630-
spin_lock(&sdei_list_lock);
631-
event->reregister = false;
632-
event->reenable = false;
633-
spin_unlock(&sdei_list_lock);
634-
635632
sdei_event_destroy(event);
636633
pr_warn("Failed to register event %u: %d\n", event_num,
637634
err);
635+
} else {
636+
spin_lock(&sdei_list_lock);
637+
event->reregister = true;
638+
spin_unlock(&sdei_list_lock);
638639
}
640+
cpus_read_unlock();
639641
} while (0);
640642
mutex_unlock(&sdei_events_lock);
641643

0 commit comments

Comments
 (0)