lib: sbi_ipi: Validate hartids against domain, not HSM state

Commit 37eaca4ab3 ("lib: sbi_ipi: Return error for invalid hartids")
added a weight check against the HSM-interruptible mask, which excludes
harts in STOPPED state. This causes sbi_ipi_send_many() to return
SBI_EINVAL when the kernel sends a remote fence (e.g. TLB shootdown)
whose hmask includes a hart that was stopped by CPU hotplug:

  __sbi_rfence_v02_call: hbase = [0] hmask = [0x3] failed (error [-22])

Validate requested hartids against the domain's assigned hartmask
instead. This still rejects truly invalid or cross-domain hartids, but
allows HSM-STOPPED harts to be silently skipped — which is safe because
a stopped hart will do a full local TLB flush on its next HSM start
before re-entering S-mode.

Fixes: 37eaca4ab3 ("lib: sbi_ipi: Return error for invalid hartids")
Signed-off-by: Chen Pei <cp0613@linux.alibaba.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Link: https://lore.kernel.org/r/20260612115208.118132-1-cp0613@linux.alibaba.com
Signed-off-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
Chen Pei
2026-07-21 11:28:59 +05:30
committed by Anup Patel
parent 92bea7bdb2
commit 110f28518a
+9 -2
View File
@@ -136,6 +136,7 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
if (hbase != -1UL) {
struct sbi_hartmask tmp_mask = { 0 };
struct sbi_hartmask domain_mask;
int count = sbi_popcount(hmask);
for (i = hbase; hmask; i++, hmask >>= 1) {
@@ -143,10 +144,16 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
sbi_hartmask_set_hartid(i, &tmp_mask);
}
sbi_hartmask_and(&target_mask, &target_mask, &tmp_mask);
/* Validate hartids against domain assignment, not HSM state */
rc = sbi_domain_get_assigned_hartmask(dom, &domain_mask);
if (rc)
return rc;
if (sbi_hartmask_weight(&target_mask) != count)
sbi_hartmask_and(&domain_mask, &domain_mask, &tmp_mask);
if (sbi_hartmask_weight(&domain_mask) != count)
return SBI_EINVAL;
sbi_hartmask_and(&target_mask, &target_mask, &tmp_mask);
}
/* Send IPIs */