Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

soc: qcom: smp2p: Add support for smp2p v2

smp2p v2 adds support for allowing remote processors to write outbound
smp2p items without completing the feature negotiation. This is required
for processors that start before linux to write out signals like error
and clock ready and unblock their bootup.

If a remote processor only supports v1, smp2p can version down by
mirroring the peer version during the negotiation stage.

When using smp2p version 2, the remote does not wait for the ssr ack
before setting the items. To accommodate this, set the last_value of all
the entries to 0 when SSR is detected. This forces smp2p to detect the
new values written by the remote. Because the SSR ack is skipped, the
down transition of bits is missed in smp2p version 2.

Signed-off-by: Chris Lew <chris.lew@oss.qualcomm.com>
Signed-off-by: Deepak Kumar Singh <deepak.singh@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20260127-smp2pv2-v3-2-4060b859b1e2@oss.qualcomm.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>

authored by

Chris Lew and committed by
Bjorn Andersson
42c4cf5d 8a9a7b9d

+44 -4
+44 -4
drivers/soc/qcom/smp2p.c
··· 36 36 * The driver uses the Linux GPIO and interrupt framework to expose a virtual 37 37 * GPIO for each outbound entry and a virtual interrupt controller for each 38 38 * inbound entry. 39 + * 40 + * V2 of SMP2P allows remote processors to write to outbound smp2p items before 41 + * the full smp2p connection is negotiated. This is important for processors 42 + * started before linux runs. 39 43 */ 40 44 41 45 #define SMP2P_MAX_ENTRY 16 ··· 51 47 52 48 #define SMP2P_MAGIC 0x504d5324 53 49 #define SMP2P_ALL_FEATURES SMP2P_FEATURE_SSR_ACK 50 + #define MAX_VERSION 2 54 51 55 52 /** 56 53 * struct smp2p_smem_item - in memory communication structure 57 54 * @magic: magic number 58 - * @version: version - must be 1 55 + * @version: version 59 56 * @features: features flag - currently unused 60 57 * @local_pid: processor id of sending end 61 58 * @remote_pid: processor id of receiving end ··· 185 180 static bool qcom_smp2p_check_ssr(struct qcom_smp2p *smp2p) 186 181 { 187 182 struct smp2p_smem_item *in = smp2p->in; 183 + struct smp2p_entry *entry; 184 + bool restart_done; 188 185 bool restart; 189 186 190 187 if (!smp2p->ssr_ack_enabled) 191 188 return false; 192 189 193 - restart = in->flags & BIT(SMP2P_FLAGS_RESTART_DONE_BIT); 190 + restart_done = in->flags & BIT(SMP2P_FLAGS_RESTART_DONE_BIT); 191 + restart = restart_done != smp2p->ssr_ack; 192 + list_for_each_entry(entry, &smp2p->inbound, node) { 193 + if (!entry->value) 194 + continue; 195 + entry->last_value = 0; 196 + } 194 197 195 - return restart != smp2p->ssr_ack; 198 + return restart; 196 199 } 197 200 198 201 static void qcom_smp2p_do_ssr_ack(struct qcom_smp2p *smp2p) ··· 232 219 233 220 smp2p->negotiation_done = true; 234 221 trace_smp2p_negotiate(smp2p->dev, out->features); 222 + } else if (in->version && in->version < out->version) { 223 + out->version = in->version; 224 + qcom_smp2p_kick(smp2p); 235 225 } 226 + } 227 + 228 + static int qcom_smp2p_in_version(struct qcom_smp2p *smp2p) 229 + { 230 + unsigned int smem_id = smp2p->smem_items[SMP2P_INBOUND]; 231 + unsigned int pid = smp2p->remote_pid; 232 + struct smp2p_smem_item *in; 233 + size_t size; 234 + 235 + in = qcom_smem_get(pid, smem_id, &size); 236 + if (IS_ERR(in)) 237 + return 0; 238 + 239 + return in->version; 236 240 } 237 241 238 242 static void qcom_smp2p_start_in(struct qcom_smp2p *smp2p) ··· 546 516 struct smp2p_smem_item *out; 547 517 unsigned smem_id = smp2p->smem_items[SMP2P_OUTBOUND]; 548 518 unsigned pid = smp2p->remote_pid; 519 + u8 in_version; 549 520 int ret; 550 521 551 522 ret = qcom_smem_alloc(pid, smem_id, sizeof(*out)); ··· 568 537 out->valid_entries = 0; 569 538 out->features = SMP2P_ALL_FEATURES; 570 539 540 + in_version = qcom_smp2p_in_version(smp2p); 541 + if (in_version > MAX_VERSION) { 542 + dev_err(smp2p->dev, "Unsupported smp2p version %d\n", in_version); 543 + return -EINVAL; 544 + } 545 + 571 546 /* 572 547 * Make sure the rest of the header is written before we validate the 573 548 * item by writing a valid version number. 574 549 */ 575 550 wmb(); 576 - out->version = 1; 551 + if (in_version && in_version <= 2) 552 + out->version = in_version; 553 + else 554 + out->version = 2; 577 555 578 556 qcom_smp2p_kick(smp2p); 579 557