Commit f674193b authored by James Morse's avatar James Morse Committed by Greg Kroah-Hartman

firmware: arm_sdei: Use cpus_read_lock() to avoid races with cpuhp

[ Upstream commit 54f529a6 ]

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: default avatarJames Morse <james.morse@arm.com>
Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 5fe40ed2
...@@ -410,14 +410,19 @@ int sdei_event_enable(u32 event_num) ...@@ -410,14 +410,19 @@ int sdei_event_enable(u32 event_num)
return -ENOENT; return -ENOENT;
} }
spin_lock(&sdei_list_lock);
event->reenable = true;
spin_unlock(&sdei_list_lock);
cpus_read_lock();
if (event->type == SDEI_EVENT_TYPE_SHARED) if (event->type == SDEI_EVENT_TYPE_SHARED)
err = sdei_api_event_enable(event->event_num); err = sdei_api_event_enable(event->event_num);
else else
err = sdei_do_cross_call(_local_event_enable, event); err = sdei_do_cross_call(_local_event_enable, event);
if (!err) {
spin_lock(&sdei_list_lock);
event->reenable = true;
spin_unlock(&sdei_list_lock);
}
cpus_read_unlock();
mutex_unlock(&sdei_events_lock); mutex_unlock(&sdei_events_lock);
return err; return err;
...@@ -619,21 +624,18 @@ int sdei_event_register(u32 event_num, sdei_event_callback *cb, void *arg) ...@@ -619,21 +624,18 @@ int sdei_event_register(u32 event_num, sdei_event_callback *cb, void *arg)
break; break;
} }
spin_lock(&sdei_list_lock); cpus_read_lock();
event->reregister = true;
spin_unlock(&sdei_list_lock);
err = _sdei_event_register(event); err = _sdei_event_register(event);
if (err) { if (err) {
spin_lock(&sdei_list_lock);
event->reregister = false;
event->reenable = false;
spin_unlock(&sdei_list_lock);
sdei_event_destroy(event); sdei_event_destroy(event);
pr_warn("Failed to register event %u: %d\n", event_num, pr_warn("Failed to register event %u: %d\n", event_num,
err); err);
} else {
spin_lock(&sdei_list_lock);
event->reregister = true;
spin_unlock(&sdei_list_lock);
} }
cpus_read_unlock();
} while (0); } while (0);
mutex_unlock(&sdei_events_lock); mutex_unlock(&sdei_events_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment