From 23a9665dbc4ceb946eb6e6ed0987b718edab3268 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Wed, 4 Feb 2015 10:57:01 -0700 Subject: [PATCH] platform: msm: Add snapshot of missing msm_bus driver changes The msm_bus driver provides offers a means of managing performance levels for the buses, fabrics and NoCs, which connect the peripherals and processes within MSM chipsets. This snapshot is taken to merge missing changes from msm-3.18 to msm-3.10 Change-Id: If6fff441265716632ee2b8d666cbbdaf5974a34e Signed-off-by: Alok Chauhan Signed-off-by: Kiran Gunda --- .../bindings/arm/msm/msm_bus_adhoc.txt | 47 +- drivers/platform/msm/msm_bus/Makefile | 12 +- drivers/platform/msm/msm_bus/msm_bus_adhoc.h | 57 +- .../platform/msm/msm_bus/msm_bus_arb_adhoc.c | 701 ++++++++---- drivers/platform/msm/msm_bus/msm_bus_bimc.c | 997 +----------------- .../platform/msm/msm_bus/msm_bus_bimc_adhoc.c | 718 +++++++++++++ .../platform/msm/msm_bus/msm_bus_client_api.c | 40 +- drivers/platform/msm/msm_bus/msm_bus_core.h | 15 +- drivers/platform/msm/msm_bus/msm_bus_dbg.c | 47 +- .../platform/msm/msm_bus/msm_bus_dbg_voter.c | 107 +- .../msm/msm_bus/msm_bus_fabric_adhoc.c | 858 +++++++-------- drivers/platform/msm/msm_bus/msm_bus_noc.c | 268 ----- .../platform/msm/msm_bus/msm_bus_noc_adhoc.c | 590 +++++++++++ .../platform/msm/msm_bus/msm_bus_of_adhoc.c | 307 +++++- include/dt-bindings/msm/msm-bus-ids.h | 5 + include/linux/msm-bus.h | 26 +- include/linux/msm_bus_rules.h | 1 + include/trace/events/trace_msm_bus.h | 34 + 18 files changed, 2767 insertions(+), 2063 deletions(-) create mode 100644 drivers/platform/msm/msm_bus/msm_bus_bimc_adhoc.c create mode 100644 drivers/platform/msm/msm_bus/msm_bus_noc_adhoc.c diff --git a/Documentation/devicetree/bindings/arm/msm/msm_bus_adhoc.txt b/Documentation/devicetree/bindings/arm/msm/msm_bus_adhoc.txt index b47bbb4a2e1e..96e42c5660e7 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm_bus_adhoc.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm_bus_adhoc.txt @@ -57,14 +57,33 @@ qcom,qos-off: Parameter that represents the delta between QoS register address space for different devices. Typically these optional properties are used for devices that represent fabric devices. -qcom,util-fact: Parameter that represents the DDR utilization factor. It is - represented as actual util-factor * 100. +qcom,agg-scheme: Parameter that represents the aggregation scheme to be used for the + node. This parameter defaults to LEGACY scheme. The valid options + are LEGACY/SCHEME_1. +qcom,util-fact: Parameter that represents the DDR utilization factor to be used in + LEGACY scheme. It is represented as actual util-factor * 100. qcom,vrail-comp: Parameter that represents the voltage rail compensation to push - the bus to the next level if needed. It is represented as actual - vrail-comp * 100. + the bus to the next level if needed in LEGACY and SCHEME 1 aggregation + schemes. It is represented as actual vrail-comp * 100. +qcom,util-levels: Array of tuples that represent a bandwidth threshold and util factor + to be used uptil the given threshold. qcom,bus-type: Parameter that represents the bus type such as BIMC or NOC. Typically these optional properties are used for devices that represent fabric devices. +bus-gdsc-supply: Optional fabric device parameter that is a reference to the dual + context GDSC supply that is needed before clock operations. +bus-a-gdsc-supply: Optional fabric device parameter that is a reference to an active + only context GDSC supply that is needed before clock operations. +bus-qos-gdsc-supply: Optional node or fabric device parameter that is a reference to a GDSC + supply that is needed before use of the clock needed to program + QoS registers. +node-gdsc-supply: Optional node device parameter that is a reference to a GDSC supply + that is needed before node-clock operations. +qcom,enable-only-clk: Optional property that is represents if the clock doesn't support + the clk_set_rate API and should only be enabled/disabled. +qcom,setrate-only-clk: Optional property that is indicates that bus driver should only + set a rate on a clock handle and not call the enable/disable + clock API. clock-names: Optional property that represents the clock name associated with the device "bus_clk", "bus_a_clk"; clocks: Property pair that represents the clock controller and the clock @@ -103,7 +122,6 @@ qcom,blacklist: An array of phandles that represent devices that this de intermediate nodes. qcom,agg-ports: The number of aggregation ports on the bus. - The following properties are optional as collecting data via coresight might and are present on child nodes that represent NOC devices. The documentation for coresight properties can be found in: @@ -117,6 +135,14 @@ coresight-child-list List of phandles pointing to the children of this component. coresight-child-ports List of input port numbers of the children. +The following sub-nodes are optional parameters: + +qcom,node-qos-clks: Optional node listing all the clocks and regulators required for programming of + QoS registers. Usually these are associated with fabric nodes. + clock-names: An array of clock names for QoS programming, + clocks: An array of clock phandles corresponding to the clock names listed above. + clock-name-gdsc: + An optional property listing the regulator associated with a given clock name. Example: @@ -130,6 +156,9 @@ Example: label = "fab-snoc"; qcom,fab-dev; qcom,bypass-qos-prg; + qcom,agg-scheme = ; + qcom,util-levels = <450000 133>, + <750000 154>; qcom,base-name = "snoc-base"; qcom,base-offset = <0x7000>; qcom,qos-off = <0x1000>; @@ -137,11 +166,19 @@ Example: clock-names = "bus_clk", "bus_a_clk"; clocks = <&clock_rpm clk_snoc_msmbus_clk>, <&clock_rpm clk_snoc_msmbus_a_clk>; + qcom,node-qos-clks { + clock-names = "q0-clk", "q1-clk"; + clocks = <&clock_gcc clk_q0_clk>, + <&clock_gcc clk_q1_clk>; + q0-clk-supply = <&gdsc_q0_clk>; + }; }; mm_int_bimc: mm-int-bimc { cell-id = <10003>; label = "mm-int-bimc"; + qcom,util-fact = <154>; + qcom,vrail-comp = <100>; qcom,ap-owned; qcom,connections = <&snoc_bimc_1_mas>; qcom,bus-dev = <&fab_snoc>; diff --git a/drivers/platform/msm/msm_bus/Makefile b/drivers/platform/msm/msm_bus/Makefile index d108d8b194d3..e43705a80976 100644 --- a/drivers/platform/msm/msm_bus/Makefile +++ b/drivers/platform/msm/msm_bus/Makefile @@ -1,24 +1,26 @@ # # Makefile for msm-bus driver specific files # -obj-y += msm_bus_bimc.o msm_bus_noc.o msm_bus_core.o msm_bus_client_api.o +obj-y += msm_bus_core.o msm_bus_client_api.o obj-$(CONFIG_OF) += msm_bus_of.o obj-$(CONFIG_MSM_RPM_SMD) += msm_bus_rpm_smd.o ifdef CONFIG_BUS_TOPOLOGY_ADHOC - obj-y += msm_bus_fabric_adhoc.o msm_bus_arb_adhoc.o msm_bus_rules.o + obj-y += msm_bus_fabric_adhoc.o msm_bus_arb_adhoc.o msm_bus_rules.o \ + msm_bus_bimc_adhoc.o msm_bus_noc_adhoc.o obj-$(CONFIG_OF) += msm_bus_of_adhoc.o obj-$(CONFIG_DEBUG_BUS_VOTER) += msm_bus_dbg_voter.o obj-$(CONFIG_CORESIGHT) += msm_buspm_coresight_adhoc.o else - obj-y += msm_bus_fabric.o msm_bus_config.o msm_bus_arb.o + obj-y += msm_bus_fabric.o msm_bus_config.o msm_bus_arb.o \ + msm_bus_bimc.o msm_bus_noc.o obj-$(CONFIG_CORESIGHT) += msm_buspm_coresight.o endif ifdef CONFIG_ARCH_MSM8974 - obj-$(CONFIG_ARCH_MSM8974) += msm_bus_board_8974.o + obj-$(CONFIG_ARCH_MSM8974) += msm_bus_board_8974.o else - obj-y += msm_bus_id.o + obj-y += msm_bus_id.o endif obj-$(CONFIG_DEBUG_FS) += msm_bus_dbg.o diff --git a/drivers/platform/msm/msm_bus/msm_bus_adhoc.h b/drivers/platform/msm/msm_bus/msm_bus_adhoc.h index 06a7c71b3394..d65b0f0bf8d1 100644 --- a/drivers/platform/msm/msm_bus/msm_bus_adhoc.h +++ b/drivers/platform/msm/msm_bus/msm_bus_adhoc.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -28,6 +28,7 @@ struct link_node { struct device *next_dev; struct list_head link; uint32_t in_use; + const char *cl_name; }; /* New types introduced for adhoc topology */ @@ -46,8 +47,12 @@ struct msm_bus_noc_ops { }; struct nodebw { - uint64_t ab[NUM_CTX]; - bool dirty; + uint64_t sum_ab; + uint64_t last_sum_ab; + uint64_t max_ib; + uint64_t cur_clk_hz; + uint32_t util_used; + uint32_t vrail_used; }; struct msm_bus_fab_device_type { @@ -57,8 +62,6 @@ struct msm_bus_fab_device_type { uint32_t base_offset; uint32_t qos_freq; uint32_t qos_off; - uint32_t util_fact; - uint32_t vrail_comp; struct msm_bus_noc_ops noc_ops; enum msm_bus_hw_sel bus_type; bool bypass_qos_prg; @@ -80,6 +83,20 @@ struct qos_params_type { u64 bw_buffer; }; +struct node_util_levels_type { + uint64_t threshold; + uint32_t util_fact; +}; + +struct node_agg_params_type { + uint32_t agg_scheme; + uint32_t num_aggports; + unsigned int buswidth; + uint32_t vrail_comp; + uint32_t num_util_levels; + struct node_util_levels_type *util_levels; +}; + struct msm_bus_node_info_type { const char *name; unsigned int id; @@ -100,12 +117,10 @@ struct msm_bus_node_info_type { struct device **black_connections; unsigned int bus_device_id; struct device *bus_device; - unsigned int buswidth; struct rule_update_path_info rule; uint64_t lim_bw; - uint32_t util_fact; - uint32_t vrail_comp; - uint32_t num_aggports; + bool defer_qos; + struct node_agg_params_type agg_params; }; struct msm_bus_node_device_type { @@ -113,21 +128,29 @@ struct msm_bus_node_device_type { struct msm_bus_fab_device_type *fabdev; int num_lnodes; struct link_node *lnode_list; - uint64_t cur_clk_hz[NUM_CTX]; - struct nodebw node_ab; + struct nodebw node_bw[NUM_CTX]; struct list_head link; unsigned int ap_owned; struct nodeclk clk[NUM_CTX]; - struct nodeclk qos_clk; + struct nodeclk bus_qos_clk; + uint32_t num_node_qos_clks; + struct nodeclk *node_qos_clks; + struct device_node *of_node; + struct device dev; + bool dirty; + struct list_head dev_link; + struct list_head devlist; }; +static inline struct msm_bus_node_device_type *to_msm_bus_node(struct device *d) +{ + return container_of(d, struct msm_bus_node_device_type, dev); +} + + int msm_bus_enable_limiter(struct msm_bus_node_device_type *nodedev, int throttle_en, uint64_t lim_bw); -int msm_bus_update_clks(struct msm_bus_node_device_type *nodedev, - int ctx, int **dirty_nodes, int *num_dirty); -int msm_bus_commit_data(int *dirty_nodes, int ctx, int num_dirty); -int msm_bus_update_bw(struct msm_bus_node_device_type *nodedev, int ctx, - int64_t add_bw, int **dirty_nodes, int *num_dirty); +int msm_bus_commit_data(struct list_head *clist); void *msm_bus_realloc_devmem(struct device *dev, void *p, size_t old_size, size_t new_size, gfp_t flags); diff --git a/drivers/platform/msm/msm_bus/msm_bus_arb_adhoc.c b/drivers/platform/msm/msm_bus/msm_bus_arb_adhoc.c index 54880356a6b4..8adbbf781247 100644 --- a/drivers/platform/msm/msm_bus/msm_bus_arb_adhoc.c +++ b/drivers/platform/msm/msm_bus/msm_bus_arb_adhoc.c @@ -36,8 +36,9 @@ struct handle_type { }; static struct handle_type handle_list; -struct list_head input_list; -struct list_head apply_list; +static LIST_HEAD(input_list); +static LIST_HEAD(apply_list); +static LIST_HEAD(commit_list); DEFINE_RT_MUTEX(msm_bus_adhoc_lock); @@ -97,7 +98,7 @@ uint64_t msm_bus_div64(unsigned int w, uint64_t bw) int msm_bus_device_match_adhoc(struct device *dev, void *id) { int ret = 0; - struct msm_bus_node_device_type *bnode = dev->platform_data; + struct msm_bus_node_device_type *bnode = to_msm_bus_node(dev); if (bnode) ret = (bnode->node_info->id == *(unsigned int *)id); @@ -108,7 +109,7 @@ int msm_bus_device_match_adhoc(struct device *dev, void *id) } static int gen_lnode(struct device *dev, - int next_hop, int prev_idx) + int next_hop, int prev_idx, const char *cl_name) { struct link_node *lnode; struct msm_bus_node_device_type *cur_dev = NULL; @@ -117,7 +118,7 @@ static int gen_lnode(struct device *dev, if (!dev) goto exit_gen_lnode; - cur_dev = dev->platform_data; + cur_dev = to_msm_bus_node(dev); if (!cur_dev) { MSM_BUS_ERR("%s: Null device ptr", __func__); goto exit_gen_lnode; @@ -166,6 +167,7 @@ static int gen_lnode(struct device *dev, } lnode->in_use = 1; + lnode->cl_name = cl_name; if (next_hop == cur_dev->node_info->id) { lnode->next = -1; lnode->next_dev = NULL; @@ -206,6 +208,7 @@ static int remove_lnode(struct msm_bus_node_device_type *cur_dev, cur_dev->lnode_list[lnode_idx].next = -1; cur_dev->lnode_list[lnode_idx].next_dev = NULL; cur_dev->lnode_list[lnode_idx].in_use = 0; + cur_dev->lnode_list[lnode_idx].cl_name = NULL; } exit_remove_lnode: @@ -213,7 +216,8 @@ exit_remove_lnode: } static int prune_path(struct list_head *route_list, int dest, int src, - struct list_head *black_list, int found) + struct list_head *black_list, int found, + const char *cl_name) { struct bus_search_type *search_node, *temp_search_node; struct msm_bus_node_device_type *bus_node; @@ -233,7 +237,7 @@ static int prune_path(struct list_head *route_list, int dest, int src, goto exit_prune_path; } - lnode_hop = gen_lnode(dest_dev, search_dev_id, lnode_hop); + lnode_hop = gen_lnode(dest_dev, search_dev_id, lnode_hop, cl_name); list_for_each_entry_reverse(search_node, route_list, link) { list_for_each_entry(bus_node, &search_node->node_list, link) { @@ -257,7 +261,7 @@ static int prune_path(struct list_head *route_list, int dest, int src, lnode_hop = gen_lnode(dest_dev, search_dev_id, - lnode_hop); + lnode_hop, cl_name); search_dev_id = bus_node->node_info->id; break; @@ -290,25 +294,23 @@ static void setup_bl_list(struct msm_bus_node_device_type *node, for (i = 0; i < node->node_info->num_blist; i++) { struct msm_bus_node_device_type *bdev; - bdev = node->node_info->black_connections[i]->platform_data; + bdev = to_msm_bus_node(node->node_info->black_connections[i]); list_add_tail(&bdev->link, black_list); } } -static int getpath(int src, int dest) +static int getpath(struct device *src_dev, int dest, const char *cl_name) { struct list_head traverse_list; struct list_head edge_list; struct list_head route_list; struct list_head black_list; - struct device *src_dev = bus_find_device(&msm_bus_type, NULL, - (void *) &src, - msm_bus_device_match_adhoc); struct msm_bus_node_device_type *src_node; struct bus_search_type *search_node; int found = 0; int depth_index = 0; int first_hop = -1; + int src; INIT_LIST_HEAD(&traverse_list); INIT_LIST_HEAD(&edge_list); @@ -316,15 +318,16 @@ static int getpath(int src, int dest) INIT_LIST_HEAD(&black_list); if (!src_dev) { - MSM_BUS_ERR("%s: Cannot locate src dev %d", __func__, src); + MSM_BUS_ERR("%s: Cannot locate src dev ", __func__); goto exit_getpath; } - src_node = src_dev->platform_data; + src_node = to_msm_bus_node(src_dev); if (!src_node) { - MSM_BUS_ERR("%s:Fatal, Source dev %d not found", __func__, src); + MSM_BUS_ERR("%s:Fatal, Source node not found", __func__); goto exit_getpath; } + src = src_node->node_info->id; list_add_tail(&src_node->link, &traverse_list); while ((!found && !list_empty(&traverse_list))) { @@ -349,9 +352,9 @@ static int getpath(int src, int dest) bool skip; struct msm_bus_node_device_type *node_conn; - node_conn = bus_node->node_info-> - dev_connections[i]-> - platform_data; + node_conn = + to_msm_bus_node(bus_node->node_info-> + dev_connections[i]); if (node_conn->node_info-> is_traversed) { MSM_BUS_ERR("Circ Path %d\n", @@ -385,77 +388,213 @@ static int getpath(int src, int dest) } reset_traversed: copy_remaining_nodes(&edge_list, &traverse_list, &route_list); - first_hop = prune_path(&route_list, dest, src, &black_list, found); + first_hop = prune_path(&route_list, dest, src, &black_list, found, + cl_name); exit_getpath: return first_hop; } -static uint64_t arbitrate_bus_req(struct msm_bus_node_device_type *bus_dev, - int ctx) +static uint64_t scheme1_agg_scheme(struct msm_bus_node_device_type *bus_dev, + struct msm_bus_node_device_type *fab_dev, int ctx) { - int i; - uint64_t max_ib = 0; - uint64_t sum_ab = 0; + uint64_t max_ib; + uint64_t sum_ab; uint64_t bw_max_hz; - struct msm_bus_node_device_type *fab_dev = NULL; uint32_t util_fact = 0; uint32_t vrail_comp = 0; + struct node_util_levels_type *utils; + int i; + int num_util_levels; - /* Find max ib */ - for (i = 0; i < bus_dev->num_lnodes; i++) { - max_ib = max(max_ib, bus_dev->lnode_list[i].lnode_ib[ctx]); - sum_ab += bus_dev->lnode_list[i].lnode_ab[ctx]; - } /* - * Account for Util factor and vrail comp. The new aggregation - * formula is: + * Account for Util factor and vrail comp. + * Util factor is picked according to the current sum(AB) for this + * node and for this context. + * Vrail comp is fixed for the entire performance range. + * They default to 100 if absent. + * + * The aggregated clock is computed as: * Freq_hz = max((sum(ab) * util_fact)/num_chan, max(ib)/vrail_comp) * / bus-width - * util_fact and vrail comp are obtained from fabric/Node's dts - * properties. - * They default to 100 if absent. */ - fab_dev = bus_dev->node_info->bus_device->platform_data; - /* Don't do this for virtual fabrics */ - if (fab_dev && fab_dev->fabdev) { - util_fact = bus_dev->node_info->util_fact ? - bus_dev->node_info->util_fact : - fab_dev->fabdev->util_fact; - vrail_comp = bus_dev->node_info->vrail_comp ? - bus_dev->node_info->vrail_comp : - fab_dev->fabdev->vrail_comp; + if (bus_dev->node_info->agg_params.num_util_levels) { + utils = bus_dev->node_info->agg_params.util_levels; + num_util_levels = + bus_dev->node_info->agg_params.num_util_levels; + } else { + utils = fab_dev->node_info->agg_params.util_levels; + num_util_levels = + fab_dev->node_info->agg_params.num_util_levels; + } + + sum_ab = bus_dev->node_bw[ctx].sum_ab; + max_ib = bus_dev->node_bw[ctx].max_ib; + + for (i = 0; i < num_util_levels; i++) { + if (sum_ab < utils[i].threshold) { + util_fact = utils[i].util_fact; + break; + } + } + if (i == num_util_levels) + util_fact = utils[(num_util_levels - 1)].util_fact; + + vrail_comp = bus_dev->node_info->agg_params.vrail_comp ? + bus_dev->node_info->agg_params.vrail_comp : + fab_dev->node_info->agg_params.vrail_comp; + + bus_dev->node_bw[ctx].vrail_used = vrail_comp; + bus_dev->node_bw[ctx].util_used = util_fact; + + if (util_fact && (util_fact != 100)) { sum_ab *= util_fact; sum_ab = msm_bus_div64(100, sum_ab); + } + + if (vrail_comp && (vrail_comp != 100)) { max_ib *= 100; max_ib = msm_bus_div64(vrail_comp, max_ib); } /* Account for multiple channels if any */ - if (bus_dev->node_info->num_aggports > 1) - sum_ab = msm_bus_div64(bus_dev->node_info->num_aggports, + if (bus_dev->node_info->agg_params.num_aggports > 1) + sum_ab = msm_bus_div64( + bus_dev->node_info->agg_params.num_aggports, sum_ab); - if (!bus_dev->node_info->buswidth) { + if (!bus_dev->node_info->agg_params.buswidth) { MSM_BUS_WARN("No bus width found for %d. Using default\n", bus_dev->node_info->id); - bus_dev->node_info->buswidth = 8; + bus_dev->node_info->agg_params.buswidth = 8; } bw_max_hz = max(max_ib, sum_ab); - bw_max_hz = msm_bus_div64(bus_dev->node_info->buswidth, + bw_max_hz = msm_bus_div64(bus_dev->node_info->agg_params.buswidth, bw_max_hz); return bw_max_hz; } +static uint64_t legacy_agg_scheme(struct msm_bus_node_device_type *bus_dev, + struct msm_bus_node_device_type *fab_dev, int ctx) +{ + uint64_t max_ib; + uint64_t sum_ab; + uint64_t bw_max_hz; + uint32_t util_fact = 0; + uint32_t vrail_comp = 0; + + /* + * Util_fact and vrail comp are obtained from fabric/Node's dts + * properties and are fixed for the entire performance range. + * They default to 100 if absent. + * + * The clock frequency is computed as: + * Freq_hz = max((sum(ab) * util_fact)/num_chan, max(ib)/vrail_comp) + * / bus-width + */ + util_fact = fab_dev->node_info->agg_params.util_levels[0].util_fact; + vrail_comp = fab_dev->node_info->agg_params.vrail_comp; + + if (bus_dev->node_info->agg_params.num_util_levels) + util_fact = + bus_dev->node_info->agg_params.util_levels[0].util_fact ? + bus_dev->node_info->agg_params.util_levels[0].util_fact : + util_fact; + + vrail_comp = bus_dev->node_info->agg_params.vrail_comp ? + bus_dev->node_info->agg_params.vrail_comp : + vrail_comp; + + bus_dev->node_bw[ctx].vrail_used = vrail_comp; + bus_dev->node_bw[ctx].util_used = util_fact; + sum_ab = bus_dev->node_bw[ctx].sum_ab; + max_ib = bus_dev->node_bw[ctx].max_ib; + + if (util_fact && (util_fact != 100)) { + sum_ab *= util_fact; + sum_ab = msm_bus_div64(100, sum_ab); + } + + if (vrail_comp && (vrail_comp != 100)) { + max_ib *= 100; + max_ib = msm_bus_div64(vrail_comp, max_ib); + } + + /* Account for multiple channels if any */ + if (bus_dev->node_info->agg_params.num_aggports > 1) + sum_ab = msm_bus_div64( + bus_dev->node_info->agg_params.num_aggports, + sum_ab); + + if (!bus_dev->node_info->agg_params.buswidth) { + MSM_BUS_WARN("No bus width found for %d. Using default\n", + bus_dev->node_info->id); + bus_dev->node_info->agg_params.buswidth = 8; + } + + bw_max_hz = max(max_ib, sum_ab); + bw_max_hz = msm_bus_div64(bus_dev->node_info->agg_params.buswidth, + bw_max_hz); + + return bw_max_hz; +} + +static uint64_t aggregate_bus_req(struct msm_bus_node_device_type *bus_dev, + int ctx) +{ + uint64_t bw_hz = 0; + int i; + struct msm_bus_node_device_type *fab_dev = NULL; + uint32_t agg_scheme; + uint64_t max_ib = 0; + uint64_t sum_ab = 0; + + if (!bus_dev || !to_msm_bus_node(bus_dev->node_info->bus_device)) { + MSM_BUS_ERR("Bus node pointer is Invalid"); + goto exit_agg_bus_req; + } + + fab_dev = to_msm_bus_node(bus_dev->node_info->bus_device); + for (i = 0; i < bus_dev->num_lnodes; i++) { + max_ib = max(max_ib, bus_dev->lnode_list[i].lnode_ib[ctx]); + sum_ab += bus_dev->lnode_list[i].lnode_ab[ctx]; + } + + bus_dev->node_bw[ctx].sum_ab = sum_ab; + bus_dev->node_bw[ctx].max_ib = max_ib; + + if (bus_dev->node_info->agg_params.agg_scheme != AGG_SCHEME_NONE) + agg_scheme = bus_dev->node_info->agg_params.agg_scheme; + else + agg_scheme = fab_dev->node_info->agg_params.agg_scheme; + + switch (agg_scheme) { + case AGG_SCHEME_1: + bw_hz = scheme1_agg_scheme(bus_dev, fab_dev, ctx); + break; + case AGG_SCHEME_LEG: + bw_hz = legacy_agg_scheme(bus_dev, fab_dev, ctx); + break; + default: + panic("Invalid Bus aggregation scheme"); + } + +exit_agg_bus_req: + return bw_hz; +} + + static void del_inp_list(struct list_head *list) { struct rule_update_path_info *rule_node; struct rule_update_path_info *rule_node_tmp; - list_for_each_entry_safe(rule_node, rule_node_tmp, list, link) + list_for_each_entry_safe(rule_node, rule_node_tmp, list, link) { list_del(&rule_node->link); + rule_node->added = false; + } } static void del_op_list(struct list_head *list) @@ -489,7 +628,7 @@ static int msm_bus_apply_rules(struct list_head *list, bool after_clk_commit) MSM_BUS_ERR("Can't find dev node for %d", rule->id); continue; } - dev_info = dev->platform_data; + dev_info = to_msm_bus_node(dev); ret = msm_bus_enable_limiter(dev_info, rule->throttle, rule->lim_bw); @@ -500,61 +639,58 @@ static int msm_bus_apply_rules(struct list_head *list, bool after_clk_commit) return ret; } -static uint64_t get_node_aggab(struct msm_bus_node_device_type *bus_dev) +static void commit_data(void) { - int i; - int ctx; - uint64_t max_agg_ab = 0; - uint64_t agg_ab = 0; + bool rules_registered = msm_rule_are_rules_registered(); - for (ctx = 0; ctx < NUM_CTX; ctx++) { - for (i = 0; i < bus_dev->num_lnodes; i++) - agg_ab += bus_dev->lnode_list[i].lnode_ab[ctx]; - - if (bus_dev->node_info->num_aggports > 1) - agg_ab = msm_bus_div64(bus_dev->node_info->num_aggports, - agg_ab); - - max_agg_ab = max(max_agg_ab, agg_ab); + if (rules_registered) { + msm_rules_update_path(&input_list, &apply_list); + msm_bus_apply_rules(&apply_list, false); } - return max_agg_ab; -} + msm_bus_commit_data(&commit_list); -static uint64_t get_node_ib(struct msm_bus_node_device_type *bus_dev) -{ - int i; - int ctx; - uint64_t max_ib = 0; - - for (ctx = 0; ctx < NUM_CTX; ctx++) { - for (i = 0; i < bus_dev->num_lnodes; i++) - max_ib = max(max_ib, - bus_dev->lnode_list[i].lnode_ib[ctx]); + if (rules_registered) { + msm_bus_apply_rules(&apply_list, true); + del_inp_list(&input_list); + del_op_list(&apply_list); } - return max_ib; + INIT_LIST_HEAD(&input_list); + INIT_LIST_HEAD(&apply_list); + INIT_LIST_HEAD(&commit_list); } -static int update_path(int src, int dest, uint64_t req_ib, uint64_t req_bw, - uint64_t cur_ib, uint64_t cur_bw, int src_idx, int ctx) +static void add_node_to_clist(struct msm_bus_node_device_type *node) +{ + struct msm_bus_node_device_type *node_parent = + to_msm_bus_node(node->node_info->bus_device); + + if (!node->dirty) { + list_add_tail(&node->link, &commit_list); + node->dirty = true; + } + + if (!node_parent->dirty) { + list_add_tail(&node_parent->link, &commit_list); + node_parent->dirty = true; + } +} + +static int update_path(struct device *src_dev, int dest, uint64_t act_req_ib, + uint64_t act_req_bw, uint64_t slp_req_ib, + uint64_t slp_req_bw, uint64_t cur_ib, uint64_t cur_bw, + int src_idx, int ctx) { - struct device *src_dev = NULL; struct device *next_dev = NULL; struct link_node *lnode = NULL; struct msm_bus_node_device_type *dev_info = NULL; int curr_idx; int ret = 0; - int *dirty_nodes = NULL; - int num_dirty = 0; struct rule_update_path_info *rule_node; bool rules_registered = msm_rule_are_rules_registered(); - src_dev = bus_find_device(&msm_bus_type, NULL, - (void *) &src, - msm_bus_device_match_adhoc); - - if (!src_dev) { - MSM_BUS_ERR("%s: Can't find source device %d", __func__, src); + if (IS_ERR_OR_NULL(src_dev)) { + MSM_BUS_ERR("%s: No source device", __func__); ret = -ENODEV; goto exit_update_path; } @@ -568,11 +704,10 @@ static int update_path(int src, int dest, uint64_t req_ib, uint64_t req_bw, } curr_idx = src_idx; - INIT_LIST_HEAD(&input_list); - INIT_LIST_HEAD(&apply_list); - while (next_dev) { - dev_info = next_dev->platform_data; + int i; + + dev_info = to_msm_bus_node(next_dev); if (curr_idx >= dev_info->num_lnodes) { MSM_BUS_ERR("%s: Invalid lnode Idx %d num lnodes %d", @@ -582,67 +717,47 @@ static int update_path(int src, int dest, uint64_t req_ib, uint64_t req_bw, } lnode = &dev_info->lnode_list[curr_idx]; - lnode->lnode_ib[ctx] = req_ib; - lnode->lnode_ab[ctx] = req_bw; - - dev_info->cur_clk_hz[ctx] = arbitrate_bus_req(dev_info, ctx); - - /* Start updating the clocks at the first hop. - * Its ok to figure out the aggregated - * request at this node. - */ - if (src_dev != next_dev) { - ret = msm_bus_update_clks(dev_info, ctx, &dirty_nodes, - &num_dirty); - if (ret) { - MSM_BUS_ERR("%s: Failed to update clks dev %d", - __func__, dev_info->node_info->id); - goto exit_update_path; - } - } - - ret = msm_bus_update_bw(dev_info, ctx, req_bw, &dirty_nodes, - &num_dirty); - if (ret) { - MSM_BUS_ERR("%s: Failed to update bw dev %d", - __func__, dev_info->node_info->id); + if (!lnode) { + MSM_BUS_ERR("%s: Invalid lnode ptr lnode %d", + __func__, curr_idx); + ret = -ENXIO; goto exit_update_path; } + lnode->lnode_ib[ACTIVE_CTX] = act_req_ib; + lnode->lnode_ab[ACTIVE_CTX] = act_req_bw; + lnode->lnode_ib[DUAL_CTX] = slp_req_ib; + lnode->lnode_ab[DUAL_CTX] = slp_req_bw; + + for (i = 0; i < NUM_CTX; i++) + dev_info->node_bw[i].cur_clk_hz = + aggregate_bus_req(dev_info, i); + + add_node_to_clist(dev_info); if (rules_registered) { rule_node = &dev_info->node_info->rule; rule_node->id = dev_info->node_info->id; - rule_node->ib = get_node_ib(dev_info); - rule_node->ab = get_node_aggab(dev_info); - rule_node->clk = max(dev_info->cur_clk_hz[ACTIVE_CTX], - dev_info->cur_clk_hz[DUAL_CTX]); - list_add_tail(&rule_node->link, &input_list); + rule_node->ib = dev_info->node_bw[ACTIVE_CTX].max_ib; + rule_node->ab = dev_info->node_bw[ACTIVE_CTX].sum_ab; + rule_node->clk = + dev_info->node_bw[ACTIVE_CTX].cur_clk_hz; + if (!rule_node->added) { + list_add_tail(&rule_node->link, &input_list); + rule_node->added = true; + } } next_dev = lnode->next_dev; curr_idx = lnode->next; } - if (rules_registered) { - msm_rules_update_path(&input_list, &apply_list); - msm_bus_apply_rules(&apply_list, false); - } - - msm_bus_commit_data(dirty_nodes, ctx, num_dirty); - - if (rules_registered) { - msm_bus_apply_rules(&apply_list, true); - del_inp_list(&input_list); - del_op_list(&apply_list); - } exit_update_path: return ret; } -static int remove_path(int src, int dst, uint64_t cur_ib, uint64_t cur_ab, - int src_idx, int active_only) +static int remove_path(struct device *src_dev, int dst, uint64_t cur_ib, + uint64_t cur_ab, int src_idx, int active_only) { - struct device *src_dev = NULL; struct device *next_dev = NULL; struct link_node *lnode = NULL; struct msm_bus_node_device_type *dev_info = NULL; @@ -653,8 +768,13 @@ static int remove_path(int src, int dst, uint64_t cur_ib, uint64_t cur_ab, /* Update the current path to zero out all request from * this cient on all paths */ + if (!src_dev) { + MSM_BUS_ERR("%s: Can't find source device", __func__); + ret = -ENODEV; + goto exit_remove_path; + } - ret = update_path(src, dst, 0, 0, cur_ib, cur_ab, src_idx, + ret = update_path(src_dev, dst, 0, 0, 0, 0, cur_ib, cur_ab, src_idx, active_only); if (ret) { MSM_BUS_ERR("%s: Error zeroing out path ctx %d", @@ -662,19 +782,10 @@ static int remove_path(int src, int dst, uint64_t cur_ib, uint64_t cur_ab, goto exit_remove_path; } - src_dev = bus_find_device(&msm_bus_type, NULL, - (void *) &src, - msm_bus_device_match_adhoc); - if (!src_dev) { - MSM_BUS_ERR("%s: Can't find source device %d", __func__, src); - ret = -ENODEV; - goto exit_remove_path; - } - next_dev = src_dev; while (next_dev) { - dev_info = next_dev->platform_data; + dev_info = to_msm_bus_node(next_dev); lnode = &dev_info->lnode_list[cur_idx]; next_idx = lnode->next; next_dev = lnode->next_dev; @@ -705,28 +816,28 @@ static void getpath_debug(int src, int curr, int active_only) } idx = curr; - devinfo = dev_node->platform_data; + devinfo = to_msm_bus_node(dev_node); dev_it = dev_node; MSM_BUS_ERR("Route list Src %d", src); while (dev_it) { struct msm_bus_node_device_type *busdev = - devinfo->node_info->bus_device->platform_data; + to_msm_bus_node(devinfo->node_info->bus_device); MSM_BUS_ERR("Hop[%d] at Device %d ctx %d", hop, devinfo->node_info->id, active_only); for (i = 0; i < NUM_CTX; i++) { MSM_BUS_ERR("dev info sel ib %llu", - devinfo->cur_clk_hz[i]); + devinfo->node_bw[i].cur_clk_hz); MSM_BUS_ERR("dev info sel ab %llu", - devinfo->node_ab.ab[i]); + devinfo->node_bw[i].sum_ab); } dev_it = devinfo->lnode_list[idx].next_dev; idx = devinfo->lnode_list[idx].next; if (dev_it) - devinfo = dev_it->platform_data; + devinfo = to_msm_bus_node(dev_it); MSM_BUS_ERR("Bus Device %d", busdev->node_info->id); MSM_BUS_ERR("Bus Clock %llu", busdev->clk[active_only].rate); @@ -744,6 +855,7 @@ static void unregister_client_adhoc(uint32_t cl) int lnode, src, curr, dest; uint64_t cur_clk, cur_bw; struct msm_bus_client *client; + struct device *src_dev; rt_mutex_lock(&msm_bus_adhoc_lock); if (!cl) { @@ -772,11 +884,13 @@ static void unregister_client_adhoc(uint32_t cl) dest = client->pdata->usecase[curr].vectors[i].dst; lnode = client->src_pnode[i]; + src_dev = client->src_devs[i]; cur_clk = client->pdata->usecase[curr].vectors[i].ib; cur_bw = client->pdata->usecase[curr].vectors[i].ab; - remove_path(src, dest, cur_clk, cur_bw, lnode, + remove_path(src_dev, dest, cur_clk, cur_bw, lnode, pdata->active_only); } + commit_data(); msm_bus_dbg_client_data(client->pdata, MSM_BUS_DBG_UNREGISTER, cl); kfree(client->src_pnode); kfree(client); @@ -857,6 +971,7 @@ static uint32_t register_client_adhoc(struct msm_bus_scale_pdata *pdata) int i; struct msm_bus_client *client = NULL; int *lnode; + struct device *dev; uint32_t handle = 0; rt_mutex_lock(&msm_bus_adhoc_lock); @@ -874,6 +989,14 @@ static uint32_t register_client_adhoc(struct msm_bus_scale_pdata *pdata) } client->src_pnode = lnode; + client->src_devs = kzalloc(pdata->usecase->num_paths * + sizeof(struct device *), GFP_KERNEL); + if (IS_ERR_OR_NULL(client->src_devs)) { + MSM_BUS_ERR("%s: Error allocating pathnode ptr!", __func__); + goto exit_register_client; + } + client->curr = -1; + for (i = 0; i < pdata->usecase->num_paths; i++) { src = pdata->usecase->vectors[i].src; dest = pdata->usecase->vectors[i].dst; @@ -883,8 +1006,17 @@ static uint32_t register_client_adhoc(struct msm_bus_scale_pdata *pdata) __func__, src, dest); goto exit_register_client; } + dev = bus_find_device(&msm_bus_type, NULL, + (void *) &src, + msm_bus_device_match_adhoc); + if (IS_ERR_OR_NULL(dev)) { + MSM_BUS_ERR("%s:Failed to find path.src %d dest %d", + __func__, src, dest); + goto exit_register_client; + } + client->src_devs[i] = dev; - lnode[i] = getpath(src, dest); + lnode[i] = getpath(dev, dest, client->pdata->name); if (lnode[i] < 0) { MSM_BUS_ERR("%s:Failed to find path.src %d dest %d", __func__, src, dest); @@ -902,12 +1034,133 @@ exit_register_client: return handle; } -static int update_request_adhoc(uint32_t cl, unsigned int index) +static int update_client_paths(struct msm_bus_client *client, bool log_trns, + unsigned int idx) { + int lnode, src, dest, cur_idx; + uint64_t req_clk, req_bw, curr_clk, curr_bw, slp_clk, slp_bw; int i, ret = 0; struct msm_bus_scale_pdata *pdata; - int lnode, src, curr, dest; - uint64_t req_clk, req_bw, curr_clk, curr_bw; + struct device *src_dev; + + if (!client) { + MSM_BUS_ERR("Client handle Null"); + ret = -ENXIO; + goto exit_update_client_paths; + } + + pdata = client->pdata; + if (!pdata) { + MSM_BUS_ERR("Client pdata Null"); + ret = -ENXIO; + goto exit_update_client_paths; + } + + cur_idx = client->curr; + client->curr = idx; + for (i = 0; i < pdata->usecase->num_paths; i++) { + src = pdata->usecase[idx].vectors[i].src; + dest = pdata->usecase[idx].vectors[i].dst; + + lnode = client->src_pnode[i]; + src_dev = client->src_devs[i]; + req_clk = client->pdata->usecase[idx].vectors[i].ib; + req_bw = client->pdata->usecase[idx].vectors[i].ab; + if (cur_idx < 0) { + curr_clk = 0; + curr_bw = 0; + } else { + curr_clk = + client->pdata->usecase[cur_idx].vectors[i].ib; + curr_bw = client->pdata->usecase[cur_idx].vectors[i].ab; + MSM_BUS_DBG("%s:ab: %llu ib: %llu\n", __func__, + curr_bw, curr_clk); + } + + if (pdata->active_only) { + slp_clk = 0; + slp_bw = 0; + } else { + slp_clk = req_clk; + slp_bw = req_bw; + } + + ret = update_path(src_dev, dest, req_clk, req_bw, slp_clk, + slp_bw, curr_clk, curr_bw, lnode, pdata->active_only); + + if (ret) { + MSM_BUS_ERR("%s: Update path failed! %d ctx %d\n", + __func__, ret, pdata->active_only); + goto exit_update_client_paths; + } + + if (log_trns) + getpath_debug(src, lnode, pdata->active_only); + } + commit_data(); +exit_update_client_paths: + return ret; +} + +static int update_context(uint32_t cl, bool active_only, + unsigned int ctx_idx) +{ + int ret = 0; + struct msm_bus_scale_pdata *pdata; + struct msm_bus_client *client; + + rt_mutex_lock(&msm_bus_adhoc_lock); + if (!cl) { + MSM_BUS_ERR("%s: Invalid client handle %d", __func__, cl); + ret = -ENXIO; + goto exit_update_context; + } + + client = handle_list.cl_list[cl]; + if (!client) { + ret = -ENXIO; + goto exit_update_context; + } + + pdata = client->pdata; + if (!pdata) { + ret = -ENXIO; + goto exit_update_context; + } + if (pdata->active_only == active_only) { + MSM_BUS_ERR("No change in context(%d==%d), skip\n", + pdata->active_only, active_only); + ret = -ENXIO; + goto exit_update_context; + } + + if (ctx_idx >= pdata->num_usecases) { + MSM_BUS_ERR("Client %u passed invalid index: %d\n", + cl, ctx_idx); + ret = -ENXIO; + goto exit_update_context; + } + + pdata->active_only = active_only; + + msm_bus_dbg_client_data(client->pdata, ctx_idx , cl); + ret = update_client_paths(client, false, ctx_idx); + if (ret) { + pr_err("%s: Err updating path\n", __func__); + goto exit_update_context; + } + + trace_bus_update_request_end(pdata->name); + +exit_update_context: + rt_mutex_unlock(&msm_bus_adhoc_lock); + return ret; +} + +static int update_request_adhoc(uint32_t cl, unsigned int index) +{ + int ret = 0; + struct msm_bus_scale_pdata *pdata; struct msm_bus_client *client; const char *test_cl = "Null"; bool log_transaction = false; @@ -921,6 +1174,12 @@ static int update_request_adhoc(uint32_t cl, unsigned int index) } client = handle_list.cl_list[cl]; + if (!client) { + MSM_BUS_ERR("%s: Invalid client pointer ", __func__); + ret = -ENXIO; + goto exit_update_request; + } + pdata = client->pdata; if (!pdata) { MSM_BUS_ERR("%s: Client data Null.[client didn't register]", @@ -942,46 +1201,20 @@ static int update_request_adhoc(uint32_t cl, unsigned int index) goto exit_update_request; } - curr = client->curr; - client->curr = index; - if (!strcmp(test_cl, pdata->name)) log_transaction = true; MSM_BUS_DBG("%s: cl: %u index: %d curr: %d num_paths: %d\n", __func__, cl, index, client->curr, client->pdata->usecase->num_paths); - msm_bus_dbg_client_data(client->pdata, index , cl); - for (i = 0; i < pdata->usecase->num_paths; i++) { - src = client->pdata->usecase[index].vectors[i].src; - dest = client->pdata->usecase[index].vectors[i].dst; - - lnode = client->src_pnode[i]; - req_clk = client->pdata->usecase[index].vectors[i].ib; - req_bw = client->pdata->usecase[index].vectors[i].ab; - if (curr < 0) { - curr_clk = 0; - curr_bw = 0; - } else { - curr_clk = client->pdata->usecase[curr].vectors[i].ib; - curr_bw = client->pdata->usecase[curr].vectors[i].ab; - MSM_BUS_DBG("%s:ab: %llu ib: %llu\n", __func__, - curr_bw, curr_clk); - } - - ret = update_path(src, dest, req_clk, req_bw, - curr_clk, curr_bw, lnode, pdata->active_only); - - if (ret) { - MSM_BUS_ERR("%s: Update path failed! %d ctx %d\n", - __func__, ret, ACTIVE_CTX); - goto exit_update_request; - } - - if (log_transaction) - getpath_debug(src, lnode, pdata->active_only); + ret = update_client_paths(client, log_transaction, index); + if (ret) { + pr_err("%s: Err updating path\n", __func__); + goto exit_update_request; } + trace_bus_update_request_end(pdata->name); + exit_update_request: rt_mutex_unlock(&msm_bus_adhoc_lock); return ret; @@ -1001,6 +1234,7 @@ static int update_bw_adhoc(struct msm_bus_client_handle *cl, u64 ab, u64 ib) int ret = 0; char *test_cl = "test-client"; bool log_transaction = false; + u64 slp_ib, slp_ab; rt_mutex_lock(&msm_bus_adhoc_lock); @@ -1015,13 +1249,21 @@ static int update_bw_adhoc(struct msm_bus_client_handle *cl, u64 ab, u64 ib) msm_bus_dbg_rec_transaction(cl, ab, ib); - if ((cl->cur_ib == ib) && (cl->cur_ab == ab)) { + if ((cl->cur_act_ib == ib) && (cl->cur_act_ab == ab)) { MSM_BUS_DBG("%s:no change in request", cl->name); goto exit_update_request; } - ret = update_path(cl->mas, cl->slv, ib, ab, cl->cur_ib, cl->cur_ab, - cl->first_hop, cl->active_only); + if (cl->active_only) { + slp_ib = 0; + slp_ab = 0; + } else { + slp_ib = ib; + slp_ab = ab; + } + + ret = update_path(cl->mas_dev, cl->slv, ib, ab, slp_ib, slp_ab, + cl->cur_act_ib, cl->cur_act_ab, cl->first_hop, cl->active_only); if (ret) { MSM_BUS_ERR("%s: Update path failed! %d active_only %d\n", @@ -1029,8 +1271,11 @@ static int update_bw_adhoc(struct msm_bus_client_handle *cl, u64 ab, u64 ib) goto exit_update_request; } - cl->cur_ib = ib; - cl->cur_ab = ab; + commit_data(); + cl->cur_act_ib = ib; + cl->cur_act_ab = ab; + cl->cur_slp_ib = slp_ib; + cl->cur_slp_ab = slp_ab; if (log_transaction) getpath_debug(cl->mas, cl->first_hop, cl->active_only); @@ -1041,6 +1286,48 @@ exit_update_request: return ret; } +static int update_bw_context(struct msm_bus_client_handle *cl, u64 act_ab, + u64 act_ib, u64 slp_ib, u64 slp_ab) +{ + int ret = 0; + + rt_mutex_lock(&msm_bus_adhoc_lock); + if (!cl) { + MSM_BUS_ERR("Invalid client handle %p", cl); + ret = -ENXIO; + goto exit_change_context; + } + + if ((cl->cur_act_ib == act_ib) && + (cl->cur_act_ab == act_ab) && + (cl->cur_slp_ib == slp_ib) && + (cl->cur_slp_ab == slp_ab)) { + MSM_BUS_ERR("No change in vote"); + goto exit_change_context; + } + + if (!slp_ab && !slp_ib) + cl->active_only = true; + msm_bus_dbg_rec_transaction(cl, cl->cur_act_ab, cl->cur_slp_ib); + ret = update_path(cl->mas_dev, cl->slv, act_ib, act_ab, slp_ib, slp_ab, + cl->cur_act_ab, cl->cur_act_ab, cl->first_hop, + cl->active_only); + if (ret) { + MSM_BUS_ERR("%s: Update path failed! %d active_only %d\n", + __func__, ret, cl->active_only); + goto exit_change_context; + } + commit_data(); + cl->cur_act_ib = act_ib; + cl->cur_act_ab = act_ab; + cl->cur_slp_ib = slp_ib; + cl->cur_slp_ab = slp_ab; + trace_bus_update_request_end(cl->name); +exit_change_context: + rt_mutex_unlock(&msm_bus_adhoc_lock); + return ret; +} + static void unregister_adhoc(struct msm_bus_client_handle *cl) { rt_mutex_lock(&msm_bus_adhoc_lock); @@ -1052,9 +1339,9 @@ static void unregister_adhoc(struct msm_bus_client_handle *cl) MSM_BUS_DBG("%s: Unregistering client %p", __func__, cl); - remove_path(cl->mas, cl->slv, cl->cur_ib, cl->cur_ab, + remove_path(cl->mas_dev, cl->slv, cl->cur_act_ib, cl->cur_act_ab, cl->first_hop, cl->active_only); - + commit_data(); msm_bus_dbg_remove_client(cl); kfree(cl); exit_unregister_client: @@ -1062,7 +1349,6 @@ exit_unregister_client: return; } - static struct msm_bus_client_handle* register_adhoc(uint32_t mas, uint32_t slv, char *name, bool active_only) { @@ -1084,7 +1370,7 @@ register_adhoc(uint32_t mas, uint32_t slv, char *name, bool active_only) } len = strnlen(name, MAX_STR_CL); - client->name = kzalloc(len, GFP_KERNEL); + client->name = kzalloc((len + 1), GFP_KERNEL); if (!client->name) { MSM_BUS_ERR("%s: Error allocating client name buf", __func__); free_cl_mem(client); @@ -1095,7 +1381,18 @@ register_adhoc(uint32_t mas, uint32_t slv, char *name, bool active_only) client->mas = mas; client->slv = slv; - client->first_hop = getpath(client->mas, client->slv); + + client->mas_dev = bus_find_device(&msm_bus_type, NULL, + (void *) &mas, + msm_bus_device_match_adhoc); + if (IS_ERR_OR_NULL(client->mas_dev)) { + MSM_BUS_ERR("%s:Failed to find path.src %d dest %d", + __func__, client->mas, client->slv); + free_cl_mem(client); + goto exit_register; + } + + client->first_hop = getpath(client->mas_dev, client->slv, client->name); if (client->first_hop < 0) { MSM_BUS_ERR("%s:Failed to find path.src %d dest %d", __func__, client->mas, client->slv); @@ -1119,8 +1416,10 @@ void msm_bus_arb_setops_adhoc(struct msm_bus_arb_ops *arb_ops) arb_ops->register_client = register_client_adhoc; arb_ops->update_request = update_request_adhoc; arb_ops->unregister_client = unregister_client_adhoc; + arb_ops->update_context = update_context; arb_ops->register_cl = register_adhoc; arb_ops->unregister = unregister_adhoc; arb_ops->update_bw = update_bw_adhoc; + arb_ops->update_bw_context = update_bw_context; } diff --git a/drivers/platform/msm/msm_bus/msm_bus_bimc.c b/drivers/platform/msm/msm_bus/msm_bus_bimc.c index 693149def382..17c74b3aac8c 100644 --- a/drivers/platform/msm/msm_bus/msm_bus_bimc.c +++ b/drivers/platform/msm/msm_bus/msm_bus_bimc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -20,14 +20,6 @@ #include "msm_bus_adhoc.h" #include -enum msm_bus_bimc_slave_block { - SLAVE_BLOCK_RESERVED = 0, - SLAVE_BLOCK_SLAVE_WAY, - SLAVE_BLOCK_XPU, - SLAVE_BLOCK_ARBITER, - SLAVE_BLOCK_SCMO, -}; - enum bke_sw { BKE_OFF = 0, BKE_ON = 1, @@ -37,104 +29,6 @@ enum bke_sw { #define M_REG_BASE(b) ((b) + 0x00008000) -#define M_COMPONENT_INFO_ADDR(b, n) \ - (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000000) -enum bimc_m_component_info { - M_COMPONENT_INFO_RMSK = 0xffffff, - M_COMPONENT_INFO_INSTANCE_BMSK = 0xff0000, - M_COMPONENT_INFO_INSTANCE_SHFT = 0x10, - M_COMPONENT_INFO_SUB_TYPE_BMSK = 0xff00, - M_COMPONENT_INFO_SUB_TYPE_SHFT = 0x8, - M_COMPONENT_INFO_TYPE_BMSK = 0xff, - M_COMPONENT_INFO_TYPE_SHFT = 0x0, -}; - -#define M_CONFIG_INFO_0_ADDR(b, n) \ - (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000020) -enum bimc_m_config_info_0 { - M_CONFIG_INFO_0_RMSK = 0xff00ffff, - M_CONFIG_INFO_0_SYNC_MODE_BMSK = 0xff000000, - M_CONFIG_INFO_0_SYNC_MODE_SHFT = 0x18, - M_CONFIG_INFO_0_CONNECTION_TYPE_BMSK = 0xff00, - M_CONFIG_INFO_0_CONNECTION_TYPE_SHFT = 0x8, - M_CONFIG_INFO_0_FUNC_BMSK = 0xff, - M_CONFIG_INFO_0_FUNC_SHFT = 0x0, -}; - -#define M_CONFIG_INFO_1_ADDR(b, n) \ - (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000030) -enum bimc_m_config_info_1 { - M_CONFIG_INFO_1_RMSK = 0xffffffff, - M_CONFIG_INFO_1_SWAY_CONNECTIVITY_BMSK = 0xffffffff, - M_CONFIG_INFO_1_SWAY_CONNECTIVITY_SHFT = 0x0, -}; - -#define M_CONFIG_INFO_2_ADDR(b, n) \ - (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000040) -enum bimc_m_config_info_2 { - M_CONFIG_INFO_2_RMSK = 0xffffffff, - M_CONFIG_INFO_2_M_DATA_WIDTH_BMSK = 0xffff0000, - M_CONFIG_INFO_2_M_DATA_WIDTH_SHFT = 0x10, - M_CONFIG_INFO_2_M_TID_WIDTH_BMSK = 0xff00, - M_CONFIG_INFO_2_M_TID_WIDTH_SHFT = 0x8, - M_CONFIG_INFO_2_M_MID_WIDTH_BMSK = 0xff, - M_CONFIG_INFO_2_M_MID_WIDTH_SHFT = 0x0, -}; - -#define M_CONFIG_INFO_3_ADDR(b, n) \ - (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000050) -enum bimc_m_config_info_3 { - M_CONFIG_INFO_3_RMSK = 0xffffffff, - M_CONFIG_INFO_3_RCH_DEPTH_BMSK = 0xff000000, - M_CONFIG_INFO_3_RCH_DEPTH_SHFT = 0x18, - M_CONFIG_INFO_3_BCH_DEPTH_BMSK = 0xff0000, - M_CONFIG_INFO_3_BCH_DEPTH_SHFT = 0x10, - M_CONFIG_INFO_3_WCH_DEPTH_BMSK = 0xff00, - M_CONFIG_INFO_3_WCH_DEPTH_SHFT = 0x8, - M_CONFIG_INFO_3_ACH_DEPTH_BMSK = 0xff, - M_CONFIG_INFO_3_ACH_DEPTH_SHFT = 0x0, -}; - -#define M_CONFIG_INFO_4_ADDR(b, n) \ - (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000060) -enum bimc_m_config_info_4 { - M_CONFIG_INFO_4_RMSK = 0xffff, - M_CONFIG_INFO_4_REORDER_BUF_DEPTH_BMSK = 0xff00, - M_CONFIG_INFO_4_REORDER_BUF_DEPTH_SHFT = 0x8, - M_CONFIG_INFO_4_REORDER_TABLE_DEPTH_BMSK = 0xff, - M_CONFIG_INFO_4_REORDER_TABLE_DEPTH_SHFT = 0x0, -}; - -#define M_CONFIG_INFO_5_ADDR(b, n) \ - (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000070) -enum bimc_m_config_info_5 { - M_CONFIG_INFO_5_RMSK = 0x111, - M_CONFIG_INFO_5_MP2ARB_PIPELINE_EN_BMSK = 0x100, - M_CONFIG_INFO_5_MP2ARB_PIPELINE_EN_SHFT = 0x8, - M_CONFIG_INFO_5_MPBUF_PIPELINE_EN_BMSK = 0x10, - M_CONFIG_INFO_5_MPBUF_PIPELINE_EN_SHFT = 0x4, - M_CONFIG_INFO_5_M2MP_PIPELINE_EN_BMSK = 0x1, - M_CONFIG_INFO_5_M2MP_PIPELINE_EN_SHFT = 0x0, -}; - -#define M_INT_STATUS_ADDR(b, n) \ - (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000100) -enum bimc_m_int_status { - M_INT_STATUS_RMSK = 0x3, -}; - -#define M_INT_CLR_ADDR(b, n) \ - (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000108) -enum bimc_m_int_clr { - M_INT_CLR_RMSK = 0x3, -}; - -#define M_INT_EN_ADDR(b, n) \ - (M_REG_BASE(b) + (0x4000 * (n)) + 0x0000010c) -enum bimc_m_int_en { - M_INT_EN_RMSK = 0x3, -}; - #define M_CLK_CTRL_ADDR(b, n) \ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000200) enum bimc_m_clk_ctrl { @@ -145,18 +39,6 @@ enum bimc_m_clk_ctrl { M_CLK_CTRL_CORE_CLK_GATING_EN_SHFT = 0x0, }; -#define M_MODE_ADDR(b, n) \ - (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000210) -enum bimc_m_mode { - M_MODE_RMSK = 0xf0000011, - M_MODE_WR_GATHER_BEATS_BMSK = 0xf0000000, - M_MODE_WR_GATHER_BEATS_SHFT = 0x1c, - M_MODE_NARROW_WR_BMSK = 0x10, - M_MODE_NARROW_WR_SHFT = 0x4, - M_MODE_ORDERING_MODEL_BMSK = 0x1, - M_MODE_ORDERING_MODEL_SHFT = 0x0, -}; - #define M_PRIOLVL_OVERRIDE_ADDR(b, n) \ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000230) enum bimc_m_priolvl_override { @@ -337,689 +219,6 @@ enum bimc_m_bke_health_3 { M_BKE_HEALTH_3_CONFIG_PRIOLVL_SHFT = 0x0, }; -#define M_BUF_STATUS_ADDR(b, n) \ - (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000400) -enum bimc_m_buf_status { - M_BUF_STATUS_RMSK = 0xf03f030, - M_BUF_STATUS_RCH_DATA_WR_FULL_BMSK = 0x8000000, - M_BUF_STATUS_RCH_DATA_WR_FULL_SHFT = 0x1b, - M_BUF_STATUS_RCH_DATA_WR_EMPTY_BMSK = 0x4000000, - M_BUF_STATUS_RCH_DATA_WR_EMPTY_SHFT = 0x1a, - M_BUF_STATUS_RCH_CTRL_WR_FULL_BMSK = 0x2000000, - M_BUF_STATUS_RCH_CTRL_WR_FULL_SHFT = 0x19, - M_BUF_STATUS_RCH_CTRL_WR_EMPTY_BMSK = 0x1000000, - M_BUF_STATUS_RCH_CTRL_WR_EMPTY_SHFT = 0x18, - M_BUF_STATUS_BCH_WR_FULL_BMSK = 0x20000, - M_BUF_STATUS_BCH_WR_FULL_SHFT = 0x11, - M_BUF_STATUS_BCH_WR_EMPTY_BMSK = 0x10000, - M_BUF_STATUS_BCH_WR_EMPTY_SHFT = 0x10, - M_BUF_STATUS_WCH_DATA_RD_FULL_BMSK = 0x8000, - M_BUF_STATUS_WCH_DATA_RD_FULL_SHFT = 0xf, - M_BUF_STATUS_WCH_DATA_RD_EMPTY_BMSK = 0x4000, - M_BUF_STATUS_WCH_DATA_RD_EMPTY_SHFT = 0xe, - M_BUF_STATUS_WCH_CTRL_RD_FULL_BMSK = 0x2000, - M_BUF_STATUS_WCH_CTRL_RD_FULL_SHFT = 0xd, - M_BUF_STATUS_WCH_CTRL_RD_EMPTY_BMSK = 0x1000, - M_BUF_STATUS_WCH_CTRL_RD_EMPTY_SHFT = 0xc, - M_BUF_STATUS_ACH_RD_FULL_BMSK = 0x20, - M_BUF_STATUS_ACH_RD_FULL_SHFT = 0x5, - M_BUF_STATUS_ACH_RD_EMPTY_BMSK = 0x10, - M_BUF_STATUS_ACH_RD_EMPTY_SHFT = 0x4, -}; -/*BIMC Generic */ - -#define S_REG_BASE(b) ((b) + 0x00048000) - -#define S_COMPONENT_INFO_ADDR(b, n) \ - (S_REG_BASE(b) + (0x8000 * (n)) + 0x00000000) -enum bimc_s_component_info { - S_COMPONENT_INFO_RMSK = 0xffffff, - S_COMPONENT_INFO_INSTANCE_BMSK = 0xff0000, - S_COMPONENT_INFO_INSTANCE_SHFT = 0x10, - S_COMPONENT_INFO_SUB_TYPE_BMSK = 0xff00, - S_COMPONENT_INFO_SUB_TYPE_SHFT = 0x8, - S_COMPONENT_INFO_TYPE_BMSK = 0xff, - S_COMPONENT_INFO_TYPE_SHFT = 0x0, -}; - -#define S_HW_INFO_ADDR(b, n) \ - (S_REG_BASE(b) + (0x80000 * (n)) + 0x00000010) -enum bimc_s_hw_info { - S_HW_INFO_RMSK = 0xffffffff, - S_HW_INFO_MAJOR_BMSK = 0xff000000, - S_HW_INFO_MAJOR_SHFT = 0x18, - S_HW_INFO_BRANCH_BMSK = 0xff0000, - S_HW_INFO_BRANCH_SHFT = 0x10, - S_HW_INFO_MINOR_BMSK = 0xff00, - S_HW_INFO_MINOR_SHFT = 0x8, - S_HW_INFO_ECO_BMSK = 0xff, - S_HW_INFO_ECO_SHFT = 0x0, -}; - - -/* S_SCMO_GENERIC */ - -#define S_SCMO_REG_BASE(b) ((b) + 0x00048000) - -#define S_SCMO_CONFIG_INFO_0_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000020) -enum bimc_s_scmo_config_info_0 { - S_SCMO_CONFIG_INFO_0_RMSK = 0xffffffff, - S_SCMO_CONFIG_INFO_0_DATA_WIDTH_BMSK = 0xffff0000, - S_SCMO_CONFIG_INFO_0_DATA_WIDTH_SHFT = 0x10, - S_SCMO_CONFIG_INFO_0_TID_WIDTH_BMSK = 0xff00, - S_SCMO_CONFIG_INFO_0_TID_WIDTH_SHFT = 0x8, - S_SCMO_CONFIG_INFO_0_MID_WIDTH_BMSK = 0xff, - S_SCMO_CONFIG_INFO_0_MID_WIDTH_SHFT = 0x0, -}; - -#define S_SCMO_CONFIG_INFO_1_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000030) -enum bimc_s_scmo_config_info_1 { - S_SCMO_CONFIG_INFO_1_RMSK = 0xffffffff, - S_SCMO_CONFIG_INFO_1_MPORT_CONNECTIVITY_BMSK = 0xffffffff, - S_SCMO_CONFIG_INFO_1_MPORT_CONNECTIVITY_SHFT = 0x0, -}; - -#define S_SCMO_CONFIG_INFO_2_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000040) -enum bimc_s_scmo_config_info_2 { - S_SCMO_CONFIG_INFO_2_RMSK = 0xff00ff, - S_SCMO_CONFIG_INFO_2_NUM_GLOBAL_MONS_BMSK = 0xff0000, - S_SCMO_CONFIG_INFO_2_NUM_GLOBAL_MONS_SHFT = 0x10, - S_SCMO_CONFIG_INFO_2_VMID_WIDTH_BMSK = 0xff, - S_SCMO_CONFIG_INFO_2_VMID_WIDTH_SHFT = 0x0, -}; - -#define S_SCMO_CONFIG_INFO_3_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000050) -enum bimc_s_scmo_config_info_3 { - S_SCMO_CONFIG_INFO_3_RMSK = 0xffffffff, - S_SCMO_CONFIG_INFO_3_RCH0_CTRL_DEPTH_BMSK = 0xff000000, - S_SCMO_CONFIG_INFO_3_RCH0_CTRL_DEPTH_SHFT = 0x18, - S_SCMO_CONFIG_INFO_3_RCH0_DEPTH_BMSK = 0xff0000, - S_SCMO_CONFIG_INFO_3_RCH0_DEPTH_SHFT = 0x10, - S_SCMO_CONFIG_INFO_3_BCH_DEPTH_BMSK = 0xff00, - S_SCMO_CONFIG_INFO_3_BCH_DEPTH_SHFT = 0x8, - S_SCMO_CONFIG_INFO_3_WCH_DEPTH_BMSK = 0xff, - S_SCMO_CONFIG_INFO_3_WCH_DEPTH_SHFT = 0x0, -}; - -#define S_SCMO_CONFIG_INFO_4_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000060) -enum bimc_s_scmo_config_info_4 { - S_SCMO_CONFIG_INFO_4_RMSK = 0xffff, - S_SCMO_CONFIG_INFO_4_RCH1_CTRL_DEPTH_BMSK = 0xff00, - S_SCMO_CONFIG_INFO_4_RCH1_CTRL_DEPTH_SHFT = 0x8, - S_SCMO_CONFIG_INFO_4_RCH1_DEPTH_BMSK = 0xff, - S_SCMO_CONFIG_INFO_4_RCH1_DEPTH_SHFT = 0x0, -}; - -#define S_SCMO_CONFIG_INFO_5_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000070) -enum bimc_s_scmo_config_info_5 { - S_SCMO_CONFIG_INFO_5_RMSK = 0xffff, - S_SCMO_CONFIG_INFO_5_DPE_CQ_DEPTH_BMSK = 0xff00, - S_SCMO_CONFIG_INFO_5_DPE_CQ_DEPTH_SHFT = 0x8, - S_SCMO_CONFIG_INFO_5_DDR_BUS_WIDTH_BMSK = 0xff, - S_SCMO_CONFIG_INFO_5_DDR_BUS_WIDTH_SHFT = 0x0, -}; - -#define S_SCMO_CONFIG_INFO_6_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000080) -enum bimc_s_scmo_config_info_6 { - S_SCMO_CONFIG_INFO_6_RMSK = 0x1111, - S_SCMO_CONFIG_INFO_6_WBUFC_PIPE_BMSK = 0x1000, - S_SCMO_CONFIG_INFO_6_WBUFC_PIPE_SHFT = 0xc, - S_SCMO_CONFIG_INFO_6_RDOPT_PIPE_BMSK = 0x100, - S_SCMO_CONFIG_INFO_6_RDOPT_PIPE_SHFT = 0x8, - S_SCMO_CONFIG_INFO_6_ACHAN_INTF_PIPE_BMSK = 0x10, - S_SCMO_CONFIG_INFO_6_ACHAN_INTF_PIPE_SHFT = 0x4, - S_SCMO_CONFIG_INFO_6_ADDR_DECODE_HT_BMSK = 0x1, - S_SCMO_CONFIG_INFO_6_ADDR_DECODE_HT_SHFT = 0x0, -}; - -#define S_SCMO_INT_STATUS_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000100) -enum bimc_s_scmo_int_status { - S_SCMO_INT_STATUS_RMSK = 0x1, - S_SCMO_INT_STATUS_ERR_OCCURED_BMSK = 0x1, - S_SCMO_INT_STATUS_ERR_OCCURED_SHFT = 0x0, -}; - -#define S_SCMO_INT_CLR_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000108) -enum bimc_s_scmo_int_clr { - S_SCMO_INT_CLR_RMSK = 0x1, - S_SCMO_INT_CLR_IRQ_CLR_BMSK = 0x1, - S_SCMO_INT_CLR_IRQ_CLR_SHFT = 0x0, -}; - -#define S_SCMO_INT_EN_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x0000010c) -enum bimc_s_scmo_int_en { - S_SCMO_INT_EN_RMSK = 0x1, - S_SCMO_INT_EN_IRQ_EN_BMSK = 0x1, - S_SCMO_INT_EN_IRQ_EN_SHFT = 0x0, -}; - -#define S_SCMO_ESYN_ADDR_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000120) -enum bimc_s_scmo_esyn_addr { - S_SCMO_ESYN_ADDR_RMSK = 0xffffffff, - S_SCMO_ESYN_ADDR_ESYN_ADDR_ERR_ADDR_BMSK = 0xffffffff, - S_SCMO_ESYN_ADDR_ESYN_ADDR_ERR_ADDR_SHFT = 0x0, -}; - -#define S_SCMO_ESYN_APACKET_0_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000128) -enum bimc_s_scmo_esyn_apacket_0 { - S_SCMO_ESYN_APACKET_0_RMSK = 0xff1fffff, - S_SCMO_ESYN_APACKET_0_ERR_ATID_BMSK = 0xff000000, - S_SCMO_ESYN_APACKET_0_ERR_ATID_SHFT = 0x18, - S_SCMO_ESYN_APACKET_0_ERR_AVMID_BMSK = 0x1f0000, - S_SCMO_ESYN_APACKET_0_ERR_AVMID_SHFT = 0x10, - S_SCMO_ESYN_APACKET_0_ERR_AMID_BMSK = 0xffff, - S_SCMO_ESYN_APACKET_0_ERR_AMID_SHFT = 0x0, -}; - -#define S_SCMO_ESYN_APACKET_1_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x0000012c) -enum bimc_s_scmo_esyn_apacket_1 { - S_SCMO_ESYN_APACKET_1_RMSK = 0x10ff117, - S_SCMO_ESYN_APACKET_1_ERR_CODE_BMSK = 0x1000000, - S_SCMO_ESYN_APACKET_1_ERR_CODE_SHFT = 0x18, - S_SCMO_ESYN_APACKET_1_ERR_ALEN_BMSK = 0xf0000, - S_SCMO_ESYN_APACKET_1_ERR_ALEN_SHFT = 0x10, - S_SCMO_ESYN_APACKET_1_ERR_ASIZE_BMSK = 0xe000, - S_SCMO_ESYN_APACKET_1_ERR_ASIZE_SHFT = 0xd, - S_SCMO_ESYN_APACKET_1_ERR_ABURST_BMSK = 0x1000, - S_SCMO_ESYN_APACKET_1_ERR_ABURST_SHFT = 0xc, - S_SCMO_ESYN_APACKET_1_ERR_AEXCLUSIVE_BMSK = 0x100, - S_SCMO_ESYN_APACKET_1_ERR_AEXCLUSIVE_SHFT = 0x8, - S_SCMO_ESYN_APACKET_1_ERR_APRONTS_BMSK = 0x10, - S_SCMO_ESYN_APACKET_1_ERR_APRONTS_SHFT = 0x4, - S_SCMO_ESYN_APACKET_1_ERR_AOOORD_BMSK = 0x4, - S_SCMO_ESYN_APACKET_1_ERR_AOOORD_SHFT = 0x2, - S_SCMO_ESYN_APACKET_1_ERR_AOOOWR_BMSK = 0x2, - S_SCMO_ESYN_APACKET_1_ERR_AOOOWR_SHFT = 0x1, - S_SCMO_ESYN_APACKET_1_ERR_AWRITE_BMSK = 0x1, - S_SCMO_ESYN_APACKET_1_ERR_AWRITE_SHFT = 0x0, -}; - -#define S_SCMO_CLK_CTRL_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000200) -enum bimc_s_scmo_clk_ctrl { - S_SCMO_CLK_CTRL_RMSK = 0xffff1111, - S_SCMO_CLK_CTRL_PEN_CMD_CG_EN_BMSK = 0x10000, - S_SCMO_CLK_CTRL_PEN_CMD_CG_EN_SHFT = 0x10, - S_SCMO_CLK_CTRL_RCH_CG_EN_BMSK = 0x1000, - S_SCMO_CLK_CTRL_RCH_CG_EN_SHFT = 0xc, - S_SCMO_CLK_CTRL_FLUSH_CG_EN_BMSK = 0x100, - S_SCMO_CLK_CTRL_FLUSH_CG_EN_SHFT = 0x8, - S_SCMO_CLK_CTRL_WCH_CG_EN_BMSK = 0x10, - S_SCMO_CLK_CTRL_WCH_CG_EN_SHFT = 0x4, - S_SCMO_CLK_CTRL_ACH_CG_EN_BMSK = 0x1, - S_SCMO_CLK_CTRL_ACH_CG_EN_SHFT = 0x0, -}; - -#define S_SCMO_SLV_INTERLEAVE_CFG_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000400) -enum bimc_s_scmo_slv_interleave_cfg { - S_SCMO_SLV_INTERLEAVE_CFG_RMSK = 0xff, - S_SCMO_SLV_INTERLEAVE_CFG_INTERLEAVE_CS1_BMSK = 0x10, - S_SCMO_SLV_INTERLEAVE_CFG_INTERLEAVE_CS1_SHFT = 0x4, - S_SCMO_SLV_INTERLEAVE_CFG_INTERLEAVE_CS0_BMSK = 0x1, - S_SCMO_SLV_INTERLEAVE_CFG_INTERLEAVE_CS0_SHFT = 0x0, -}; - -#define S_SCMO_ADDR_BASE_CSn_ADDR(b, n, o) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000410 + 0x4 * (o)) -enum bimc_s_scmo_addr_base_csn { - S_SCMO_ADDR_BASE_CSn_RMSK = 0xffff, - S_SCMO_ADDR_BASE_CSn_MAXn = 1, - S_SCMO_ADDR_BASE_CSn_ADDR_BASE_BMSK = 0xfc, - S_SCMO_ADDR_BASE_CSn_ADDR_BASE_SHFT = 0x2, -}; - -#define S_SCMO_ADDR_MAP_CSn_ADDR(b, n, o) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000420 + 0x4 * (o)) -enum bimc_s_scmo_addr_map_csn { - S_SCMO_ADDR_MAP_CSn_RMSK = 0xffff, - S_SCMO_ADDR_MAP_CSn_MAXn = 1, - S_SCMO_ADDR_MAP_CSn_RANK_EN_BMSK = 0x8000, - S_SCMO_ADDR_MAP_CSn_RANK_EN_SHFT = 0xf, - S_SCMO_ADDR_MAP_CSn_ADDR_MODE_BMSK = 0x1000, - S_SCMO_ADDR_MAP_CSn_ADDR_MODE_SHFT = 0xc, - S_SCMO_ADDR_MAP_CSn_BANK_SIZE_BMSK = 0x100, - S_SCMO_ADDR_MAP_CSn_BANK_SIZE_SHFT = 0x8, - S_SCMO_ADDR_MAP_CSn_ROW_SIZE_BMSK = 0x30, - S_SCMO_ADDR_MAP_CSn_ROW_SIZE_SHFT = 0x4, - S_SCMO_ADDR_MAP_CSn_COL_SIZE_BMSK = 0x3, - S_SCMO_ADDR_MAP_CSn_COL_SIZE_SHFT = 0x0, -}; - -#define S_SCMO_ADDR_MASK_CSn_ADDR(b, n, o) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000430 + 0x4 * (0)) -enum bimc_s_scmo_addr_mask_csn { - S_SCMO_ADDR_MASK_CSn_RMSK = 0xffff, - S_SCMO_ADDR_MASK_CSn_MAXn = 1, - S_SCMO_ADDR_MASK_CSn_ADDR_MASK_BMSK = 0xfc, - S_SCMO_ADDR_MASK_CSn_ADDR_MASK_SHFT = 0x2, -}; - -#define S_SCMO_SLV_STATUS_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000450) -enum bimc_s_scmo_slv_status { - S_SCMO_SLV_STATUS_RMSK = 0xff3, - S_SCMO_SLV_STATUS_GLOBAL_MONS_IN_USE_BMSK = 0xff0, - S_SCMO_SLV_STATUS_GLOBAL_MONS_IN_USE_SHFT = 0x4, - S_SCMO_SLV_STATUS_SLAVE_IDLE_BMSK = 0x3, - S_SCMO_SLV_STATUS_SLAVE_IDLE_SHFT = 0x0, -}; - -#define S_SCMO_CMD_BUF_CFG_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000500) -enum bimc_s_scmo_cmd_buf_cfg { - S_SCMO_CMD_BUF_CFG_RMSK = 0xf1f, - S_SCMO_CMD_BUF_CFG_CMD_ORDERING_BMSK = 0x300, - S_SCMO_CMD_BUF_CFG_CMD_ORDERING_SHFT = 0x8, - S_SCMO_CMD_BUF_CFG_HP_CMD_AREQPRIO_MAP_BMSK = 0x10, - S_SCMO_CMD_BUF_CFG_HP_CMD_AREQPRIO_MAP_SHFT = 0x4, - S_SCMO_CMD_BUF_CFG_HP_CMD_Q_DEPTH_BMSK = 0x7, - S_SCMO_CMD_BUF_CFG_HP_CMD_Q_DEPTH_SHFT = 0x0, -}; - -#define S_SCM_CMD_BUF_STATUS_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000520) -enum bimc_s_scm_cmd_buf_status { - S_SCMO_CMD_BUF_STATUS_RMSK = 0x77, - S_SCMO_CMD_BUF_STATUS_HP_CMD_BUF_ENTRIES_IN_USE_BMSK = 0x70, - S_SCMO_CMD_BUF_STATUS_HP_CMD_BUF_ENTRIES_IN_USE_SHFT = 0x4, - S_SCMO_CMD_BUF_STATUS_LP_CMD_BUF_ENTRIES_IN_USE_BMSK = 0x7, - S_SCMO_CMD_BUF_STATUS_LP_CMD_BUF_ENTRIES_IN_USE_SHFT = 0x0, -}; - -#define S_SCMO_RCH_SEL_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000540) -enum bimc_s_scmo_rch_sel { - S_SCMO_RCH_SEL_RMSK = 0xffffffff, - S_SCMO_CMD_BUF_STATUS_RCH_PORTS_BMSK = 0xffffffff, - S_SCMO_CMD_BUF_STATUS_RCH_PORTS_SHFT = 0x0, -}; - -#define S_SCMO_RCH_BKPR_CFG_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000544) -enum bimc_s_scmo_rch_bkpr_cfg { - S_SCMO_RCH_BKPR_CFG_RMSK = 0xffffffff, - S_SCMO_RCH_BKPR_CFG_RCH1_FIFO_BKPR_HI_TH_BMSK = 0x3f000000, - S_SCMO_RCH_BKPR_CFG_RCH1_FIFO_BKPR_HI_TH_SHFT = 0x18, - S_SCMO_RCH_BKPR_CFG_RCH1_FIFO_BKPR_LO_TH_BMSK = 0x3f0000, - S_SCMO_RCH_BKPR_CFG_RCH1_FIFO_BKPR_LO_TH_SHFT = 0x10, - S_SCMO_RCH_BKPR_CFG_RCH0_FIFO_BKPR_HI_TH_BMSK = 0x3f00, - S_SCMO_RCH_BKPR_CFG_RCH0_FIFO_BKPR_HI_TH_SHFT = 0x8, - S_SCMO_RCH_BKPR_CFG_RCH0_FIFO_BKPR_LO_TH_BMSK = 0x3f, - S_SCMO_RCH_BKPR_CFG_RCH0_FIFO_BKPR_LO_TH_SHFT = 0x0, -}; - -#define S_SCMO_RCH_STATUS_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000560) -enum bimc_s_scmo_rch_status { - S_SCMO_RCH_STATUS_RMSK = 0x33333, - S_SCMO_RCH_STATUS_PRQ_FIFO_FULL_BMSK = 0x20000, - S_SCMO_RCH_STATUS_PRQ_FIFO_FULL_SHFT = 0x11, - S_SCMO_RCH_STATUS_PRQ_FIFO_EMPTY_BMSK = 0x10000, - S_SCMO_RCH_STATUS_PRQ_FIFO_EMPTY_SHFT = 0x10, - S_SCMO_RCH_STATUS_RCH1_QUAL_FIFO_FULL_BMSK = 0x2000, - S_SCMO_RCH_STATUS_RCH1_QUAL_FIFO_FULL_SHFT = 0xd, - S_SCMO_RCH_STATUS_RCH1_QUAL_FIFO_EMPTY_BMSK = 0x1000, - S_SCMO_RCH_STATUS_RCH1_QUAL_FIFO_EMPTY_SHFT = 0xc, - S_SCMO_RCH_STATUS_RCH1_DATA_FIFO_FULL_BMSK = 0x200, - S_SCMO_RCH_STATUS_RCH1_DATA_FIFO_FULL_SHFT = 0x9, - S_SCMO_RCH_STATUS_RCH1_DATA_FIFO_EMPTY_BMSK = 0x100, - S_SCMO_RCH_STATUS_RCH1_DATA_FIFO_EMPTY_SHFT = 0x8, - S_SCMO_RCH_STATUS_RCH0_QUAL_FIFO_FULL_BMSK = 0x20, - S_SCMO_RCH_STATUS_RCH0_QUAL_FIFO_FULL_SHFT = 0x5, - S_SCMO_RCH_STATUS_RCH0_QUAL_FIFO_EMPTY_BMSK = 0x10, - S_SCMO_RCH_STATUS_RCH0_QUAL_FIFO_EMPTY_SHFT = 0x4, - S_SCMO_RCH_STATUS_RCH0_DATA_FIFO_FULL_BMSK = 0x2, - S_SCMO_RCH_STATUS_RCH0_DATA_FIFO_FULL_SHFT = 0x1, - S_SCMO_RCH_STATUS_RCH0_DATA_FIFO_EMPTY_BMSK = 0x1, - S_SCMO_RCH_STATUS_RCH0_DATA_FIFO_EMPTY_SHFT = 0x0, -}; - -#define S_SCMO_WCH_BUF_CFG_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000580) -enum bimc_s_scmo_wch_buf_cfg { - S_SCMO_WCH_BUF_CFG_RMSK = 0xff, - S_SCMO_WCH_BUF_CFG_WRITE_BLOCK_READ_BMSK = 0x10, - S_SCMO_WCH_BUF_CFG_WRITE_BLOCK_READ_SHFT = 0x4, - S_SCMO_WCH_BUF_CFG_COALESCE_EN_BMSK = 0x1, - S_SCMO_WCH_BUF_CFG_COALESCE_EN_SHFT = 0x0, -}; - -#define S_SCMO_WCH_STATUS_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x000005a0) -enum bimc_s_scmo_wch_status { - S_SCMO_WCH_STATUS_RMSK = 0x333, - S_SCMO_WCH_STATUS_BRESP_FIFO_FULL_BMSK = 0x200, - S_SCMO_WCH_STATUS_BRESP_FIFO_FULL_SHFT = 0x9, - S_SCMO_WCH_STATUS_BRESP_FIFO_EMPTY_BMSK = 0x100, - S_SCMO_WCH_STATUS_BRESP_FIFO_EMPTY_SHFT = 0x8, - S_SCMO_WCH_STATUS_WDATA_FIFO_FULL_BMSK = 0x20, - S_SCMO_WCH_STATUS_WDATA_FIFO_FULL_SHFT = 0x5, - S_SCMO_WCH_STATUS_WDATA_FIFO_EMPTY_BMSK = 0x10, - S_SCMO_WCH_STATUS_WDATA_FIFO_EMPTY_SHFT = 0x4, - S_SCMO_WCH_STATUS_WBUF_FULL_BMSK = 0x2, - S_SCMO_WCH_STATUS_WBUF_FULL_SHFT = 0x1, - S_SCMO_WCH_STATUS_WBUF_EMPTY_BMSK = 0x1, - S_SCMO_WCH_STATUS_WBUF_EMPTY_SHFT = 0x0, -}; - -#define S_SCMO_FLUSH_CFG_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x000005c0) -enum bimc_s_scmo_flush_cfg { - S_SCMO_FLUSH_CFG_RMSK = 0xffffffff, - S_SCMO_FLUSH_CFG_FLUSH_IN_ORDER_BMSK = 0x10000000, - S_SCMO_FLUSH_CFG_FLUSH_IN_ORDER_SHFT = 0x1c, - S_SCMO_FLUSH_CFG_FLUSH_IDLE_DELAY_BMSK = 0x3ff0000, - S_SCMO_FLUSH_CFG_FLUSH_IDLE_DELAY_SHFT = 0x10, - S_SCMO_FLUSH_CFG_FLUSH_UPPER_LIMIT_BMSK = 0xf00, - S_SCMO_FLUSH_CFG_FLUSH_UPPER_LIMIT_SHFT = 0x8, - S_SCMO_FLUSH_CFG_FLUSH_LOWER_LIMIT_BMSK = 0xf, - S_SCMO_FLUSH_CFG_FLUSH_LOWER_LIMIT_SHFT = 0x0, -}; - -#define S_SCMO_FLUSH_CMD_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x000005c4) -enum bimc_s_scmo_flush_cmd { - S_SCMO_FLUSH_CMD_RMSK = 0xf, - S_SCMO_FLUSH_CMD_FLUSH_ALL_BUF_BMSK = 0x3, - S_SCMO_FLUSH_CMD_FLUSH_ALL_BUF_SHFT = 0x0, -}; - -#define S_SCMO_CMD_OPT_CFG0_ADDR(b, n) \ - (S_SCM0_REG_BASE(b) + (0x8000 * (n)) + 0x00000700) -enum bimc_s_scmo_cmd_opt_cfg0 { - S_SCMO_CMD_OPT_CFG0_RMSK = 0xffffff, - S_SCMO_CMD_OPT_CFG0_IGNORE_BANK_UNAVL_BMSK = 0x100000, - S_SCMO_CMD_OPT_CFG0_IGNORE_BANK_UNAVL_SHFT = 0x14, - S_SCMO_CMD_OPT_CFG0_MASK_CMDOUT_PRI_BMSK = 0x10000, - S_SCMO_CMD_OPT_CFG0_MASK_CMDOUT_PRI_SHFT = 0x10, - S_SCMO_CMD_OPT_CFG0_DPE_CMD_REORDERING_BMSK = 0x1000, - S_SCMO_CMD_OPT_CFG0_DPE_CMD_REORDERING_SHFT = 0xc, - S_SCMO_CMD_OPT_CFG0_WR_OPT_EN_BMSK = 0x100, - S_SCMO_CMD_OPT_CFG0_WR_OPT_EN_SHFT = 0x8, - S_SCMO_CMD_OPT_CFG0_RD_OPT_EN_BMSK = 0x10, - S_SCMO_CMD_OPT_CFG0_RD_OPT_EN_SHFT = 0x4, - S_SCMO_CMD_OPT_CFG0_PAGE_MGMT_POLICY_BMSK = 0x1, - S_SCMO_CMD_OPT_CFG0_PAGE_MGMT_POLICY_SHFT = 0x0, -}; - -#define S_SCMO_CMD_OPT_CFG1_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000704) -enum bimc_s_scmo_cmd_opt_cfg1 { - S_SCMO_CMD_OPT_CFG1_RMSK = 0xffffffff, - S_SCMO_CMD_OPT_CFG1_HSTP_CMD_TIMEOUT_BMSK = 0x1f000000, - S_SCMO_CMD_OPT_CFG1_HSTP_CMD_TIMEOUT_SHFT = 0x18, - S_SCMO_CMD_OPT_CFG1_HP_CMD_TIMEOUT_BMSK = 0x1f0000, - S_SCMO_CMD_OPT_CFG1_HP_CMD_TIMEOUT_SHFT = 0x10, - S_SCMO_CMD_OPT_CFG1_MP_CMD_TIMEOUT_BMSK = 0x1f00, - S_SCMO_CMD_OPT_CFG1_MP_CMD_TIMEOUT_SHFT = 0x8, - S_SCMO_CMD_OPT_CFG1_LP_CMD_TIMEOUT_BMSK = 0x1f, - S_SCMO_CMD_OPT_CFG1_LP_CMD_TIMEOUT_SHFT = 0x0, -}; - -#define S_SCMO_CMD_OPT_CFG2_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000708) -enum bimc_s_scmo_cmd_opt_cfg2 { - S_SCMO_CMD_OPT_CFG2_RMSK = 0xff, - S_SCMO_CMD_OPT_CFG2_RWOPT_CMD_TIMEOUT_BMSK = 0xf, - S_SCMO_CMD_OPT_CFG2_RWOPT_CMD_TIMEOUT_SHFT = 0x0, -}; - -#define S_SCMO_CMD_OPT_CFG3_ADDR(b, n) \ - (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x0000070c) -enum bimc_s_scmo_cmd_opt_cfg3 { - S_SCMO_CMD_OPT_CFG3_RMSK = 0xff, - S_SCMO_CMD_OPT_CFG3_FLUSH_CMD_TIMEOUT_BMSK = 0xf, - S_SCMO_CMD_OPT_CFG3_FLUSH_CMD_TIMEOUT_SHFT = 0x0, -}; - -/* S_SWAY_GENERIC */ -#define S_SWAY_REG_BASE(b) ((b) + 0x00048000) - -#define S_SWAY_CONFIG_INFO_0_ADDR(b, n) \ - (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000020) -enum bimc_s_sway_config_info_0 { - S_SWAY_CONFIG_INFO_0_RMSK = 0xff0000ff, - S_SWAY_CONFIG_INFO_0_SYNC_MODE_BMSK = 0xff000000, - S_SWAY_CONFIG_INFO_0_SYNC_MODE_SHFT = 0x18, - S_SWAY_CONFIG_INFO_0_FUNC_BMSK = 0xff, - S_SWAY_CONFIG_INFO_0_FUNC_SHFT = 0x0, -}; - -#define S_SWAY_CONFIG_INFO_1_ADDR(b, n) \ - (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000030) -enum bimc_s_sway_config_info_1 { - S_SWAY_CONFIG_INFO_1_RMSK = 0xffffffff, - S_SWAY_CONFIG_INFO_1_MPORT_CONNECTIVITY_BMSK = 0xffffffff, - S_SWAY_CONFIG_INFO_1_MPORT_CONNECTIVITY_SHFT = 0x0, -}; - -#define S_SWAY_CONFIG_INFO_2_ADDR(b, n) \ - (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000040) -enum bimc_s_sway_config_info_2 { - S_SWAY_CONFIG_INFO_2_RMSK = 0xffff0000, - S_SWAY_CONFIG_INFO_2_MPORT_CONNECTIVITY_BMSK = 0xffff0000, - S_SWAY_CONFIG_INFO_2_MPORT_CONNECTIVITY_SHFT = 0x10, -}; - -#define S_SWAY_CONFIG_INFO_3_ADDR(b, n) \ - (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000050) -enum bimc_s_sway_config_info_3 { - S_SWAY_CONFIG_INFO_3_RMSK = 0xffffffff, - S_SWAY_CONFIG_INFO_3_RCH0_DEPTH_BMSK = 0xff000000, - S_SWAY_CONFIG_INFO_3_RCH0_DEPTH_SHFT = 0x18, - S_SWAY_CONFIG_INFO_3_BCH_DEPTH_BMSK = 0xff0000, - S_SWAY_CONFIG_INFO_3_BCH_DEPTH_SHFT = 0x10, - S_SWAY_CONFIG_INFO_3_WCH_DEPTH_BMSK = 0xff, - S_SWAY_CONFIG_INFO_3_WCH_DEPTH_SHFT = 0x0, -}; - -#define S_SWAY_CONFIG_INFO_4_ADDR(b, n) \ - (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000060) -enum bimc_s_sway_config_info_4 { - S_SWAY_CONFIG_INFO_4_RMSK = 0x800000ff, - S_SWAY_CONFIG_INFO_4_DUAL_RCH_EN_BMSK = 0x80000000, - S_SWAY_CONFIG_INFO_4_DUAL_RCH_EN_SHFT = 0x1f, - S_SWAY_CONFIG_INFO_4_RCH1_DEPTH_BMSK = 0xff, - S_SWAY_CONFIG_INFO_4_RCH1_DEPTH_SHFT = 0x0, -}; - -#define S_SWAY_CONFIG_INFO_5_ADDR(b, n) \ - (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000070) -enum bimc_s_sway_config_info_5 { - S_SWAY_CONFIG_INFO_5_RMSK = 0x800000ff, - S_SWAY_CONFIG_INFO_5_QCH_EN_BMSK = 0x80000000, - S_SWAY_CONFIG_INFO_5_QCH_EN_SHFT = 0x1f, - S_SWAY_CONFIG_INFO_5_QCH_DEPTH_BMSK = 0xff, - S_SWAY_CONFIG_INFO_5_QCH_DEPTH_SHFT = 0x0, -}; - -#define S_SWAY_CONFIG_INFO_6_ADDR(b, n) \ - (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000080) -enum bimc_s_sway_config_info_6 { - S_SWAY_CONFIG_INFO_6_RMSK = 0x1, - S_SWAY_CONFIG_INFO_6_S2SW_PIPELINE_EN_BMSK = 0x1, - S_SWAY_CONFIG_INFO_6_S2SW_PIPELINE_EN_SHFT = 0x0, -}; - -#define S_SWAY_INT_STATUS_ADDR(b, n) \ - (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000100) -enum bimc_s_sway_int_status { - S_SWAY_INT_STATUS_RMSK = 0x3, - S_SWAY_INT_STATUS_RFU_BMSK = 0x3, - S_SWAY_INT_STATUS_RFU_SHFT = 0x0, -}; - -#define S_SWAY_INT_CLR_ADDR(b, n) \ - (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000108) -enum bimc_s_sway_int_clr { - S_SWAY_INT_CLR_RMSK = 0x3, - S_SWAY_INT_CLR_RFU_BMSK = 0x3, - S_SWAY_INT_CLR_RFU_SHFT = 0x0, -}; - - -#define S_SWAY_INT_EN_ADDR(b, n) \ - (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x0000010c) -enum bimc_s_sway_int_en { - S_SWAY_INT_EN_RMSK = 0x3, - S_SWAY_INT_EN_RFU_BMSK = 0x3, - S_SWAY_INT_EN_RFU_SHFT = 0x0, -}; - -#define S_SWAY_CLK_CTRL_ADDR(b, n) \ - (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000200) -enum bimc_s_sway_clk_ctrl { - S_SWAY_CLK_CTRL_RMSK = 0x3, - S_SWAY_CLK_CTRL_SLAVE_CLK_GATING_EN_BMSK = 0x2, - S_SWAY_CLK_CTRL_SLAVE_CLK_GATING_EN_SHFT = 0x1, - S_SWAY_CLK_CTRL_CORE_CLK_GATING_EN_BMSK = 0x1, - S_SWAY_CLK_CTRL_CORE_CLK_GATING_EN_SHFT = 0x0, -}; - -#define S_SWAY_RCH_SEL_ADDR(b, n) \ - (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000210) -enum bimc_s_sway_rch_sel { - S_SWAY_RCH_SEL_RMSK = 0x7f, - S_SWAY_RCH_SEL_UNUSED_BMSK = 0x7f, - S_SWAY_RCH_SEL_UNUSED_SHFT = 0x0, -}; - - -#define S_SWAY_MAX_OUTSTANDING_REQS_ADDR(b, n) \ - (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000220) -enum bimc_s_sway_max_outstanding_reqs { - S_SWAY_MAX_OUTSTANDING_REQS_RMSK = 0xffff, - S_SWAY_MAX_OUTSTANDING_REQS_WRITE_BMSK = 0xff00, - S_SWAY_MAX_OUTSTANDING_REQS_WRITE_SHFT = 0x8, - S_SWAY_MAX_OUTSTANDING_REQS_READ_BMSK = 0xff, - S_SWAY_MAX_OUTSTANDING_REQS_READ_SHFT = 0x0, -}; - - -#define S_SWAY_BUF_STATUS_0_ADDR(b, n) \ - (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000400) -enum bimc_s_sway_buf_status_0 { - S_SWAY_BUF_STATUS_0_RMSK = 0xf0300f03, - S_SWAY_BUF_STATUS_0_RCH0_DATA_RD_FULL_BMSK = 0x80000000, - S_SWAY_BUF_STATUS_0_RCH0_DATA_RD_FULL_SHFT = 0x1f, - S_SWAY_BUF_STATUS_0_RCH0_DATA_RD_EMPTY_BMSK = 0x40000000, - S_SWAY_BUF_STATUS_0_RCH0_DATA_RD_EMPTY_SHFT = 0x1e, - S_SWAY_BUF_STATUS_0_RCH0_CTRL_RD_FULL_BMSK = 0x20000000, - S_SWAY_BUF_STATUS_0_RCH0_CTRL_RD_FULL_SHFT = 0x1d, - S_SWAY_BUF_STATUS_0_RCH0_CTRL_RD_EMPTY_BMSK = 0x10000000, - S_SWAY_BUF_STATUS_0_RCH0_CTRL_RD_EMPTY_SHFT = 0x1c, - S_SWAY_BUF_STATUS_0_BCH_RD_FULL_BMSK = 0x200000, - S_SWAY_BUF_STATUS_0_BCH_RD_FULL_SHFT = 0x15, - S_SWAY_BUF_STATUS_0_BCH_RD_EMPTY_BMSK = 0x100000, - S_SWAY_BUF_STATUS_0_BCH_RD_EMPTY_SHFT = 0x14, - S_SWAY_BUF_STATUS_0_WCH_DATA_WR_FULL_BMSK = 0x800, - S_SWAY_BUF_STATUS_0_WCH_DATA_WR_FULL_SHFT = 0xb, - S_SWAY_BUF_STATUS_0_WCH_DATA_WR_EMPTY_BMSK = 0x400, - S_SWAY_BUF_STATUS_0_WCH_DATA_WR_EMPTY_SHFT = 0xa, - S_SWAY_BUF_STATUS_0_WCH_CTRL_WR_FULL_BMSK = 0x200, - S_SWAY_BUF_STATUS_0_WCH_CTRL_WR_FULL_SHFT = 0x9, - S_SWAY_BUF_STATUS_0_WCH_CTRL_WR_EMPTY_BMSK = 0x100, - S_SWAY_BUF_STATUS_0_WCH_CTRL_WR_EMPTY_SHFT = 0x8, - S_SWAY_BUF_STATUS_0_ACH_WR_FULL_BMSK = 0x2, - S_SWAY_BUF_STATUS_0_ACH_WR_FULL_SHFT = 0x1, - S_SWAY_BUF_STATUS_0_ACH_WR_EMPTY_BMSK = 0x1, - S_SWAY_BUF_STATUS_0_ACH_WR_EMPTY_SHFT = 0x0, -}; - -#define S_SWAY_BUF_STATUS_1_ADDR(b, n) \ - (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000410) -enum bimc_s_sway_buf_status_1 { - S_SWAY_BUF_STATUS_1_RMSK = 0xf0, - S_SWAY_BUF_STATUS_1_RCH1_DATA_RD_FULL_BMSK = 0x80, - S_SWAY_BUF_STATUS_1_RCH1_DATA_RD_FULL_SHFT = 0x7, - S_SWAY_BUF_STATUS_1_RCH1_DATA_RD_EMPTY_BMSK = 0x40, - S_SWAY_BUF_STATUS_1_RCH1_DATA_RD_EMPTY_SHFT = 0x6, - S_SWAY_BUF_STATUS_1_RCH1_CTRL_RD_FULL_BMSK = 0x20, - S_SWAY_BUF_STATUS_1_RCH1_CTRL_RD_FULL_SHFT = 0x5, - S_SWAY_BUF_STATUS_1_RCH1_CTRL_RD_EMPTY_BMSK = 0x10, - S_SWAY_BUF_STATUS_1_RCH1_CTRL_RD_EMPTY_SHFT = 0x4, -}; - -#define S_SWAY_BUF_STATUS_2_ADDR(b, n) \ - (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000420) -enum bimc_s_sway_buf_status_2 { - S_SWAY_BUF_STATUS_2_RMSK = 0x30, - S_SWAY_BUF_STATUS_2_QCH_RD_FULL_BMSK = 0x20, - S_SWAY_BUF_STATUS_2_QCH_RD_FULL_SHFT = 0x5, - S_SWAY_BUF_STATUS_2_QCH_RD_EMPTY_BMSK = 0x10, - S_SWAY_BUF_STATUS_2_QCH_RD_EMPTY_SHFT = 0x4, -}; - -/* S_ARB_GENERIC */ - -#define S_ARB_REG_BASE(b) ((b) + 0x00049000) - -#define S_ARB_COMPONENT_INFO_ADDR(b, n) \ - (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000000) -enum bimc_s_arb_component_info { - S_ARB_COMPONENT_INFO_RMSK = 0xffffff, - S_ARB_COMPONENT_INFO_INSTANCE_BMSK = 0xff0000, - S_ARB_COMPONENT_INFO_INSTANCE_SHFT = 0x10, - S_ARB_COMPONENT_INFO_SUB_TYPE_BMSK = 0xff00, - S_ARB_COMPONENT_INFO_SUB_TYPE_SHFT = 0x8, - S_ARB_COMPONENT_INFO_TYPE_BMSK = 0xff, - S_ARB_COMPONENT_INFO_TYPE_SHFT = 0x0, -}; - -#define S_ARB_CONFIG_INFO_0_ADDR(b, n) \ - (S_ARB_REG_BASE(b) + (0x8000 * (n)) + 0x00000020) -enum bimc_s_arb_config_info_0 { - S_ARB_CONFIG_INFO_0_RMSK = 0x800000ff, - S_ARB_CONFIG_INFO_0_ARB2SW_PIPELINE_EN_BMSK = 0x80000000, - S_ARB_CONFIG_INFO_0_ARB2SW_PIPELINE_EN_SHFT = 0x1f, - S_ARB_CONFIG_INFO_0_FUNC_BMSK = 0xff, - S_ARB_CONFIG_INFO_0_FUNC_SHFT = 0x0, -}; - -#define S_ARB_CONFIG_INFO_1_ADDR(b, n) \ - (S_ARB_REG_BASE(b) + (0x8000 * (n)) + 0x00000030) -enum bimc_s_arb_config_info_1 { - S_ARB_CONFIG_INFO_1_RMSK = 0xffffffff, - S_ARB_CONFIG_INFO_1_MPORT_CONNECTIVITY_BMSK = 0xffffffff, - S_ARB_CONFIG_INFO_1_MPORT_CONNECTIVITY_SHFT = 0x0, -}; - -#define S_ARB_CLK_CTRL_ADDR(b) \ - (S_ARB_REG_BASE(b) + (0x8000 * (n)) + 0x00000200) -enum bimc_s_arb_clk_ctrl { - S_ARB_CLK_CTRL_RMSK = 0x1, - S_ARB_CLK_CTRL_SLAVE_CLK_GATING_EN_BMSK = 0x2, - S_ARB_CLK_CTRL_SLAVE_CLK_GATING_EN_SHFT = 0x1, - S_ARB_CLK_CTRL_CORE_CLK_GATING_EN_BMSK = 0x1, - S_ARB_CLK_CTRL_CORE_CLK_GATING_EN_SHFT = 0x0, - S_ARB_CLK_CTRL_CLK_GATING_EN_BMSK = 0x1, - S_ARB_CLK_CTRL_CLK_GATING_EN_SHFT = 0x0, -}; - -#define S_ARB_MODE_ADDR(b, n) \ - (S_ARB_REG_BASE(b) + (0x8000 * (n)) + 0x00000210) -enum bimc_s_arb_mode { - S_ARB_MODE_RMSK = 0xf0000001, - S_ARB_MODE_WR_GRANTS_AHEAD_BMSK = 0xf0000000, - S_ARB_MODE_WR_GRANTS_AHEAD_SHFT = 0x1c, - S_ARB_MODE_PRIO_RR_EN_BMSK = 0x1, - S_ARB_MODE_PRIO_RR_EN_SHFT = 0x0, -}; - #define BKE_HEALTH_MASK \ (M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_BMSK |\ M_BKE_HEALTH_0_CONFIG_AREQPRIO_BMSK |\ @@ -1071,27 +270,6 @@ void msm_bus_bimc_set_mas_clk_gate(struct msm_bus_bimc_info *binfo, wmb(); } -void msm_bus_bimc_arb_en(struct msm_bus_bimc_info *binfo, - uint32_t slv_index, bool en) -{ - uint32_t reg_val, reg_mask_val, enable, val; - - reg_mask_val = (readl_relaxed(S_ARB_CONFIG_INFO_0_ADDR(binfo-> - base, slv_index)) & S_ARB_CONFIG_INFO_0_FUNC_BMSK) - >> S_ARB_CONFIG_INFO_0_FUNC_SHFT; - enable = ENABLE(en); - val = enable << S_ARB_MODE_PRIO_RR_EN_SHFT; - if (reg_mask_val == BIMC_ARB_MODE_PRIORITY_RR) { - reg_val = readl_relaxed(S_ARB_CONFIG_INFO_0_ADDR(binfo-> - base, slv_index)) & S_ARB_MODE_RMSK; - writel_relaxed(((reg_val & (~(S_ARB_MODE_PRIO_RR_EN_BMSK))) | - (val & S_ARB_MODE_PRIO_RR_EN_BMSK)), - S_ARB_MODE_ADDR(binfo->base, slv_index)); - /* Ensure arbitration mode is set before returning */ - wmb(); - } -} - static void set_qos_mode(void __iomem *baddr, uint32_t index, uint32_t val0, uint32_t val1, uint32_t val2) { @@ -1903,64 +1081,6 @@ static int msm_bus_bimc_port_unhalt(uint32_t haltid, uint8_t mport) return 0; } -static int msm_bus_bimc_limit_mport(struct msm_bus_node_device_type *info, - void __iomem *qos_base, uint32_t qos_off, - uint32_t qos_delta, uint32_t qos_freq, - int enable_lim, u64 lim_bw) -{ - int mode; - int i; - - if (ZERO_OR_NULL_PTR(info->node_info->qport)) { - MSM_BUS_DBG("No QoS Ports to limit\n"); - return 0; - } - - if ((enable_lim == THROTTLE_ON) && lim_bw) { - mode = BIMC_QOS_MODE_LIMITER; - - if (!info->node_info->lim_bw) { - struct msm_bus_bimc_qos_mode qmode; - qmode.rl.qhealth[0].limit_commands = 1; - qmode.rl.qhealth[1].limit_commands = 0; - qmode.rl.qhealth[2].limit_commands = 0; - qmode.rl.qhealth[3].limit_commands = 0; - - for (i = 0; i < info->node_info->num_qports; i++) { - /* If not in bypass mode, update priority */ - if (mode != BIMC_QOS_MODE_BYPASS) - msm_bus_bimc_set_qos_prio(qos_base, - info->node_info->qport[i], mode, - &qmode); - } - } - - for (i = 0; i < info->node_info->num_qports; i++) { - struct msm_bus_bimc_qos_bw qbw; - /* If not in fixed mode, update bandwidth */ - if ((info->node_info->lim_bw != lim_bw)) { - qbw.ws = info->node_info->qos_params.ws; - qbw.bw = lim_bw; - qbw.gp = info->node_info->qos_params.gp; - qbw.thmp = info->node_info->qos_params.thmp; - bimc_set_static_qos_bw(qos_base, qos_freq, - info->node_info->qport[i], &qbw); - } - bke_switch(qos_base, info->node_info->qport[i], - BKE_ON, mode); - } - info->node_info->lim_bw = lim_bw; - } else { - mode = info->node_info->qos_params.mode; - for (i = 0; i < info->node_info->num_qports; i++) { - bke_switch(qos_base, info->node_info->qport[i], - BKE_OFF, mode); - } - } - info->node_info->qos_params.cur_mode = mode; - return 0; -} - static bool msm_bus_bimc_update_bw_reg(int mode) { bool ret = false; @@ -1972,107 +1092,6 @@ static bool msm_bus_bimc_update_bw_reg(int mode) return ret; } -static int msm_bus_bimc_qos_init(struct msm_bus_node_device_type *info, - void __iomem *qos_base, - uint32_t qos_off, uint32_t qos_delta, - uint32_t qos_freq) -{ - int i; - struct msm_bus_bimc_qos_mode qmode; - - switch (info->node_info->qos_params.mode) { - case BIMC_QOS_MODE_FIXED: - qmode.fixed.prio_level = info->node_info->qos_params.prio_lvl; - qmode.fixed.areq_prio_rd = info->node_info->qos_params.prio_rd; - qmode.fixed.areq_prio_wr = info->node_info->qos_params.prio_wr; - break; - case BIMC_QOS_MODE_LIMITER: - qmode.rl.qhealth[0].limit_commands = 1; - qmode.rl.qhealth[1].limit_commands = 0; - qmode.rl.qhealth[2].limit_commands = 0; - qmode.rl.qhealth[3].limit_commands = 0; - break; - default: - break; - } - - if (ZERO_OR_NULL_PTR(info->node_info->qport)) { - MSM_BUS_DBG("No QoS Ports to init\n"); - return 0; - } - - for (i = 0; i < info->node_info->num_qports; i++) { - /* If not in bypass mode, update priority */ - if (info->node_info->qos_params.mode != BIMC_QOS_MODE_BYPASS) - msm_bus_bimc_set_qos_prio(qos_base, info->node_info-> - qport[i], info->node_info->qos_params.mode, - &qmode); - - /* set mode */ - if (info->node_info->qos_params.mode == BIMC_QOS_MODE_LIMITER) - bke_switch(qos_base, info->node_info->qport[i], - BKE_OFF, BIMC_QOS_MODE_FIXED); - else - msm_bus_bimc_set_qos_mode(qos_base, - info->node_info->qport[i], - info->node_info->qos_params.mode); - } - - return 0; -} - -static int msm_bus_bimc_set_bw(struct msm_bus_node_device_type *dev, - void __iomem *qos_base, uint32_t qos_off, - uint32_t qos_delta, uint32_t qos_freq) -{ - struct msm_bus_bimc_qos_bw qbw; - int i; - int64_t bw = 0; - int ret = 0; - struct msm_bus_node_info_type *info = dev->node_info; - - if (info && info->num_qports && - ((info->qos_params.mode == BIMC_QOS_MODE_LIMITER) || - (info->qos_params.mode == BIMC_QOS_MODE_REGULATOR))) { - bw = msm_bus_div64(info->num_qports, - dev->node_ab.ab[DUAL_CTX]); - - for (i = 0; i < info->num_qports; i++) { - MSM_BUS_DBG("BIMC: Update mas_bw for ID: %d -> %llu\n", - info->id, bw); - - if (!info->qport) { - MSM_BUS_DBG("No qos ports to update!\n"); - break; - } - - qbw.bw = bw + info->qos_params.bw_buffer; - trace_bus_bimc_config_limiter(info->id, bw); - - /* Default to gp of 5us */ - qbw.gp = (info->qos_params.gp ? - info->qos_params.gp : 5000); - /* Default to thmp of 50% */ - qbw.thmp = (info->qos_params.thmp ? - info->qos_params.thmp : 50); - /* - * If the BW vote is 0 then set the QoS mode to - * Fixed. - */ - if (bw) { - bimc_set_static_qos_bw(qos_base, qos_freq, - info->qport[i], &qbw); - bke_switch(qos_base, info->qport[i], - BKE_ON, info->qos_params.mode); - } else { - bke_switch(qos_base, info->qport[i], - BKE_OFF, BIMC_QOS_MODE_FIXED); - } - } - } - return ret; -} - int msm_bus_bimc_hw_init(struct msm_bus_fabric_registration *pdata, struct msm_bus_hw_algorithm *hw_algo) { @@ -2096,17 +1115,3 @@ int msm_bus_bimc_hw_init(struct msm_bus_fabric_registration *pdata, return 0; } -int msm_bus_bimc_set_ops(struct msm_bus_node_device_type *bus_dev) -{ - if (!bus_dev) - return -ENODEV; - else { - bus_dev->fabdev->noc_ops.qos_init = msm_bus_bimc_qos_init; - bus_dev->fabdev->noc_ops.set_bw = msm_bus_bimc_set_bw; - bus_dev->fabdev->noc_ops.limit_mport = msm_bus_bimc_limit_mport; - bus_dev->fabdev->noc_ops.update_bw_reg = - msm_bus_bimc_update_bw_reg; - } - return 0; -} -EXPORT_SYMBOL(msm_bus_bimc_set_ops); diff --git a/drivers/platform/msm/msm_bus/msm_bus_bimc_adhoc.c b/drivers/platform/msm/msm_bus/msm_bus_bimc_adhoc.c new file mode 100644 index 000000000000..371ec56260e2 --- /dev/null +++ b/drivers/platform/msm/msm_bus/msm_bus_bimc_adhoc.c @@ -0,0 +1,718 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "AXI: BIMC: %s(): " fmt, __func__ + +#include +#include +#include +#include "msm_bus_core.h" +#include "msm_bus_bimc.h" +#include "msm_bus_adhoc.h" +#include + +/* M_Generic */ + +enum bke_sw { + BKE_OFF = 0, + BKE_ON = 1, +}; + +#define M_REG_BASE(b) ((b) + 0x00008000) + +#define M_MODE_ADDR(b, n) \ + (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000210) +enum bimc_m_mode { + M_MODE_RMSK = 0xf0000011, + M_MODE_WR_GATHER_BEATS_BMSK = 0xf0000000, + M_MODE_WR_GATHER_BEATS_SHFT = 0x1c, + M_MODE_NARROW_WR_BMSK = 0x10, + M_MODE_NARROW_WR_SHFT = 0x4, + M_MODE_ORDERING_MODEL_BMSK = 0x1, + M_MODE_ORDERING_MODEL_SHFT = 0x0, +}; + +#define M_PRIOLVL_OVERRIDE_ADDR(b, n) \ + (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000230) +enum bimc_m_priolvl_override { + M_PRIOLVL_OVERRIDE_RMSK = 0x301, + M_PRIOLVL_OVERRIDE_BMSK = 0x300, + M_PRIOLVL_OVERRIDE_SHFT = 0x8, + M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_BMSK = 0x1, + M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_SHFT = 0x0, +}; + +#define M_RD_CMD_OVERRIDE_ADDR(b, n) \ + (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000240) +enum bimc_m_read_command_override { + M_RD_CMD_OVERRIDE_RMSK = 0x3071f7f, + M_RD_CMD_OVERRIDE_AREQPRIO_BMSK = 0x3000000, + M_RD_CMD_OVERRIDE_AREQPRIO_SHFT = 0x18, + M_RD_CMD_OVERRIDE_AMEMTYPE_BMSK = 0x70000, + M_RD_CMD_OVERRIDE_AMEMTYPE_SHFT = 0x10, + M_RD_CMD_OVERRIDE_ATRANSIENT_BMSK = 0x1000, + M_RD_CMD_OVERRIDE_ATRANSIENT_SHFT = 0xc, + M_RD_CMD_OVERRIDE_ASHARED_BMSK = 0x800, + M_RD_CMD_OVERRIDE_ASHARED_SHFT = 0xb, + M_RD_CMD_OVERRIDE_AREDIRECT_BMSK = 0x400, + M_RD_CMD_OVERRIDE_AREDIRECT_SHFT = 0xa, + M_RD_CMD_OVERRIDE_AOOO_BMSK = 0x200, + M_RD_CMD_OVERRIDE_AOOO_SHFT = 0x9, + M_RD_CMD_OVERRIDE_AINNERSHARED_BMSK = 0x100, + M_RD_CMD_OVERRIDE_AINNERSHARED_SHFT = 0x8, + M_RD_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK = 0x40, + M_RD_CMD_OVERRIDE_OVERRIDE_AREQPRIO_SHFT = 0x6, + M_RD_CMD_OVERRIDE_OVERRIDE_ATRANSIENT_BMSK = 0x20, + M_RD_CMD_OVERRIDE_OVERRIDE_ATRANSIENT_SHFT = 0x5, + M_RD_CMD_OVERRIDE_OVERRIDE_AMEMTYPE_BMSK = 0x10, + M_RD_CMD_OVERRIDE_OVERRIDE_AMEMTYPE_SHFT = 0x4, + M_RD_CMD_OVERRIDE_OVERRIDE_ASHARED_BMSK = 0x8, + M_RD_CMD_OVERRIDE_OVERRIDE_ASHARED_SHFT = 0x3, + M_RD_CMD_OVERRIDE_OVERRIDE_AREDIRECT_BMSK = 0x4, + M_RD_CMD_OVERRIDE_OVERRIDE_AREDIRECT_SHFT = 0x2, + M_RD_CMD_OVERRIDE_OVERRIDE_AOOO_BMSK = 0x2, + M_RD_CMD_OVERRIDE_OVERRIDE_AOOO_SHFT = 0x1, + M_RD_CMD_OVERRIDE_OVERRIDE_AINNERSHARED_BMSK = 0x1, + M_RD_CMD_OVERRIDE_OVERRIDE_AINNERSHARED_SHFT = 0x0, +}; + +#define M_WR_CMD_OVERRIDE_ADDR(b, n) \ + (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000250) +enum bimc_m_write_command_override { + M_WR_CMD_OVERRIDE_RMSK = 0x3071f7f, + M_WR_CMD_OVERRIDE_AREQPRIO_BMSK = 0x3000000, + M_WR_CMD_OVERRIDE_AREQPRIO_SHFT = 0x18, + M_WR_CMD_OVERRIDE_AMEMTYPE_BMSK = 0x70000, + M_WR_CMD_OVERRIDE_AMEMTYPE_SHFT = 0x10, + M_WR_CMD_OVERRIDE_ATRANSIENT_BMSK = 0x1000, + M_WR_CMD_OVERRIDE_ATRANSIENT_SHFT = 0xc, + M_WR_CMD_OVERRIDE_ASHARED_BMSK = 0x800, + M_WR_CMD_OVERRIDE_ASHARED_SHFT = 0xb, + M_WR_CMD_OVERRIDE_AREDIRECT_BMSK = 0x400, + M_WR_CMD_OVERRIDE_AREDIRECT_SHFT = 0xa, + M_WR_CMD_OVERRIDE_AOOO_BMSK = 0x200, + M_WR_CMD_OVERRIDE_AOOO_SHFT = 0x9, + M_WR_CMD_OVERRIDE_AINNERSHARED_BMSK = 0x100, + M_WR_CMD_OVERRIDE_AINNERSHARED_SHFT = 0x8, + M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK = 0x40, + M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_SHFT = 0x6, + M_WR_CMD_OVERRIDE_OVERRIDE_ATRANSIENT_BMSK = 0x20, + M_WR_CMD_OVERRIDE_OVERRIDE_ATRANSIENT_SHFT = 0x5, + M_WR_CMD_OVERRIDE_OVERRIDE_AMEMTYPE_BMSK = 0x10, + M_WR_CMD_OVERRIDE_OVERRIDE_AMEMTYPE_SHFT = 0x4, + M_WR_CMD_OVERRIDE_OVERRIDE_ASHARED_BMSK = 0x8, + M_WR_CMD_OVERRIDE_OVERRIDE_ASHARED_SHFT = 0x3, + M_WR_CMD_OVERRIDE_OVERRIDE_AREDIRECT_BMSK = 0x4, + M_WR_CMD_OVERRIDE_OVERRIDE_AREDIRECT_SHFT = 0x2, + M_WR_CMD_OVERRIDE_OVERRIDE_AOOO_BMSK = 0x2, + M_WR_CMD_OVERRIDE_OVERRIDE_AOOO_SHFT = 0x1, + M_WR_CMD_OVERRIDE_OVERRIDE_AINNERSHARED_BMSK = 0x1, + M_WR_CMD_OVERRIDE_OVERRIDE_AINNERSHARED_SHFT = 0x0, +}; + +#define M_BKE_EN_ADDR(b, n) \ + (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000300) +enum bimc_m_bke_en { + M_BKE_EN_RMSK = 0x1, + M_BKE_EN_EN_BMSK = 0x1, + M_BKE_EN_EN_SHFT = 0x0, +}; + +/* Grant Period registers */ +#define M_BKE_GP_ADDR(b, n) \ + (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000304) +enum bimc_m_bke_grant_period { + M_BKE_GP_RMSK = 0x3ff, + M_BKE_GP_GP_BMSK = 0x3ff, + M_BKE_GP_GP_SHFT = 0x0, +}; + +/* Grant count register. + * The Grant count register represents a signed 16 bit + * value, range 0-0x7fff + */ +#define M_BKE_GC_ADDR(b, n) \ + (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000308) +enum bimc_m_bke_grant_count { + M_BKE_GC_RMSK = 0xffff, + M_BKE_GC_GC_BMSK = 0xffff, + M_BKE_GC_GC_SHFT = 0x0, +}; + +/* Threshold High Registers */ +#define M_BKE_THH_ADDR(b, n) \ + (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000320) +enum bimc_m_bke_thresh_high { + M_BKE_THH_RMSK = 0xffff, + M_BKE_THH_THRESH_BMSK = 0xffff, + M_BKE_THH_THRESH_SHFT = 0x0, +}; + +/* Threshold Medium Registers */ +#define M_BKE_THM_ADDR(b, n) \ + (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000324) +enum bimc_m_bke_thresh_medium { + M_BKE_THM_RMSK = 0xffff, + M_BKE_THM_THRESH_BMSK = 0xffff, + M_BKE_THM_THRESH_SHFT = 0x0, +}; + +/* Threshold Low Registers */ +#define M_BKE_THL_ADDR(b, n) \ + (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000328) +enum bimc_m_bke_thresh_low { + M_BKE_THL_RMSK = 0xffff, + M_BKE_THL_THRESH_BMSK = 0xffff, + M_BKE_THL_THRESH_SHFT = 0x0, +}; + +#define M_BKE_HEALTH_0_CONFIG_ADDR(b, n) \ + (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000340) +enum bimc_m_bke_health_0 { + M_BKE_HEALTH_0_CONFIG_RMSK = 0x80000303, + M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_BMSK = 0x80000000, + M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_SHFT = 0x1f, + M_BKE_HEALTH_0_CONFIG_AREQPRIO_BMSK = 0x300, + M_BKE_HEALTH_0_CONFIG_AREQPRIO_SHFT = 0x8, + M_BKE_HEALTH_0_CONFIG_PRIOLVL_BMSK = 0x3, + M_BKE_HEALTH_0_CONFIG_PRIOLVL_SHFT = 0x0, +}; + +#define M_BKE_HEALTH_1_CONFIG_ADDR(b, n) \ + (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000344) +enum bimc_m_bke_health_1 { + M_BKE_HEALTH_1_CONFIG_RMSK = 0x80000303, + M_BKE_HEALTH_1_CONFIG_LIMIT_CMDS_BMSK = 0x80000000, + M_BKE_HEALTH_1_CONFIG_LIMIT_CMDS_SHFT = 0x1f, + M_BKE_HEALTH_1_CONFIG_AREQPRIO_BMSK = 0x300, + M_BKE_HEALTH_1_CONFIG_AREQPRIO_SHFT = 0x8, + M_BKE_HEALTH_1_CONFIG_PRIOLVL_BMSK = 0x3, + M_BKE_HEALTH_1_CONFIG_PRIOLVL_SHFT = 0x0, +}; + +#define M_BKE_HEALTH_2_CONFIG_ADDR(b, n) \ + (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000348) +enum bimc_m_bke_health_2 { + M_BKE_HEALTH_2_CONFIG_RMSK = 0x80000303, + M_BKE_HEALTH_2_CONFIG_LIMIT_CMDS_BMSK = 0x80000000, + M_BKE_HEALTH_2_CONFIG_LIMIT_CMDS_SHFT = 0x1f, + M_BKE_HEALTH_2_CONFIG_AREQPRIO_BMSK = 0x300, + M_BKE_HEALTH_2_CONFIG_AREQPRIO_SHFT = 0x8, + M_BKE_HEALTH_2_CONFIG_PRIOLVL_BMSK = 0x3, + M_BKE_HEALTH_2_CONFIG_PRIOLVL_SHFT = 0x0, +}; + +#define M_BKE_HEALTH_3_CONFIG_ADDR(b, n) \ + (M_REG_BASE(b) + (0x4000 * (n)) + 0x0000034c) +enum bimc_m_bke_health_3 { + M_BKE_HEALTH_3_CONFIG_RMSK = 0x303, + M_BKE_HEALTH_3_CONFIG_AREQPRIO_BMSK = 0x300, + M_BKE_HEALTH_3_CONFIG_AREQPRIO_SHFT = 0x8, + M_BKE_HEALTH_3_CONFIG_PRIOLVL_BMSK = 0x3, + M_BKE_HEALTH_3_CONFIG_PRIOLVL_SHFT = 0x0, +}; + +#define BKE_HEALTH_MASK \ + (M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_BMSK |\ + M_BKE_HEALTH_0_CONFIG_AREQPRIO_BMSK |\ + M_BKE_HEALTH_0_CONFIG_PRIOLVL_BMSK) + +#define BKE_HEALTH_VAL(limit, areq, plvl) \ + ((((limit) << M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_SHFT) & \ + M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_BMSK) | \ + (((areq) << M_BKE_HEALTH_0_CONFIG_AREQPRIO_SHFT) & \ + M_BKE_HEALTH_0_CONFIG_AREQPRIO_BMSK) | \ + (((plvl) << M_BKE_HEALTH_0_CONFIG_PRIOLVL_SHFT) & \ + M_BKE_HEALTH_0_CONFIG_PRIOLVL_BMSK)) + +#define MAX_GRANT_PERIOD \ + (M_BKE_GP_GP_BMSK >> \ + M_BKE_GP_GP_SHFT) + +#define MAX_GC \ + (M_BKE_GC_GC_BMSK >> \ + (M_BKE_GC_GC_SHFT + 1)) + +static int bimc_div(int64_t *a, uint32_t b) +{ + if ((*a > 0) && (*a < b)) { + *a = 0; + return 1; + } else { + return do_div(*a, b); + } +} + +static void set_qos_mode(void __iomem *baddr, uint32_t index, uint32_t val0, + uint32_t val1, uint32_t val2) +{ + uint32_t reg_val, val; + + reg_val = readl_relaxed(M_PRIOLVL_OVERRIDE_ADDR(baddr, + index)) & M_PRIOLVL_OVERRIDE_RMSK; + val = val0 << M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_SHFT; + writel_relaxed(((reg_val & ~(M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_BMSK)) + | (val & M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_BMSK)), + M_PRIOLVL_OVERRIDE_ADDR(baddr, index)); + reg_val = readl_relaxed(M_RD_CMD_OVERRIDE_ADDR(baddr, index)) & + M_RD_CMD_OVERRIDE_RMSK; + val = val1 << M_RD_CMD_OVERRIDE_OVERRIDE_AREQPRIO_SHFT; + writel_relaxed(((reg_val & ~(M_RD_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK + )) | (val & M_RD_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK)), + M_RD_CMD_OVERRIDE_ADDR(baddr, index)); + reg_val = readl_relaxed(M_WR_CMD_OVERRIDE_ADDR(baddr, index)) & + M_WR_CMD_OVERRIDE_RMSK; + val = val2 << M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_SHFT; + writel_relaxed(((reg_val & ~(M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK + )) | (val & M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK)), + M_WR_CMD_OVERRIDE_ADDR(baddr, index)); + /* Ensure the priority register writes go through */ + wmb(); +} + +static void msm_bus_bimc_set_qos_mode(void __iomem *base, + uint32_t mas_index, uint8_t qmode_sel) +{ + uint32_t reg_val, val; + + switch (qmode_sel) { + case BIMC_QOS_MODE_FIXED: + reg_val = readl_relaxed(M_BKE_EN_ADDR(base, + mas_index)); + writel_relaxed((reg_val & (~M_BKE_EN_EN_BMSK)), + M_BKE_EN_ADDR(base, mas_index)); + /* + * Ensure that the book-keeping register writes + * go through before setting QoS mode. + * QoS mode registers might write beyond 1K + * boundary in future + */ + wmb(); + set_qos_mode(base, mas_index, 1, 1, 1); + break; + + case BIMC_QOS_MODE_BYPASS: + reg_val = readl_relaxed(M_BKE_EN_ADDR(base, + mas_index)); + writel_relaxed((reg_val & (~M_BKE_EN_EN_BMSK)), + M_BKE_EN_ADDR(base, mas_index)); + /* Ensure that the book-keeping register writes + * go through before setting QoS mode. + * QoS mode registers might write beyond 1K + * boundary in future + */ + wmb(); + set_qos_mode(base, mas_index, 0, 0, 0); + break; + + case BIMC_QOS_MODE_REGULATOR: + case BIMC_QOS_MODE_LIMITER: + set_qos_mode(base, mas_index, 0, 0, 0); + reg_val = readl_relaxed(M_BKE_EN_ADDR(base, + mas_index)); + val = 1 << M_BKE_EN_EN_SHFT; + /* Ensure that the book-keeping register writes + * go through before setting QoS mode. + * QoS mode registers might write beyond 1K + * boundary in future + */ + wmb(); + writel_relaxed(((reg_val & (~M_BKE_EN_EN_BMSK)) | (val & + M_BKE_EN_EN_BMSK)), M_BKE_EN_ADDR(base, + mas_index)); + break; + default: + break; + } +} + +static void set_qos_prio_rl(void __iomem *addr, uint32_t rmsk, + uint8_t index, struct msm_bus_bimc_qos_mode *qmode) +{ + uint32_t reg_val, val0, val; + + /* Note, addr is already passed with right mas_index */ + reg_val = readl_relaxed(addr) & rmsk; + val0 = BKE_HEALTH_VAL(qmode->rl.qhealth[index].limit_commands, + qmode->rl.qhealth[index].areq_prio, + qmode->rl.qhealth[index].prio_level); + val = ((reg_val & (~(BKE_HEALTH_MASK))) | (val0 & BKE_HEALTH_MASK)); + writel_relaxed(val, addr); + /* Ensure that priority for regulator/limiter modes are + * set before returning + */ + wmb(); +} + +static void msm_bus_bimc_set_qos_prio(void __iomem *base, + uint32_t mas_index, uint8_t qmode_sel, + struct msm_bus_bimc_qos_mode *qmode) +{ + uint32_t reg_val, val; + + switch (qmode_sel) { + case BIMC_QOS_MODE_FIXED: + reg_val = readl_relaxed(M_PRIOLVL_OVERRIDE_ADDR( + base, mas_index)) & M_PRIOLVL_OVERRIDE_RMSK; + val = qmode->fixed.prio_level << + M_PRIOLVL_OVERRIDE_SHFT; + writel_relaxed(((reg_val & + ~(M_PRIOLVL_OVERRIDE_BMSK)) | (val + & M_PRIOLVL_OVERRIDE_BMSK)), + M_PRIOLVL_OVERRIDE_ADDR(base, mas_index)); + + reg_val = readl_relaxed(M_RD_CMD_OVERRIDE_ADDR( + base, mas_index)) & M_RD_CMD_OVERRIDE_RMSK; + val = qmode->fixed.areq_prio_rd << + M_RD_CMD_OVERRIDE_AREQPRIO_SHFT; + writel_relaxed(((reg_val & ~(M_RD_CMD_OVERRIDE_AREQPRIO_BMSK)) + | (val & M_RD_CMD_OVERRIDE_AREQPRIO_BMSK)), + M_RD_CMD_OVERRIDE_ADDR(base, mas_index)); + + reg_val = readl_relaxed(M_WR_CMD_OVERRIDE_ADDR( + base, mas_index)) & M_WR_CMD_OVERRIDE_RMSK; + val = qmode->fixed.areq_prio_wr << + M_WR_CMD_OVERRIDE_AREQPRIO_SHFT; + writel_relaxed(((reg_val & ~(M_WR_CMD_OVERRIDE_AREQPRIO_BMSK)) + | (val & M_WR_CMD_OVERRIDE_AREQPRIO_BMSK)), + M_WR_CMD_OVERRIDE_ADDR(base, mas_index)); + /* Ensure that fixed mode register writes go through + * before returning + */ + wmb(); + break; + + case BIMC_QOS_MODE_REGULATOR: + case BIMC_QOS_MODE_LIMITER: + set_qos_prio_rl(M_BKE_HEALTH_3_CONFIG_ADDR(base, + mas_index), M_BKE_HEALTH_3_CONFIG_RMSK, 3, qmode); + set_qos_prio_rl(M_BKE_HEALTH_2_CONFIG_ADDR(base, + mas_index), M_BKE_HEALTH_2_CONFIG_RMSK, 2, qmode); + set_qos_prio_rl(M_BKE_HEALTH_1_CONFIG_ADDR(base, + mas_index), M_BKE_HEALTH_1_CONFIG_RMSK, 1, qmode); + set_qos_prio_rl(M_BKE_HEALTH_0_CONFIG_ADDR(base, + mas_index), M_BKE_HEALTH_0_CONFIG_RMSK, 0 , qmode); + break; + case BIMC_QOS_MODE_BYPASS: + default: + break; + } +} + +static void set_qos_bw_regs(void __iomem *baddr, uint32_t mas_index, + int32_t th, int32_t tm, int32_t tl, uint32_t gp, + uint32_t gc) +{ + int32_t reg_val, val; + int32_t bke_reg_val; + int16_t val2; + + /* Disable BKE before writing to registers as per spec */ + bke_reg_val = readl_relaxed(M_BKE_EN_ADDR(baddr, mas_index)); + writel_relaxed((bke_reg_val & ~(M_BKE_EN_EN_BMSK)), + M_BKE_EN_ADDR(baddr, mas_index)); + + /* Write values of registers calculated */ + reg_val = readl_relaxed(M_BKE_GP_ADDR(baddr, mas_index)) + & M_BKE_GP_RMSK; + val = gp << M_BKE_GP_GP_SHFT; + writel_relaxed(((reg_val & ~(M_BKE_GP_GP_BMSK)) | (val & + M_BKE_GP_GP_BMSK)), M_BKE_GP_ADDR(baddr, mas_index)); + + reg_val = readl_relaxed(M_BKE_GC_ADDR(baddr, mas_index)) & + M_BKE_GC_RMSK; + val = gc << M_BKE_GC_GC_SHFT; + writel_relaxed(((reg_val & ~(M_BKE_GC_GC_BMSK)) | (val & + M_BKE_GC_GC_BMSK)), M_BKE_GC_ADDR(baddr, mas_index)); + + reg_val = readl_relaxed(M_BKE_THH_ADDR(baddr, mas_index)) & + M_BKE_THH_RMSK; + val = th << M_BKE_THH_THRESH_SHFT; + writel_relaxed(((reg_val & ~(M_BKE_THH_THRESH_BMSK)) | (val & + M_BKE_THH_THRESH_BMSK)), M_BKE_THH_ADDR(baddr, mas_index)); + + reg_val = readl_relaxed(M_BKE_THM_ADDR(baddr, mas_index)) & + M_BKE_THM_RMSK; + val2 = tm << M_BKE_THM_THRESH_SHFT; + writel_relaxed(((reg_val & ~(M_BKE_THM_THRESH_BMSK)) | (val2 & + M_BKE_THM_THRESH_BMSK)), M_BKE_THM_ADDR(baddr, mas_index)); + + reg_val = readl_relaxed(M_BKE_THL_ADDR(baddr, mas_index)) & + M_BKE_THL_RMSK; + val2 = tl << M_BKE_THL_THRESH_SHFT; + writel_relaxed(((reg_val & ~(M_BKE_THL_THRESH_BMSK)) | + (val2 & M_BKE_THL_THRESH_BMSK)), M_BKE_THL_ADDR(baddr, + mas_index)); + + /* Ensure that all bandwidth register writes have completed + * before returning + */ + wmb(); +} + +static void bke_switch( + void __iomem *baddr, uint32_t mas_index, bool req, int mode) +{ + uint32_t reg_val, val, cur_val; + + val = req << M_BKE_EN_EN_SHFT; + reg_val = readl_relaxed(M_BKE_EN_ADDR(baddr, mas_index)); + cur_val = reg_val & M_BKE_EN_RMSK; + if (val == cur_val) + return; + + if (!req && mode == BIMC_QOS_MODE_FIXED) + set_qos_mode(baddr, mas_index, 1, 1, 1); + + writel_relaxed(((reg_val & ~(M_BKE_EN_EN_BMSK)) | (val & + M_BKE_EN_EN_BMSK)), M_BKE_EN_ADDR(baddr, mas_index)); + /* Make sure BKE on/off goes through before changing priorities */ + wmb(); + + if (req) + set_qos_mode(baddr, mas_index, 0, 0, 0); +} + +static void bimc_set_static_qos_bw(void __iomem *base, unsigned int qos_freq, + int mport, struct msm_bus_bimc_qos_bw *qbw) +{ + int32_t bw_mbps, thh = 0, thm, thl, gc; + int32_t gp; + u64 temp; + + if (qos_freq == 0) { + MSM_BUS_DBG("No QoS Frequency.\n"); + return; + } + + if (!(qbw->bw && qbw->gp)) { + MSM_BUS_DBG("No QoS Bandwidth or Window size\n"); + return; + } + + /* Convert bandwidth to MBPS */ + temp = qbw->bw; + bimc_div(&temp, 1000000); + bw_mbps = temp; + + /* Grant period in clock cycles + * Grant period from bandwidth structure + * is in nano seconds, QoS freq is in KHz. + * Divide by 1000 to get clock cycles. + */ + gp = (qos_freq * qbw->gp) / (1000 * NSEC_PER_USEC); + + /* Grant count = BW in MBps * Grant period + * in micro seconds + */ + gc = bw_mbps * (qbw->gp / NSEC_PER_USEC); + gc = min(gc, MAX_GC); + + /* Medium threshold = -((Medium Threshold percentage * + * Grant count) / 100) + */ + thm = -((qbw->thmp * gc) / 100); + qbw->thm = thm; + + /* Low threshold = -(Grant count) */ + thl = -gc; + qbw->thl = thl; + + MSM_BUS_DBG("%s: BKE parameters: gp %d, gc %d, thm %d thl %d thh %d", + __func__, gp, gc, thm, thl, thh); + + trace_bus_bke_params(gc, gp, thl, thm, thl); + set_qos_bw_regs(base, mport, thh, thm, thl, gp, gc); +} + +static int msm_bus_bimc_limit_mport(struct msm_bus_node_device_type *info, + void __iomem *qos_base, uint32_t qos_off, + uint32_t qos_delta, uint32_t qos_freq, + int enable_lim, u64 lim_bw) +{ + int mode; + int i; + + if (ZERO_OR_NULL_PTR(info->node_info->qport)) { + MSM_BUS_DBG("No QoS Ports to limit\n"); + return 0; + } + + if ((enable_lim == THROTTLE_ON) && lim_bw) { + mode = BIMC_QOS_MODE_LIMITER; + + if (!info->node_info->lim_bw) { + struct msm_bus_bimc_qos_mode qmode; + + qmode.rl.qhealth[0].limit_commands = 1; + qmode.rl.qhealth[1].limit_commands = 0; + qmode.rl.qhealth[2].limit_commands = 0; + qmode.rl.qhealth[3].limit_commands = 0; + + for (i = 0; i < info->node_info->num_qports; i++) { + /* If not in bypass mode, update priority */ + if (mode != BIMC_QOS_MODE_BYPASS) + msm_bus_bimc_set_qos_prio(qos_base, + info->node_info->qport[i], mode, + &qmode); + } + } + + for (i = 0; i < info->node_info->num_qports; i++) { + struct msm_bus_bimc_qos_bw qbw; + /* If not in fixed mode, update bandwidth */ + if (info->node_info->lim_bw != lim_bw) { + qbw.ws = info->node_info->qos_params.ws; + qbw.bw = lim_bw; + qbw.gp = info->node_info->qos_params.gp; + qbw.thmp = info->node_info->qos_params.thmp; + bimc_set_static_qos_bw(qos_base, qos_freq, + info->node_info->qport[i], &qbw); + } + bke_switch(qos_base, info->node_info->qport[i], + BKE_ON, mode); + } + info->node_info->lim_bw = lim_bw; + } else { + mode = info->node_info->qos_params.mode; + for (i = 0; i < info->node_info->num_qports; i++) + bke_switch(qos_base, info->node_info->qport[i], + BKE_OFF, mode); + } + info->node_info->qos_params.cur_mode = mode; + return 0; +} + +static bool msm_bus_bimc_update_bw_reg(int mode) +{ + bool ret = false; + + if ((mode == BIMC_QOS_MODE_LIMITER) + || (mode == BIMC_QOS_MODE_REGULATOR)) + ret = true; + + return ret; +} + +static int msm_bus_bimc_qos_init(struct msm_bus_node_device_type *info, + void __iomem *qos_base, + uint32_t qos_off, uint32_t qos_delta, + uint32_t qos_freq) +{ + int i; + struct msm_bus_bimc_qos_mode qmode; + + switch (info->node_info->qos_params.mode) { + case BIMC_QOS_MODE_FIXED: + qmode.fixed.prio_level = info->node_info->qos_params.prio_lvl; + qmode.fixed.areq_prio_rd = info->node_info->qos_params.prio_rd; + qmode.fixed.areq_prio_wr = info->node_info->qos_params.prio_wr; + break; + case BIMC_QOS_MODE_LIMITER: + qmode.rl.qhealth[0].limit_commands = 1; + qmode.rl.qhealth[1].limit_commands = 0; + qmode.rl.qhealth[2].limit_commands = 0; + qmode.rl.qhealth[3].limit_commands = 0; + break; + default: + break; + } + + if (ZERO_OR_NULL_PTR(info->node_info->qport)) { + MSM_BUS_DBG("No QoS Ports to init\n"); + return 0; + } + + for (i = 0; i < info->node_info->num_qports; i++) { + /* If not in bypass mode, update priority */ + if (info->node_info->qos_params.mode != BIMC_QOS_MODE_BYPASS) + msm_bus_bimc_set_qos_prio(qos_base, info->node_info-> + qport[i], info->node_info->qos_params.mode, + &qmode); + + /* set mode */ + if (info->node_info->qos_params.mode == BIMC_QOS_MODE_LIMITER) + bke_switch(qos_base, info->node_info->qport[i], + BKE_OFF, BIMC_QOS_MODE_FIXED); + else + msm_bus_bimc_set_qos_mode(qos_base, + info->node_info->qport[i], + info->node_info->qos_params.mode); + } + + return 0; +} + +static int msm_bus_bimc_set_bw(struct msm_bus_node_device_type *dev, + void __iomem *qos_base, uint32_t qos_off, + uint32_t qos_delta, uint32_t qos_freq) +{ + struct msm_bus_bimc_qos_bw qbw; + int i; + int64_t bw = 0; + int ret = 0; + struct msm_bus_node_info_type *info = dev->node_info; + + if (info && info->num_qports && + ((info->qos_params.mode == BIMC_QOS_MODE_LIMITER) || + (info->qos_params.mode == BIMC_QOS_MODE_REGULATOR))) { + bw = msm_bus_div64(info->num_qports, + dev->node_bw[ACTIVE_CTX].sum_ab); + + for (i = 0; i < info->num_qports; i++) { + MSM_BUS_DBG("BIMC: Update mas_bw for ID: %d -> %llu\n", + info->id, bw); + + if (!info->qport) { + MSM_BUS_DBG("No qos ports to update!\n"); + break; + } + + qbw.bw = bw + info->qos_params.bw_buffer; + trace_bus_bimc_config_limiter(info->id, bw); + + /* Default to gp of 5us */ + qbw.gp = (info->qos_params.gp ? + info->qos_params.gp : 5000); + /* Default to thmp of 50% */ + qbw.thmp = (info->qos_params.thmp ? + info->qos_params.thmp : 50); + /* + * If the BW vote is 0 then set the QoS mode to + * Fixed. + */ + if (bw) { + bimc_set_static_qos_bw(qos_base, qos_freq, + info->qport[i], &qbw); + bke_switch(qos_base, info->qport[i], + BKE_ON, info->qos_params.mode); + } else { + bke_switch(qos_base, info->qport[i], + BKE_OFF, BIMC_QOS_MODE_FIXED); + } + } + } + return ret; +} + +int msm_bus_bimc_set_ops(struct msm_bus_node_device_type *bus_dev) +{ + if (!bus_dev) + return -ENODEV; + bus_dev->fabdev->noc_ops.qos_init = msm_bus_bimc_qos_init; + bus_dev->fabdev->noc_ops.set_bw = msm_bus_bimc_set_bw; + bus_dev->fabdev->noc_ops.limit_mport = msm_bus_bimc_limit_mport; + bus_dev->fabdev->noc_ops.update_bw_reg = + msm_bus_bimc_update_bw_reg; + return 0; +} +EXPORT_SYMBOL(msm_bus_bimc_set_ops); diff --git a/drivers/platform/msm/msm_bus/msm_bus_client_api.c b/drivers/platform/msm/msm_bus/msm_bus_client_api.c index 5b386794fedf..25abfaf7a266 100644 --- a/drivers/platform/msm/msm_bus/msm_bus_client_api.c +++ b/drivers/platform/msm/msm_bus/msm_bus_client_api.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -67,6 +67,22 @@ int msm_bus_scale_client_update_request(uint32_t cl, unsigned int index) } EXPORT_SYMBOL(msm_bus_scale_client_update_request); +/** + * msm_bus_scale_client_update_context() - Update the context for a client + * cl: Handle to the client + * active_only: Bool to indicate dual context or active-only context. + * ctx_idx: Voting index to be used when switching contexts. + */ +int msm_bus_scale_client_update_context(uint32_t cl, bool active_only, + unsigned int ctx_idx) +{ + if (arb_ops.update_context) + return arb_ops.update_context(cl, active_only, ctx_idx); + + return -EPROBE_DEFER; +} +EXPORT_SYMBOL(msm_bus_scale_client_update_context); + /** * msm_bus_scale_unregister_client() - Unregister the client from the bus driver * @cl: Handle to the client @@ -125,6 +141,28 @@ int msm_bus_scale_update_bw(struct msm_bus_client_handle *cl, u64 ab, u64 ib) } EXPORT_SYMBOL(msm_bus_scale_update_bw); +/** + * msm_bus_scale_change_context() - Update the context for a particular client + * cl: Handle to the client + * act_ab: The average bandwidth(AB) in Bytes/s to be used in active context. + * act_ib: The instantaneous bandwidth(IB) in Bytes/s to be used in active + * context. + * slp_ib: The average bandwidth(AB) in Bytes/s to be used in dual context. + * slp_ab: The instantaneous bandwidth(IB) in Bytes/s to be used in dual + * context. + */ +int +msm_bus_scale_update_bw_context(struct msm_bus_client_handle *cl, u64 act_ab, + u64 act_ib, u64 slp_ib, u64 slp_ab) +{ + if (arb_ops.update_context) + return arb_ops.update_bw_context(cl, act_ab, act_ib, + slp_ab, slp_ib); + + return -EPROBE_DEFER; +} +EXPORT_SYMBOL(msm_bus_scale_update_bw_context); + /** * msm_bus_scale_unregister() - Update the request for bandwidth * from a particular client diff --git a/drivers/platform/msm/msm_bus/msm_bus_core.h b/drivers/platform/msm/msm_bus/msm_bus_core.h index bf28405b33f6..dc5f5b044e08 100644 --- a/drivers/platform/msm/msm_bus/msm_bus_core.h +++ b/drivers/platform/msm/msm_bus/msm_bus_core.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,7 @@ #define INTERLEAVED_VAL(fab_pdata, n) \ ((fab_pdata->il_flag) ? (n) : 1) #define KBTOB(a) (a * 1000ULL) +#define MAX_REG_NAME (50) enum msm_bus_dbg_op_type { MSM_BUS_DBG_UNREGISTER = -2, @@ -57,12 +59,16 @@ enum msm_bus_hw_sel { struct msm_bus_arb_ops { uint32_t (*register_client)(struct msm_bus_scale_pdata *pdata); int (*update_request)(uint32_t cl, unsigned int index); + int (*update_context)(uint32_t cl, bool active_only, + unsigned int ctx_idx); void (*unregister_client)(uint32_t cl); struct msm_bus_client_handle* (*register_cl)(uint32_t mas, uint32_t slv, char *name, bool active_only); int (*update_bw)(struct msm_bus_client_handle *cl, u64 ab, u64 ib); void (*unregister)(struct msm_bus_client_handle *cl); + int (*update_bw_context)(struct msm_bus_client_handle *cl, u64 act_ab, + u64 act_ib, u64 slp_ib, u64 slp_ab); }; enum { @@ -139,9 +145,13 @@ struct msm_bus_link_info { struct nodeclk { struct clk *clk; + struct regulator *reg; uint64_t rate; bool dirty; + bool enable_only_clk; + bool setrate_only_clk; bool enable; + char reg_name[MAX_REG_NAME]; }; struct msm_bus_inode_info { @@ -270,6 +280,7 @@ struct msm_bus_client { struct msm_bus_scale_pdata *pdata; int *src_pnode; int curr; + struct device **src_devs; }; uint64_t msm_bus_div64(unsigned int width, uint64_t bw); @@ -333,7 +344,7 @@ static inline void msm_bus_dbg_commit_data(const char *fabname, int op) { } -static inline void void msm_bus_dbg_remove_client +static inline void msm_bus_dbg_remove_client (const struct msm_bus_client_handle *pdata) { } diff --git a/drivers/platform/msm/msm_bus/msm_bus_dbg.c b/drivers/platform/msm/msm_bus/msm_bus_dbg.c index cda41ed74641..229e1c416c57 100644 --- a/drivers/platform/msm/msm_bus/msm_bus_dbg.c +++ b/drivers/platform/msm/msm_bus/msm_bus_dbg.c @@ -367,7 +367,7 @@ int msm_bus_dbg_rec_transaction(const struct msm_bus_client_handle *pdata, MSM_BUS_DBG("Client doesn't have a name\n"); return -EINVAL; } - pr_err("\n%s setting up debugfs %s", __func__, pdata->name); + pr_debug("\n%s setting up debugfs %s", __func__, pdata->name); cldata->file = debugfs_create_file(pdata->name, S_IRUGO, clients, (void *)pdata, &client_data_fops); } @@ -725,6 +725,47 @@ static const struct file_operations msm_bus_dbg_update_request_fops = { .write = msm_bus_dbg_update_request_write, }; +static int msm_bus_dbg_dump_clients_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t msm_bus_dbg_dump_clients_read(struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + int j, cnt; + char msg[50]; + struct msm_bus_cldata *cldata = NULL; + + cnt = scnprintf(msg, 50, + "\nDumping curent client votes to trace log\n"); + if (*ppos) + goto exit_dump_clients_read; + list_for_each_entry(cldata, &cl_list, list) { + if (IS_ERR_OR_NULL(cldata->pdata)) + continue; + for (j = 0; j < cldata->pdata->usecase->num_paths; j++) { + if (cldata->index == -1) + continue; + trace_bus_client_status( + cldata->pdata->name, + cldata->pdata->usecase[cldata->index].vectors[j].src, + cldata->pdata->usecase[cldata->index].vectors[j].dst, + cldata->pdata->usecase[cldata->index].vectors[j].ab, + cldata->pdata->usecase[cldata->index].vectors[j].ib, + cldata->pdata->active_only); + } + } +exit_dump_clients_read: + return simple_read_from_buffer(buf, count, ppos, msg, cnt); +} + +static const struct file_operations msm_bus_dbg_dump_clients_fops = { + .open = msm_bus_dbg_dump_clients_open, + .read = msm_bus_dbg_dump_clients_read, +}; + /** * msm_bus_dbg_client_data() - Add debug data for clients * @pdata: Platform data of the client @@ -860,6 +901,10 @@ static int __init msm_bus_debugfs_init(void) } } + if (debugfs_create_file("dump_clients", S_IRUGO | S_IWUSR, + clients, NULL, &msm_bus_dbg_dump_clients_fops) == NULL) + goto err; + mutex_lock(&msm_bus_dbg_fablist_lock); list_for_each_entry(fablist, &fabdata_list, list) { fablist->file = debugfs_create_file(fablist->name, S_IRUGO, diff --git a/drivers/platform/msm/msm_bus/msm_bus_dbg_voter.c b/drivers/platform/msm/msm_bus/msm_bus_dbg_voter.c index 2714d8a42399..e4c8f1f446df 100644 --- a/drivers/platform/msm/msm_bus/msm_bus_dbg_voter.c +++ b/drivers/platform/msm/msm_bus/msm_bus_dbg_voter.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. * * This program is Mree software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -154,36 +154,36 @@ static DEVICE_ATTR(floor_vote_api, S_IRUGO | S_IWUSR, static DEVICE_ATTR(floor_active_only, S_IRUGO | S_IWUSR, bus_floor_active_only_show, bus_floor_active_only_store); -static int msm_bus_floor_init_dev(struct device *fab_dev, - struct device *dev, bool is_master) +static struct msm_bus_node_device_type *msm_bus_floor_init_dev( + struct device *fab_dev, bool is_master) { struct msm_bus_node_device_type *bus_node = NULL; struct msm_bus_node_device_type *fab_node = NULL; struct msm_bus_node_info_type *node_info = NULL; + struct device *dev = NULL; int ret = 0; - if (!(fab_dev && dev)) { - ret = -ENXIO; + if (!fab_dev) { + bus_node = ERR_PTR(-ENXIO); goto exit_init_bus_dev; } - fab_node = fab_dev->platform_data; + fab_node = to_msm_bus_node(fab_dev); if (!fab_node) { pr_info("\n%s: Can't create device", __func__); - ret = -ENXIO; + bus_node = ERR_PTR(-ENXIO); goto exit_init_bus_dev; } - device_initialize(dev); - bus_node = devm_kzalloc(dev, - sizeof(struct msm_bus_node_device_type), GFP_KERNEL); - + bus_node = kzalloc(sizeof(struct msm_bus_node_device_type), GFP_KERNEL); if (!bus_node) { pr_err("%s:Bus node alloc failed\n", __func__); - ret = -ENOMEM; + bus_node = ERR_PTR(-ENOMEM); goto exit_init_bus_dev; } + dev = &bus_node->dev; + device_initialize(dev); node_info = devm_kzalloc(dev, sizeof(struct msm_bus_node_info_type), GFP_KERNEL); @@ -191,22 +191,22 @@ static int msm_bus_floor_init_dev(struct device *fab_dev, if (!node_info) { pr_err("%s:Bus node info alloc failed\n", __func__); devm_kfree(dev, bus_node); - ret = -ENOMEM; + bus_node = ERR_PTR(-ENOMEM); goto exit_init_bus_dev; } bus_node->node_info = node_info; bus_node->ap_owned = true; bus_node->node_info->bus_device = fab_dev; - bus_node->node_info->buswidth = 8; - dev->platform_data = bus_node; + bus_node->node_info->agg_params.buswidth = 8; dev->bus = &msm_bus_type; + list_add_tail(&bus_node->dev_link, &fab_node->devlist); bus_node->node_info->id = get_id(); if (bus_node->node_info->id < 0) { pr_err("%s: Failed to get id for dev. Bus:%s is_master:%d", __func__, fab_node->node_info->name, is_master); - ret = -ENXIO; + bus_node = ERR_PTR(-ENXIO); goto exit_init_bus_dev; } @@ -216,11 +216,12 @@ static int msm_bus_floor_init_dev(struct device *fab_dev, ret = device_add(dev); if (ret < 0) { pr_err("%s: Failed to add %s", __func__, dev_name(dev)); + bus_node = ERR_PTR(ret); goto exit_init_bus_dev; } exit_init_bus_dev: - return ret; + return bus_node; } static int msm_bus_floor_show_info(struct device *dev, void *data) @@ -371,30 +372,22 @@ exit_bus_floor_vote_context: } EXPORT_SYMBOL(msm_bus_floor_vote_context); -static int msm_bus_floor_setup_dev_conn(struct device *mas, struct device *slv) +static int msm_bus_floor_setup_dev_conn( + struct msm_bus_node_device_type *mas_node, + struct msm_bus_node_device_type *slv_node) { int ret = 0; int slv_id = 0; - struct msm_bus_node_device_type *mas_node = NULL; - struct msm_bus_node_device_type *slv_node = NULL; - - if (!(mas && slv)) { - pr_err("\n%s: Invalid master/slave device", __func__); - ret = -ENXIO; - goto exit_setup_dev_conn; - } - - mas_node = mas->platform_data; - slv_node = slv->platform_data; if (!(mas_node && slv_node)) { + pr_err("\n%s: Invalid master/slave device", __func__); ret = -ENXIO; goto exit_setup_dev_conn; } slv_id = slv_node->node_info->id; mas_node->node_info->num_connections = 1; - mas_node->node_info->connections = devm_kzalloc(mas, + mas_node->node_info->connections = devm_kzalloc(&mas_node->dev, (sizeof(int) * mas_node->node_info->num_connections), GFP_KERNEL); @@ -404,7 +397,7 @@ static int msm_bus_floor_setup_dev_conn(struct device *mas, struct device *slv) goto exit_setup_dev_conn; } - mas_node->node_info->dev_connections = devm_kzalloc(mas, + mas_node->node_info->dev_connections = devm_kzalloc(&mas_node->dev, (sizeof(struct device *) * mas_node->node_info->num_connections), GFP_KERNEL); @@ -416,7 +409,7 @@ static int msm_bus_floor_setup_dev_conn(struct device *mas, struct device *slv) goto exit_setup_dev_conn; } mas_node->node_info->connections[0] = slv_id; - mas_node->node_info->dev_connections[0] = slv; + mas_node->node_info->dev_connections[0] = &slv_node->dev; exit_setup_dev_conn: return ret; @@ -499,8 +492,6 @@ err_setup_floor_dev: int msm_bus_floor_init(struct device *dev) { - struct device *m_dev = NULL; - struct device *s_dev = NULL; struct msm_bus_node_device_type *mas_node = NULL; struct msm_bus_node_device_type *slv_node = NULL; struct msm_bus_node_device_type *bus_node = NULL; @@ -512,7 +503,7 @@ int msm_bus_floor_init(struct device *dev) goto exit_floor_init; } - bus_node = dev->platform_data; + bus_node = to_msm_bus_node(dev); if (!(bus_node && bus_node->node_info->is_fab_dev)) { pr_info("\n%s: Can't create voting client, not a fab device", __func__); @@ -520,57 +511,27 @@ int msm_bus_floor_init(struct device *dev) goto exit_floor_init; } - m_dev = kzalloc(sizeof(struct device), GFP_KERNEL); - if (!m_dev) { - pr_err("%s:Master Device alloc failed\n", __func__); - m_dev = NULL; - ret = -ENOMEM; - goto exit_floor_init; - } - - s_dev = kzalloc(sizeof(struct device), GFP_KERNEL); - if (!m_dev) { - pr_err("%s:Slave Device alloc failed\n", __func__); - s_dev = NULL; - kfree(m_dev); - ret = -ENOMEM; - m_dev = NULL; - goto exit_floor_init; - } - - ret = msm_bus_floor_init_dev(dev, m_dev, true); - if (ret) { + mas_node = msm_bus_floor_init_dev(dev, true); + if (IS_ERR_OR_NULL(mas_node)) { pr_err("\n%s: Error setting up master dev, bus %d", __func__, bus_node->node_info->id); - kfree(m_dev); - kfree(s_dev); goto exit_floor_init; } - ret = msm_bus_floor_init_dev(dev, s_dev, false); - if (ret) { + slv_node = msm_bus_floor_init_dev(dev, false); + if (IS_ERR_OR_NULL(slv_node)) { pr_err("\n%s: Error setting up slave dev, bus %d", __func__, bus_node->node_info->id); - kfree(m_dev); - kfree(s_dev); goto exit_floor_init; } - ret = msm_bus_floor_setup_dev_conn(m_dev, s_dev); + ret = msm_bus_floor_setup_dev_conn(mas_node, slv_node); if (ret) { pr_err("\n%s: Error setting up connections bus %d", __func__, bus_node->node_info->id); goto err_floor_init; } - mas_node = m_dev->platform_data; - slv_node = s_dev->platform_data; - if ((!(mas_node && slv_node))) { - pr_err("\n%s: Error getting mas/slv nodes bus %d", - __func__, bus_node->node_info->id); - goto err_floor_init; - } - ret = msm_bus_floor_setup_floor_dev(mas_node, slv_node, bus_node); if (ret) { pr_err("\n%s: Error getting mas/slv nodes bus %d", @@ -581,9 +542,7 @@ int msm_bus_floor_init(struct device *dev) exit_floor_init: return ret; err_floor_init: - device_unregister(m_dev); - device_unregister(s_dev); - kfree(m_dev); - kfree(s_dev); + kfree(mas_node); + kfree(slv_node); return ret; } diff --git a/drivers/platform/msm/msm_bus/msm_bus_fabric_adhoc.c b/drivers/platform/msm/msm_bus/msm_bus_fabric_adhoc.c index f7697a27b667..1734549ee2a2 100644 --- a/drivers/platform/msm/msm_bus/msm_bus_fabric_adhoc.c +++ b/drivers/platform/msm/msm_bus/msm_bus_fabric_adhoc.c @@ -23,39 +23,74 @@ #include "msm_bus_noc.h" #include "msm_bus_bimc.h" -ssize_t vrail_show(struct device *dev, struct device_attribute *attr, +static int msm_bus_dev_init_qos(struct device *dev, void *data); + +ssize_t bw_show(struct device *dev, struct device_attribute *attr, char *buf) { struct msm_bus_node_info_type *node_info = NULL; struct msm_bus_node_device_type *bus_node = NULL; + int i; + int off = 0; - bus_node = dev->platform_data; + bus_node = to_msm_bus_node(dev); if (!bus_node) return -EINVAL; + node_info = bus_node->node_info; - return snprintf(buf, PAGE_SIZE, "%u", node_info->vrail_comp); + for (i = 0; i < bus_node->num_lnodes; i++) { + if (!bus_node->lnode_list[i].in_use) + continue; + off += scnprintf((buf + off), PAGE_SIZE, + "[%d]:%s:Act_IB %llu Act_AB %llu Slp_IB %llu Slp_AB %llu\n", + i, bus_node->lnode_list[i].cl_name, + bus_node->lnode_list[i].lnode_ib[ACTIVE_CTX], + bus_node->lnode_list[i].lnode_ab[ACTIVE_CTX], + bus_node->lnode_list[i].lnode_ib[DUAL_CTX], + bus_node->lnode_list[i].lnode_ab[DUAL_CTX]); + trace_printk( + "[%d]:%s:Act_IB %llu Act_AB %llu Slp_IB %llu Slp_AB %llu\n", + i, bus_node->lnode_list[i].cl_name, + bus_node->lnode_list[i].lnode_ib[ACTIVE_CTX], + bus_node->lnode_list[i].lnode_ab[ACTIVE_CTX], + bus_node->lnode_list[i].lnode_ib[DUAL_CTX], + bus_node->lnode_list[i].lnode_ab[DUAL_CTX]); + } + off += scnprintf((buf + off), PAGE_SIZE, + "Max_Act_IB %llu Sum_Act_AB %llu Act_Util_fact %d Act_Vrail_comp %d\n", + bus_node->node_bw[ACTIVE_CTX].max_ib, + bus_node->node_bw[ACTIVE_CTX].sum_ab, + bus_node->node_bw[ACTIVE_CTX].util_used, + bus_node->node_bw[ACTIVE_CTX].vrail_used); + off += scnprintf((buf + off), PAGE_SIZE, + "Max_Slp_IB %llu Sum_Slp_AB %llu Slp_Util_fact %d Slp_Vrail_comp %d\n", + bus_node->node_bw[DUAL_CTX].max_ib, + bus_node->node_bw[DUAL_CTX].sum_ab, + bus_node->node_bw[DUAL_CTX].util_used, + bus_node->node_bw[DUAL_CTX].vrail_used); + trace_printk( + "Max_Act_IB %llu Sum_Act_AB %llu Act_Util_fact %d Act_Vrail_comp %d\n", + bus_node->node_bw[ACTIVE_CTX].max_ib, + bus_node->node_bw[ACTIVE_CTX].sum_ab, + bus_node->node_bw[ACTIVE_CTX].util_used, + bus_node->node_bw[ACTIVE_CTX].vrail_used); + trace_printk( + "Max_Slp_IB %llu Sum_Slp_AB %lluSlp_Util_fact %d Slp_Vrail_comp %d\n", + bus_node->node_bw[DUAL_CTX].max_ib, + bus_node->node_bw[DUAL_CTX].sum_ab, + bus_node->node_bw[DUAL_CTX].util_used, + bus_node->node_bw[DUAL_CTX].vrail_used); + return off; } -ssize_t vrail_store(struct device *dev, struct device_attribute *attr, +ssize_t bw_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct msm_bus_node_info_type *node_info = NULL; - struct msm_bus_node_device_type *bus_node = NULL; - int ret = 0; - - bus_node = dev->platform_data; - if (!bus_node) - return -EINVAL; - node_info = bus_node->node_info; - - ret = sscanf(buf, "%u", &node_info->vrail_comp); - if (ret != 1) - return -EINVAL; return count; } -DEVICE_ATTR(vrail, 0600, vrail_show, vrail_store); +DEVICE_ATTR(bw, 0600, bw_show, bw_store); struct static_rules_type { int num_rules; @@ -64,11 +99,105 @@ struct static_rules_type { static struct static_rules_type static_rules; -static int enable_nodeclk(struct nodeclk *nclk) +static int bus_get_reg(struct nodeclk *nclk, struct device *dev) +{ + int ret = 0; + struct msm_bus_node_device_type *node_dev; + + if (!(dev && nclk)) + return -ENXIO; + + node_dev = to_msm_bus_node(dev); + if (!strlen(nclk->reg_name)) { + dev_dbg(dev, "No regulator exist for node %d\n", + node_dev->node_info->id); + goto exit_of_get_reg; + } else { + if (!(IS_ERR_OR_NULL(nclk->reg))) + goto exit_of_get_reg; + + nclk->reg = devm_regulator_get(dev, nclk->reg_name); + if (IS_ERR_OR_NULL(nclk->reg)) { + dev_err(dev, "Error: Failed to get reg %s", + nclk->reg_name); + ret = + (IS_ERR(nclk->reg) ? PTR_ERR(nclk->reg) : -ENXIO); + } else { + dev_dbg(dev, "Successfully got regulator for %d\n", + node_dev->node_info->id); + } + } + +exit_of_get_reg: + return ret; +} + +static int bus_enable_reg(struct nodeclk *nclk) { int ret = 0; - if (!nclk->enable) { + if (!nclk) { + ret = -ENXIO; + goto exit_bus_enable_reg; + } + + if ((IS_ERR_OR_NULL(nclk->reg))) { + ret = -ENXIO; + goto exit_bus_enable_reg; + } + + ret = regulator_enable(nclk->reg); + if (ret) { + MSM_BUS_ERR("Failed to enable regulator for\n"); + goto exit_bus_enable_reg; + } + pr_debug("%s: Enabled Reg\n", __func__); +exit_bus_enable_reg: + return ret; +} + +static int bus_disable_reg(struct nodeclk *nclk) +{ + int ret = 0; + + if (!nclk) { + ret = -ENXIO; + goto exit_bus_disable_reg; + } + + if ((IS_ERR_OR_NULL(nclk->reg))) { + ret = -ENXIO; + goto exit_bus_disable_reg; + } + + regulator_disable(nclk->reg); + pr_debug("%s: Disabled Reg\n", __func__); +exit_bus_disable_reg: + return ret; +} + +static int enable_nodeclk(struct nodeclk *nclk, struct device *dev) +{ + int ret = 0; + + if (!nclk->enable && !nclk->setrate_only_clk) { + if (dev && strlen(nclk->reg_name)) { + if (IS_ERR_OR_NULL(nclk->reg)) { + ret = bus_get_reg(nclk, dev); + if (ret) { + dev_err(dev, "\nFailed to get reg %d", + ret); + goto exit_enable_nodeclk; + } + } + + ret = bus_enable_reg(nclk); + if (ret) { + dev_err(dev, "\nFailed to enable reg %d", + ret); + goto exit_enable_nodeclk; + } + } ret = clk_prepare_enable(nclk->clk); if (ret) { @@ -77,6 +206,7 @@ static int enable_nodeclk(struct nodeclk *nclk) } else nclk->enable = true; } +exit_enable_nodeclk: return ret; } @@ -84,9 +214,10 @@ static int disable_nodeclk(struct nodeclk *nclk) { int ret = 0; - if (nclk->enable) { + if (nclk->enable && !nclk->setrate_only_clk) { clk_disable_unprepare(nclk->clk); nclk->enable = false; + bus_disable_reg(nclk); } return ret; } @@ -95,77 +226,20 @@ static int setrate_nodeclk(struct nodeclk *nclk, long rate) { int ret = 0; - ret = clk_set_rate(nclk->clk, rate); + if (!nclk->enable_only_clk) + ret = clk_set_rate(nclk->clk, rate); if (ret) MSM_BUS_ERR("%s: failed to setrate clk", __func__); return ret; } -static int msm_bus_agg_fab_clks(struct device *bus_dev, void *data) -{ - struct msm_bus_node_device_type *node = NULL; - int ret = 0; - int ctx = *(int *)data; - - if (ctx >= NUM_CTX) { - MSM_BUS_ERR("%s: Invalid Context %d", __func__, ctx); - goto exit_agg_fab_clks; - } - - node = bus_dev->platform_data; - if (!node) { - MSM_BUS_ERR("%s: Can't get device info", __func__); - goto exit_agg_fab_clks; - } - - if (!node->node_info->is_fab_dev) { - struct msm_bus_node_device_type *bus_dev = NULL; - - bus_dev = node->node_info->bus_device->platform_data; - - if (node->cur_clk_hz[ctx] >= bus_dev->cur_clk_hz[ctx]) - bus_dev->cur_clk_hz[ctx] = node->cur_clk_hz[ctx]; - } - -exit_agg_fab_clks: - return ret; -} - -static int msm_bus_reset_fab_clks(struct device *bus_dev, void *data) -{ - struct msm_bus_node_device_type *node = NULL; - int ret = 0; - int ctx = *(int *)data; - - if (ctx >= NUM_CTX) { - MSM_BUS_ERR("%s: Invalid Context %d", __func__, ctx); - goto exit_reset_fab_clks; - } - - node = bus_dev->platform_data; - if (!node) { - MSM_BUS_ERR("%s: Can't get device info", __func__); - goto exit_reset_fab_clks; - } - - if (node->node_info->is_fab_dev) { - node->cur_clk_hz[ctx] = 0; - MSM_BUS_DBG("Resetting for node %d", node->node_info->id); - } -exit_reset_fab_clks: - return ret; -} - - -static int send_rpm_msg(struct device *device) +static int send_rpm_msg(struct msm_bus_node_device_type *ndev, int ctx) { int ret = 0; - int ctx; int rsc_type; - struct msm_bus_node_device_type *ndev = - device->platform_data; struct msm_rpm_kvp rpm_kvp; + int rpm_ctx; if (!ndev) { MSM_BUS_ERR("%s: Error getting node info.", __func__); @@ -176,54 +250,48 @@ static int send_rpm_msg(struct device *device) rpm_kvp.length = sizeof(uint64_t); rpm_kvp.key = RPM_MASTER_FIELD_BW; - for (ctx = MSM_RPM_CTX_ACTIVE_SET; ctx <= MSM_RPM_CTX_SLEEP_SET; - ctx++) { - if (ctx == MSM_RPM_CTX_ACTIVE_SET) - rpm_kvp.data = - (uint8_t *)&ndev->node_ab.ab[MSM_RPM_CTX_ACTIVE_SET]; - else { - rpm_kvp.data = - (uint8_t *) &ndev->node_ab.ab[MSM_RPM_CTX_SLEEP_SET]; - } + if (ctx == DUAL_CTX) + rpm_ctx = MSM_RPM_CTX_SLEEP_SET; + else + rpm_ctx = MSM_RPM_CTX_ACTIVE_SET; - if (ndev->node_info->mas_rpm_id != -1) { - rsc_type = RPM_BUS_MASTER_REQ; - ret = msm_rpm_send_message(ctx, rsc_type, - ndev->node_info->mas_rpm_id, &rpm_kvp, 1); - if (ret) { - MSM_BUS_ERR("%s: Failed to send RPM message:", + rpm_kvp.data = (uint8_t *)&ndev->node_bw[ctx].sum_ab; + + if (ndev->node_info->mas_rpm_id != -1) { + rsc_type = RPM_BUS_MASTER_REQ; + ret = msm_rpm_send_message(rpm_ctx, rsc_type, + ndev->node_info->mas_rpm_id, &rpm_kvp, 1); + if (ret) { + MSM_BUS_ERR("%s: Failed to send RPM message:", + __func__); + MSM_BUS_ERR("%s:Node Id %d RPM id %d", + __func__, ndev->node_info->id, + ndev->node_info->mas_rpm_id); + goto exit_send_rpm_msg; + } + } + + if (ndev->node_info->slv_rpm_id != -1) { + rsc_type = RPM_BUS_SLAVE_REQ; + ret = msm_rpm_send_message(rpm_ctx, rsc_type, + ndev->node_info->slv_rpm_id, &rpm_kvp, 1); + if (ret) { + MSM_BUS_ERR("%s: Failed to send RPM message:", __func__); - MSM_BUS_ERR("%s:Node Id %d RPM id %d", - __func__, ndev->node_info->id, - ndev->node_info->mas_rpm_id); - goto exit_send_rpm_msg; - } - } - - if (ndev->node_info->slv_rpm_id != -1) { - rsc_type = RPM_BUS_SLAVE_REQ; - ret = msm_rpm_send_message(ctx, rsc_type, - ndev->node_info->slv_rpm_id, &rpm_kvp, 1); - if (ret) { - MSM_BUS_ERR("%s: Failed to send RPM message:", - __func__); - MSM_BUS_ERR("%s: Node Id %d RPM id %d", - __func__, ndev->node_info->id, - ndev->node_info->slv_rpm_id); - goto exit_send_rpm_msg; - } + MSM_BUS_ERR("%s: Node Id %d RPM id %d", + __func__, ndev->node_info->id, + ndev->node_info->slv_rpm_id); + goto exit_send_rpm_msg; } } exit_send_rpm_msg: return ret; } -static int flush_bw_data(struct device *node_device, int ctx) +static int flush_bw_data(struct msm_bus_node_device_type *node_info, int ctx) { - struct msm_bus_node_device_type *node_info; int ret = 0; - node_info = node_device->platform_data; if (!node_info) { MSM_BUS_ERR("%s: Unable to find bus device for device %d", __func__, node_info->node_info->id); @@ -231,14 +299,20 @@ static int flush_bw_data(struct device *node_device, int ctx) goto exit_flush_bw_data; } - if (node_info->node_ab.dirty) { + if (node_info->node_bw[ctx].last_sum_ab != + node_info->node_bw[ctx].sum_ab) { if (node_info->ap_owned) { struct msm_bus_node_device_type *bus_device = - node_info->node_info->bus_device->platform_data; + to_msm_bus_node(node_info->node_info->bus_device); struct msm_bus_fab_device_type *fabdev = bus_device->fabdev; - if (fabdev && fabdev->noc_ops.update_bw_reg && + /* + * For AP owned ports, only care about the Active + * context bandwidth. + */ + if (fabdev && (ctx == ACTIVE_CTX) && + fabdev->noc_ops.update_bw_reg && fabdev->noc_ops.update_bw_reg (node_info->node_info->qos_params.mode)) ret = fabdev->noc_ops.set_bw(node_info, @@ -247,13 +321,14 @@ static int flush_bw_data(struct device *node_device, int ctx) fabdev->qos_off, fabdev->qos_freq); } else { - ret = send_rpm_msg(node_device); + ret = send_rpm_msg(node_info, ctx); if (ret) MSM_BUS_ERR("%s: Failed to send RPM msg for%d", __func__, node_info->node_info->id); } - node_info->node_ab.dirty = false; + node_info->node_bw[ctx].last_sum_ab = + node_info->node_bw[ctx].sum_ab; } exit_flush_bw_data: @@ -261,13 +336,11 @@ exit_flush_bw_data: } -static int flush_clk_data(struct device *node_device, int ctx) +static int flush_clk_data(struct msm_bus_node_device_type *node, int ctx) { - struct msm_bus_node_device_type *node; struct nodeclk *nodeclk = NULL; int ret = 0; - node = node_device->platform_data; if (!node) { MSM_BUS_ERR("Unable to find bus device"); ret = -ENODEV; @@ -275,16 +348,16 @@ static int flush_clk_data(struct device *node_device, int ctx) } nodeclk = &node->clk[ctx]; - if (node->node_info->is_fab_dev) { - if (nodeclk->rate != node->cur_clk_hz[ctx]) { - nodeclk->rate = node->cur_clk_hz[ctx]; - nodeclk->dirty = true; - } - } - if (nodeclk && nodeclk->clk && nodeclk->dirty) { + if (IS_ERR_OR_NULL(nodeclk) || IS_ERR_OR_NULL(nodeclk->clk)) + goto exit_flush_clk_data; + + if (nodeclk->rate != node->node_bw[ctx].cur_clk_hz) { long rounded_rate; + nodeclk->rate = node->node_bw[ctx].cur_clk_hz; + nodeclk->dirty = true; + if (nodeclk->rate) { rounded_rate = clk_round_rate(nodeclk->clk, nodeclk->rate); @@ -298,15 +371,17 @@ static int flush_clk_data(struct device *node_device, int ctx) goto exit_flush_clk_data; } - ret = enable_nodeclk(nodeclk); + ret = enable_nodeclk(nodeclk, &node->dev); if ((node->node_info->is_fab_dev) && - !IS_ERR_OR_NULL(node->qos_clk.clk)) - ret = enable_nodeclk(&node->qos_clk); + !IS_ERR_OR_NULL(node->bus_qos_clk.clk)) + ret = enable_nodeclk(&node->bus_qos_clk, + &node->dev); } else { if ((node->node_info->is_fab_dev) && - !IS_ERR_OR_NULL(node->qos_clk.clk)) - ret = disable_nodeclk(&node->qos_clk); + !IS_ERR_OR_NULL(node->bus_qos_clk.clk)) + ret = + disable_nodeclk(&node->bus_qos_clk); ret = disable_nodeclk(nodeclk); } @@ -319,52 +394,64 @@ static int flush_clk_data(struct device *node_device, int ctx) } MSM_BUS_DBG("%s: Updated %d clk to %llu", __func__, node->node_info->id, nodeclk->rate); - } exit_flush_clk_data: /* Reset the aggregated clock rate for fab devices*/ if (node && node->node_info->is_fab_dev) - node->cur_clk_hz[ctx] = 0; + node->node_bw[ctx].cur_clk_hz = 0; if (nodeclk) nodeclk->dirty = 0; return ret; } -int msm_bus_commit_data(int *dirty_nodes, int ctx, int num_dirty) +static int msm_bus_agg_fab_clks(struct msm_bus_node_device_type *bus_dev) { int ret = 0; - int i = 0; + struct msm_bus_node_device_type *node; + int ctx; - /* Aggregate the bus clocks */ - bus_for_each_dev(&msm_bus_type, NULL, (void *)&ctx, - msm_bus_agg_fab_clks); - - for (i = 0; i < num_dirty; i++) { - struct device *node_device = - bus_find_device(&msm_bus_type, NULL, - (void *)&dirty_nodes[i], - msm_bus_device_match_adhoc); - - if (!node_device) { - MSM_BUS_ERR("Can't find device for %d", dirty_nodes[i]); - continue; + list_for_each_entry(node, &bus_dev->devlist, dev_link) { + for (ctx = 0; ctx < NUM_CTX; ctx++) { + if (node->node_bw[ctx].cur_clk_hz >= + bus_dev->node_bw[ctx].cur_clk_hz) + bus_dev->node_bw[ctx].cur_clk_hz = + node->node_bw[ctx].cur_clk_hz; } - - ret = flush_bw_data(node_device, ctx); - if (ret) - MSM_BUS_ERR("%s: Error flushing bw data for node %d", - __func__, dirty_nodes[i]); - - ret = flush_clk_data(node_device, ctx); - if (ret) - MSM_BUS_ERR("%s: Error flushing clk data for node %d", - __func__, dirty_nodes[i]); } - kfree(dirty_nodes); - /* Aggregate the bus clocks */ - bus_for_each_dev(&msm_bus_type, NULL, (void *)&ctx, - msm_bus_reset_fab_clks); + return ret; +} + +int msm_bus_commit_data(struct list_head *clist) +{ + int ret = 0; + int ctx; + struct msm_bus_node_device_type *node; + struct msm_bus_node_device_type *node_tmp; + + list_for_each_entry(node, clist, link) { + /* Aggregate the bus clocks */ + if (node->node_info->is_fab_dev) + msm_bus_agg_fab_clks(node); + } + + list_for_each_entry_safe(node, node_tmp, clist, link) { + if (unlikely(node->node_info->defer_qos)) + msm_bus_dev_init_qos(&node->dev, NULL); + + for (ctx = 0; ctx < NUM_CTX; ctx++) { + ret = flush_clk_data(node, ctx); + if (ret) + MSM_BUS_ERR("%s: Err flushing clk data for:%d", + __func__, node->node_info->id); + ret = flush_bw_data(node, ctx); + if (ret) + MSM_BUS_ERR("%s: Error flushing bw data for %d", + __func__, node->node_info->id); + } + node->dirty = false; + list_del_init(&node->link); + } return ret; } @@ -394,142 +481,6 @@ exit_realloc_devmem: return ret; } - -static int add_dirty_node(int **dirty_nodes, int id, int *num_dirty) -{ - int i; - int found = 0; - int ret = 0; - int *dnode = NULL; - - for (i = 0; i < *num_dirty; i++) { - if ((*dirty_nodes)[i] == id) { - found = 1; - break; - } - } - - if (!found) { - (*num_dirty)++; - dnode = - krealloc(*dirty_nodes, sizeof(int) * (*num_dirty), - GFP_KERNEL); - - if (ZERO_OR_NULL_PTR(dnode)) { - MSM_BUS_ERR("%s: Failure allocating dirty nodes array", - __func__); - ret = -ENOMEM; - } else { - *dirty_nodes = dnode; - (*dirty_nodes)[(*num_dirty) - 1] = id; - } - } - - return ret; -} - -int msm_bus_update_bw(struct msm_bus_node_device_type *nodedev, int ctx, - int64_t add_bw, int **dirty_nodes, int *num_dirty) -{ - int ret = 0; - int i, j; - uint64_t cur_ab_slp = 0; - uint64_t cur_ab_act = 0; - - if (nodedev->node_info->virt_dev) - goto exit_update_bw; - - for (i = 0; i < NUM_CTX; i++) { - for (j = 0; j < nodedev->num_lnodes; j++) { - if (i == DUAL_CTX) { - cur_ab_act += - nodedev->lnode_list[j].lnode_ab[i]; - cur_ab_slp += - nodedev->lnode_list[j].lnode_ab[i]; - } else - cur_ab_act += - nodedev->lnode_list[j].lnode_ab[i]; - } - } - - if (nodedev->node_ab.ab[MSM_RPM_CTX_ACTIVE_SET] != cur_ab_act) { - nodedev->node_ab.ab[MSM_RPM_CTX_ACTIVE_SET] = cur_ab_act; - nodedev->node_ab.ab[MSM_RPM_CTX_SLEEP_SET] = cur_ab_slp; - nodedev->node_ab.dirty = true; - ret = add_dirty_node(dirty_nodes, nodedev->node_info->id, - num_dirty); - - if (ret) { - MSM_BUS_ERR("%s: Failed to add dirty node %d", __func__, - nodedev->node_info->id); - goto exit_update_bw; - } - } - -exit_update_bw: - return ret; -} - -int msm_bus_update_clks(struct msm_bus_node_device_type *nodedev, - int ctx, int **dirty_nodes, int *num_dirty) -{ - int status = 0; - struct nodeclk *nodeclk; - struct nodeclk *busclk; - struct msm_bus_node_device_type *bus_info = NULL; - uint64_t req_clk; - - bus_info = nodedev->node_info->bus_device->platform_data; - - if (!bus_info) { - MSM_BUS_ERR("%s: Unable to find bus device for device %d", - __func__, nodedev->node_info->id); - status = -ENODEV; - goto exit_set_clks; - } - - req_clk = nodedev->cur_clk_hz[ctx]; - busclk = &bus_info->clk[ctx]; - - if (busclk->rate != req_clk) { - busclk->rate = req_clk; - busclk->dirty = 1; - MSM_BUS_DBG("%s: Modifying bus clk %d Rate %llu", __func__, - bus_info->node_info->id, req_clk); - status = add_dirty_node(dirty_nodes, bus_info->node_info->id, - num_dirty); - - if (status) { - MSM_BUS_ERR("%s: Failed to add dirty node %d", __func__, - bus_info->node_info->id); - goto exit_set_clks; - } - } - - req_clk = nodedev->cur_clk_hz[ctx]; - nodeclk = &nodedev->clk[ctx]; - - if (IS_ERR_OR_NULL(nodeclk)) - goto exit_set_clks; - - if (!nodeclk->dirty || (nodeclk->dirty && (nodeclk->rate < req_clk))) { - nodeclk->rate = req_clk; - nodeclk->dirty = 1; - MSM_BUS_DBG("%s: Modifying node clk %d Rate %llu", __func__, - nodedev->node_info->id, req_clk); - status = add_dirty_node(dirty_nodes, nodedev->node_info->id, - num_dirty); - if (status) { - MSM_BUS_ERR("%s: Failed to add dirty node %d", __func__, - nodedev->node_info->id); - goto exit_set_clks; - } - } - -exit_set_clks: - return status; -} - static void msm_bus_fab_init_noc_ops(struct msm_bus_node_device_type *bus_dev) { switch (bus_dev->fabdev->bus_type) { @@ -544,117 +495,60 @@ static void msm_bus_fab_init_noc_ops(struct msm_bus_node_device_type *bus_dev) } } -static int msm_bus_qos_disable_clk(struct msm_bus_node_device_type *node, - int disable_bus_qos_clk) +static int msm_bus_disable_node_qos_clk(struct msm_bus_node_device_type *node) { struct msm_bus_node_device_type *bus_node = NULL; + int i; int ret = 0; - if (!node) { + if (!node || (!to_msm_bus_node(node->node_info->bus_device))) { ret = -ENXIO; - goto exit_disable_qos_clk; + goto exit_disable_node_qos_clk; } + bus_node = to_msm_bus_node(node->node_info->bus_device); - bus_node = node->node_info->bus_device->platform_data; + for (i = 0; i < bus_node->num_node_qos_clks; i++) + ret = disable_nodeclk(&bus_node->node_qos_clks[i]); - if (!bus_node) { - ret = -ENXIO; - goto exit_disable_qos_clk; - } - - if (disable_bus_qos_clk) - ret = disable_nodeclk(&bus_node->clk[DUAL_CTX]); - - if (ret) { - MSM_BUS_ERR("%s: Failed to disable bus clk, node %d", - __func__, node->node_info->id); - goto exit_disable_qos_clk; - } - - if (!IS_ERR_OR_NULL(node->qos_clk.clk)) { - ret = disable_nodeclk(&node->qos_clk); - - if (ret) { - MSM_BUS_ERR("%s: Failed to disable mas qos clk,node %d", - __func__, node->node_info->id); - goto exit_disable_qos_clk; - } - } - -exit_disable_qos_clk: +exit_disable_node_qos_clk: return ret; } -static int msm_bus_qos_enable_clk(struct msm_bus_node_device_type *node) +static int msm_bus_enable_node_qos_clk(struct msm_bus_node_device_type *node) { struct msm_bus_node_device_type *bus_node = NULL; + int i; + int ret; long rounded_rate; - int ret = 0; - int bus_qos_enabled = 0; - if (!node) { + if (!node || (!to_msm_bus_node(node->node_info->bus_device))) { ret = -ENXIO; - goto exit_enable_qos_clk; + goto exit_enable_node_qos_clk; } + bus_node = to_msm_bus_node(node->node_info->bus_device); - bus_node = node->node_info->bus_device->platform_data; - - if (!bus_node) { - ret = -ENXIO; - goto exit_enable_qos_clk; - } - - /* Check if the bus clk is already set before trying to set it - * Do this only during - * a. Bootup - * b. Only for bus clks - **/ - if (!clk_get_rate(bus_node->clk[DUAL_CTX].clk)) { - rounded_rate = clk_round_rate(bus_node->clk[DUAL_CTX].clk, 1); - ret = setrate_nodeclk(&bus_node->clk[DUAL_CTX], rounded_rate); - if (ret) { - MSM_BUS_ERR("%s: Failed to set bus clk, node %d", - __func__, node->node_info->id); - goto exit_enable_qos_clk; + for (i = 0; i < bus_node->num_node_qos_clks; i++) { + if (!bus_node->node_qos_clks[i].enable_only_clk) { + rounded_rate = + clk_round_rate( + bus_node->node_qos_clks[i].clk, 1); + ret = setrate_nodeclk(&bus_node->node_qos_clks[i], + rounded_rate); + if (ret) + MSM_BUS_ERR("%s: Failed set rate clk, node %d", + __func__, node->node_info->id); } - } - - ret = enable_nodeclk(&bus_node->clk[DUAL_CTX]); - if (ret) { - MSM_BUS_ERR("%s: Failed to enable bus clk, node %d", - __func__, node->node_info->id); - goto exit_enable_qos_clk; - } - bus_qos_enabled = 1; - - if (!IS_ERR_OR_NULL(bus_node->qos_clk.clk)) { - ret = enable_nodeclk(&bus_node->qos_clk); + ret = enable_nodeclk(&bus_node->node_qos_clks[i], + node->node_info->bus_device); if (ret) { - MSM_BUS_ERR("%s: Failed to enable bus QOS clk, node %d", - __func__, node->node_info->id); - goto exit_enable_qos_clk; - } - } - - if (!IS_ERR_OR_NULL(node->qos_clk.clk)) { - rounded_rate = clk_round_rate(node->qos_clk.clk, 1); - ret = setrate_nodeclk(&node->qos_clk, rounded_rate); - if (ret) { - MSM_BUS_ERR("%s: Failed to enable mas qos clk, node %d", - __func__, node->node_info->id); - goto exit_enable_qos_clk; + pr_err("%s: Failed to set Qos Clks ret %d", + __func__, ret); + msm_bus_disable_node_qos_clk(node); + goto exit_enable_node_qos_clk; } - ret = enable_nodeclk(&node->qos_clk); - if (ret) { - MSM_BUS_ERR("Err enable mas qos clk, node %d ret %d", - node->node_info->id, ret); - goto exit_enable_qos_clk; - } } - ret = bus_qos_enabled; - -exit_enable_qos_clk: +exit_enable_node_qos_clk: return ret; } @@ -677,7 +571,7 @@ int msm_bus_enable_limiter(struct msm_bus_node_device_type *node_dev, goto exit_enable_limiter; } - bus_node_dev = node_dev->node_info->bus_device->platform_data; + bus_node_dev = to_msm_bus_node(node_dev->node_info->bus_device); if (!bus_node_dev) { MSM_BUS_ERR("Unable to get bus device infofor %d", node_dev->node_info->id); @@ -709,8 +603,7 @@ static int msm_bus_dev_init_qos(struct device *dev, void *data) int ret = 0; struct msm_bus_node_device_type *node_dev = NULL; - node_dev = dev->platform_data; - + node_dev = to_msm_bus_node(dev); if (!node_dev) { MSM_BUS_ERR("%s: Unable to get node device info" , __func__); ret = -ENXIO; @@ -722,7 +615,8 @@ static int msm_bus_dev_init_qos(struct device *dev, void *data) if (node_dev->ap_owned) { struct msm_bus_node_device_type *bus_node_info; - bus_node_info = node_dev->node_info->bus_device->platform_data; + bus_node_info = + to_msm_bus_node(node_dev->node_info->bus_device); if (!bus_node_info) { MSM_BUS_ERR("%s: Unable to get bus device infofor %d", @@ -742,10 +636,11 @@ static int msm_bus_dev_init_qos(struct device *dev, void *data) if (bus_node_info->fabdev->bypass_qos_prg) goto exit_init_qos; - ret = msm_bus_qos_enable_clk(node_dev); + ret = msm_bus_enable_node_qos_clk(node_dev); if (ret < 0) { MSM_BUS_ERR("Can't Enable QoS clk %d", node_dev->node_info->id); + node_dev->node_info->defer_qos = true; goto exit_init_qos; } @@ -755,7 +650,8 @@ static int msm_bus_dev_init_qos(struct device *dev, void *data) bus_node_info->fabdev->base_offset, bus_node_info->fabdev->qos_off, bus_node_info->fabdev->qos_freq); - ret = msm_bus_qos_disable_clk(node_dev, ret); + ret = msm_bus_disable_node_qos_clk(node_dev); + node_dev->node_info->defer_qos = false; } } else MSM_BUS_ERR("%s: Skipping QOS init for %d", @@ -772,7 +668,7 @@ static int msm_bus_fabric_init(struct device *dev, struct msm_bus_node_device_type *node_dev = NULL; int ret = 0; - node_dev = dev->platform_data; + node_dev = to_msm_bus_node(dev); if (!node_dev) { MSM_BUS_ERR("%s: Unable to get bus device info" , __func__); ret = -ENXIO; @@ -801,8 +697,6 @@ static int msm_bus_fabric_init(struct device *dev, fabdev->qos_freq = pdata->fabdev->qos_freq; fabdev->bus_type = pdata->fabdev->bus_type; fabdev->bypass_qos_prg = pdata->fabdev->bypass_qos_prg; - fabdev->util_fact = pdata->fabdev->util_fact; - fabdev->vrail_comp = pdata->fabdev->vrail_comp; msm_bus_fab_init_noc_ops(node_dev); fabdev->qos_base = devm_ioremap(dev, @@ -823,27 +717,71 @@ static int msm_bus_init_clk(struct device *bus_dev, struct msm_bus_node_device_type *pdata) { unsigned int ctx; - int ret = 0; - struct msm_bus_node_device_type *node_dev = bus_dev->platform_data; + struct msm_bus_node_device_type *node_dev = to_msm_bus_node(bus_dev); + int i; for (ctx = 0; ctx < NUM_CTX; ctx++) { if (!IS_ERR_OR_NULL(pdata->clk[ctx].clk)) { node_dev->clk[ctx].clk = pdata->clk[ctx].clk; + node_dev->clk[ctx].enable_only_clk = + pdata->clk[ctx].enable_only_clk; + node_dev->clk[ctx].setrate_only_clk = + pdata->clk[ctx].setrate_only_clk; node_dev->clk[ctx].enable = false; node_dev->clk[ctx].dirty = false; - MSM_BUS_ERR("%s: Valid node clk node %d ctx %d", + strlcpy(node_dev->clk[ctx].reg_name, + pdata->clk[ctx].reg_name, MAX_REG_NAME); + node_dev->clk[ctx].reg = NULL; + bus_get_reg(&node_dev->clk[ctx], bus_dev); + pr_info("%s: Valid node clk node %d ctx %d\n", __func__, node_dev->node_info->id, ctx); } } - if (!IS_ERR_OR_NULL(pdata->qos_clk.clk)) { - node_dev->qos_clk.clk = pdata->qos_clk.clk; - node_dev->qos_clk.enable = false; - MSM_BUS_ERR("%s: Valid Iface clk node %d", __func__, + if (!IS_ERR_OR_NULL(pdata->bus_qos_clk.clk)) { + node_dev->bus_qos_clk.clk = pdata->bus_qos_clk.clk; + node_dev->bus_qos_clk.enable_only_clk = + pdata->bus_qos_clk.enable_only_clk; + node_dev->bus_qos_clk.setrate_only_clk = + pdata->bus_qos_clk.setrate_only_clk; + node_dev->bus_qos_clk.enable = false; + strlcpy(node_dev->bus_qos_clk.reg_name, + pdata->bus_qos_clk.reg_name, MAX_REG_NAME); + node_dev->bus_qos_clk.reg = NULL; + pr_info("%s: Valid bus qos clk node %d\n", __func__, node_dev->node_info->id); } - return ret; + if (pdata->num_node_qos_clks) { + node_dev->num_node_qos_clks = pdata->num_node_qos_clks; + node_dev->node_qos_clks = devm_kzalloc(bus_dev, + (node_dev->num_node_qos_clks * sizeof(struct nodeclk)), + GFP_KERNEL); + if (!node_dev->node_qos_clks) { + dev_err(bus_dev, "Failed to alloc memory for qos clk"); + return -ENOMEM; + } + + for (i = 0; i < pdata->num_node_qos_clks; i++) { + node_dev->node_qos_clks[i].clk = + pdata->node_qos_clks[i].clk; + node_dev->node_qos_clks[i].enable_only_clk = + pdata->node_qos_clks[i].enable_only_clk; + node_dev->node_qos_clks[i].setrate_only_clk = + pdata->node_qos_clks[i].setrate_only_clk; + node_dev->node_qos_clks[i].enable = false; + strlcpy(node_dev->node_qos_clks[i].reg_name, + pdata->node_qos_clks[i].reg_name, MAX_REG_NAME); + node_dev->node_qos_clks[i].reg = NULL; + pr_info("%s: Valid qos clk[%d] node %d %d Reg%s\n", + __func__, i, + node_dev->node_info->id, + node_dev->num_node_qos_clks, + node_dev->node_qos_clks[i].reg_name); + } + } + + return 0; } static int msm_bus_copy_node_info(struct msm_bus_node_device_type *pdata, @@ -854,7 +792,7 @@ static int msm_bus_copy_node_info(struct msm_bus_node_device_type *pdata, struct msm_bus_node_info_type *pdata_node_info = NULL; struct msm_bus_node_device_type *bus_node = NULL; - bus_node = bus_dev->platform_data; + bus_node = to_msm_bus_node(bus_dev); if (!bus_node || !pdata) { ret = -ENXIO; @@ -874,8 +812,6 @@ static int msm_bus_copy_node_info(struct msm_bus_node_device_type *pdata, node_info->num_connections = pdata_node_info->num_connections; node_info->num_blist = pdata_node_info->num_blist; node_info->num_qports = pdata_node_info->num_qports; - node_info->num_aggports = pdata_node_info->num_aggports; - node_info->buswidth = pdata_node_info->buswidth; node_info->virt_dev = pdata_node_info->virt_dev; node_info->is_fab_dev = pdata_node_info->is_fab_dev; node_info->qos_params.mode = pdata_node_info->qos_params.mode; @@ -890,8 +826,28 @@ static int msm_bus_copy_node_info(struct msm_bus_node_device_type *pdata, node_info->qos_params.thmp = pdata_node_info->qos_params.thmp; node_info->qos_params.ws = pdata_node_info->qos_params.ws; node_info->qos_params.bw_buffer = pdata_node_info->qos_params.bw_buffer; - node_info->util_fact = pdata_node_info->util_fact; - node_info->vrail_comp = pdata_node_info->vrail_comp; + node_info->agg_params.buswidth = pdata_node_info->agg_params.buswidth; + node_info->agg_params.agg_scheme = + pdata_node_info->agg_params.agg_scheme; + node_info->agg_params.vrail_comp = + pdata_node_info->agg_params.vrail_comp; + node_info->agg_params.num_aggports = + pdata_node_info->agg_params.num_aggports; + node_info->agg_params.num_util_levels = + pdata_node_info->agg_params.num_util_levels; + node_info->agg_params.util_levels = devm_kzalloc(bus_dev, + sizeof(struct node_util_levels_type) * + node_info->agg_params.num_util_levels, + GFP_KERNEL); + if (!node_info->agg_params.util_levels) { + MSM_BUS_ERR("%s: Agg util level alloc failed\n", __func__); + ret = -ENOMEM; + goto exit_copy_node_info; + } + memcpy(node_info->agg_params.util_levels, + pdata_node_info->agg_params.util_levels, + sizeof(struct node_util_levels_type) * + pdata_node_info->agg_params.num_util_levels); node_info->dev_connections = devm_kzalloc(bus_dev, sizeof(struct device *) * @@ -975,25 +931,19 @@ static struct device *msm_bus_device_init( struct msm_bus_node_info_type *node_info = NULL; int ret = 0; - bus_dev = kzalloc(sizeof(struct device), GFP_KERNEL); - if (!bus_dev) { - MSM_BUS_ERR("%s:Device alloc failed\n", __func__); - bus_dev = NULL; - goto exit_device_init; - } /** * Init here so we can use devm calls */ - device_initialize(bus_dev); - bus_node = devm_kzalloc(bus_dev, - sizeof(struct msm_bus_node_device_type), GFP_KERNEL); + bus_node = kzalloc(sizeof(struct msm_bus_node_device_type), GFP_KERNEL); if (!bus_node) { MSM_BUS_ERR("%s:Bus node alloc failed\n", __func__); kfree(bus_dev); bus_dev = NULL; goto exit_device_init; } + bus_dev = &bus_node->dev; + device_initialize(bus_dev); node_info = devm_kzalloc(bus_dev, sizeof(struct msm_bus_node_info_type), GFP_KERNEL); @@ -1007,7 +957,7 @@ static struct device *msm_bus_device_init( bus_node->node_info = node_info; bus_node->ap_owned = pdata->ap_owned; - bus_dev->platform_data = bus_node; + bus_dev->of_node = pdata->of_node; if (msm_bus_copy_node_info(pdata, bus_dev) < 0) { devm_kfree(bus_dev, bus_node); @@ -1034,7 +984,8 @@ static struct device *msm_bus_device_init( bus_dev = NULL; goto exit_device_init; } - device_create_file(bus_dev, &dev_attr_vrail); + device_create_file(bus_dev, &dev_attr_bw); + INIT_LIST_HEAD(&bus_node->devlist); exit_device_init: return bus_dev; @@ -1045,8 +996,9 @@ static int msm_bus_setup_dev_conn(struct device *bus_dev, void *data) struct msm_bus_node_device_type *bus_node = NULL; int ret = 0; int j; + struct msm_bus_node_device_type *fab; - bus_node = bus_dev->platform_data; + bus_node = to_msm_bus_node(bus_dev); if (!bus_node) { MSM_BUS_ERR("%s: Can't get device info", __func__); ret = -ENODEV; @@ -1069,6 +1021,8 @@ static int msm_bus_setup_dev_conn(struct device *bus_dev, void *data) goto exit_setup_dev_conn; } bus_node->node_info->bus_device = bus_parent_device; + fab = to_msm_bus_node(bus_parent_device); + list_add_tail(&bus_node->dev_link, &fab->devlist); } bus_node->node_info->is_traversed = false; @@ -1115,7 +1069,7 @@ static int msm_bus_node_debug(struct device *bus_dev, void *data) int ret = 0; struct msm_bus_node_device_type *bus_node = NULL; - bus_node = bus_dev->platform_data; + bus_node = to_msm_bus_node(bus_dev); if (!bus_node) { MSM_BUS_ERR("%s: Can't get device info", __func__); ret = -ENODEV; @@ -1123,11 +1077,10 @@ static int msm_bus_node_debug(struct device *bus_dev, void *data) } MSM_BUS_DBG("Device = %d buswidth %u", bus_node->node_info->id, - bus_node->node_info->buswidth); + bus_node->node_info->agg_params.buswidth); for (j = 0; j < bus_node->node_info->num_connections; j++) { struct msm_bus_node_device_type *bdev = - (struct msm_bus_node_device_type *) - bus_node->node_info->dev_connections[j]->platform_data; + to_msm_bus_node(bus_node->node_info->dev_connections[j]); MSM_BUS_DBG("\n\t Connection[%d] %d", j, bdev->node_info->id); } @@ -1138,6 +1091,26 @@ exit_node_debug: return ret; } +static int msm_bus_free_dev(struct device *dev, void *data) +{ + struct msm_bus_node_device_type *bus_node = NULL; + + bus_node = to_msm_bus_node(dev); + + if (bus_node) + MSM_BUS_ERR("\n%s: Removing device %d", __func__, + bus_node->node_info->id); + device_unregister(dev); + kfree(bus_node); + return 0; +} + +int msm_bus_device_remove(struct platform_device *pdev) +{ + bus_for_each_dev(&msm_bus_type, NULL, NULL, msm_bus_free_dev); + return 0; +} + static int msm_bus_device_probe(struct platform_device *pdev) { unsigned int i, ret; @@ -1170,6 +1143,11 @@ static int msm_bus_device_probe(struct platform_device *pdev) } ret = msm_bus_init_clk(node_dev, &pdata->info[i]); + if (ret) { + MSM_BUS_ERR("\n Failed to init bus clk. ret %d", ret); + msm_bus_device_remove(pdev); + goto exit_device_probe; + } /*Is this a fabric device ?*/ if (pdata->info[i].node_info->is_fab_dev) { MSM_BUS_DBG("%s: %d is a fab", __func__, @@ -1237,24 +1215,6 @@ int msm_bus_device_rules_remove(struct platform_device *pdev) return 0; } -static int msm_bus_free_dev(struct device *dev, void *data) -{ - struct msm_bus_node_device_type *bus_node = NULL; - - bus_node = dev->platform_data; - - if (bus_node) - MSM_BUS_ERR("\n%s: Removing device %d", __func__, - bus_node->node_info->id); - device_unregister(dev); - return 0; -} - -int msm_bus_device_remove(struct platform_device *pdev) -{ - bus_for_each_dev(&msm_bus_type, NULL, NULL, msm_bus_free_dev); - return 0; -} static struct of_device_id rules_match[] = { {.compatible = "qcom,msm-bus-static-bw-rules"}, diff --git a/drivers/platform/msm/msm_bus/msm_bus_noc.c b/drivers/platform/msm/msm_bus/msm_bus_noc.c index d91b0e0fca31..7f7c74202412 100644 --- a/drivers/platform/msm/msm_bus/msm_bus_noc.c +++ b/drivers/platform/msm/msm_bus/msm_bus_noc.c @@ -32,28 +32,6 @@ #define NOC_QOS_REG_BASE(b, o) ((b) + (o)) -#define NOC_QOS_ID_COREIDn_ADDR(b, o, n, d) \ - (NOC_QOS_REG_BASE(b, o) + (d) * (n)) -enum noc_qos_id_coreidn { - NOC_QOS_ID_COREIDn_RMSK = 0xffffffff, - NOC_QOS_ID_COREIDn_MAXn = 32, - NOC_QOS_ID_COREIDn_CORECHSUM_BMSK = 0xffffff00, - NOC_QOS_ID_COREIDn_CORECHSUM_SHFT = 0x8, - NOC_QOS_ID_COREIDn_CORETYPEID_BMSK = 0xff, - NOC_QOS_ID_COREIDn_CORETYPEID_SHFT = 0x0, -}; - -#define NOC_QOS_ID_REVISIONIDn_ADDR(b, o, n, d) \ - (NOC_QOS_REG_BASE(b, o) + 0x4 + (d) * (n)) -enum noc_qos_id_revisionidn { - NOC_QOS_ID_REVISIONIDn_RMSK = 0xffffffff, - NOC_QOS_ID_REVISIONIDn_MAXn = 32, - NOC_QOS_ID_REVISIONIDn_FLEXNOCID_BMSK = 0xffffff00, - NOC_QOS_ID_REVISIONIDn_FLEXNOCID_SHFT = 0x8, - NOC_QOS_ID_REVISIONIDn_USERID_BMSK = 0xff, - NOC_QOS_ID_REVISIONIDn_USERID_SHFT = 0x0, -}; - #define NOC_QOS_PRIORITYn_ADDR(b, o, n, d) \ (NOC_QOS_REG_BASE(b, o) + 0x8 + (d) * (n)) enum noc_qos_id_priorityn { @@ -657,238 +635,6 @@ static int msm_bus_noc_port_unhalt(uint32_t haltid, uint8_t mport) return 0; } -static int msm_bus_noc_qos_init(struct msm_bus_node_device_type *info, - void __iomem *qos_base, - uint32_t qos_off, uint32_t qos_delta, - uint32_t qos_freq) -{ - struct msm_bus_noc_qos_priority prio; - int ret = 0; - int i; - - prio.p1 = info->node_info->qos_params.prio1; - prio.p0 = info->node_info->qos_params.prio0; - - if (!info->node_info->qport) { - MSM_BUS_DBG("No QoS Ports to init\n"); - ret = 0; - goto err_qos_init; - } - - for (i = 0; i < info->node_info->num_qports; i++) { - if (info->node_info->qos_params.mode != NOC_QOS_MODE_BYPASS) { - noc_set_qos_priority(qos_base, qos_off, - info->node_info->qport[i], qos_delta, - &prio); - - if (info->node_info->qos_params.mode != - NOC_QOS_MODE_FIXED) { - struct msm_bus_noc_qos_bw qbw; - qbw.ws = info->node_info->qos_params.ws; - qbw.bw = 0; - msm_bus_noc_set_qos_bw(qos_base, qos_off, - qos_freq, - info->node_info->qport[i], - qos_delta, - info->node_info->qos_params.mode, - &qbw); - } - } - - noc_set_qos_mode(qos_base, qos_off, info->node_info->qport[i], - qos_delta, info->node_info->qos_params.mode, - (1 << info->node_info->qos_params.mode)); - } -err_qos_init: - return ret; -} - -static int msm_bus_noc_set_bw(struct msm_bus_node_device_type *dev, - void __iomem *qos_base, - uint32_t qos_off, uint32_t qos_delta, - uint32_t qos_freq) -{ - int ret = 0; - uint64_t bw = 0; - int i; - struct msm_bus_node_info_type *info = dev->node_info; - - if (info && info->num_qports && - ((info->qos_params.mode == NOC_QOS_MODE_REGULATOR) || - (info->qos_params.mode == - NOC_QOS_MODE_LIMITER))) { - struct msm_bus_noc_qos_bw qos_bw; - - bw = msm_bus_div64(info->num_qports, - dev->node_ab.ab[DUAL_CTX]); - - for (i = 0; i < info->num_qports; i++) { - if (!info->qport) { - MSM_BUS_DBG("No qos ports to update!\n"); - break; - } - - qos_bw.bw = bw; - qos_bw.ws = info->qos_params.ws; - msm_bus_noc_set_qos_bw(qos_base, qos_off, qos_freq, - info->qport[i], qos_delta, - (1 << info->qos_params.mode), &qos_bw); - MSM_BUS_DBG("NOC: QoS: Update mas_bw: ws: %u\n", - qos_bw.ws); - } - } - return ret; -} - -static int msm_bus_noc_set_lim_mode(struct msm_bus_node_device_type *info, - void __iomem *qos_base, uint32_t qos_off, - uint32_t qos_delta, uint32_t qos_freq, - u64 lim_bw) -{ - int i; - - if (info && info->node_info->num_qports) { - struct msm_bus_noc_qos_bw qos_bw; - if (lim_bw != info->node_info->lim_bw) { - for (i = 0; i < info->node_info->num_qports; i++) { - qos_bw.bw = lim_bw; - qos_bw.ws = info->node_info->qos_params.ws; - msm_bus_noc_set_qos_bw(qos_base, - qos_off, qos_freq, - info->node_info->qport[i], qos_delta, - (1 << NOC_QOS_MODE_LIMITER), &qos_bw); - } - info->node_info->lim_bw = lim_bw; - } - - for (i = 0; i < info->node_info->num_qports; i++) { - noc_set_qos_mode(qos_base, qos_off, - info->node_info->qport[i], - qos_delta, - NOC_QOS_MODE_LIMITER, - (1 << NOC_QOS_MODE_LIMITER)); - } - } - - return 0; -} - -static int msm_bus_noc_set_reg_mode(struct msm_bus_node_device_type *info, - void __iomem *qos_base, uint32_t qos_off, - uint32_t qos_delta, uint32_t qos_freq, - u64 lim_bw) -{ - int i; - - if (info && info->node_info->num_qports) { - struct msm_bus_noc_qos_priority prio; - struct msm_bus_noc_qos_bw qos_bw; - - for (i = 0; i < info->node_info->num_qports; i++) { - prio.p1 = - info->node_info->qos_params.reg_prio1; - prio.p0 = - info->node_info->qos_params.reg_prio0; - noc_set_qos_priority(qos_base, qos_off, - info->node_info->qport[i], - qos_delta, - &prio); - } - - if (lim_bw != info->node_info->lim_bw) { - for (i = 0; i < info->node_info->num_qports; i++) { - qos_bw.bw = lim_bw; - qos_bw.ws = info->node_info->qos_params.ws; - msm_bus_noc_set_qos_bw(qos_base, qos_off, - qos_freq, - info->node_info->qport[i], qos_delta, - (1 << NOC_QOS_MODE_REGULATOR), &qos_bw); - } - info->node_info->lim_bw = lim_bw; - } - - for (i = 0; i < info->node_info->num_qports; i++) { - noc_set_qos_mode(qos_base, qos_off, - info->node_info->qport[i], - qos_delta, - NOC_QOS_MODE_REGULATOR, - (1 << NOC_QOS_MODE_REGULATOR)); - } - } - return 0; -} - -static int msm_bus_noc_set_def_mode(struct msm_bus_node_device_type *info, - void __iomem *qos_base, uint32_t qos_off, - uint32_t qos_delta, uint32_t qos_freq, - u64 lim_bw) -{ - int i; - - for (i = 0; i < info->node_info->num_qports; i++) { - if (info->node_info->qos_params.mode == - NOC_QOS_MODE_FIXED) { - struct msm_bus_noc_qos_priority prio; - - prio.p1 = - info->node_info->qos_params.prio1; - prio.p0 = - info->node_info->qos_params.prio0; - noc_set_qos_priority(qos_base, qos_off, - info->node_info->qport[i], - qos_delta, &prio); - } - noc_set_qos_mode(qos_base, qos_off, - info->node_info->qport[i], - qos_delta, - info->node_info->qos_params.mode, - (1 << info->node_info->qos_params.mode)); - } - return 0; -} - -static int msm_bus_noc_limit_mport(struct msm_bus_node_device_type *info, - void __iomem *qos_base, uint32_t qos_off, - uint32_t qos_delta, uint32_t qos_freq, - int enable_lim, u64 lim_bw) -{ - int ret = 0; - - if (!(info && info->node_info->num_qports)) { - MSM_BUS_ERR("Invalid Node info or no Qports to program"); - ret = -ENXIO; - goto exit_limit_mport; - } - - if (lim_bw) { - switch (enable_lim) { - case THROTTLE_REG: - { - msm_bus_noc_set_reg_mode(info, qos_base, qos_off, - qos_delta, qos_freq, lim_bw); - break; - } - case THROTTLE_ON: - { - msm_bus_noc_set_lim_mode(info, qos_base, qos_off, - qos_delta, qos_freq, lim_bw); - break; - } - default: - { - msm_bus_noc_set_def_mode(info, qos_base, qos_off, - qos_delta, qos_freq, lim_bw); - break; - } - } - } else - msm_bus_noc_set_def_mode(info, qos_base, qos_off, - qos_delta, qos_freq, lim_bw); - -exit_limit_mport: - return ret; -} - int msm_bus_noc_hw_init(struct msm_bus_fabric_registration *pdata, struct msm_bus_hw_algorithm *hw_algo) { @@ -909,17 +655,3 @@ int msm_bus_noc_hw_init(struct msm_bus_fabric_registration *pdata, return 0; } -int msm_bus_noc_set_ops(struct msm_bus_node_device_type *bus_dev) -{ - if (!bus_dev) - return -ENODEV; - else { - bus_dev->fabdev->noc_ops.qos_init = msm_bus_noc_qos_init; - bus_dev->fabdev->noc_ops.set_bw = msm_bus_noc_set_bw; - bus_dev->fabdev->noc_ops.limit_mport = msm_bus_noc_limit_mport; - bus_dev->fabdev->noc_ops.update_bw_reg = - msm_bus_noc_update_bw_reg; - } - return 0; -} -EXPORT_SYMBOL(msm_bus_noc_set_ops); diff --git a/drivers/platform/msm/msm_bus/msm_bus_noc_adhoc.c b/drivers/platform/msm/msm_bus/msm_bus_noc_adhoc.c new file mode 100644 index 000000000000..a47faaccf16d --- /dev/null +++ b/drivers/platform/msm/msm_bus/msm_bus_noc_adhoc.c @@ -0,0 +1,590 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "AXI: NOC: %s(): " fmt, __func__ + +#include +#include +#include +#include "msm_bus_core.h" +#include "msm_bus_noc.h" +#include "msm_bus_adhoc.h" + +/* NOC_QOS generic */ +#define __CLZ(x) ((8 * sizeof(uint32_t)) - 1 - __fls(x)) +#define SAT_SCALE 16 /* 16 bytes minimum for saturation */ +#define BW_SCALE 256 /* 1/256 byte per cycle unit */ +#define QOS_DEFAULT_BASEOFFSET 0x00003000 +#define QOS_DEFAULT_DELTA 0x80 +#define MAX_BW_FIELD (NOC_QOS_BWn_BW_BMSK >> NOC_QOS_BWn_BW_SHFT) +#define MAX_SAT_FIELD (NOC_QOS_SATn_SAT_BMSK >> NOC_QOS_SATn_SAT_SHFT) +#define MIN_SAT_FIELD 1 +#define MIN_BW_FIELD 1 + +#define NOC_QOS_REG_BASE(b, o) ((b) + (o)) + +#define NOC_QOS_PRIORITYn_ADDR(b, o, n, d) \ + (NOC_QOS_REG_BASE(b, o) + 0x8 + (d) * (n)) +enum noc_qos_id_priorityn { + NOC_QOS_PRIORITYn_RMSK = 0x0000000f, + NOC_QOS_PRIORITYn_MAXn = 32, + NOC_QOS_PRIORITYn_P1_BMSK = 0xc, + NOC_QOS_PRIORITYn_P1_SHFT = 0x2, + NOC_QOS_PRIORITYn_P0_BMSK = 0x3, + NOC_QOS_PRIORITYn_P0_SHFT = 0x0, +}; + +#define NOC_QOS_MODEn_ADDR(b, o, n, d) \ + (NOC_QOS_REG_BASE(b, o) + 0xC + (d) * (n)) +enum noc_qos_id_moden_rmsk { + NOC_QOS_MODEn_RMSK = 0x00000003, + NOC_QOS_MODEn_MAXn = 32, + NOC_QOS_MODEn_MODE_BMSK = 0x3, + NOC_QOS_MODEn_MODE_SHFT = 0x0, +}; + +#define NOC_QOS_BWn_ADDR(b, o, n, d) \ + (NOC_QOS_REG_BASE(b, o) + 0x10 + (d) * (n)) +enum noc_qos_id_bwn { + NOC_QOS_BWn_RMSK = 0x0000ffff, + NOC_QOS_BWn_MAXn = 32, + NOC_QOS_BWn_BW_BMSK = 0xffff, + NOC_QOS_BWn_BW_SHFT = 0x0, +}; + +/* QOS Saturation registers */ +#define NOC_QOS_SATn_ADDR(b, o, n, d) \ + (NOC_QOS_REG_BASE(b, o) + 0x14 + (d) * (n)) +enum noc_qos_id_saturationn { + NOC_QOS_SATn_RMSK = 0x000003ff, + NOC_QOS_SATn_MAXn = 32, + NOC_QOS_SATn_SAT_BMSK = 0x3ff, + NOC_QOS_SATn_SAT_SHFT = 0x0, +}; + +static int noc_div(uint64_t *a, uint32_t b) +{ + if ((*a > 0) && (*a < b)) { + *a = 0; + return 1; + } else { + return do_div(*a, b); + } +} + +/** + * Calculates bw hardware is using from register values + * bw returned is in bytes/sec + */ +static uint64_t noc_bw(uint32_t bw_field, uint32_t qos_freq) +{ + uint64_t res; + uint32_t rem, scale; + + res = 2 * qos_freq * bw_field; + scale = BW_SCALE * 1000; + rem = noc_div(&res, scale); + MSM_BUS_DBG("NOC: Calculated bw: %llu\n", res * 1000000ULL); + return res * 1000000ULL; +} + +/** + * Calculate the max BW in Bytes/s for a given time-base. + */ +static uint32_t noc_bw_ceil(long int bw_field, uint32_t qos_freq_khz) +{ + uint64_t bw_temp = 2 * qos_freq_khz * bw_field; + uint32_t scale = 1000 * BW_SCALE; + + noc_div(&bw_temp, scale); + return bw_temp * 1000000; +} +#define MAX_BW(timebase) noc_bw_ceil(MAX_BW_FIELD, (timebase)) + +/** + * Calculates ws hardware is using from register values + * ws returned is in nanoseconds + */ +static uint32_t noc_ws(uint64_t bw, uint32_t sat, uint32_t qos_freq) +{ + if (bw && qos_freq) { + uint32_t bwf = bw * qos_freq; + uint64_t scale = 1000000000000LL * BW_SCALE * + SAT_SCALE * sat; + noc_div(&scale, bwf); + MSM_BUS_DBG("NOC: Calculated ws: %llu\n", scale); + return scale; + } + + return 0; +} +#define MAX_WS(bw, timebase) noc_ws((bw), MAX_SAT_FIELD, (timebase)) + +/* Calculate bandwidth field value for requested bandwidth */ +static uint32_t noc_bw_field(uint64_t bw_bps, uint32_t qos_freq_khz) +{ + uint32_t bw_field = 0; + + if (bw_bps) { + uint32_t rem; + uint64_t bw_capped = min_t(uint64_t, bw_bps, + MAX_BW(qos_freq_khz)); + uint64_t bwc = bw_capped * BW_SCALE; + uint64_t qf = 2 * qos_freq_khz * 1000; + + rem = noc_div(&bwc, qf); + bw_field = (uint32_t)max_t(unsigned long, bwc, MIN_BW_FIELD); + bw_field = (uint32_t)min_t(unsigned long, bw_field, + MAX_BW_FIELD); + } + + MSM_BUS_DBG("NOC: bw_field: %u\n", bw_field); + return bw_field; +} + +static uint32_t noc_sat_field(uint64_t bw, uint32_t ws, uint32_t qos_freq) +{ + uint32_t sat_field = 0; + + if (bw) { + /* Limit to max bw and scale bw to 100 KB increments */ + uint64_t tbw, tscale; + uint64_t bw_scaled = min_t(uint64_t, bw, MAX_BW(qos_freq)); + uint32_t rem = noc_div(&bw_scaled, 100000); + + /** + SATURATION = + (BW [MBps] * integration window [us] * + time base frequency [MHz]) / (256 * 16) + */ + tbw = bw_scaled * ws * qos_freq; + tscale = BW_SCALE * SAT_SCALE * 1000000LL; + rem = noc_div(&tbw, tscale); + sat_field = (uint32_t)max_t(unsigned long, tbw, MIN_SAT_FIELD); + sat_field = (uint32_t)min_t(unsigned long, sat_field, + MAX_SAT_FIELD); + } + + MSM_BUS_DBG("NOC: sat_field: %d\n", sat_field); + return sat_field; +} + +static void noc_set_qos_mode(void __iomem *base, uint32_t qos_off, + uint32_t mport, uint32_t qos_delta, uint8_t mode, + uint8_t perm_mode) +{ + if (mode < NOC_QOS_MODE_MAX && + ((1 << mode) & perm_mode)) { + uint32_t reg_val; + + reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(base, qos_off, + mport, qos_delta)) & NOC_QOS_MODEn_RMSK; + writel_relaxed(((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK))) | + (mode & NOC_QOS_MODEn_MODE_BMSK)), + NOC_QOS_MODEn_ADDR(base, qos_off, mport, qos_delta)); + } + /* Ensure qos mode is set before exiting */ + wmb(); +} + +static void noc_set_qos_priority(void __iomem *base, uint32_t qos_off, + uint32_t mport, uint32_t qos_delta, + struct msm_bus_noc_qos_priority *priority) +{ + uint32_t reg_val, val; + + reg_val = readl_relaxed(NOC_QOS_PRIORITYn_ADDR(base, qos_off, mport, + qos_delta)) & NOC_QOS_PRIORITYn_RMSK; + val = priority->p1 << NOC_QOS_PRIORITYn_P1_SHFT; + writel_relaxed(((reg_val & (~(NOC_QOS_PRIORITYn_P1_BMSK))) | + (val & NOC_QOS_PRIORITYn_P1_BMSK)), + NOC_QOS_PRIORITYn_ADDR(base, qos_off, mport, qos_delta)); + + reg_val = readl_relaxed(NOC_QOS_PRIORITYn_ADDR(base, qos_off, mport, + qos_delta)) + & NOC_QOS_PRIORITYn_RMSK; + writel_relaxed(((reg_val & (~(NOC_QOS_PRIORITYn_P0_BMSK))) | + (priority->p0 & NOC_QOS_PRIORITYn_P0_BMSK)), + NOC_QOS_PRIORITYn_ADDR(base, qos_off, mport, qos_delta)); + /* Ensure qos priority is set before exiting */ + wmb(); +} + +static void msm_bus_noc_set_qos_bw(void __iomem *base, uint32_t qos_off, + uint32_t qos_freq, uint32_t mport, uint32_t qos_delta, + uint8_t perm_mode, struct msm_bus_noc_qos_bw *qbw) +{ + uint32_t reg_val, val, mode; + + if (!qos_freq) { + MSM_BUS_DBG("Zero QoS Freq\n"); + return; + } + + /* If Limiter or Regulator modes are not supported, bw not available*/ + if (perm_mode & (NOC_QOS_PERM_MODE_LIMITER | + NOC_QOS_PERM_MODE_REGULATOR)) { + uint32_t bw_val = noc_bw_field(qbw->bw, qos_freq); + uint32_t sat_val = noc_sat_field(qbw->bw, qbw->ws, + qos_freq); + + MSM_BUS_DBG("NOC: BW: perm_mode: %d bw_val: %d, sat_val: %d\n", + perm_mode, bw_val, sat_val); + /* + * If in Limiter/Regulator mode, first go to fixed mode. + * Clear QoS accumulator + **/ + mode = readl_relaxed(NOC_QOS_MODEn_ADDR(base, qos_off, + mport, qos_delta)) & NOC_QOS_MODEn_MODE_BMSK; + if (mode == NOC_QOS_MODE_REGULATOR || mode == + NOC_QOS_MODE_LIMITER) { + reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR( + base, qos_off, mport, qos_delta)); + val = NOC_QOS_MODE_FIXED; + writel_relaxed((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK))) + | (val & NOC_QOS_MODEn_MODE_BMSK), + NOC_QOS_MODEn_ADDR(base, qos_off, mport, + qos_delta)); + } + + reg_val = readl_relaxed(NOC_QOS_BWn_ADDR(base, qos_off, mport, + qos_delta)); + val = bw_val << NOC_QOS_BWn_BW_SHFT; + writel_relaxed(((reg_val & (~(NOC_QOS_BWn_BW_BMSK))) | + (val & NOC_QOS_BWn_BW_BMSK)), + NOC_QOS_BWn_ADDR(base, qos_off, mport, qos_delta)); + + MSM_BUS_DBG("NOC: BW: Wrote value: 0x%x\n", ((reg_val & + (~NOC_QOS_BWn_BW_BMSK)) | (val & + NOC_QOS_BWn_BW_BMSK))); + + reg_val = readl_relaxed(NOC_QOS_SATn_ADDR(base, qos_off, + mport, qos_delta)); + val = sat_val << NOC_QOS_SATn_SAT_SHFT; + writel_relaxed(((reg_val & (~(NOC_QOS_SATn_SAT_BMSK))) | + (val & NOC_QOS_SATn_SAT_BMSK)), + NOC_QOS_SATn_ADDR(base, qos_off, mport, qos_delta)); + + MSM_BUS_DBG("NOC: SAT: Wrote value: 0x%x\n", ((reg_val & + (~NOC_QOS_SATn_SAT_BMSK)) | (val & + NOC_QOS_SATn_SAT_BMSK))); + + /* Set mode back to what it was initially */ + reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(base, qos_off, + mport, qos_delta)); + writel_relaxed((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK))) + | (mode & NOC_QOS_MODEn_MODE_BMSK), + NOC_QOS_MODEn_ADDR(base, qos_off, mport, qos_delta)); + /* Ensure that all writes for bandwidth registers have + * completed before returning + */ + wmb(); + } +} + +uint8_t msm_bus_noc_get_qos_mode(void __iomem *base, uint32_t qos_off, + uint32_t mport, uint32_t qos_delta, uint32_t mode, uint32_t perm_mode) +{ + if (NOC_QOS_MODES_ALL_PERM == perm_mode) + return readl_relaxed(NOC_QOS_MODEn_ADDR(base, qos_off, + mport, qos_delta)) & NOC_QOS_MODEn_MODE_BMSK; + else + return 31 - __CLZ(mode & + NOC_QOS_MODES_ALL_PERM); +} + +void msm_bus_noc_get_qos_priority(void __iomem *base, uint32_t qos_off, + uint32_t mport, uint32_t qos_delta, + struct msm_bus_noc_qos_priority *priority) +{ + priority->p1 = (readl_relaxed(NOC_QOS_PRIORITYn_ADDR(base, qos_off, + mport, qos_delta)) & NOC_QOS_PRIORITYn_P1_BMSK) >> + NOC_QOS_PRIORITYn_P1_SHFT; + + priority->p0 = (readl_relaxed(NOC_QOS_PRIORITYn_ADDR(base, qos_off, + mport, qos_delta)) & NOC_QOS_PRIORITYn_P0_BMSK) >> + NOC_QOS_PRIORITYn_P0_SHFT; +} + +void msm_bus_noc_get_qos_bw(void __iomem *base, uint32_t qos_off, + uint32_t qos_freq, + uint32_t mport, uint32_t qos_delta, uint8_t perm_mode, + struct msm_bus_noc_qos_bw *qbw) +{ + if (perm_mode & (NOC_QOS_PERM_MODE_LIMITER | + NOC_QOS_PERM_MODE_REGULATOR)) { + uint32_t bw_val = readl_relaxed(NOC_QOS_BWn_ADDR( + base, qos_off, mport, qos_delta)) & NOC_QOS_BWn_BW_BMSK; + uint32_t sat = readl_relaxed(NOC_QOS_SATn_ADDR( + base, qos_off, mport, qos_delta)) + & NOC_QOS_SATn_SAT_BMSK; + + qbw->bw = noc_bw(bw_val, qos_freq); + qbw->ws = noc_ws(qbw->bw, sat, qos_freq); + } else { + qbw->bw = 0; + qbw->ws = 0; + } +} + +static bool msm_bus_noc_update_bw_reg(int mode) +{ + bool ret = false; + + if ((mode == NOC_QOS_MODE_LIMITER) || + (mode == NOC_QOS_MODE_REGULATOR)) + ret = true; + + return ret; +} + +static int msm_bus_noc_qos_init(struct msm_bus_node_device_type *info, + void __iomem *qos_base, + uint32_t qos_off, uint32_t qos_delta, + uint32_t qos_freq) +{ + struct msm_bus_noc_qos_priority prio; + int ret = 0; + int i; + + prio.p1 = info->node_info->qos_params.prio1; + prio.p0 = info->node_info->qos_params.prio0; + + if (!info->node_info->qport) { + MSM_BUS_DBG("No QoS Ports to init\n"); + ret = 0; + goto err_qos_init; + } + + for (i = 0; i < info->node_info->num_qports; i++) { + if (info->node_info->qos_params.mode != NOC_QOS_MODE_BYPASS) { + noc_set_qos_priority(qos_base, qos_off, + info->node_info->qport[i], qos_delta, + &prio); + + if (info->node_info->qos_params.mode != + NOC_QOS_MODE_FIXED) { + struct msm_bus_noc_qos_bw qbw; + + qbw.ws = info->node_info->qos_params.ws; + qbw.bw = 0; + msm_bus_noc_set_qos_bw(qos_base, qos_off, + qos_freq, + info->node_info->qport[i], + qos_delta, + info->node_info->qos_params.mode, + &qbw); + } + } + + noc_set_qos_mode(qos_base, qos_off, info->node_info->qport[i], + qos_delta, info->node_info->qos_params.mode, + (1 << info->node_info->qos_params.mode)); + } +err_qos_init: + return ret; +} + +static int msm_bus_noc_set_bw(struct msm_bus_node_device_type *dev, + void __iomem *qos_base, + uint32_t qos_off, uint32_t qos_delta, + uint32_t qos_freq) +{ + int ret = 0; + uint64_t bw = 0; + int i; + struct msm_bus_node_info_type *info = dev->node_info; + + if (info && info->num_qports && + ((info->qos_params.mode == NOC_QOS_MODE_REGULATOR) || + (info->qos_params.mode == + NOC_QOS_MODE_LIMITER))) { + struct msm_bus_noc_qos_bw qos_bw; + + bw = msm_bus_div64(info->num_qports, + dev->node_bw[ACTIVE_CTX].sum_ab); + + for (i = 0; i < info->num_qports; i++) { + if (!info->qport) { + MSM_BUS_DBG("No qos ports to update!\n"); + break; + } + + qos_bw.bw = bw; + qos_bw.ws = info->qos_params.ws; + msm_bus_noc_set_qos_bw(qos_base, qos_off, qos_freq, + info->qport[i], qos_delta, + (1 << info->qos_params.mode), &qos_bw); + MSM_BUS_DBG("NOC: QoS: Update mas_bw: ws: %u\n", + qos_bw.ws); + } + } + return ret; +} + +static int msm_bus_noc_set_lim_mode(struct msm_bus_node_device_type *info, + void __iomem *qos_base, uint32_t qos_off, + uint32_t qos_delta, uint32_t qos_freq, + u64 lim_bw) +{ + int i; + + if (info && info->node_info->num_qports) { + struct msm_bus_noc_qos_bw qos_bw; + + if (lim_bw != info->node_info->lim_bw) { + for (i = 0; i < info->node_info->num_qports; i++) { + qos_bw.bw = lim_bw; + qos_bw.ws = info->node_info->qos_params.ws; + msm_bus_noc_set_qos_bw(qos_base, + qos_off, qos_freq, + info->node_info->qport[i], qos_delta, + (1 << NOC_QOS_MODE_LIMITER), &qos_bw); + } + info->node_info->lim_bw = lim_bw; + } + + for (i = 0; i < info->node_info->num_qports; i++) { + noc_set_qos_mode(qos_base, qos_off, + info->node_info->qport[i], + qos_delta, + NOC_QOS_MODE_LIMITER, + (1 << NOC_QOS_MODE_LIMITER)); + } + } + + return 0; +} + +static int msm_bus_noc_set_reg_mode(struct msm_bus_node_device_type *info, + void __iomem *qos_base, uint32_t qos_off, + uint32_t qos_delta, uint32_t qos_freq, + u64 lim_bw) +{ + int i; + + if (info && info->node_info->num_qports) { + struct msm_bus_noc_qos_priority prio; + struct msm_bus_noc_qos_bw qos_bw; + + for (i = 0; i < info->node_info->num_qports; i++) { + prio.p1 = + info->node_info->qos_params.reg_prio1; + prio.p0 = + info->node_info->qos_params.reg_prio0; + noc_set_qos_priority(qos_base, qos_off, + info->node_info->qport[i], + qos_delta, + &prio); + } + + if (lim_bw != info->node_info->lim_bw) { + for (i = 0; i < info->node_info->num_qports; i++) { + qos_bw.bw = lim_bw; + qos_bw.ws = info->node_info->qos_params.ws; + msm_bus_noc_set_qos_bw(qos_base, qos_off, + qos_freq, + info->node_info->qport[i], qos_delta, + (1 << NOC_QOS_MODE_REGULATOR), &qos_bw); + } + info->node_info->lim_bw = lim_bw; + } + + for (i = 0; i < info->node_info->num_qports; i++) { + noc_set_qos_mode(qos_base, qos_off, + info->node_info->qport[i], + qos_delta, + NOC_QOS_MODE_REGULATOR, + (1 << NOC_QOS_MODE_REGULATOR)); + } + } + return 0; +} + +static int msm_bus_noc_set_def_mode(struct msm_bus_node_device_type *info, + void __iomem *qos_base, uint32_t qos_off, + uint32_t qos_delta, uint32_t qos_freq, + u64 lim_bw) +{ + int i; + + for (i = 0; i < info->node_info->num_qports; i++) { + if (info->node_info->qos_params.mode == + NOC_QOS_MODE_FIXED) { + struct msm_bus_noc_qos_priority prio; + + prio.p1 = + info->node_info->qos_params.prio1; + prio.p0 = + info->node_info->qos_params.prio0; + noc_set_qos_priority(qos_base, qos_off, + info->node_info->qport[i], + qos_delta, &prio); + } + noc_set_qos_mode(qos_base, qos_off, + info->node_info->qport[i], + qos_delta, + info->node_info->qos_params.mode, + (1 << info->node_info->qos_params.mode)); + } + return 0; +} + +static int msm_bus_noc_limit_mport(struct msm_bus_node_device_type *info, + void __iomem *qos_base, uint32_t qos_off, + uint32_t qos_delta, uint32_t qos_freq, + int enable_lim, u64 lim_bw) +{ + int ret = 0; + + if (!(info && info->node_info->num_qports)) { + MSM_BUS_ERR("Invalid Node info or no Qports to program"); + ret = -ENXIO; + goto exit_limit_mport; + } + + if (lim_bw) { + switch (enable_lim) { + case THROTTLE_REG: + msm_bus_noc_set_reg_mode(info, qos_base, qos_off, + qos_delta, qos_freq, lim_bw); + break; + case THROTTLE_ON: + msm_bus_noc_set_lim_mode(info, qos_base, qos_off, + qos_delta, qos_freq, lim_bw); + break; + default: + msm_bus_noc_set_def_mode(info, qos_base, qos_off, + qos_delta, qos_freq, lim_bw); + break; + } + } else + msm_bus_noc_set_def_mode(info, qos_base, qos_off, + qos_delta, qos_freq, lim_bw); + +exit_limit_mport: + return ret; +} + +int msm_bus_noc_set_ops(struct msm_bus_node_device_type *bus_dev) +{ + if (!bus_dev) + return -ENODEV; + + bus_dev->fabdev->noc_ops.qos_init = msm_bus_noc_qos_init; + bus_dev->fabdev->noc_ops.set_bw = msm_bus_noc_set_bw; + bus_dev->fabdev->noc_ops.limit_mport = msm_bus_noc_limit_mport; + bus_dev->fabdev->noc_ops.update_bw_reg = msm_bus_noc_update_bw_reg; + + return 0; +} +EXPORT_SYMBOL(msm_bus_noc_set_ops); diff --git a/drivers/platform/msm/msm_bus/msm_bus_of_adhoc.c b/drivers/platform/msm/msm_bus/msm_bus_of_adhoc.c index 8262a82d5c1c..669dcc60389f 100644 --- a/drivers/platform/msm/msm_bus/msm_bus_of_adhoc.c +++ b/drivers/platform/msm/msm_bus/msm_bus_of_adhoc.c @@ -29,6 +29,7 @@ #define DEFAULT_QOS_FREQ 19200 #define DEFAULT_UTIL_FACT 100 #define DEFAULT_VRAIL_COMP 100 +#define DEFAULT_AGG_SCHEME AGG_SCHEME_LEG static int get_qos_mode(struct platform_device *pdev, struct device_node *node, const char *qos_mode) @@ -148,21 +149,6 @@ static struct msm_bus_fab_device_type *get_fab_device_info( fab_dev->qos_freq = DEFAULT_QOS_FREQ; } - ret = of_property_read_u32(dev_node, "qcom,util-fact", - &fab_dev->util_fact); - if (ret) { - dev_info(&pdev->dev, "Util-fact is missing, default to %d\n", - DEFAULT_UTIL_FACT); - fab_dev->util_fact = DEFAULT_UTIL_FACT; - } - - ret = of_property_read_u32(dev_node, "qcom,vrail-comp", - &fab_dev->vrail_comp); - if (ret) { - dev_info(&pdev->dev, "Vrail-comp is missing, default to %d\n", - DEFAULT_VRAIL_COMP); - fab_dev->vrail_comp = DEFAULT_VRAIL_COMP; - } return fab_dev; @@ -228,6 +214,159 @@ static void get_qos_params( } +static int msm_bus_of_parse_clk_array(struct device_node *dev_node, + struct device_node *gdsc_node, + struct platform_device *pdev, struct nodeclk **clk_arr, + int *num_clks, int id) +{ + int ret = 0; + int idx = 0; + struct property *prop; + const char *clk_name; + int clks = 0; + + clks = of_property_count_strings(dev_node, "clock-names"); + if (clks < 0) { + pr_info("%s: No qos clks node %d\n", __func__, id); + ret = clks; + goto exit_of_parse_clk_array; + } + + *num_clks = clks; + *clk_arr = devm_kzalloc(&pdev->dev, + (clks * sizeof(struct nodeclk)), GFP_KERNEL); + + if (!(*clk_arr)) { + pr_err("%s: Error allocating clk nodes for %d\n", __func__, id); + ret = -ENOMEM; + *num_clks = 0; + goto exit_of_parse_clk_array; + } + + of_property_for_each_string(dev_node, "clock-names", prop, clk_name) { + char gdsc_string[MAX_REG_NAME]; + + (*clk_arr)[idx].clk = of_clk_get_by_name(dev_node, clk_name); + + if (IS_ERR_OR_NULL((*clk_arr)[idx].clk)) { + dev_err(&pdev->dev, + "Failed to get clk %s for bus%d ", clk_name, + id); + continue; + } + if (strnstr(clk_name, "no-rate", strlen(clk_name))) + (*clk_arr)[idx].enable_only_clk = true; + + scnprintf(gdsc_string, MAX_REG_NAME, "%s-supply", clk_name); + + if (of_find_property(gdsc_node, gdsc_string, NULL)) + scnprintf((*clk_arr)[idx].reg_name, + MAX_REG_NAME, "%s", clk_name); + else + scnprintf((*clk_arr)[idx].reg_name, + MAX_REG_NAME, "%c", '\0'); + + idx++; + } +exit_of_parse_clk_array: + return ret; +} + +static void get_agg_params( + struct device_node * const dev_node, + struct platform_device * const pdev, + struct msm_bus_node_info_type *node_info) +{ + int ret; + + + ret = of_property_read_u32(dev_node, "qcom,buswidth", + &node_info->agg_params.buswidth); + if (ret) { + dev_dbg(&pdev->dev, "Using default 8 bytes %d", node_info->id); + node_info->agg_params.buswidth = 8; + } + + ret = of_property_read_u32(dev_node, "qcom,agg-ports", + &node_info->agg_params.num_aggports); + if (ret) + node_info->agg_params.num_aggports = node_info->num_qports; + + ret = of_property_read_u32(dev_node, "qcom,agg-scheme", + &node_info->agg_params.agg_scheme); + if (ret) { + if (node_info->is_fab_dev) + node_info->agg_params.agg_scheme = DEFAULT_AGG_SCHEME; + else { + node_info->agg_params.agg_scheme = AGG_SCHEME_NONE; + goto exit_get_agg_params; + } + } + + ret = of_property_read_u32(dev_node, "qcom,vrail-comp", + &node_info->agg_params.vrail_comp); + if (ret) { + if (node_info->is_fab_dev) + node_info->agg_params.vrail_comp = DEFAULT_VRAIL_COMP; + else + node_info->agg_params.vrail_comp = 0; + } + + if (node_info->agg_params.agg_scheme == AGG_SCHEME_LEG) { + node_info->agg_params.num_util_levels = 1; + node_info->agg_params.util_levels = devm_kzalloc(&pdev->dev, + (node_info->agg_params.num_util_levels * + sizeof(struct node_util_levels_type)), GFP_KERNEL); + if (IS_ERR_OR_NULL(node_info->agg_params.util_levels)) + goto err_get_agg_params; + + ret = of_property_read_u32(dev_node, "qcom,util-fact", + &node_info->agg_params.util_levels[0].util_fact); + if (ret) { + if (node_info->is_fab_dev) + node_info->agg_params.util_levels[0].util_fact + = DEFAULT_UTIL_FACT; + } + } else if (node_info->agg_params.agg_scheme == AGG_SCHEME_1) { + uint32_t len = 0; + const uint32_t *util_levels; + int i, index = 0; + + util_levels = + of_get_property(dev_node, "qcom,util-levels", &len); + if (!util_levels) + goto err_get_agg_params; + + node_info->agg_params.num_util_levels = + len / (sizeof(uint32_t) * 2); + node_info->agg_params.util_levels = devm_kzalloc(&pdev->dev, + (node_info->agg_params.num_util_levels * + sizeof(struct node_util_levels_type)), GFP_KERNEL); + + if (IS_ERR_OR_NULL(node_info->agg_params.util_levels)) + goto err_get_agg_params; + + for (i = 0; i < node_info->agg_params.num_util_levels; i++) { + node_info->agg_params.util_levels[i].threshold = + KBTOB(be32_to_cpu(util_levels[index++])); + node_info->agg_params.util_levels[i].util_fact = + be32_to_cpu(util_levels[index++]); + dev_dbg(&pdev->dev, "[%d]:Thresh:%llu util_fact:%d\n", + i, + node_info->agg_params.util_levels[i].threshold, + node_info->agg_params.util_levels[i].util_fact); + } + } else { + dev_err(&pdev->dev, "Agg scheme%d unknown, using default\n", + node_info->agg_params.agg_scheme); + goto err_get_agg_params; + } + +exit_get_agg_params: + return; +err_get_agg_params: + node_info->agg_params.agg_scheme = DEFAULT_AGG_SCHEME; +} static struct msm_bus_node_info_type *get_node_info_data( struct device_node * const dev_node, @@ -262,11 +401,6 @@ static struct msm_bus_node_info_type *get_node_info_data( node_info->qport = get_arr(pdev, dev_node, "qcom,qport", &node_info->num_qports); - ret = of_property_read_u32(dev_node, "qcom,agg-ports", - &node_info->num_aggports); - if (ret) - node_info->num_aggports = node_info->num_qports; - if (of_get_property(dev_node, "qcom,connections", &size)) { node_info->num_connections = size / sizeof(int); node_info->connections = devm_kzalloc(&pdev->dev, size, @@ -324,12 +458,6 @@ static struct msm_bus_node_info_type *get_node_info_data( node_info->is_fab_dev = of_property_read_bool(dev_node, "qcom,fab-dev"); node_info->virt_dev = of_property_read_bool(dev_node, "qcom,virt-dev"); - ret = of_property_read_u32(dev_node, "qcom,buswidth", - &node_info->buswidth); - if (ret) { - dev_dbg(&pdev->dev, "Using default 8 bytes %d", node_info->id); - node_info->buswidth = 8; - } ret = of_property_read_u32(dev_node, "qcom,mas-rpm-id", &node_info->mas_rpm_id); @@ -344,14 +472,8 @@ static struct msm_bus_node_info_type *get_node_info_data( dev_dbg(&pdev->dev, "slv rpm id is missing\n"); node_info->slv_rpm_id = -1; } - ret = of_property_read_u32(dev_node, "qcom,util-fact", - &node_info->util_fact); - if (ret) - node_info->util_fact = 0; - ret = of_property_read_u32(dev_node, "qcom,vrail-comp", - &node_info->vrail_comp); - if (ret) - node_info->vrail_comp = 0; + + get_agg_params(dev_node, pdev, node_info); get_qos_params(dev_node, pdev, node_info); return node_info; @@ -362,11 +484,14 @@ node_info_err: return NULL; } -static unsigned int get_bus_node_device_data( +static int get_bus_node_device_data( struct device_node * const dev_node, struct platform_device * const pdev, struct msm_bus_node_device_type * const node_device) { + bool enable_only; + bool setrate_only; + node_device->node_info = get_node_info_data(dev_node, pdev); if (IS_ERR_OR_NULL(node_device->node_info)) { dev_err(&pdev->dev, "Error: Node info missing\n"); @@ -376,6 +501,7 @@ static unsigned int get_bus_node_device_data( "qcom,ap-owned"); if (node_device->node_info->is_fab_dev) { + struct device_node *qos_clk_node; dev_err(&pdev->dev, "Dev %d\n", node_device->node_info->id); if (!node_device->node_info->virt_dev) { @@ -388,43 +514,132 @@ static unsigned int get_bus_node_device_data( return -ENODATA; } } + + enable_only = of_property_read_bool(dev_node, + "qcom,enable-only-clk"); + node_device->clk[DUAL_CTX].enable_only_clk = enable_only; + node_device->clk[ACTIVE_CTX].enable_only_clk = enable_only; + + /* + * Doesn't make sense to have a clk handle you can't enable or + * set rate on. + */ + if (!enable_only) { + setrate_only = of_property_read_bool(dev_node, + "qcom,setrate-only-clk"); + node_device->clk[DUAL_CTX].setrate_only_clk = + setrate_only; + node_device->clk[ACTIVE_CTX].setrate_only_clk = + setrate_only; + } + node_device->clk[DUAL_CTX].clk = of_clk_get_by_name(dev_node, "bus_clk"); - if (IS_ERR_OR_NULL(node_device->clk[DUAL_CTX].clk)) + if (IS_ERR_OR_NULL(node_device->clk[DUAL_CTX].clk)) { + int ret; dev_err(&pdev->dev, "%s:Failed to get bus clk for bus%d ctx%d", __func__, node_device->node_info->id, DUAL_CTX); + ret = (IS_ERR(node_device->clk[DUAL_CTX].clk) ? + PTR_ERR(node_device->clk[DUAL_CTX].clk) : -ENXIO); + return ret; + } + + if (of_find_property(dev_node, "bus-gdsc-supply", NULL)) + scnprintf(node_device->clk[DUAL_CTX].reg_name, + MAX_REG_NAME, "%s", "bus-gdsc"); + else + scnprintf(node_device->clk[DUAL_CTX].reg_name, + MAX_REG_NAME, "%c", '\0'); node_device->clk[ACTIVE_CTX].clk = of_clk_get_by_name(dev_node, "bus_a_clk"); - if (IS_ERR_OR_NULL(node_device->clk[ACTIVE_CTX].clk)) + if (IS_ERR_OR_NULL(node_device->clk[ACTIVE_CTX].clk)) { + int ret; dev_err(&pdev->dev, "Failed to get bus clk for bus%d ctx%d", node_device->node_info->id, ACTIVE_CTX); + ret = (IS_ERR(node_device->clk[DUAL_CTX].clk) ? + PTR_ERR(node_device->clk[DUAL_CTX].clk) : -ENXIO); + return ret; + } - node_device->qos_clk.clk = of_clk_get_by_name(dev_node, + if (of_find_property(dev_node, "bus-a-gdsc-supply", NULL)) + scnprintf(node_device->clk[ACTIVE_CTX].reg_name, + MAX_REG_NAME, "%s", "bus-a-gdsc"); + else + scnprintf(node_device->clk[ACTIVE_CTX].reg_name, + MAX_REG_NAME, "%c", '\0'); + + node_device->bus_qos_clk.clk = of_clk_get_by_name(dev_node, "bus_qos_clk"); - if (IS_ERR_OR_NULL(node_device->qos_clk.clk)) + if (IS_ERR_OR_NULL(node_device->bus_qos_clk.clk)) { dev_dbg(&pdev->dev, "%s:Failed to get bus qos clk for %d", __func__, node_device->node_info->id); + scnprintf(node_device->bus_qos_clk.reg_name, + MAX_REG_NAME, "%c", '\0'); + } else { + if (of_find_property(dev_node, "bus-qos-gdsc-supply", + NULL)) + scnprintf(node_device->bus_qos_clk.reg_name, + MAX_REG_NAME, "%s", "bus-qos-gdsc"); + else + scnprintf(node_device->bus_qos_clk.reg_name, + MAX_REG_NAME, "%c", '\0'); + } + + qos_clk_node = of_find_node_by_name(dev_node, + "qcom,node-qos-clks"); + + if (qos_clk_node) + msm_bus_of_parse_clk_array(qos_clk_node, dev_node, pdev, + &node_device->node_qos_clks, + &node_device->num_node_qos_clks, + node_device->node_info->id); if (msmbus_coresight_init_adhoc(pdev, dev_node)) dev_warn(&pdev->dev, "Coresight support absent for bus: %d\n", node_device->node_info->id); } else { - node_device->qos_clk.clk = of_clk_get_by_name(dev_node, + node_device->bus_qos_clk.clk = of_clk_get_by_name(dev_node, "bus_qos_clk"); - if (IS_ERR_OR_NULL(node_device->qos_clk.clk)) + if (IS_ERR_OR_NULL(node_device->bus_qos_clk.clk)) dev_dbg(&pdev->dev, "%s:Failed to get bus qos clk for mas%d", __func__, node_device->node_info->id); + if (of_find_property(dev_node, "bus-qos-gdsc-supply", + NULL)) + scnprintf(node_device->bus_qos_clk.reg_name, + MAX_REG_NAME, "%s", "bus-qos-gdsc"); + else + scnprintf(node_device->bus_qos_clk.reg_name, + MAX_REG_NAME, "%c", '\0'); + + enable_only = of_property_read_bool(dev_node, + "qcom,enable-only-clk"); + node_device->clk[DUAL_CTX].enable_only_clk = enable_only; + node_device->bus_qos_clk.enable_only_clk = enable_only; + + /* + * Doesn't make sense to have a clk handle you can't enable or + * set rate on. + */ + if (!enable_only) { + setrate_only = of_property_read_bool(dev_node, + "qcom,setrate-only-clk"); + node_device->clk[DUAL_CTX].setrate_only_clk = + setrate_only; + node_device->clk[ACTIVE_CTX].setrate_only_clk = + setrate_only; + } + node_device->clk[DUAL_CTX].clk = of_clk_get_by_name(dev_node, "node_clk"); @@ -434,6 +649,13 @@ static unsigned int get_bus_node_device_data( __func__, node_device->node_info->id, DUAL_CTX); + if (of_find_property(dev_node, "node-gdsc-supply", NULL)) + scnprintf(node_device->clk[DUAL_CTX].reg_name, + MAX_REG_NAME, "%s", "node-gdsc"); + else + scnprintf(node_device->clk[DUAL_CTX].reg_name, + MAX_REG_NAME, "%c", '\0'); + } return 0; } @@ -482,6 +704,7 @@ struct msm_bus_device_node_registration dev_err(&pdev->dev, "Error: unable to initialize bus nodes\n"); goto node_reg_err_1; } + pdata->info[i].of_node = child_node; i++; } @@ -493,7 +716,7 @@ struct msm_bus_device_node_registration pdata->info[i].node_info->num_connections); dev_dbg(&pdev->dev, "\nbus_device_id %d\n buswidth %d\n", pdata->info[i].node_info->bus_device_id, - pdata->info[i].node_info->buswidth); + pdata->info[i].node_info->agg_params.buswidth); for (j = 0; j < pdata->info[i].node_info->num_connections; j++) { dev_dbg(&pdev->dev, "connection[%d]: %d\n", j, diff --git a/include/dt-bindings/msm/msm-bus-ids.h b/include/dt-bindings/msm/msm-bus-ids.h index 85872771118d..850eacacf87d 100644 --- a/include/dt-bindings/msm/msm-bus-ids.h +++ b/include/dt-bindings/msm/msm-bus-ids.h @@ -13,6 +13,11 @@ #ifndef __MSM_BUS_IDS_H #define __MSM_BUS_IDS_H +/* Aggregation types */ +#define AGG_SCHEME_NONE 0 +#define AGG_SCHEME_LEG 1 +#define AGG_SCHEME_1 2 + /* Topology related enums */ #define MSM_BUS_FAB_DEFAULT 0 #define MSM_BUS_FAB_APPSS 0 diff --git a/include/linux/msm-bus.h b/include/linux/msm-bus.h index 56c96b54c404..c5a3284e8336 100644 --- a/include/linux/msm-bus.h +++ b/include/linux/msm-bus.h @@ -71,8 +71,11 @@ struct msm_bus_client_handle { int mas; int slv; int first_hop; - u64 cur_ib; - u64 cur_ab; + struct device *mas_dev; + u64 cur_act_ib; + u64 cur_act_ab; + u64 cur_slp_ib; + u64 cur_slp_ab; bool active_only; }; @@ -89,12 +92,16 @@ int __init msm_bus_fabric_init_driver(void); uint32_t msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata); int msm_bus_scale_client_update_request(uint32_t cl, unsigned int index); void msm_bus_scale_unregister_client(uint32_t cl); +int msm_bus_scale_client_update_context(uint32_t cl, bool active_only, + unsigned int ctx_idx); struct msm_bus_client_handle* msm_bus_scale_register(uint32_t mas, uint32_t slv, char *name, bool active_only); void msm_bus_scale_unregister(struct msm_bus_client_handle *cl); int msm_bus_scale_update_bw(struct msm_bus_client_handle *cl, u64 ab, u64 ib); +int msm_bus_scale_update_bw_context(struct msm_bus_client_handle *cl, + u64 act_ab, u64 act_ib, u64 slp_ib, u64 slp_ab); /* AXI Port configuration APIs */ int msm_bus_axi_porthalt(int master_port); int msm_bus_axi_portunhalt(int master_port); @@ -115,6 +122,13 @@ msm_bus_scale_client_update_request(uint32_t cl, unsigned int index) return 0; } +static inline int +msm_bus_scale_client_update_context(uint32_t cl, bool active_only, + unsigned int ctx_idx) +{ + return 0; +} + static inline void msm_bus_scale_unregister_client(uint32_t cl) { @@ -147,6 +161,14 @@ msm_bus_scale_update_bw(struct msm_bus_client_handle *cl, u64 ab, u64 ib) return 0; } +static inline int +msm_bus_scale_update_bw_context(struct msm_bus_client_handle *cl, u64 act_ab, + u64 act_ib, u64 slp_ib, u64 slp_ab) + +{ + return 0; +} + #endif #if defined(CONFIG_OF) && defined(CONFIG_MSM_BUS_SCALING) diff --git a/include/linux/msm_bus_rules.h b/include/linux/msm_bus_rules.h index 1b384566f0c5..ef09191b1f62 100644 --- a/include/linux/msm_bus_rules.h +++ b/include/linux/msm_bus_rules.h @@ -25,6 +25,7 @@ struct rule_update_path_info { u64 ab; u64 ib; u64 clk; + bool added; struct list_head link; }; diff --git a/include/trace/events/trace_msm_bus.h b/include/trace/events/trace_msm_bus.h index 711ce2ad047f..f115e6b62d60 100644 --- a/include/trace/events/trace_msm_bus.h +++ b/include/trace/events/trace_msm_bus.h @@ -170,6 +170,40 @@ TRACE_EVENT(bus_bke_params, __entry->gc, __entry->gp, __entry->thl, __entry->thm, __entry->thh) ); + +TRACE_EVENT(bus_client_status, + + TP_PROTO(const char *name, int src, int dest, + unsigned long long ab, unsigned long long ib, int active_only), + + TP_ARGS(name, src, dest, ab, ib, active_only), + + TP_STRUCT__entry( + __string(name, name) + __field(int, src) + __field(int, dest) + __field(u64, ab) + __field(u64, ib) + __field(int, active_only) + ), + + TP_fast_assign( + __assign_str(name, name); + __entry->src = src; + __entry->dest = dest; + __entry->ab = ab; + __entry->ib = ib; + __entry->active_only = active_only; + ), + + TP_printk("name=%s src=%d dest=%d ab=%llu ib=%llu active_only=%d", + __get_str(name), + __entry->src, + __entry->dest, + (unsigned long long)__entry->ab, + (unsigned long long)__entry->ib, + __entry->active_only) +); #endif #define TRACE_INCLUDE_FILE trace_msm_bus #include