struct clk *iface_clk;
struct clk *bus_clk;
struct icc_path *path;
- struct completion waitq_comp;
+ struct completion *waitq_comps;
struct reset_controller_dev reset;
/* control access to the interconnect path */
u64 dload_mode_addr;
struct qcom_tzmem_pool *mempool;
+ unsigned int wq_cnt;
};
struct qcom_scm_current_perm_info {
#define QCOM_DLOAD_MINIDUMP 2
#define QCOM_DLOAD_BOTHDUMP 3
+#define QCOM_SCM_DEFAULT_WAITQ_COUNT 1
+
static const char * const qcom_scm_convention_names[] = {
[SMC_CONVENTION_UNKNOWN] = "unknown",
[SMC_CONVENTION_ARM_32] = "smc arm 32",
return 0;
}
+static int qcom_scm_query_waitq_count(struct qcom_scm *scm)
+{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_WAITQ,
+ .cmd = QCOM_SCM_WAITQ_GET_INFO,
+ .owner = ARM_SMCCC_OWNER_SIP
+ };
+ struct qcom_scm_res res;
+ int ret;
+
+ ret = qcom_scm_call_atomic(scm->dev, &desc, &res);
+ if (ret)
+ return ret;
+
+ return res.result[0] & GENMASK(7, 0);
+}
+
static int qcom_scm_get_waitq_irq(struct qcom_scm *scm)
{
struct qcom_scm_desc desc = {
return irq_create_fwspec_mapping(&fwspec);
}
-static int qcom_scm_assert_valid_wq_ctx(u32 wq_ctx)
+static struct completion *qcom_scm_get_completion(u32 wq_ctx)
{
- /* FW currently only supports a single wq_ctx (zero).
- * TODO: Update this logic to include dynamic allocation and lookup of
- * completion structs when FW supports more wq_ctx values.
- */
- if (wq_ctx != 0) {
- dev_err(__scm->dev, "Firmware unexpectedly passed non-zero wq_ctx\n");
- return -EINVAL;
- }
+ struct completion *wq;
- return 0;
+ if (WARN_ON_ONCE(wq_ctx >= __scm->wq_cnt))
+ return ERR_PTR(-EINVAL);
+
+ wq = &__scm->waitq_comps[wq_ctx];
+
+ return wq;
}
int qcom_scm_wait_for_wq_completion(u32 wq_ctx)
{
- int ret;
+ struct completion *wq;
- ret = qcom_scm_assert_valid_wq_ctx(wq_ctx);
- if (ret)
- return ret;
+ wq = qcom_scm_get_completion(wq_ctx);
+ if (IS_ERR(wq))
+ return PTR_ERR(wq);
- wait_for_completion(&__scm->waitq_comp);
+ wait_for_completion(wq);
return 0;
}
static int qcom_scm_waitq_wakeup(unsigned int wq_ctx)
{
- int ret;
+ struct completion *wq;
- ret = qcom_scm_assert_valid_wq_ctx(wq_ctx);
- if (ret)
- return ret;
+ wq = qcom_scm_get_completion(wq_ctx);
+ if (IS_ERR(wq))
+ return PTR_ERR(wq);
- complete(&__scm->waitq_comp);
+ complete(wq);
return 0;
}
struct qcom_tzmem_pool_config pool_config;
struct qcom_scm *scm;
int irq, ret;
+ int i;
scm = devm_kzalloc(&pdev->dev, sizeof(*scm), GFP_KERNEL);
if (!scm)
if (ret < 0)
return ret;
- init_completion(&scm->waitq_comp);
mutex_init(&scm->scm_bw_lock);
scm->path = devm_of_icc_get(&pdev->dev, NULL);
return dev_err_probe(scm->dev, PTR_ERR(scm->mempool),
"Failed to create the SCM memory pool\n");
+ ret = qcom_scm_query_waitq_count(scm);
+ scm->wq_cnt = ret < 0 ? QCOM_SCM_DEFAULT_WAITQ_COUNT : ret;
+ scm->waitq_comps = devm_kcalloc(&pdev->dev, scm->wq_cnt, sizeof(*scm->waitq_comps),
+ GFP_KERNEL);
+ if (!scm->waitq_comps)
+ return -ENOMEM;
+
+ for (i = 0; i < scm->wq_cnt; i++)
+ init_completion(&scm->waitq_comps[i]);
+
irq = qcom_scm_get_waitq_irq(scm);
if (irq < 0)
irq = platform_get_irq_optional(pdev, 0);