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

Merge branch 'icc-syncstate' into icc-next

* icc-syncstate:
interconnect: Add get_bw() callback
interconnect: Add sync state support
interconnect: qcom: Use icc_sync_state

Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>

+77
+67
drivers/interconnect/core.c
··· 26 26 27 27 static DEFINE_IDR(icc_idr); 28 28 static LIST_HEAD(icc_providers); 29 + static int providers_count; 30 + static bool synced_state; 29 31 static DEFINE_MUTEX(icc_lock); 30 32 static struct dentry *icc_debugfs_dir; 31 33 ··· 269 267 } 270 268 p->aggregate(node, r->tag, avg_bw, peak_bw, 271 269 &node->avg_bw, &node->peak_bw); 270 + 271 + /* during boot use the initial bandwidth as a floor value */ 272 + if (!synced_state) { 273 + node->avg_bw = max(node->avg_bw, node->init_avg); 274 + node->peak_bw = max(node->peak_bw, node->init_peak); 275 + } 272 276 } 273 277 274 278 return 0; ··· 966 958 node->provider = provider; 967 959 list_add_tail(&node->node_list, &provider->nodes); 968 960 961 + /* get the initial bandwidth values and sync them with hardware */ 962 + if (provider->get_bw) { 963 + provider->get_bw(node, &node->init_avg, &node->init_peak); 964 + } else { 965 + node->init_avg = INT_MAX; 966 + node->init_peak = INT_MAX; 967 + } 968 + node->avg_bw = node->init_avg; 969 + node->peak_bw = node->init_peak; 970 + provider->set(node, node); 971 + node->avg_bw = 0; 972 + node->peak_bw = 0; 973 + 969 974 mutex_unlock(&icc_lock); 970 975 } 971 976 EXPORT_SYMBOL_GPL(icc_node_add); ··· 1074 1053 } 1075 1054 EXPORT_SYMBOL_GPL(icc_provider_del); 1076 1055 1056 + static int of_count_icc_providers(struct device_node *np) 1057 + { 1058 + struct device_node *child; 1059 + int count = 0; 1060 + 1061 + for_each_available_child_of_node(np, child) { 1062 + if (of_property_read_bool(child, "#interconnect-cells")) 1063 + count++; 1064 + count += of_count_icc_providers(child); 1065 + } 1066 + of_node_put(np); 1067 + 1068 + return count; 1069 + } 1070 + 1071 + void icc_sync_state(struct device *dev) 1072 + { 1073 + struct icc_provider *p; 1074 + struct icc_node *n; 1075 + static int count; 1076 + 1077 + count++; 1078 + 1079 + if (count < providers_count) 1080 + return; 1081 + 1082 + mutex_lock(&icc_lock); 1083 + synced_state = true; 1084 + list_for_each_entry(p, &icc_providers, provider_list) { 1085 + dev_dbg(p->dev, "interconnect provider is in synced state\n"); 1086 + list_for_each_entry(n, &p->nodes, node_list) { 1087 + if (n->init_avg || n->init_peak) { 1088 + aggregate_requests(n); 1089 + p->set(n, n); 1090 + } 1091 + } 1092 + } 1093 + mutex_unlock(&icc_lock); 1094 + } 1095 + EXPORT_SYMBOL_GPL(icc_sync_state); 1096 + 1077 1097 static int __init icc_init(void) 1078 1098 { 1099 + struct device_node *root = of_find_node_by_path("/"); 1100 + 1101 + providers_count = of_count_icc_providers(root); 1102 + of_node_put(root); 1103 + 1079 1104 icc_debugfs_dir = debugfs_create_dir("interconnect", NULL); 1080 1105 debugfs_create_file("interconnect_summary", 0444, 1081 1106 icc_debugfs_dir, NULL, &icc_summary_fops);
+1
drivers/interconnect/qcom/osm-l3.c
··· 322 322 .driver = { 323 323 .name = "osm-l3", 324 324 .of_match_table = osm_l3_of_match, 325 + .sync_state = icc_sync_state, 325 326 }, 326 327 }; 327 328 module_platform_driver(osm_l3_driver);
+1
drivers/interconnect/qcom/sc7180.c
··· 633 633 .driver = { 634 634 .name = "qnoc-sc7180", 635 635 .of_match_table = qnoc_of_match, 636 + .sync_state = icc_sync_state, 636 637 }, 637 638 }; 638 639 module_platform_driver(qnoc_driver);
+1
drivers/interconnect/qcom/sdm845.c
··· 559 559 .driver = { 560 560 .name = "qnoc-sdm845", 561 561 .of_match_table = qnoc_of_match, 562 + .sync_state = icc_sync_state, 562 563 }, 563 564 }; 564 565 module_platform_driver(qnoc_driver);
+7
include/linux/interconnect-provider.h
··· 49 49 * @aggregate: pointer to device specific aggregate operation function 50 50 * @pre_aggregate: pointer to device specific function that is called 51 51 * before the aggregation begins (optional) 52 + * @get_bw: pointer to device specific function to get current bandwidth 52 53 * @xlate: provider-specific callback for mapping nodes from phandle arguments 53 54 * @xlate_extended: vendor-specific callback for mapping node data from phandle arguments 54 55 * @dev: the device this interconnect provider belongs to ··· 64 63 int (*aggregate)(struct icc_node *node, u32 tag, u32 avg_bw, 65 64 u32 peak_bw, u32 *agg_avg, u32 *agg_peak); 66 65 void (*pre_aggregate)(struct icc_node *node); 66 + int (*get_bw)(struct icc_node *node, u32 *avg, u32 *peak); 67 67 struct icc_node* (*xlate)(struct of_phandle_args *spec, void *data); 68 68 struct icc_node_data* (*xlate_extended)(struct of_phandle_args *spec, void *data); 69 69 struct device *dev; ··· 88 86 * @req_list: a list of QoS constraint requests associated with this node 89 87 * @avg_bw: aggregated value of average bandwidth requests from all consumers 90 88 * @peak_bw: aggregated value of peak bandwidth requests from all consumers 89 + * @init_avg: average bandwidth value that is read from the hardware during init 90 + * @init_peak: peak bandwidth value that is read from the hardware during init 91 91 * @data: pointer to private data 92 92 */ 93 93 struct icc_node { ··· 106 102 struct hlist_head req_list; 107 103 u32 avg_bw; 108 104 u32 peak_bw; 105 + u32 init_avg; 106 + u32 init_peak; 109 107 void *data; 110 108 }; 111 109 ··· 125 119 int icc_provider_add(struct icc_provider *provider); 126 120 int icc_provider_del(struct icc_provider *provider); 127 121 struct icc_node_data *of_icc_get_from_provider(struct of_phandle_args *spec); 122 + void icc_sync_state(struct device *dev); 128 123 129 124 #else 130 125