[PATCH 03/53] interconnect: qcom: icc-rpmh: Store direct BCM voter references

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



It makes zero (or less) sense to consume BCM voters per interconnect
provider. They are shared throughout the entire system and it's enough
to keep a single reference to each of them.

Since the list of these voters is common across SoCs and across buses
on them, turn to caching a pointer to each voter at a dt-bindings-defined
index in a shared array to make accesses O(1) (instead of a clunky
loop-based lookup) and vastly save on redefining & referencing the same
set over and over again.

Signed-off-by: Konrad Dybcio <konrad.dybcio@xxxxxxxxxx>
---
 drivers/interconnect/qcom/bcm-voter.c | 29 ++++++++++++++++++++++++++++-
 drivers/interconnect/qcom/icc-rpmh.c  | 16 +++++++++-------
 drivers/interconnect/qcom/icc-rpmh.h  |  4 ++++
 3 files changed, 41 insertions(+), 8 deletions(-)

diff --git a/drivers/interconnect/qcom/bcm-voter.c b/drivers/interconnect/qcom/bcm-voter.c
index d5f2a6b5376b..f8fbddb87e6b 100644
--- a/drivers/interconnect/qcom/bcm-voter.c
+++ b/drivers/interconnect/qcom/bcm-voter.c
@@ -19,6 +19,17 @@
 static LIST_HEAD(bcm_voters);
 static DEFINE_MUTEX(bcm_voter_lock);
 
+struct bcm_voter *qcom_icc_bcm_voters[ICC_BCM_VOTER_MAX] = { };
+EXPORT_SYMBOL_GPL(qcom_icc_bcm_voters);
+
+static const char * const bcm_voter_names[ICC_BCM_VOTER_MAX] = {
+	[ICC_BCM_VOTER_APPS] = "APPS",
+	[ICC_BCM_VOTER_DISP] = "DISP",
+	[ICC_BCM_VOTER_CAM0] = "CAM0",
+	[ICC_BCM_VOTER_CAM1] = "CAM1",
+	[ICC_BCM_VOTER_CAM2] = "CAM2",
+};
+
 /**
  * struct bcm_voter - Bus Clock Manager voter
  * @dev: reference to the device that communicates with the BCM
@@ -37,6 +48,7 @@ struct bcm_voter {
 	struct list_head ws_list;
 	struct list_head voter_node;
 	u32 tcs_wait;
+	u32 voter_idx;
 };
 
 static int cmp_vcd(void *priv, const struct list_head *a, const struct list_head *b)
@@ -353,12 +365,27 @@ static int qcom_icc_bcm_voter_probe(struct platform_device *pdev)
 	if (of_property_read_u32(np, "qcom,tcs-wait", &voter->tcs_wait))
 		voter->tcs_wait = QCOM_ICC_TAG_ACTIVE_ONLY;
 
+	/*
+	 * This is the best guess we can make..
+	 * Not registering BCMs correctly would be gamebreaking anyway!
+	 */
+	if (of_property_read_u32(np, "qcom,bcm-voter-idx", &voter->voter_idx))
+		voter->voter_idx = ICC_BCM_VOTER_APPS;
+
 	mutex_init(&voter->lock);
 	INIT_LIST_HEAD(&voter->commit_list);
 	INIT_LIST_HEAD(&voter->ws_list);
 
 	mutex_lock(&bcm_voter_lock);
-	list_add_tail(&voter->voter_node, &bcm_voters);
+	/* Do not attempt to register BCMs with the same ID twice! */
+	if (qcom_icc_bcm_voters[voter->voter_idx]) {
+		mutex_unlock(&bcm_voter_lock);
+		dev_err(&pdev->dev, "Attempted to overwrite %s BCM voter!\n",
+			bcm_voter_names[voter->voter_idx]);
+		return -EINVAL;
+	}
+
+	qcom_icc_bcm_voters[voter->voter_idx] = voter;
 	mutex_unlock(&bcm_voter_lock);
 
 	return 0;
diff --git a/drivers/interconnect/qcom/icc-rpmh.c b/drivers/interconnect/qcom/icc-rpmh.c
index fdb5e58e408b..53298148f24b 100644
--- a/drivers/interconnect/qcom/icc-rpmh.c
+++ b/drivers/interconnect/qcom/icc-rpmh.c
@@ -20,9 +20,9 @@
  */
 void qcom_icc_pre_aggregate(struct icc_node *node)
 {
-	size_t i;
-	struct qcom_icc_node *qn;
 	struct qcom_icc_provider *qp;
+	struct qcom_icc_node *qn;
+	int i;
 
 	qn = node->data;
 	qp = to_qcom_provider(node->provider);
@@ -33,7 +33,7 @@ void qcom_icc_pre_aggregate(struct icc_node *node)
 	}
 
 	for (i = 0; i < qn->num_bcms; i++)
-		qcom_icc_bcm_voter_add(qp->voter, qn->bcms[i]);
+		qcom_icc_bcm_voter_add(qcom_icc_bcm_voters[ICC_BCM_VOTER_APPS], qn->bcms[i]);
 }
 EXPORT_SYMBOL_GPL(qcom_icc_pre_aggregate);
 
@@ -95,7 +95,7 @@ int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
 
 	qp = to_qcom_provider(node->provider);
 
-	qcom_icc_bcm_voter_commit(qp->voter);
+	qcom_icc_bcm_voter_commit(qcom_icc_bcm_voters[ICC_BCM_VOTER_APPS]);
 
 	return 0;
 }
@@ -167,6 +167,7 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
 	struct icc_provider *provider;
 	struct qcom_icc_node * const *qnodes, *qn;
 	struct qcom_icc_provider *qp;
+	struct device_node *bcm_node;
 	struct icc_node *node;
 	size_t num_nodes, i, j;
 	int ret;
@@ -200,9 +201,10 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
 	qp->bcms = desc->bcms;
 	qp->num_bcms = desc->num_bcms;
 
-	qp->voter = of_bcm_voter_get(qp->dev, NULL);
-	if (IS_ERR(qp->voter))
-		return PTR_ERR(qp->voter);
+	/* Ensure the BCM voter is reachable (unless we don't have any) */
+	qp->voter = qcom_icc_bcm_voters[ICC_BCM_VOTER_APPS];
+	if (qp->num_bcms && !qp->voter)
+		return -EPROBE_DEFER;
 
 	for (i = 0; i < qp->num_bcms; i++)
 		qcom_icc_bcm_init(qp->bcms[i], dev);
diff --git a/drivers/interconnect/qcom/icc-rpmh.h b/drivers/interconnect/qcom/icc-rpmh.h
index 7843d8864d6b..5634d302963a 100644
--- a/drivers/interconnect/qcom/icc-rpmh.h
+++ b/drivers/interconnect/qcom/icc-rpmh.h
@@ -88,6 +88,7 @@ struct qcom_icc_node {
  * communicating with RPMh
  * @list: used to link to other bcms when compiling lists for commit
  * @ws_list: used to keep track of bcms that may transition between wake/sleep
+ * @voter_idx: index of the BCM voter used to convey votes to AOSS
  * @num_nodes: total number of @num_nodes
  * @nodes: list of qcom_icc_nodes that this BCM encapsulates
  */
@@ -104,6 +105,7 @@ struct qcom_icc_bcm {
 	struct bcm_db aux_data;
 	struct list_head list;
 	struct list_head ws_list;
+	u8 voter_idx;
 	size_t num_nodes;
 	struct qcom_icc_node *nodes[];
 };
@@ -138,4 +140,6 @@ void qcom_icc_pre_aggregate(struct icc_node *node);
 int qcom_icc_rpmh_probe(struct platform_device *pdev);
 int qcom_icc_rpmh_remove(struct platform_device *pdev);
 
+extern struct bcm_voter *qcom_icc_bcm_voters[ICC_BCM_VOTER_MAX];
+
 #endif

-- 
2.41.0




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux