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

Merge branch 'icc-rpm' into icc-next

This patch set is to support bucket in icc-rpm driver, so it implements
the similar mechanism in the icc-rpmh driver.

It uses interconnect path tag to indicate the bandwidth voting is for
which buckets, and there have three kinds of buckets: AWC, WAKE and
SLEEP, finally the wake and sleep bucket values are used to set the
corresponding clock (active and sleep clocks). So far, we keep the AWC
bucket but doesn't really use it.

Link: https://lore.kernel.org/r/20220712015929.2789881-1-leo.yan@linaro.org
Signed-off-by: Georgi Djakov <djakov@kernel.org>

+207 -55
+5 -1
Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml
··· 45 45 - qcom,sdm660-snoc 46 46 47 47 '#interconnect-cells': 48 - const: 1 48 + description: | 49 + Value: <1> is one cell in an interconnect specifier for the 50 + interconnect node id, <2> requires the interconnect node id and an 51 + extra path tag. 52 + enum: [ 1, 2 ] 49 53 50 54 clocks: 51 55 minItems: 2
+3
drivers/interconnect/qcom/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 3 + obj-$(CONFIG_INTERCONNECT_QCOM) += interconnect_qcom.o 4 + 5 + interconnect_qcom-y := icc-common.o 3 6 icc-bcm-voter-objs := bcm-voter.o 4 7 qnoc-msm8916-objs := msm8916.o 5 8 qnoc-msm8939-objs := msm8939.o
+34
drivers/interconnect/qcom/icc-common.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2022 Linaro Ltd. 4 + */ 5 + 6 + #include <linux/of.h> 7 + #include <linux/slab.h> 8 + 9 + #include "icc-common.h" 10 + 11 + struct icc_node_data *qcom_icc_xlate_extended(struct of_phandle_args *spec, void *data) 12 + { 13 + struct icc_node_data *ndata; 14 + struct icc_node *node; 15 + 16 + node = of_icc_xlate_onecell(spec, data); 17 + if (IS_ERR(node)) 18 + return ERR_CAST(node); 19 + 20 + ndata = kzalloc(sizeof(*ndata), GFP_KERNEL); 21 + if (!ndata) 22 + return ERR_PTR(-ENOMEM); 23 + 24 + ndata->node = node; 25 + 26 + if (spec->args_count == 2) 27 + ndata->tag = spec->args[1]; 28 + 29 + if (spec->args_count > 2) 30 + pr_warn("%pOF: Too many arguments, path tag is not parsed\n", spec->np); 31 + 32 + return ndata; 33 + } 34 + EXPORT_SYMBOL_GPL(qcom_icc_xlate_extended);
+13
drivers/interconnect/qcom/icc-common.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2022 Linaro Ltd. 4 + */ 5 + 6 + #ifndef __DRIVERS_INTERCONNECT_QCOM_ICC_COMMON_H__ 7 + #define __DRIVERS_INTERCONNECT_QCOM_ICC_COMMON_H__ 8 + 9 + #include <linux/interconnect-provider.h> 10 + 11 + struct icc_node_data *qcom_icc_xlate_extended(struct of_phandle_args *spec, void *data); 12 + 13 + #endif
+144 -28
drivers/interconnect/qcom/icc-rpm.c
··· 16 16 #include <linux/slab.h> 17 17 18 18 #include "smd-rpm.h" 19 + #include "icc-common.h" 19 20 #include "icc-rpm.h" 20 21 21 22 /* QNOC QoS */ ··· 234 233 return ret; 235 234 } 236 235 237 - static int qcom_icc_set(struct icc_node *src, struct icc_node *dst) 236 + static int __qcom_icc_set(struct icc_node *n, struct qcom_icc_node *qn, 237 + u64 sum_bw) 238 238 { 239 - struct qcom_icc_provider *qp; 240 - struct qcom_icc_node *qn; 241 - struct icc_provider *provider; 242 - struct icc_node *n; 243 - u64 sum_bw; 244 - u64 max_peak_bw; 245 - u64 rate; 246 - u32 agg_avg = 0; 247 - u32 agg_peak = 0; 248 - int ret, i; 249 - 250 - qn = src->data; 251 - provider = src->provider; 252 - qp = to_qcom_provider(provider); 253 - 254 - list_for_each_entry(n, &provider->nodes, node_list) 255 - provider->aggregate(n, 0, n->avg_bw, n->peak_bw, 256 - &agg_avg, &agg_peak); 257 - 258 - sum_bw = icc_units_to_bps(agg_avg); 259 - max_peak_bw = icc_units_to_bps(agg_peak); 239 + int ret; 260 240 261 241 if (!qn->qos.ap_owned) { 262 242 /* send bandwidth request message to the RPM processor */ ··· 246 264 return ret; 247 265 } else if (qn->qos.qos_mode != -1) { 248 266 /* set bandwidth directly from the AP */ 249 - ret = qcom_icc_qos_set(src, sum_bw); 267 + ret = qcom_icc_qos_set(n, sum_bw); 250 268 if (ret) 251 269 return ret; 252 270 } 253 271 254 - rate = max(sum_bw, max_peak_bw); 272 + return 0; 273 + } 255 274 256 - do_div(rate, qn->buswidth); 257 - rate = min_t(u64, rate, LONG_MAX); 275 + /** 276 + * qcom_icc_pre_bw_aggregate - cleans up values before re-aggregate requests 277 + * @node: icc node to operate on 278 + */ 279 + static void qcom_icc_pre_bw_aggregate(struct icc_node *node) 280 + { 281 + struct qcom_icc_node *qn; 282 + size_t i; 283 + 284 + qn = node->data; 285 + for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) { 286 + qn->sum_avg[i] = 0; 287 + qn->max_peak[i] = 0; 288 + } 289 + } 290 + 291 + /** 292 + * qcom_icc_bw_aggregate - aggregate bw for buckets indicated by tag 293 + * @node: node to aggregate 294 + * @tag: tag to indicate which buckets to aggregate 295 + * @avg_bw: new bw to sum aggregate 296 + * @peak_bw: new bw to max aggregate 297 + * @agg_avg: existing aggregate avg bw val 298 + * @agg_peak: existing aggregate peak bw val 299 + */ 300 + static int qcom_icc_bw_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, 301 + u32 peak_bw, u32 *agg_avg, u32 *agg_peak) 302 + { 303 + size_t i; 304 + struct qcom_icc_node *qn; 305 + 306 + qn = node->data; 307 + 308 + if (!tag) 309 + tag = QCOM_ICC_TAG_ALWAYS; 310 + 311 + for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) { 312 + if (tag & BIT(i)) { 313 + qn->sum_avg[i] += avg_bw; 314 + qn->max_peak[i] = max_t(u32, qn->max_peak[i], peak_bw); 315 + } 316 + } 317 + 318 + *agg_avg += avg_bw; 319 + *agg_peak = max_t(u32, *agg_peak, peak_bw); 320 + return 0; 321 + } 322 + 323 + /** 324 + * qcom_icc_bus_aggregate - aggregate bandwidth by traversing all nodes 325 + * @provider: generic interconnect provider 326 + * @agg_avg: an array for aggregated average bandwidth of buckets 327 + * @agg_peak: an array for aggregated peak bandwidth of buckets 328 + * @max_agg_avg: pointer to max value of aggregated average bandwidth 329 + */ 330 + static void qcom_icc_bus_aggregate(struct icc_provider *provider, 331 + u64 *agg_avg, u64 *agg_peak, 332 + u64 *max_agg_avg) 333 + { 334 + struct icc_node *node; 335 + struct qcom_icc_node *qn; 336 + int i; 337 + 338 + /* Initialise aggregate values */ 339 + for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) { 340 + agg_avg[i] = 0; 341 + agg_peak[i] = 0; 342 + } 343 + 344 + *max_agg_avg = 0; 345 + 346 + /* 347 + * Iterate nodes on the interconnect and aggregate bandwidth 348 + * requests for every bucket. 349 + */ 350 + list_for_each_entry(node, &provider->nodes, node_list) { 351 + qn = node->data; 352 + for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) { 353 + agg_avg[i] += qn->sum_avg[i]; 354 + agg_peak[i] = max_t(u64, agg_peak[i], qn->max_peak[i]); 355 + } 356 + } 357 + 358 + /* Find maximum values across all buckets */ 359 + for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) 360 + *max_agg_avg = max_t(u64, *max_agg_avg, agg_avg[i]); 361 + } 362 + 363 + static int qcom_icc_set(struct icc_node *src, struct icc_node *dst) 364 + { 365 + struct qcom_icc_provider *qp; 366 + struct qcom_icc_node *src_qn = NULL, *dst_qn = NULL; 367 + struct icc_provider *provider; 368 + u64 sum_bw; 369 + u64 rate; 370 + u64 agg_avg[QCOM_ICC_NUM_BUCKETS], agg_peak[QCOM_ICC_NUM_BUCKETS]; 371 + u64 max_agg_avg; 372 + int ret, i; 373 + int bucket; 374 + 375 + src_qn = src->data; 376 + if (dst) 377 + dst_qn = dst->data; 378 + provider = src->provider; 379 + qp = to_qcom_provider(provider); 380 + 381 + qcom_icc_bus_aggregate(provider, agg_avg, agg_peak, &max_agg_avg); 382 + 383 + sum_bw = icc_units_to_bps(max_agg_avg); 384 + 385 + ret = __qcom_icc_set(src, src_qn, sum_bw); 386 + if (ret) 387 + return ret; 388 + if (dst_qn) { 389 + ret = __qcom_icc_set(dst, dst_qn, sum_bw); 390 + if (ret) 391 + return ret; 392 + } 258 393 259 394 for (i = 0; i < qp->num_clks; i++) { 395 + /* 396 + * Use WAKE bucket for active clock, otherwise, use SLEEP bucket 397 + * for other clocks. If a platform doesn't set interconnect 398 + * path tags, by default use sleep bucket for all clocks. 399 + * 400 + * Note, AMC bucket is not supported yet. 401 + */ 402 + if (!strcmp(qp->bus_clks[i].id, "bus_a")) 403 + bucket = QCOM_ICC_BUCKET_WAKE; 404 + else 405 + bucket = QCOM_ICC_BUCKET_SLEEP; 406 + 407 + rate = icc_units_to_bps(max(agg_avg[bucket], agg_peak[bucket])); 408 + do_div(rate, src_qn->buswidth); 409 + rate = min_t(u64, rate, LONG_MAX); 410 + 260 411 if (qp->bus_clk_rate[i] == rate) 261 412 continue; 262 413 ··· 509 394 INIT_LIST_HEAD(&provider->nodes); 510 395 provider->dev = dev; 511 396 provider->set = qcom_icc_set; 512 - provider->aggregate = icc_std_aggregate; 513 - provider->xlate = of_icc_xlate_onecell; 397 + provider->pre_aggregate = qcom_icc_pre_bw_aggregate; 398 + provider->aggregate = qcom_icc_bw_aggregate; 399 + provider->xlate_extended = qcom_icc_xlate_extended; 514 400 provider->data = data; 515 401 516 402 ret = icc_provider_add(provider);
+6
drivers/interconnect/qcom/icc-rpm.h
··· 6 6 #ifndef __DRIVERS_INTERCONNECT_QCOM_ICC_RPM_H 7 7 #define __DRIVERS_INTERCONNECT_QCOM_ICC_RPM_H 8 8 9 + #include <dt-bindings/interconnect/qcom,icc.h> 10 + 9 11 #define RPM_BUS_MASTER_REQ 0x73616d62 10 12 #define RPM_BUS_SLAVE_REQ 0x766c7362 11 13 ··· 67 65 * @links: an array of nodes where we can go next while traversing 68 66 * @num_links: the total number of @links 69 67 * @buswidth: width of the interconnect between a node and the bus (bytes) 68 + * @sum_avg: current sum aggregate value of all avg bw requests 69 + * @max_peak: current max aggregate value of all peak bw requests 70 70 * @mas_rpm_id: RPM id for devices that are bus masters 71 71 * @slv_rpm_id: RPM id for devices that are bus slaves 72 72 * @qos: NoC QoS setting parameters ··· 79 75 const u16 *links; 80 76 u16 num_links; 81 77 u16 buswidth; 78 + u64 sum_avg[QCOM_ICC_NUM_BUCKETS]; 79 + u64 max_peak[QCOM_ICC_NUM_BUCKETS]; 82 80 int mas_rpm_id; 83 81 int slv_rpm_id; 84 82 struct qcom_icc_qos qos;
+1 -25
drivers/interconnect/qcom/icc-rpmh.c
··· 11 11 #include <linux/slab.h> 12 12 13 13 #include "bcm-voter.h" 14 + #include "icc-common.h" 14 15 #include "icc-rpmh.h" 15 16 16 17 /** ··· 100 99 return 0; 101 100 } 102 101 EXPORT_SYMBOL_GPL(qcom_icc_set); 103 - 104 - struct icc_node_data *qcom_icc_xlate_extended(struct of_phandle_args *spec, void *data) 105 - { 106 - struct icc_node_data *ndata; 107 - struct icc_node *node; 108 - 109 - node = of_icc_xlate_onecell(spec, data); 110 - if (IS_ERR(node)) 111 - return ERR_CAST(node); 112 - 113 - ndata = kzalloc(sizeof(*ndata), GFP_KERNEL); 114 - if (!ndata) 115 - return ERR_PTR(-ENOMEM); 116 - 117 - ndata->node = node; 118 - 119 - if (spec->args_count == 2) 120 - ndata->tag = spec->args[1]; 121 - 122 - if (spec->args_count > 2) 123 - pr_warn("%pOF: Too many arguments, path tag is not parsed\n", spec->np); 124 - 125 - return ndata; 126 - } 127 - EXPORT_SYMBOL_GPL(qcom_icc_xlate_extended); 128 102 129 103 /** 130 104 * qcom_icc_bcm_init - populates bcm aux data and connect qnodes
-1
drivers/interconnect/qcom/icc-rpmh.h
··· 131 131 int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, 132 132 u32 peak_bw, u32 *agg_avg, u32 *agg_peak); 133 133 int qcom_icc_set(struct icc_node *src, struct icc_node *dst); 134 - struct icc_node_data *qcom_icc_xlate_extended(struct of_phandle_args *spec, void *data); 135 134 int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev); 136 135 void qcom_icc_pre_aggregate(struct icc_node *node); 137 136 int qcom_icc_rpmh_probe(struct platform_device *pdev);
+1
drivers/interconnect/qcom/sm8450.c
··· 12 12 #include <dt-bindings/interconnect/qcom,sm8450.h> 13 13 14 14 #include "bcm-voter.h" 15 + #include "icc-common.h" 15 16 #include "icc-rpmh.h" 16 17 #include "sm8450.h" 17 18