static int msm_bus_node_debug(struct device *bus_dev, void *data) { int j; int ret = 0; struct msm_bus_node_device_type *bus_node = NULL; bus_node = bus_dev->platform_data; if (!bus_node) { MSM_BUS_ERR("%s: Can't get device info", __func__); ret = -ENODEV; goto exit_node_debug; } MSM_BUS_DBG("Device = %d buswidth %u", bus_node->node_info->id, bus_node->node_info->buswidth); for (j = 0; j < bus_node->node_info->num_connections; j++) { struct msm_bus_node_device_type *bdev = (struct msm_bus_node_device_type *) bus_node->node_info->dev_connections[j]->platform_data; MSM_BUS_DBG("\n\t Connection[%d] %d", j, bdev->node_info->id); } exit_node_debug: return ret; }
bool msm_bus_rpm_is_mem_interleaved(void) { int status = 0; struct msm_rpm_iv_pair il[2]; uint16_t id[2]; il[0].value = 0; il[1].value = 0; status = msm_bus_board_rpm_get_il_ids(id); if (status) { MSM_BUS_DBG("Dynamic check not supported, " "default: Interleaved memory\n"); goto inter; } il[0].id = id[0]; il[1].id = id[1]; status = msm_rpm_get_status(il, ARRAY_SIZE(il)); if (status) { MSM_BUS_ERR("Status read for interleaving returned: %d\n" "Using interleaved memory by default\n", status); goto inter; } if ((il[0].value & 0xFFFF0000) != (il[1].value & 0xFFFF0000)) { MSM_BUS_DBG("Non-interleaved memory\n"); return false; } inter: MSM_BUS_DBG("Interleaved memory\n"); return true; }
int msm_bus_update_clks(struct msm_bus_node_device_type *nodedev, int ctx, int **dirty_nodes, int *num_dirty) { int status = 0; struct nodeclk *nodeclk; struct nodeclk *busclk; struct msm_bus_node_device_type *bus_info = NULL; uint64_t req_clk; bus_info = nodedev->node_info->bus_device->platform_data; if (!bus_info) { MSM_BUS_ERR("%s: Unable to find bus device for device %d", __func__, nodedev->node_info->id); status = -ENODEV; goto exit_set_clks; } req_clk = nodedev->cur_clk_hz[ctx]; busclk = &bus_info->clk[ctx]; if (busclk->rate != req_clk) { busclk->rate = req_clk; busclk->dirty = 1; MSM_BUS_DBG("%s: Modifying bus clk %d Rate %llu", __func__, bus_info->node_info->id, req_clk); status = add_dirty_node(dirty_nodes, bus_info->node_info->id, num_dirty); if (status) { MSM_BUS_ERR("%s: Failed to add dirty node %d", __func__, bus_info->node_info->id); goto exit_set_clks; } } req_clk = nodedev->cur_clk_hz[ctx]; nodeclk = &nodedev->clk[ctx]; if (IS_ERR_OR_NULL(nodeclk)) goto exit_set_clks; if (!nodeclk->dirty || (nodeclk->dirty && (nodeclk->rate < req_clk))) { nodeclk->rate = req_clk; nodeclk->dirty = 1; MSM_BUS_DBG("%s: Modifying node clk %d Rate %llu", __func__, nodedev->node_info->id, req_clk); status = add_dirty_node(dirty_nodes, nodedev->node_info->id, num_dirty); if (status) { MSM_BUS_ERR("%s: Failed to add dirty node %d", __func__, nodedev->node_info->id); goto exit_set_clks; } } exit_set_clks: return status; }
static void msm_bus_bimc_config_limiter( struct msm_bus_fabric_registration *fab_pdata, struct msm_bus_inode_info *info) { struct msm_bus_bimc_info *binfo; int mode, i, ports; binfo = (struct msm_bus_bimc_info *)fab_pdata->hw_data; ports = info->node_info->num_mports; if (!info->node_info->qport) { MSM_BUS_DBG("No QoS Ports to init\n"); return; } if (info->cur_lim_bw) mode = BIMC_QOS_MODE_LIMITER; else mode = info->node_info->mode; switch (mode) { case BIMC_QOS_MODE_BYPASS: case BIMC_QOS_MODE_FIXED: for (i = 0; i < ports; i++) bke_switch(binfo->base, info->node_info->qport[i], BKE_OFF, mode); break; case BIMC_QOS_MODE_REGULATOR: case BIMC_QOS_MODE_LIMITER: if (info->cur_lim_bw != info->cur_prg_bw) { MSM_BUS_DBG("Enabled BKE throttling node %d to %llu\n", info->node_info->id, info->cur_lim_bw); trace_bus_bimc_config_limiter(info->node_info->id, info->cur_lim_bw); for (i = 0; i < ports; i++) { /* If not in fixed mode, update bandwidth */ struct msm_bus_bimc_qos_bw qbw; qbw.ws = info->node_info->ws; qbw.bw = info->cur_lim_bw; qbw.gp = info->node_info->bimc_gp; qbw.thmp = info->node_info->bimc_thmp; bimc_set_static_qos_bw(binfo->base, binfo->qos_freq, info->node_info->qport[i], &qbw); bke_switch(binfo->base, info->node_info->qport[i], BKE_ON, mode); info->cur_prg_bw = qbw.bw; } } break; default: break; } }
int reset_pnodes(int curr, int pnode) { struct msm_bus_inode_info *info; struct msm_bus_fabric_device *fabdev; int index, next_pnode; fabdev = msm_bus_get_fabric_device(GET_FABID(curr)); if (!fabdev) { MSM_BUS_ERR("Fabric not found for: %d\n", (GET_FABID(curr))); return -ENXIO; } index = GET_INDEX(pnode); info = fabdev->algo->find_node(fabdev, curr); if (!info) { MSM_BUS_ERR("Cannot find node info!\n"); return -ENXIO; } MSM_BUS_DBG("Starting the loop--remove\n"); do { struct msm_bus_inode_info *hop; fabdev = msm_bus_get_fabric_device(GET_FABID(curr)); if (!fabdev) { MSM_BUS_ERR("Fabric not found\n"); return -ENXIO; } next_pnode = info->pnode[index].next; info->pnode[index].next = -2; curr = GET_NODE(next_pnode); index = GET_INDEX(next_pnode); if (IS_NODE(curr)) hop = fabdev->algo->find_node(fabdev, curr); else hop = fabdev->algo->find_gw_node(fabdev, curr); if (!hop) { MSM_BUS_ERR("Null Info found for hop\n"); return -ENXIO; } MSM_BUS_DBG("%d[%d] = %d\n", info->node_info->priv_id, index, info->pnode[index].next); MSM_BUS_DBG("num_pnodes: %d: %d\n", info->node_info->priv_id, info->num_pnodes); info = hop; } while (GET_NODE(info->pnode[index].next) != info->node_info->priv_id); info->pnode[index].next = -2; MSM_BUS_DBG("%d[%d] = %d\n", info->node_info->priv_id, index, info->pnode[index].next); MSM_BUS_DBG("num_pnodes: %d: %d\n", info->node_info->priv_id, info->num_pnodes); return 0; }
static int msm_bus_rpm_commit_arb(struct msm_bus_fabric_registration *fab_pdata, int ctx, void *rpm_data, struct commit_data *cd, bool valid) { int i, status = 0, rsc_type, key; MSM_BUS_DBG("Context: %d\n", ctx); rsc_type = RPM_BUS_MASTER_REQ; key = RPM_MASTER_FIELD_BW; for (i = 0; i < fab_pdata->nmasters; i++) { if (cd->mas_arb[i].dirty) { MSM_BUS_DBG("MAS HWID: %d, BW: %llu DIRTY: %d\n", cd->mas_arb[i].hw_id, cd->mas_arb[i].bw, cd->mas_arb[i].dirty); status = msm_bus_rpm_req(ctx, rsc_type, key, &cd->mas_arb[i], valid); if (status) { MSM_BUS_ERR("RPM: Req fail: mas:%d, bw:%llu\n", cd->mas_arb[i].hw_id, cd->mas_arb[i].bw); break; } else { cd->mas_arb[i].dirty = false; } } } rsc_type = RPM_BUS_SLAVE_REQ; key = RPM_SLAVE_FIELD_BW; for (i = 0; i < fab_pdata->nslaves; i++) { if (cd->slv_arb[i].dirty) { MSM_BUS_DBG("SLV HWID: %d, BW: %llu DIRTY: %d\n", cd->slv_arb[i].hw_id, cd->slv_arb[i].bw, cd->slv_arb[i].dirty); status = msm_bus_rpm_req(ctx, rsc_type, key, &cd->slv_arb[i], valid); if (status) { MSM_BUS_ERR("RPM: Req fail: slv:%d, bw:%llu\n", cd->slv_arb[i].hw_id, cd->slv_arb[i].bw); break; } else { cd->slv_arb[i].dirty = false; } } } return status; }
static u64 *get_th_params(struct platform_device *pdev, const struct device_node *node, const char *prop, int *nports) { int size = 0, ret; u64 *ret_arr = NULL; int *arr = NULL; int i; if (of_get_property(node, prop, &size)) { *nports = size / sizeof(int); } else { pr_debug("Property %s not available\n", prop); *nports = 0; return NULL; } ret_arr = devm_kzalloc(&pdev->dev, (*nports * sizeof(u64)), GFP_KERNEL); arr = kzalloc(size, GFP_KERNEL); if ((size > 0) && (ZERO_OR_NULL_PTR(arr) || ZERO_OR_NULL_PTR(ret_arr))) { if (arr) kfree(arr); else if (ret_arr) devm_kfree(&pdev->dev, ret_arr); pr_err("Error: Failed to alloc mem for %s\n", prop); return NULL; } ret = of_property_read_u32_array(node, prop, (u32 *)arr, *nports); if (ret) { pr_err("Error in reading property: %s\n", prop); goto err; } for (i = 0; i < *nports; i++) ret_arr[i] = (uint64_t)KBTOB(arr[i]); MSM_BUS_DBG("%s: num entries %d prop %s", __func__, *nports, prop); for (i = 0; i < *nports; i++) MSM_BUS_DBG("Th %d val %llu", i, ret_arr[i]); kfree(arr); return ret_arr; err: kfree(arr); devm_kfree(&pdev->dev, ret_arr); return NULL; }
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 uint64_t get_vfe_bw(void) { int vfe_id = MSM_BUS_MASTER_VFE; int iid = msm_bus_board_get_iid(vfe_id); int fabid; struct msm_bus_fabric_device *fabdev; struct msm_bus_inode_info *info; uint64_t vfe_bw = 0; fabid = GET_FABID(iid); fabdev = msm_bus_get_fabric_device(fabid); if (!fabdev) { MSM_BUS_ERR("Fabric not found for: %d\n", fabid); goto exit_get_vfe_bw; } info = fabdev->algo->find_node(fabdev, iid); if (!info) { MSM_BUS_ERR("%s: Can't find node %d", __func__, vfe_id); goto exit_get_vfe_bw; } vfe_bw = get_node_sumab(info); MSM_BUS_DBG("vfe_ab %llu", vfe_bw); exit_get_vfe_bw: return vfe_bw; }
static int msm_bus_dev_init_qos(struct device *dev, void *data) { int ret = 0; struct msm_bus_node_device_type *node_dev = NULL; node_dev = dev->platform_data; if (!node_dev) { MSM_BUS_ERR("%s: Unable to get node device info" , __func__); ret = -ENXIO; goto exit_init_qos; } MSM_BUS_DBG("Device = %d", node_dev->node_info->id); if (node_dev->ap_owned) { struct msm_bus_node_device_type *bus_node_info; bus_node_info = node_dev->node_info->bus_device->platform_data; if (!bus_node_info) { MSM_BUS_ERR("%s: Unable to get bus device infofor %d", __func__, node_dev->node_info->id); ret = -ENXIO; goto exit_init_qos; } if (bus_node_info->fabdev && bus_node_info->fabdev->noc_ops.qos_init) { int ret = 0; if (node_dev->ap_owned && (node_dev->node_info->qos_params.mode) != -1) { if (bus_node_info->fabdev->bypass_qos_prg) goto exit_init_qos; ret = msm_bus_qos_enable_clk(node_dev); if (ret < 0) { MSM_BUS_ERR("Can't Enable QoS clk %d", node_dev->node_info->id); goto exit_init_qos; } bus_node_info->fabdev->noc_ops.qos_init( node_dev, bus_node_info->fabdev->qos_base, bus_node_info->fabdev->base_offset, bus_node_info->fabdev->qos_off, bus_node_info->fabdev->qos_freq); msm_bus_qos_disable_clk(node_dev, ret); } } else MSM_BUS_ERR("%s: Skipping QOS init for %d", __func__, node_dev->node_info->id); } exit_init_qos: return ret; }
static int flush_clk_data(struct device *node_device, int ctx) { struct msm_bus_node_device_type *node; struct nodeclk *nodeclk = NULL; int ret = 0; node = node_device->platform_data; if (!node) { MSM_BUS_ERR("%s: Unable to find bus device for device %d", __func__, node->node_info->id); ret = -ENODEV; goto exit_flush_clk_data; } nodeclk = &node->clk[ctx]; if (node->node_info->is_fab_dev) { if (nodeclk->rate != node->cur_clk_hz[ctx]) { nodeclk->rate = node->cur_clk_hz[ctx]; nodeclk->dirty = true; } } if (nodeclk && nodeclk->clk && nodeclk->dirty) { long rounded_rate; if (nodeclk->rate) { rounded_rate = clk_round_rate(nodeclk->clk, nodeclk->rate); ret = setrate_nodeclk(nodeclk, rounded_rate); if (ret) { MSM_BUS_ERR("%s: Failed to set_rate %lu for %d", __func__, rounded_rate, node->node_info->id); ret = -ENODEV; goto exit_flush_clk_data; } ret = enable_nodeclk(nodeclk); } else ret = disable_nodeclk(nodeclk); if (ret) { MSM_BUS_ERR("%s: Failed to enable for %d", __func__, node->node_info->id); ret = -ENODEV; goto exit_flush_clk_data; } MSM_BUS_DBG("%s: Updated %d clk to %llu", __func__, node->node_info->id, nodeclk->rate); } exit_flush_clk_data: /* Reset the aggregated clock rate for fab devices*/ if (node->node_info->is_fab_dev) node->cur_clk_hz[ctx] = 0; nodeclk->dirty = 0; return ret; }
static int msm_bus_bimc_commit(struct msm_bus_fabric_registration *fab_pdata, void *hw_data, void **cdata) { MSM_BUS_DBG("\nReached BIMC Commit\n"); msm_bus_remote_hw_commit(fab_pdata, hw_data, cdata); return 0; }
static uint32_t noc_sat_field(uint64_t bw, uint32_t ws, uint32_t qos_freq) { uint32_t sat_field = 0, win; 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); /** * Calculate saturation from windows size. * WS must be at least one arb period. * Saturation must not exceed max field size * * Bandwidth is in 100KB increments * Window size is in ns * qos_freq is in KHz */ win = max(ws, 1000000 / qos_freq); tbw = bw_scaled * win * qos_freq; tscale = 10000000ULL * BW_SCALE * SAT_SCALE; rem = noc_div(&tbw, tscale); sat_field = (uint32_t)min_t(uint64_t, tbw, MAX_SAT_FIELD); } MSM_BUS_DBG("NOC: sat_field: %d\n", sat_field); return sat_field; }
static void init_health_regs(struct msm_bus_bimc_info *binfo, struct msm_bus_inode_info *info, struct msm_bus_bimc_qos_mode *qmode, int mode) { int i; if (mode == 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; if (!info->node_info->qport) { MSM_BUS_DBG("No QoS Ports to init\n"); return; } for (i = 0; i < info->node_info->num_mports; i++) { /* If not in bypass mode, update priority */ if (mode != BIMC_QOS_MODE_BYPASS) msm_bus_bimc_set_qos_prio(binfo->base, info->node_info->qport[i], mode, qmode); } } }
/** * msm_bus_scale_unregister_client() - Unregister the client from the bus driver * @cl: Handle to the client */ void msm_bus_scale_unregister_client(uint32_t cl) { int i; struct msm_bus_client *client = (struct msm_bus_client *)(cl); bool warn = false; if (IS_ERR_OR_NULL(client)) return; for (i = 0; i < client->pdata->usecase->num_paths; i++) { if ((client->pdata->usecase[0].vectors[i].ab) || (client->pdata->usecase[0].vectors[i].ib)) { warn = true; break; } } if (warn) { int num_paths = client->pdata->usecase->num_paths; int ab[num_paths], ib[num_paths]; WARN(1, "%s called unregister with non-zero vectors\n", client->pdata->name); /* * Save client values and zero them out to * cleanly unregister */ for (i = 0; i < num_paths; i++) { ab[i] = client->pdata->usecase[0].vectors[i].ab; ib[i] = client->pdata->usecase[0].vectors[i].ib; client->pdata->usecase[0].vectors[i].ab = 0; client->pdata->usecase[0].vectors[i].ib = 0; } msm_bus_scale_client_update_request(cl, 0); /* Restore client vectors if required for re-registering. */ for (i = 0; i < num_paths; i++) { client->pdata->usecase[0].vectors[i].ab = ab[i]; client->pdata->usecase[0].vectors[i].ib = ib[i]; } } else if (client->curr != 0) msm_bus_scale_client_update_request(cl, 0); MSM_BUS_DBG("Unregistering client %d\n", cl); #ifdef SEC_FEATURE_USE_RT_MUTEX rt_mutex_lock(&msm_bus_lock); #else mutex_lock(&msm_bus_lock); #endif msm_bus_scale_client_reset_pnodes(cl); msm_bus_dbg_client_data(client->pdata, MSM_BUS_DBG_UNREGISTER, cl); #ifdef SEC_FEATURE_USE_RT_MUTEX rt_mutex_unlock(&msm_bus_lock); #else mutex_unlock(&msm_bus_lock); #endif kfree(client->src_pnode); kfree(client); }
/** * msm_bus_commit_fn() - Commits the data for fabric to rpm * @dev: fabric device * @data: NULL */ static int msm_bus_commit_fn(struct device *dev, void *data) { int ret = 0; struct msm_bus_fabric_device *fabdev = to_msm_bus_fabric_device(dev); MSM_BUS_DBG("Committing: fabid: %d\n", fabdev->id); ret = fabdev->algo->commit(fabdev); return ret; }
/** * add_path_node: Adds the path information to the current node * @info: Internal node info structure * @next: Combination of the id and index of the next node * Function returns: Number of pnodes (path_nodes) on success, * error on failure. * * Every node maintains the list of path nodes. A path node is * reached by finding the node-id and index stored at the current * node. This makes updating the paths with requested bw and clock * values efficient, as it avoids lookup for each update-path request. */ static int add_path_node(struct msm_bus_inode_info *info, int next) { struct path_node *pnode; int i; if (ZERO_OR_NULL_PTR(info)) { MSM_BUS_ERR("Cannot find node info!: id :%d\n", info->node_info->priv_id); return -ENXIO; } for (i = 0; i <= info->num_pnodes; i++) { if (info->pnode[i].next == -2) { MSM_BUS_DBG("Reusing pnode for info: %d at index: %d\n", info->node_info->priv_id, i); info->pnode[i].clk[DUAL_CTX] = 0; info->pnode[i].clk[ACTIVE_CTX] = 0; info->pnode[i].bw[DUAL_CTX] = 0; info->pnode[i].bw[ACTIVE_CTX] = 0; info->pnode[i].next = next; MSM_BUS_DBG("%d[%d] : (%d, %d)\n", info->node_info->priv_id, i, GET_NODE(next), GET_INDEX(next)); return i; } } info->num_pnodes++; pnode = krealloc(info->pnode, ((info->num_pnodes + 1) * sizeof(struct path_node)) , GFP_KERNEL); if (ZERO_OR_NULL_PTR(pnode)) { MSM_BUS_ERR("Error creating path node!\n"); info->num_pnodes--; return -ENOMEM; } info->pnode = pnode; info->pnode[info->num_pnodes].clk[DUAL_CTX] = 0; info->pnode[info->num_pnodes].clk[ACTIVE_CTX] = 0; info->pnode[info->num_pnodes].bw[DUAL_CTX] = 0; info->pnode[info->num_pnodes].bw[ACTIVE_CTX] = 0; info->pnode[info->num_pnodes].next = next; MSM_BUS_DBG("%d[%d] : (%d, %d)\n", info->node_info->priv_id, info->num_pnodes, GET_NODE(next), GET_INDEX(next)); return info->num_pnodes; }
static int msm_bus_commit_limiter(struct device *dev, void *data) { int ret = 0; struct msm_bus_fabric_device *fabdev = to_msm_bus_fabric_device(dev); MSM_BUS_DBG("fabid: %d\n", fabdev->id); program_nr_limits(fabdev); return ret; }
static int msm_bus_rpm_req(int ctx, uint32_t rsc_type, uint32_t key, struct msm_bus_node_hw_info *hw_info, bool valid) { struct msm_rpm_request *rpm_req; int ret = 0, msg_id; if (ctx == ACTIVE_CTX) ctx = MSM_RPM_CTX_ACTIVE_SET; else if (ctx == DUAL_CTX) ctx = MSM_RPM_CTX_SLEEP_SET; rpm_req = msm_rpm_create_request(ctx, rsc_type, hw_info->hw_id, 1); if (rpm_req == NULL) { MSM_BUS_WARN("RPM: Couldn't create RPM Request\n"); return -ENXIO; } if (valid) { ret = msm_rpm_add_kvp_data(rpm_req, key, (const uint8_t *) &hw_info->bw, (int)(sizeof(uint64_t))); if (ret) { MSM_BUS_WARN("RPM: Add KVP failed for RPM Req:%u\n", rsc_type); goto free_rpm_request; } MSM_BUS_DBG("Added Key: %d, Val: %llu, size: %zu\n", key, hw_info->bw, sizeof(uint64_t)); } else { /* Invalidate RPM requests */ ret = msm_rpm_add_kvp_data(rpm_req, 0, NULL, 0); if (ret) { MSM_BUS_WARN("RPM: Add KVP failed for RPM Req:%u\n", rsc_type); goto free_rpm_request; } } msg_id = msm_rpm_send_request(rpm_req); if (!msg_id) { MSM_BUS_WARN("RPM: No message ID for req\n"); ret = -ENXIO; goto free_rpm_request; } ret = msm_rpm_wait_for_ack(msg_id); if (ret) { MSM_BUS_WARN("RPM: Ack failed\n"); goto free_rpm_request; } free_rpm_request: msm_rpm_free_request(rpm_req); return ret; }
static int msm_bus_bimc_allocate_commit_data(struct msm_bus_fabric_registration *fab_pdata, void **cdata, int ctx) { struct msm_bus_bimc_commit **cd = (struct msm_bus_bimc_commit **)cdata; struct msm_bus_bimc_info *binfo = (struct msm_bus_bimc_info *)fab_pdata->hw_data; MSM_BUS_DBG("Allocating BIMC commit data\n"); *cd = kzalloc(sizeof(struct msm_bus_bimc_commit), GFP_KERNEL); if (!*cd) { MSM_BUS_DBG("Couldn't alloc mem for cdata\n"); return -ENOMEM; } (*cd)->mas = binfo->cdata[ctx].mas; (*cd)->slv = binfo->cdata[ctx].slv; return 0; }
static uint64_t get_mdp_bw(void) { int ids[] = {MSM_BUS_MASTER_MDP_PORT0, MSM_BUS_MASTER_MDP_PORT1}; int i; uint64_t mdp_ab = 0; uint32_t ff = 0; for (i = 0; i < ARRAY_SIZE(ids); i++) { int iid = msm_bus_board_get_iid(ids[i]); int fabid; struct msm_bus_fabric_device *fabdev; struct msm_bus_inode_info *info; fabid = GET_FABID(iid); fabdev = msm_bus_get_fabric_device(fabid); if (!fabdev) { MSM_BUS_ERR("Fabric not found for: %d\n", fabid); continue; } info = fabdev->algo->find_node(fabdev, iid); if (!info) { MSM_BUS_ERR("%s: Can't find node %d", __func__, ids[i]); continue; } mdp_ab += get_node_sumab(info); MSM_BUS_DBG("mdp_ab %llu", mdp_ab); ff = info->node_info->ff; } if (ff) { mdp_ab = msm_bus_div64(2 * ff, 100 * mdp_ab); } else { MSM_BUS_ERR("MDP FF is 0"); mdp_ab = 0; } MSM_BUS_DBG("MDP BW %llu\n", mdp_ab); return mdp_ab; }
/** * 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; }
static uint64_t get_node_sumab(struct msm_bus_inode_info *info) { int i; uint64_t maxab = 0; for (i = 0; i <= info->num_pnodes; i++) maxab += info->pnode[i].bw[DUAL_CTX]; MSM_BUS_DBG("%s: Node %d numpnodes %d maxib %llu", __func__, info->num_pnodes, info->node_info->id, maxab); return maxab; }
static void bimc_init_mas_reg(struct msm_bus_bimc_info *binfo, struct msm_bus_inode_info *info, struct msm_bus_bimc_qos_mode *qmode, int mode) { int i; switch (mode) { case BIMC_QOS_MODE_FIXED: qmode->fixed.prio_level = info->node_info->prio_lvl; qmode->fixed.areq_prio_rd = info->node_info->prio_rd; qmode->fixed.areq_prio_wr = info->node_info->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 (!info->node_info->qport) { MSM_BUS_DBG("No QoS Ports to init\n"); return; } for (i = 0; i < info->node_info->num_mports; i++) { /* If not in bypass mode, update priority */ if (mode != BIMC_QOS_MODE_BYPASS) { msm_bus_bimc_set_qos_prio(binfo->base, info->node_info-> qport[i], mode, qmode); /* If not in fixed mode, update bandwidth */ if (mode != BIMC_QOS_MODE_FIXED) { struct msm_bus_bimc_qos_bw qbw; qbw.ws = info->node_info->ws; qbw.bw = info->node_info->bimc_bw[0]; qbw.gp = info->node_info->bimc_gp; qbw.thmp = info->node_info->bimc_thmp; bimc_set_static_qos_bw(binfo->base, binfo->qos_freq, info->node_info->qport[i], &qbw); } } /* set mode */ msm_bus_bimc_set_qos_mode(binfo->base, info->node_info->qport[i], mode); } }
bool msm_bus_rpm_is_mem_interleaved(void) { int status = 0; struct msm_rpm_iv_pair il[2]; uint16_t id[2]; il[0].value = 0; il[1].value = 0; status = msm_bus_board_rpm_get_il_ids(id); if (status) { MSM_BUS_DBG("Dynamic check not supported, " "default: Interleaved memory\n"); goto inter; } il[0].id = id[0]; il[1].id = id[1]; status = msm_rpm_get_status(il, ARRAY_SIZE(il)); if (status) { MSM_BUS_ERR("Status read for interleaving returned: %d\n" "Using interleaved memory by default\n", status); goto inter; } /* * If the start address of EBI1-CH0 is the same as * the start address of EBI1-CH1, the memory is interleaved. * The start addresses are stored in the 16 MSBs of the status * register */ if ((il[0].value & 0xFFFF0000) != (il[1].value & 0xFFFF0000)) { MSM_BUS_DBG("Non-interleaved memory\n"); return false; } inter: MSM_BUS_DBG("Interleaved memory\n"); return true; }
/** * 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; }
static int msm_bus_rpm_compare_cdata( struct msm_bus_fabric_registration *fab_pdata, struct commit_data *cd1, struct commit_data *cd2) { size_t n; int ret; n = sizeof(struct msm_bus_node_hw_info) * fab_pdata->nmasters * 2; ret = memcmp(cd1->mas_arb, cd2->mas_arb, n); if (ret) { MSM_BUS_DBG("Master Arb Data not equal\n"); return ret; } n = sizeof(struct msm_bus_node_hw_info) * fab_pdata->nslaves * 2; ret = memcmp(cd1->slv_arb, cd2->slv_arb, n); if (ret) { MSM_BUS_DBG("Master Arb Data not equal\n"); return ret; } return 0; }
static uint64_t get_node_maxib(struct msm_bus_inode_info *info) { int i, ctx; uint64_t maxib = 0; for (i = 0; i <= info->num_pnodes; i++) { for (ctx = 0; ctx < NUM_CTX; ctx++) maxib = max(info->pnode[i].clk[ctx], maxib); } MSM_BUS_DBG("%s: Node %d numpnodes %d maxib %llu", __func__, info->num_pnodes, info->node_info->id, maxib); return maxib; }
/** * msm_bus_scale_unregister_client() - Unregister the client from the bus driver * @cl: Handle to the client */ void msm_bus_scale_unregister_client(uint32_t cl) { struct msm_bus_client *client = (struct msm_bus_client *)(cl); if (IS_ERR(client) || (!client)) return; if (client->curr != 0) msm_bus_scale_client_update_request(cl, 0); MSM_BUS_DBG("Unregistering client %d\n", cl); mutex_lock(&msm_bus_lock); msm_bus_scale_client_reset_pnodes(cl); msm_bus_dbg_client_data(client->pdata, MSM_BUS_DBG_UNREGISTER, cl); mutex_unlock(&msm_bus_lock); kfree(client->src_pnode); kfree(client); }
void msm_bus_scale_client_reset_pnodes(uint32_t cl) { int i, src, pnode, index; struct msm_bus_client *client = (struct msm_bus_client *)(cl); if (IS_ERR(client)) { MSM_BUS_ERR("msm_bus_scale_reset_pnodes error\n"); return; } index = 0; for (i = 0; i < client->pdata->usecase->num_paths; i++) { src = msm_bus_board_get_iid( client->pdata->usecase[index].vectors[i].src); pnode = client->src_pnode[i]; MSM_BUS_DBG("(%d, %d)\n", GET_NODE(pnode), GET_INDEX(pnode)); reset_pnodes(src, pnode); } }