msm: camera: cpas: Add support for SmartQoS feature
This feature dynamically calculates priority lut low values for real time write NIUs whenever there is a change in real time bw vote on any of these NIUs and write the registers. CRs-Fixed: 2976535 Change-Id: I5a1433436da87915b20584d3002648699c985998 Signed-off-by: Pavan Kumar Chilamkurthi <pchilamk@codeaurora.org>
Cette révision appartient à :
@@ -26,7 +26,7 @@ module_param(cam_min_camnoc_ib_bw, uint, 0644);
|
||||
static void cam_cpas_update_monitor_array(struct cam_hw_info *cpas_hw,
|
||||
const char *identifier_string, int32_t identifier_value);
|
||||
static void cam_cpas_dump_monitor_array(
|
||||
struct cam_cpas *cpas_core);
|
||||
struct cam_hw_info *cpas_hw);
|
||||
|
||||
static void cam_cpas_process_bw_overrides(
|
||||
struct cam_cpas_bus_client *bus_client, uint64_t *ab, uint64_t *ib,
|
||||
@@ -527,6 +527,200 @@ static int cam_cpas_hw_dump_camnoc_buff_fill_info(
|
||||
|
||||
}
|
||||
|
||||
static void cam_cpas_print_smart_qos_priority(
|
||||
struct cam_hw_info *cpas_hw)
|
||||
{
|
||||
struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
|
||||
struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
|
||||
struct cam_cpas_private_soc *soc_private =
|
||||
(struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
|
||||
struct cam_cpas_tree_node *niu_node;
|
||||
uint8_t i;
|
||||
int32_t reg_indx = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC];
|
||||
char log_buf[CAM_CPAS_LOG_BUF_LEN] = {0};
|
||||
size_t len = 0;
|
||||
uint32_t val = 0;
|
||||
|
||||
for (i = 0; i < soc_private->smart_qos_info->num_rt_wr_nius; i++) {
|
||||
niu_node = soc_private->smart_qos_info->rt_wr_niu_node[i];
|
||||
|
||||
val = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base +
|
||||
niu_node->pri_lut_low_offset);
|
||||
|
||||
len += scnprintf((log_buf + len), (CAM_CPAS_LOG_BUF_LEN - len),
|
||||
" [%s:0x%x]", niu_node->node_name, val);
|
||||
}
|
||||
|
||||
CAM_INFO(CAM_CPAS, "SmartQoS [Node Pri_lut_low] %s", log_buf);
|
||||
}
|
||||
|
||||
static bool cam_cpas_is_new_rt_bw_lower(
|
||||
const struct cam_hw_info *cpas_hw)
|
||||
{
|
||||
struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
|
||||
int i;
|
||||
struct cam_cpas_axi_port *temp_axi_port = NULL;
|
||||
uint64_t applied_total = 0, new_total = 0;
|
||||
|
||||
for (i = 0; i < cpas_core->num_axi_ports; i++) {
|
||||
temp_axi_port = &cpas_core->axi_port[i];
|
||||
|
||||
if (temp_axi_port->is_rt) {
|
||||
CAM_DBG(CAM_PERF, "Port %s applied %llu new %llu",
|
||||
temp_axi_port->axi_port_name, temp_axi_port->applied_ab_bw,
|
||||
temp_axi_port->ab_bw);
|
||||
|
||||
applied_total += temp_axi_port->applied_ab_bw;
|
||||
new_total += temp_axi_port->ab_bw;
|
||||
}
|
||||
}
|
||||
|
||||
return (new_total < applied_total) ? true : false;
|
||||
}
|
||||
|
||||
static void cam_cpas_reset_niu_priorities(
|
||||
struct cam_hw_info *cpas_hw)
|
||||
{
|
||||
struct cam_cpas_private_soc *soc_private =
|
||||
(struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < soc_private->smart_qos_info->num_rt_wr_nius; i++)
|
||||
soc_private->smart_qos_info->rt_wr_niu_node[i]->applied_priority = 0x0;
|
||||
}
|
||||
|
||||
static bool cam_cpas_calculate_smart_qos(
|
||||
struct cam_hw_info *cpas_hw)
|
||||
{
|
||||
struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
|
||||
struct cam_cpas_private_soc *soc_private =
|
||||
(struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
|
||||
struct cam_cpas_tree_node *niu_node;
|
||||
uint8_t i;
|
||||
bool needs_update = false;
|
||||
uint64_t bw_per_kb, max_bw_per_kb = 0, remainder, ramp_val;
|
||||
int8_t pos;
|
||||
uint32_t priority;
|
||||
uint8_t val;
|
||||
|
||||
for (i = 0; i < soc_private->smart_qos_info->num_rt_wr_nius; i++) {
|
||||
niu_node = soc_private->smart_qos_info->rt_wr_niu_node[i];
|
||||
|
||||
bw_per_kb = niu_node->camnoc_bw;
|
||||
remainder = do_div(bw_per_kb, niu_node->niu_size);
|
||||
|
||||
if (max_bw_per_kb < bw_per_kb)
|
||||
max_bw_per_kb = bw_per_kb;
|
||||
|
||||
CAM_DBG(CAM_PERF,
|
||||
"NIU[%d][%s] : camnoc_bw %llu, niu_size %u, bw_per_kb %lld, remainder %lld max_bw_per_kb %lld",
|
||||
i, niu_node->node_name, niu_node->camnoc_bw, niu_node->niu_size,
|
||||
bw_per_kb, remainder, max_bw_per_kb);
|
||||
}
|
||||
|
||||
if (!max_bw_per_kb) {
|
||||
CAM_DBG(CAM_PERF, "No valid bw on NIU nodes");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < soc_private->smart_qos_info->num_rt_wr_nius; i++) {
|
||||
niu_node = soc_private->smart_qos_info->rt_wr_niu_node[i];
|
||||
|
||||
bw_per_kb = niu_node->camnoc_bw;
|
||||
remainder = do_div(bw_per_kb, niu_node->niu_size); // --> dropping remainder
|
||||
|
||||
priority = 0;
|
||||
|
||||
for (pos = 7; pos >= 0; pos--) {
|
||||
if (pos == 0) {
|
||||
val = soc_private->smart_qos_info->rt_wr_priority_min;
|
||||
} else if (pos == 7) {
|
||||
val = soc_private->smart_qos_info->rt_wr_priority_max;
|
||||
} else {
|
||||
ramp_val = pos * bw_per_kb;
|
||||
remainder = do_div(ramp_val, max_bw_per_kb);
|
||||
|
||||
CAM_DBG(CAM_PERF,
|
||||
"pos=%d, bw_per_kb=%lld, pos*bw_per_kb=%lld, ramp_val=%lld, remainder=%lld, max_bw_per_kb=%lld",
|
||||
pos, bw_per_kb, pos * bw_per_kb, ramp_val, remainder,
|
||||
max_bw_per_kb);
|
||||
|
||||
// round the value
|
||||
if ((remainder * 2) >= max_bw_per_kb)
|
||||
ramp_val += 1;
|
||||
|
||||
val = (uint8_t)(ramp_val);
|
||||
val += soc_private->smart_qos_info->rt_wr_priority_min;
|
||||
val = min(val, soc_private->smart_qos_info->rt_wr_priority_max);
|
||||
}
|
||||
|
||||
priority = priority << 4;
|
||||
priority |= val;
|
||||
|
||||
CAM_DBG(CAM_PERF, "pos=%d, val=0x%x, priority=0x%x", pos, val, priority);
|
||||
}
|
||||
|
||||
niu_node->curr_priority = priority;
|
||||
|
||||
if (niu_node->curr_priority != niu_node->applied_priority)
|
||||
needs_update = true;
|
||||
|
||||
CAM_DBG(CAM_PERF,
|
||||
"Node[%d][%s] : camnoc_bw=%lld, niu_size=%d, bw_per_kb %lld, Priority applied 0x%x new 0x%x needs_update %d",
|
||||
i, niu_node->node_name, niu_node->camnoc_bw, niu_node->niu_size, bw_per_kb,
|
||||
niu_node->applied_priority, niu_node->curr_priority,
|
||||
needs_update);
|
||||
}
|
||||
|
||||
if (cpas_core->smart_qos_dump && needs_update) {
|
||||
for (i = 0; i < soc_private->smart_qos_info->num_rt_wr_nius; i++) {
|
||||
niu_node = soc_private->smart_qos_info->rt_wr_niu_node[i];
|
||||
CAM_INFO(CAM_PERF,
|
||||
"Node[%d][%s] : camnoc_bw=%lld, niu_size=%d, offset 0x%x, Priority new 0x%x applied 0x%x",
|
||||
i, niu_node->node_name, niu_node->camnoc_bw, niu_node->niu_size,
|
||||
niu_node->pri_lut_low_offset,
|
||||
niu_node->curr_priority, niu_node->applied_priority);
|
||||
}
|
||||
}
|
||||
|
||||
return needs_update;
|
||||
}
|
||||
|
||||
static int cam_cpas_apply_smart_qos(
|
||||
struct cam_hw_info *cpas_hw)
|
||||
{
|
||||
struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
|
||||
struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
|
||||
struct cam_cpas_private_soc *soc_private =
|
||||
(struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
|
||||
struct cam_cpas_tree_node *niu_node;
|
||||
uint8_t i;
|
||||
int32_t reg_indx = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC];
|
||||
|
||||
if (cpas_core->smart_qos_dump) {
|
||||
CAM_INFO(CAM_PERF, "Printing SmartQos values before update");
|
||||
cam_cpas_print_smart_qos_priority(cpas_hw);
|
||||
}
|
||||
|
||||
for (i = 0; i < soc_private->smart_qos_info->num_rt_wr_nius; i++) {
|
||||
niu_node = soc_private->smart_qos_info->rt_wr_niu_node[i];
|
||||
|
||||
if (niu_node->curr_priority != niu_node->applied_priority) {
|
||||
cam_io_w_mb(niu_node->curr_priority,
|
||||
soc_info->reg_map[reg_indx].mem_base +
|
||||
niu_node->pri_lut_low_offset);
|
||||
niu_node->applied_priority = niu_node->curr_priority;
|
||||
}
|
||||
}
|
||||
|
||||
if (cpas_core->smart_qos_dump) {
|
||||
CAM_INFO(CAM_PERF, "Printing SmartQos values after update");
|
||||
cam_cpas_print_smart_qos_priority(cpas_hw);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cam_cpas_util_set_camnoc_axi_clk_rate(
|
||||
struct cam_hw_info *cpas_hw)
|
||||
{
|
||||
@@ -856,6 +1050,8 @@ static int cam_cpas_util_apply_client_axi_vote(
|
||||
struct cam_axi_vote *axi_vote)
|
||||
{
|
||||
struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
|
||||
struct cam_cpas_private_soc *soc_private =
|
||||
(struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
|
||||
struct cam_axi_vote *con_axi_vote = NULL;
|
||||
struct cam_cpas_axi_port *mnoc_axi_port = NULL;
|
||||
struct cam_cpas_tree_node *curr_tree_node = NULL;
|
||||
@@ -869,6 +1065,8 @@ static int cam_cpas_util_apply_client_axi_vote(
|
||||
par_camnoc_old = 0, par_mnoc_ab_old = 0, par_mnoc_ib_old = 0;
|
||||
int rc = 0, i = 0;
|
||||
uint64_t applied_ab = 0, applied_ib = 0;
|
||||
bool apply_smart_qos = false;
|
||||
bool rt_bw_updated = false;
|
||||
|
||||
mutex_lock(&cpas_core->tree_lock);
|
||||
if (!cpas_client->tree_node_valid) {
|
||||
@@ -1015,6 +1213,37 @@ static int cam_cpas_util_apply_client_axi_vote(
|
||||
goto unlock_tree;
|
||||
}
|
||||
|
||||
if (soc_private->enable_smart_qos) {
|
||||
CAM_DBG(CAM_PERF, "Start QoS update for client[%s][%d]",
|
||||
cpas_client->data.identifier, cpas_client->data.cell_index);
|
||||
for (i = 0; i < cpas_core->num_axi_ports; i++) {
|
||||
if (mnoc_axi_port_updated[i] && cpas_core->axi_port[i].is_rt) {
|
||||
rt_bw_updated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rt_bw_updated) {
|
||||
apply_smart_qos = cam_cpas_calculate_smart_qos(cpas_hw);
|
||||
|
||||
if (apply_smart_qos && cam_cpas_is_new_rt_bw_lower(cpas_hw)) {
|
||||
/*
|
||||
* If new BW is low, apply QoS first and then vote,
|
||||
* otherwise vote first and then apply QoS
|
||||
*/
|
||||
CAM_DBG(CAM_PERF, "Apply Smart QoS first");
|
||||
rc = cam_cpas_apply_smart_qos(cpas_hw);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"Failed in Smart QoS rc=%d", rc);
|
||||
goto unlock_tree;
|
||||
}
|
||||
|
||||
apply_smart_qos = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vote_start_clients:
|
||||
for (i = 0; i < cpas_core->num_axi_ports; i++) {
|
||||
if (mnoc_axi_port_updated[i])
|
||||
@@ -1055,10 +1284,23 @@ vote_start_clients:
|
||||
mnoc_axi_port->applied_ab_bw = applied_ab;
|
||||
mnoc_axi_port->applied_ib_bw = applied_ib;
|
||||
}
|
||||
|
||||
rc = cam_cpas_camnoc_set_vote_axi_clk_rate(
|
||||
cpas_hw, camnoc_axi_port_updated);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS, "Failed in setting axi clk rate rc=%d", rc);
|
||||
goto unlock_tree;
|
||||
}
|
||||
|
||||
if (soc_private->enable_smart_qos && apply_smart_qos) {
|
||||
CAM_DBG(CAM_PERF, "Apply Smart QoS after bw votes");
|
||||
|
||||
rc = cam_cpas_apply_smart_qos(cpas_hw);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS, "Failed in Smart QoS rc=%d", rc);
|
||||
goto unlock_tree;
|
||||
}
|
||||
}
|
||||
|
||||
unlock_tree:
|
||||
mutex_unlock(&cpas_core->tree_lock);
|
||||
@@ -1528,6 +1770,9 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args,
|
||||
CAM_DBG(CAM_CPAS, "irq_count=%d\n",
|
||||
atomic_read(&cpas_core->irq_count));
|
||||
|
||||
if (soc_private->enable_smart_qos)
|
||||
cam_cpas_reset_niu_priorities(cpas_hw);
|
||||
|
||||
cam_smmu_reset_cb_page_fault_cnt();
|
||||
cpas_hw->hw_state = CAM_HW_STATE_POWER_UP;
|
||||
}
|
||||
@@ -1910,6 +2155,9 @@ static int cam_cpas_log_vote(struct cam_hw_info *cpas_hw)
|
||||
struct cam_cpas_tree_node *curr_node;
|
||||
struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
|
||||
|
||||
if ((cpas_core->streamon_clients > 0) && soc_private->enable_smart_qos)
|
||||
cam_cpas_print_smart_qos_priority(cpas_hw);
|
||||
|
||||
/*
|
||||
* First print rpmh registers as early as possible to catch nearest
|
||||
* state of rpmh after an issue (overflow) occurs.
|
||||
@@ -2006,7 +2254,7 @@ static int cam_cpas_log_vote(struct cam_hw_info *cpas_hw)
|
||||
curr_node->mnoc_ab_bw, curr_node->mnoc_ib_bw);
|
||||
}
|
||||
|
||||
cam_cpas_dump_monitor_array(cpas_core);
|
||||
cam_cpas_dump_monitor_array(cpas_hw);
|
||||
|
||||
if (cpas_core->internal_ops.print_poweron_settings)
|
||||
cpas_core->internal_ops.print_poweron_settings(cpas_hw);
|
||||
@@ -2108,7 +2356,8 @@ static void cam_cpas_update_monitor_array(struct cam_hw_info *cpas_hw,
|
||||
|
||||
if (j >= CAM_CAMNOC_FILL_LVL_REG_INFO_MAX) {
|
||||
CAM_WARN(CAM_CPAS,
|
||||
"CPAS monitor reg info buffer full, max : %d", j);
|
||||
"CPAS monitor reg info buffer full, max : %d",
|
||||
j);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2120,11 +2369,25 @@ static void cam_cpas_update_monitor_array(struct cam_hw_info *cpas_hw,
|
||||
}
|
||||
|
||||
entry->num_camnoc_lvl_regs = j;
|
||||
|
||||
if (soc_private->enable_smart_qos) {
|
||||
for (i = 0; i < soc_private->smart_qos_info->num_rt_wr_nius; i++) {
|
||||
struct cam_cpas_tree_node *niu_node =
|
||||
soc_private->smart_qos_info->rt_wr_niu_node[i];
|
||||
|
||||
entry->rt_wr_niu_pri_lut[i] =
|
||||
cam_io_r_mb(soc_info->reg_map[reg_camnoc].mem_base +
|
||||
niu_node->pri_lut_low_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cam_cpas_dump_monitor_array(
|
||||
struct cam_cpas *cpas_core)
|
||||
struct cam_hw_info *cpas_hw)
|
||||
{
|
||||
struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
|
||||
struct cam_cpas_private_soc *soc_private =
|
||||
(struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
|
||||
int i = 0, j = 0;
|
||||
int64_t state_head = 0;
|
||||
uint32_t index, num_entries, oldest_entry;
|
||||
@@ -2205,9 +2468,22 @@ static void cam_cpas_dump_monitor_array(
|
||||
(entry->camnoc_fill_level[j] & 0x7FF),
|
||||
(entry->camnoc_fill_level[j] & 0x7F0000) >> 16);
|
||||
}
|
||||
|
||||
CAM_INFO(CAM_CPAS, "CAMNOC REG[Queued Pending] %s", log_buf);
|
||||
|
||||
if (soc_private->enable_smart_qos) {
|
||||
len = 0;
|
||||
for (j = 0; j < soc_private->smart_qos_info->num_rt_wr_nius; j++) {
|
||||
struct cam_cpas_tree_node *niu_node =
|
||||
soc_private->smart_qos_info->rt_wr_niu_node[j];
|
||||
|
||||
len += scnprintf((log_buf + len),
|
||||
(CAM_CPAS_LOG_BUF_LEN - len), " [%s: 0x%x]",
|
||||
niu_node->node_name,
|
||||
entry->rt_wr_niu_pri_lut[j]);
|
||||
}
|
||||
CAM_INFO(CAM_CPAS, "SmartQoS [Node: Pri_lut_low] %s", log_buf);
|
||||
}
|
||||
|
||||
index = (index + 1) % CAM_CPAS_MONITOR_MAX_ENTRIES;
|
||||
}
|
||||
}
|
||||
@@ -2665,6 +2941,9 @@ static int cam_cpas_util_create_debugfs(struct cam_cpas *cpas_core)
|
||||
dbgfileptr = debugfs_create_bool("full_state_dump", 0644,
|
||||
cpas_core->dentry, &cpas_core->full_state_dump);
|
||||
|
||||
dbgfileptr = debugfs_create_bool("smart_qos_dump", 0644,
|
||||
cpas_core->dentry, &cpas_core->smart_qos_dump);
|
||||
|
||||
if (IS_ERR(dbgfileptr)) {
|
||||
if (PTR_ERR(dbgfileptr) == -ENODEV)
|
||||
CAM_WARN(CAM_CPAS, "DebugFS not enabled in kernel!");
|
||||
@@ -2716,6 +2995,7 @@ int cam_cpas_hw_probe(struct platform_device *pdev,
|
||||
cpas_hw->open_count = 0;
|
||||
cpas_core->ahb_bus_scaling_disable = false;
|
||||
cpas_core->full_state_dump = false;
|
||||
cpas_core->smart_qos_dump = false;
|
||||
|
||||
atomic64_set(&cpas_core->monitor_head, -1);
|
||||
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#define CAM_CPAS_MAX_CLIENTS 42
|
||||
#define CAM_CPAS_MAX_AXI_PORTS 6
|
||||
#define CAM_CPAS_MAX_TREE_LEVELS 4
|
||||
#define CAM_CPAS_MAX_RT_WR_NIU_NODES 10
|
||||
#define CAM_CPAS_MAX_GRAN_PATHS_PER_CLIENT 32
|
||||
#define CAM_CPAS_PATH_DATA_MAX 40
|
||||
#define CAM_CPAS_TRANSACTION_MAX 2
|
||||
@@ -162,6 +163,7 @@ struct cam_cpas_bus_client {
|
||||
* @axi_port_name: Name of this AXI port
|
||||
* @bus_client: bus client info for this port
|
||||
* @ib_bw_voting_needed: if this port can update ib bw dynamically
|
||||
* @is_rt: if this port represents a real time axi port
|
||||
* @axi_port_node: Node representing AXI Port info in device tree
|
||||
* @ab_bw: AB bw value for this port
|
||||
* @ib_bw: IB bw value for this port
|
||||
@@ -174,6 +176,7 @@ struct cam_cpas_axi_port {
|
||||
const char *axi_port_name;
|
||||
struct cam_cpas_bus_client bus_client;
|
||||
bool ib_bw_voting_needed;
|
||||
bool is_rt;
|
||||
struct device_node *axi_port_node;
|
||||
uint64_t ab_bw;
|
||||
uint64_t ib_bw;
|
||||
@@ -225,22 +228,24 @@ struct cam_cpas_axi_port_debug_info {
|
||||
* monitoring registers
|
||||
* @camnoc_port_name: Camnoc port names
|
||||
* @camnoc_fill_level: Camnoc fill level register info
|
||||
* @rt_wr_niu_pri_lut: priority lut low values of RT Wr NIUs
|
||||
*/
|
||||
struct cam_cpas_monitor {
|
||||
struct timespec64 timestamp;
|
||||
char identifier_string[128];
|
||||
int32_t identifier_value;
|
||||
struct timespec64 timestamp;
|
||||
char identifier_string[128];
|
||||
int32_t identifier_value;
|
||||
struct cam_cpas_axi_port_debug_info axi_info[CAM_CPAS_MAX_AXI_PORTS];
|
||||
uint64_t applied_camnoc_clk;
|
||||
unsigned int applied_ahb_level;
|
||||
uint32_t fe_ddr;
|
||||
uint32_t be_ddr;
|
||||
uint32_t fe_mnoc;
|
||||
uint32_t be_mnoc;
|
||||
uint32_t be_shub;
|
||||
uint32_t num_camnoc_lvl_regs;
|
||||
const char *camnoc_port_name[CAM_CAMNOC_FILL_LVL_REG_INFO_MAX];
|
||||
uint32_t camnoc_fill_level[CAM_CAMNOC_FILL_LVL_REG_INFO_MAX];
|
||||
uint64_t applied_camnoc_clk;
|
||||
unsigned int applied_ahb_level;
|
||||
uint32_t fe_ddr;
|
||||
uint32_t be_ddr;
|
||||
uint32_t fe_mnoc;
|
||||
uint32_t be_mnoc;
|
||||
uint32_t be_shub;
|
||||
uint32_t num_camnoc_lvl_regs;
|
||||
const char *camnoc_port_name[CAM_CAMNOC_FILL_LVL_REG_INFO_MAX];
|
||||
uint32_t camnoc_fill_level[CAM_CAMNOC_FILL_LVL_REG_INFO_MAX];
|
||||
uint32_t rt_wr_niu_pri_lut[CAM_CPAS_MAX_RT_WR_NIU_NODES];
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -269,6 +274,8 @@ struct cam_cpas_monitor {
|
||||
* @monitor_head: Monitor array head
|
||||
* @monitor_entries: cpas monitor array
|
||||
* @full_state_dump: Whether to enable full cpas state dump or not
|
||||
* @smart_qos_dump: Whether to dump smart qos information on update
|
||||
* @camnoc_info: Pointer to camnoc header info
|
||||
*/
|
||||
struct cam_cpas {
|
||||
struct cam_cpas_hw_caps hw_caps;
|
||||
@@ -294,6 +301,7 @@ struct cam_cpas {
|
||||
atomic64_t monitor_head;
|
||||
struct cam_cpas_monitor monitor_entries[CAM_CPAS_MONITOR_MAX_ENTRIES];
|
||||
bool full_state_dump;
|
||||
bool smart_qos_dump;
|
||||
void *camnoc_info;
|
||||
};
|
||||
|
||||
|
@@ -194,6 +194,7 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
|
||||
struct cam_cpas_client *curr_client = NULL;
|
||||
const char *client_name = NULL;
|
||||
uint32_t client_idx = 0, cell_idx = 0;
|
||||
uint8_t niu_idx = 0;
|
||||
int rc = 0, count = 0, i;
|
||||
|
||||
camera_bus_node = of_get_child_by_name(of_node, "camera-bus-nodes");
|
||||
@@ -219,6 +220,9 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
|
||||
soc_private->level_node[level_idx] = level_node;
|
||||
}
|
||||
|
||||
if (soc_private->enable_smart_qos)
|
||||
soc_private->smart_qos_info->num_rt_wr_nius = 0;
|
||||
|
||||
for (level_idx = (CAM_CPAS_MAX_TREE_LEVELS - 1); level_idx >= 0;
|
||||
level_idx--) {
|
||||
level_node = soc_private->level_node[level_idx];
|
||||
@@ -262,6 +266,47 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (soc_private->enable_smart_qos &&
|
||||
(level_idx == 1) &&
|
||||
of_property_read_bool(curr_node, "rt-wr-niu")) {
|
||||
|
||||
rc = of_property_read_u32(curr_node,
|
||||
"priority-lut-low-offset",
|
||||
&curr_node_ptr->pri_lut_low_offset);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"Invalid priority offset rc %d",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(curr_node, "niu-size",
|
||||
&curr_node_ptr->niu_size);
|
||||
if (rc || !curr_node_ptr->niu_size) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"Invalid niu size rc %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
niu_idx = soc_private->smart_qos_info->num_rt_wr_nius;
|
||||
if (niu_idx >= CAM_CPAS_MAX_RT_WR_NIU_NODES) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"Invalid number of level1 nodes %d",
|
||||
soc_private->smart_qos_info->num_rt_wr_nius);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
soc_private->smart_qos_info->rt_wr_niu_node[niu_idx] =
|
||||
curr_node_ptr;
|
||||
soc_private->smart_qos_info->num_rt_wr_nius++;
|
||||
|
||||
CAM_DBG(CAM_CPAS,
|
||||
"level1[%d] : Node %s idx %d priority offset 0x%x, NIU size %dKB",
|
||||
niu_idx,
|
||||
curr_node_ptr->node_name, curr_node_ptr->cell_idx,
|
||||
curr_node_ptr->pri_lut_low_offset, curr_node_ptr->niu_size);
|
||||
}
|
||||
|
||||
curr_node_ptr->camnoc_max_needed = camnoc_max_needed;
|
||||
rc = of_property_read_u32(curr_node, "bus-width-factor",
|
||||
&curr_node_ptr->bus_width_factor);
|
||||
@@ -365,6 +410,10 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
|
||||
[mnoc_idx].ib_bw_voting_needed
|
||||
= of_property_read_bool(curr_node,
|
||||
"ib-bw-voting-needed");
|
||||
cpas_core->axi_port
|
||||
[mnoc_idx].is_rt
|
||||
= of_property_read_bool(curr_node,
|
||||
"rt-axi-port");
|
||||
curr_node_ptr->axi_port_idx = mnoc_idx;
|
||||
mnoc_idx++;
|
||||
cpas_core->num_axi_ports++;
|
||||
@@ -1012,12 +1061,89 @@ int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw,
|
||||
soc_private->num_vdd_ahb_mapping = count;
|
||||
}
|
||||
|
||||
soc_private->enable_smart_qos = of_property_read_bool(of_node,
|
||||
"enable-smart-qos");
|
||||
|
||||
if (soc_private->enable_smart_qos) {
|
||||
uint32_t value1, value2;
|
||||
|
||||
soc_private->smart_qos_info = kzalloc(sizeof(struct cam_cpas_smart_qos_info),
|
||||
GFP_KERNEL);
|
||||
if (!soc_private->smart_qos_info) {
|
||||
rc = -ENOMEM;
|
||||
goto cleanup_clients;
|
||||
}
|
||||
|
||||
/*
|
||||
* If enabled, we expect min and max priority values,
|
||||
* so treat as fatal error if not available.
|
||||
*/
|
||||
rc = of_property_read_u32(of_node, "rt-wr-priority-min",
|
||||
&value1);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS, "Invalid min Qos priority rc %d", rc);
|
||||
goto cleanup_clients;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(of_node, "rt-wr-priority-max",
|
||||
&value2);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS, "Invalid min Qos priority rc %d", rc);
|
||||
goto cleanup_clients;
|
||||
}
|
||||
|
||||
soc_private->smart_qos_info->rt_wr_priority_min = (uint8_t)value1;
|
||||
soc_private->smart_qos_info->rt_wr_priority_max = (uint8_t)value2;
|
||||
|
||||
CAM_DBG(CAM_CPAS,
|
||||
"SmartQoS enabled, rt_wr_priority_min=%u, rt_wr_priority_max=%u",
|
||||
(uint32_t)soc_private->smart_qos_info->rt_wr_priority_min,
|
||||
(uint32_t)soc_private->smart_qos_info->rt_wr_priority_max);
|
||||
} else {
|
||||
CAM_DBG(CAM_CPAS, "SmartQoS not enabled, use static settings");
|
||||
soc_private->smart_qos_info = NULL;
|
||||
}
|
||||
|
||||
rc = cam_cpas_parse_node_tree(cpas_core, of_node, soc_private);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS, "Node tree parsing failed rc: %d", rc);
|
||||
goto cleanup_tree;
|
||||
}
|
||||
|
||||
/* If SmartQoS is enabled, we expect few tags in dtsi, validate */
|
||||
if (soc_private->enable_smart_qos) {
|
||||
int port_idx;
|
||||
bool rt_port_exists = false;
|
||||
|
||||
if ((soc_private->smart_qos_info->num_rt_wr_nius == 0) ||
|
||||
(soc_private->smart_qos_info->num_rt_wr_nius >
|
||||
CAM_CPAS_MAX_RT_WR_NIU_NODES)) {
|
||||
CAM_ERR(CAM_CPAS, "Invalid number of level1 nodes %d",
|
||||
soc_private->smart_qos_info->num_rt_wr_nius);
|
||||
rc = -EINVAL;
|
||||
goto cleanup_tree;
|
||||
}
|
||||
|
||||
for (port_idx = 0; port_idx < cpas_core->num_axi_ports;
|
||||
port_idx++) {
|
||||
CAM_DBG(CAM_CPAS, "[%d] : Port[%s] is_rt=%d",
|
||||
port_idx, cpas_core->axi_port[port_idx].axi_port_name,
|
||||
cpas_core->axi_port[port_idx].is_rt);
|
||||
if (cpas_core->axi_port[port_idx].is_rt) {
|
||||
rt_port_exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rt_port_exists) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"RT AXI port not tagged, num ports %d",
|
||||
cpas_core->num_axi_ports);
|
||||
rc = -EINVAL;
|
||||
goto cleanup_tree;
|
||||
}
|
||||
}
|
||||
|
||||
/* Optional rpmh bcm info */
|
||||
count = of_property_count_u32_elems(of_node, "rpmh-bcm-info");
|
||||
/*
|
||||
@@ -1125,6 +1251,7 @@ int cam_cpas_soc_deinit_resources(struct cam_hw_soc_info *soc_info)
|
||||
CAM_ERR(CAM_CPAS, "release platform failed, rc=%d", rc);
|
||||
|
||||
kfree(soc_private->llcc_info);
|
||||
kfree(soc_private->smart_qos_info);
|
||||
kfree(soc_info->soc_private);
|
||||
soc_info->soc_private = NULL;
|
||||
|
||||
|
@@ -50,6 +50,11 @@ struct cam_cpas_vdd_ahb_mapping {
|
||||
* @tree_dev_node: Device node from devicetree for current tree node
|
||||
* @parent_node: Pointer to node one or more level above the current level
|
||||
* (starting from end node of cpas client)
|
||||
* @pri_lut_low_offset: Register offset value for priority lut low.
|
||||
* Valid only for level1 nodes (representing NIUs)
|
||||
* @niu_size: Size of NIU that this node represents. Size in KB
|
||||
* @curr_priority: New calculated priority
|
||||
* @applied_priority: Currently applied priority
|
||||
*
|
||||
*/
|
||||
struct cam_cpas_tree_node {
|
||||
@@ -71,6 +76,10 @@ struct cam_cpas_tree_node {
|
||||
bool constituent_paths[CAM_CPAS_PATH_DATA_MAX];
|
||||
struct device_node *tree_dev_node;
|
||||
struct cam_cpas_tree_node *parent_node;
|
||||
uint32_t pri_lut_low_offset;
|
||||
uint32_t niu_size;
|
||||
uint32_t curr_priority;
|
||||
uint32_t applied_priority;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -110,6 +119,23 @@ struct cam_sys_cache_info {
|
||||
struct llcc_slice_desc *slic_desc;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* struct cam_cpas_smart_qos_info : Smart QOS info
|
||||
*
|
||||
* @rt_wr_priority_min: Minimum priority value for rt write nius
|
||||
* @rt_wr_priority_max: Maximum priority value for rt write nius
|
||||
* @num_rt_wr_nius: Number of RT Wr NIUs
|
||||
* @rt_wr_niu_node: List of level1 nodes representing RT Wr NIUs
|
||||
*/
|
||||
struct cam_cpas_smart_qos_info {
|
||||
uint8_t rt_wr_priority_min;
|
||||
uint8_t rt_wr_priority_max;
|
||||
uint8_t num_rt_wr_nius;
|
||||
struct cam_cpas_tree_node *rt_wr_niu_node[CAM_CPAS_MAX_RT_WR_NIU_NODES];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* struct cam_cpas_private_soc : CPAS private DT info
|
||||
*
|
||||
@@ -134,7 +160,9 @@ struct cam_sys_cache_info {
|
||||
* @num_feature_info: number of feature_info entries
|
||||
* @feature_info: Structure for storing feature information
|
||||
* @num_caches: Number of last level caches
|
||||
* @llcc_info: Cache info
|
||||
* @llcc_info: Cache info
|
||||
* @enable_smart_qos: Whether to enable Smart QoS mechanism on current chipset
|
||||
* @smart_qos_info: Pointer to smart qos info
|
||||
*/
|
||||
struct cam_cpas_private_soc {
|
||||
const char *arch_compat;
|
||||
@@ -157,6 +185,8 @@ struct cam_cpas_private_soc {
|
||||
struct cam_cpas_feature_info feature_info[CAM_CPAS_MAX_FUSE_FEATURE];
|
||||
uint32_t num_caches;
|
||||
struct cam_sys_cache_info *llcc_info;
|
||||
bool enable_smart_qos;
|
||||
struct cam_cpas_smart_qos_info *smart_qos_info;
|
||||
};
|
||||
|
||||
void cam_cpas_util_debug_parse_data(struct cam_cpas_private_soc *soc_private);
|
||||
|
Référencer dans un nouveau ticket
Bloquer un utilisateur