Loading drivers/soc/qcom/smp2p.c +104 −29 Original line number Diff line number Diff line Loading @@ -40,8 +40,12 @@ #define SMP2P_MAX_ENTRY_NAME 16 #define SMP2P_FEATURE_SSR_ACK 0x1 #define SMP2P_FLAGS_RESTART_DONE_BIT 0 #define SMP2P_FLAGS_RESTART_ACK_BIT 1 #define SMP2P_MAGIC 0x504d5324 #define SMP2P_VERSION 1 #define SMP2P_FEATURES SMP2P_FEATURE_SSR_ACK /** * struct smp2p_smem_item - in memory communication structure Loading Loading @@ -135,6 +139,10 @@ struct qcom_smp2p { unsigned valid_entries; bool ssr_ack_enabled; bool ssr_ack; bool open; unsigned local_pid; unsigned remote_pid; Loading Loading @@ -163,42 +171,64 @@ static void qcom_smp2p_kick(struct qcom_smp2p *smp2p) } } /** * qcom_smp2p_intr() - interrupt handler for incoming notifications * @irq: unused * @data: smp2p driver context * * Handle notifications from the remote side to handle newly allocated entries * or any changes to the state bits of existing entries. */ static irqreturn_t qcom_smp2p_intr(int irq, void *data) static bool qcom_smp2p_check_ssr(struct qcom_smp2p *smp2p) { struct smp2p_smem_item *in; struct smp2p_entry *entry; struct qcom_smp2p *smp2p = data; unsigned long status; unsigned smem_id = smp2p->smem_items[SMP2P_INBOUND]; unsigned pid = smp2p->remote_pid; size_t size; int irq_pin; char buf[SMP2P_MAX_ENTRY_NAME]; struct smp2p_smem_item *in = smp2p->in; bool restart; if (!smp2p->ssr_ack_enabled) return false; restart = in->flags & BIT(SMP2P_FLAGS_RESTART_DONE_BIT); if (restart == smp2p->ssr_ack) return false; return true; } static void qcom_smp2p_do_ssr_ack(struct qcom_smp2p *smp2p) { struct smp2p_smem_item *out = smp2p->out; u32 ack; u32 val; int i; in = smp2p->in; smp2p->ssr_ack = ack = !smp2p->ssr_ack; ack = ack << SMP2P_FLAGS_RESTART_ACK_BIT; /* Acquire smem item, if not already found */ if (!in) { in = qcom_smem_get(pid, smem_id, &size); if (IS_ERR(in)) { dev_err(smp2p->dev, "Unable to acquire remote smp2p item\n"); return IRQ_HANDLED; val = out->flags & ~BIT(SMP2P_FLAGS_RESTART_ACK_BIT); val |= ack; out->flags = val; qcom_smp2p_kick(smp2p); } smp2p->in = in; static void qcom_smp2p_negotiate(struct qcom_smp2p *smp2p) { struct smp2p_smem_item *out = smp2p->out; struct smp2p_smem_item *in = smp2p->in; u32 features; if (in->version == out->version) { features = in->features & out->features; out->features = features; if (features & SMP2P_FEATURE_SSR_ACK) smp2p->ssr_ack_enabled = true; smp2p->open = true; } } static void qcom_smp2p_notify_in(struct qcom_smp2p *smp2p) { struct smp2p_smem_item *in = smp2p->in; struct smp2p_entry *entry; unsigned long status; int irq_pin; char buf[SMP2P_MAX_ENTRY_NAME]; u32 val; int i; /* Match newly created entries */ for (i = smp2p->valid_entries; i < in->valid_entries; i++) { list_for_each_entry(entry, &smp2p->inbound, node) { Loading Loading @@ -240,6 +270,50 @@ static irqreturn_t qcom_smp2p_intr(int irq, void *data) } } } } /** * qcom_smp2p_intr() - interrupt handler for incoming notifications * @irq: unused * @data: smp2p driver context * * Handle notifications from the remote side to handle newly allocated entries * or any changes to the state bits of existing entries. */ static irqreturn_t qcom_smp2p_intr(int irq, void *data) { struct smp2p_smem_item *in; struct qcom_smp2p *smp2p = data; unsigned int smem_id = smp2p->smem_items[SMP2P_INBOUND]; unsigned int pid = smp2p->remote_pid; size_t size; in = smp2p->in; /* Acquire smem item, if not already found */ if (!in) { in = qcom_smem_get(pid, smem_id, &size); if (IS_ERR(in)) { dev_err(smp2p->dev, "Unable to acquire remote smp2p item\n"); return IRQ_HANDLED; } smp2p->in = in; } if (!smp2p->open) qcom_smp2p_negotiate(smp2p); if (smp2p->open) { bool do_restart; do_restart = qcom_smp2p_check_ssr(smp2p); qcom_smp2p_notify_in(smp2p); if (do_restart) qcom_smp2p_do_ssr_ack(smp2p); } return IRQ_HANDLED; } Loading Loading @@ -397,13 +471,14 @@ static int qcom_smp2p_alloc_outbound_item(struct qcom_smp2p *smp2p) out->remote_pid = smp2p->remote_pid; out->total_entries = SMP2P_MAX_ENTRY; out->valid_entries = 0; out->features = SMP2P_FEATURES; /* * Make sure the rest of the header is written before we validate the * item by writing a valid version number. */ wmb(); out->version = 1; out->version = SMP2P_VERSION; qcom_smp2p_kick(smp2p); Loading Loading
drivers/soc/qcom/smp2p.c +104 −29 Original line number Diff line number Diff line Loading @@ -40,8 +40,12 @@ #define SMP2P_MAX_ENTRY_NAME 16 #define SMP2P_FEATURE_SSR_ACK 0x1 #define SMP2P_FLAGS_RESTART_DONE_BIT 0 #define SMP2P_FLAGS_RESTART_ACK_BIT 1 #define SMP2P_MAGIC 0x504d5324 #define SMP2P_VERSION 1 #define SMP2P_FEATURES SMP2P_FEATURE_SSR_ACK /** * struct smp2p_smem_item - in memory communication structure Loading Loading @@ -135,6 +139,10 @@ struct qcom_smp2p { unsigned valid_entries; bool ssr_ack_enabled; bool ssr_ack; bool open; unsigned local_pid; unsigned remote_pid; Loading Loading @@ -163,42 +171,64 @@ static void qcom_smp2p_kick(struct qcom_smp2p *smp2p) } } /** * qcom_smp2p_intr() - interrupt handler for incoming notifications * @irq: unused * @data: smp2p driver context * * Handle notifications from the remote side to handle newly allocated entries * or any changes to the state bits of existing entries. */ static irqreturn_t qcom_smp2p_intr(int irq, void *data) static bool qcom_smp2p_check_ssr(struct qcom_smp2p *smp2p) { struct smp2p_smem_item *in; struct smp2p_entry *entry; struct qcom_smp2p *smp2p = data; unsigned long status; unsigned smem_id = smp2p->smem_items[SMP2P_INBOUND]; unsigned pid = smp2p->remote_pid; size_t size; int irq_pin; char buf[SMP2P_MAX_ENTRY_NAME]; struct smp2p_smem_item *in = smp2p->in; bool restart; if (!smp2p->ssr_ack_enabled) return false; restart = in->flags & BIT(SMP2P_FLAGS_RESTART_DONE_BIT); if (restart == smp2p->ssr_ack) return false; return true; } static void qcom_smp2p_do_ssr_ack(struct qcom_smp2p *smp2p) { struct smp2p_smem_item *out = smp2p->out; u32 ack; u32 val; int i; in = smp2p->in; smp2p->ssr_ack = ack = !smp2p->ssr_ack; ack = ack << SMP2P_FLAGS_RESTART_ACK_BIT; /* Acquire smem item, if not already found */ if (!in) { in = qcom_smem_get(pid, smem_id, &size); if (IS_ERR(in)) { dev_err(smp2p->dev, "Unable to acquire remote smp2p item\n"); return IRQ_HANDLED; val = out->flags & ~BIT(SMP2P_FLAGS_RESTART_ACK_BIT); val |= ack; out->flags = val; qcom_smp2p_kick(smp2p); } smp2p->in = in; static void qcom_smp2p_negotiate(struct qcom_smp2p *smp2p) { struct smp2p_smem_item *out = smp2p->out; struct smp2p_smem_item *in = smp2p->in; u32 features; if (in->version == out->version) { features = in->features & out->features; out->features = features; if (features & SMP2P_FEATURE_SSR_ACK) smp2p->ssr_ack_enabled = true; smp2p->open = true; } } static void qcom_smp2p_notify_in(struct qcom_smp2p *smp2p) { struct smp2p_smem_item *in = smp2p->in; struct smp2p_entry *entry; unsigned long status; int irq_pin; char buf[SMP2P_MAX_ENTRY_NAME]; u32 val; int i; /* Match newly created entries */ for (i = smp2p->valid_entries; i < in->valid_entries; i++) { list_for_each_entry(entry, &smp2p->inbound, node) { Loading Loading @@ -240,6 +270,50 @@ static irqreturn_t qcom_smp2p_intr(int irq, void *data) } } } } /** * qcom_smp2p_intr() - interrupt handler for incoming notifications * @irq: unused * @data: smp2p driver context * * Handle notifications from the remote side to handle newly allocated entries * or any changes to the state bits of existing entries. */ static irqreturn_t qcom_smp2p_intr(int irq, void *data) { struct smp2p_smem_item *in; struct qcom_smp2p *smp2p = data; unsigned int smem_id = smp2p->smem_items[SMP2P_INBOUND]; unsigned int pid = smp2p->remote_pid; size_t size; in = smp2p->in; /* Acquire smem item, if not already found */ if (!in) { in = qcom_smem_get(pid, smem_id, &size); if (IS_ERR(in)) { dev_err(smp2p->dev, "Unable to acquire remote smp2p item\n"); return IRQ_HANDLED; } smp2p->in = in; } if (!smp2p->open) qcom_smp2p_negotiate(smp2p); if (smp2p->open) { bool do_restart; do_restart = qcom_smp2p_check_ssr(smp2p); qcom_smp2p_notify_in(smp2p); if (do_restart) qcom_smp2p_do_ssr_ack(smp2p); } return IRQ_HANDLED; } Loading Loading @@ -397,13 +471,14 @@ static int qcom_smp2p_alloc_outbound_item(struct qcom_smp2p *smp2p) out->remote_pid = smp2p->remote_pid; out->total_entries = SMP2P_MAX_ENTRY; out->valid_entries = 0; out->features = SMP2P_FEATURES; /* * Make sure the rest of the header is written before we validate the * item by writing a valid version number. */ wmb(); out->version = 1; out->version = SMP2P_VERSION; qcom_smp2p_kick(smp2p); Loading