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 <alokc@codeaurora.org>
Signed-off-by: Kiran Gunda <kgunda@codeaurora.org>
This commit is contained in:
Alok Chauhan 2015-02-04 10:57:01 -07:00
parent b9161e20e8
commit 23a9665dbc
18 changed files with 2767 additions and 2063 deletions

View File

@ -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 = <SCHEME_1>;
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>;

View File

@ -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

View File

@ -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);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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 <linux/slab.h>
#include <linux/io.h>
#include <linux/msm-bus-board.h>
#include "msm_bus_core.h"
#include "msm_bus_bimc.h"
#include "msm_bus_adhoc.h"
#include <trace/events/trace_msm_bus.h>
/* 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);

View File

@ -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

View File

@ -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 <linux/device.h>
#include <linux/radix-tree.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/msm-bus-board.h>
#include <linux/msm-bus.h>
@ -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)
{
}

View File

@ -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,

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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 <linux/slab.h>
#include <linux/io.h>
#include <linux/msm-bus-board.h>
#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);

View File

@ -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,

View File

@ -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

View File

@ -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)

View File

@ -25,6 +25,7 @@ struct rule_update_path_info {
u64 ab;
u64 ib;
u64 clk;
bool added;
struct list_head link;
};

View File

@ -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 <trace/define_trace.h>