static int msm_bus_agg_fab_clks(struct device *bus_dev, void *data) { struct msm_bus_node_device_type *node = NULL; int ret = 0; int ctx = *(int *)data; if (ctx >= NUM_CTX) { MSM_BUS_ERR("%s: Invalid Context %d", __func__, ctx); goto exit_agg_fab_clks; } node = bus_dev->platform_data; if (!node) { MSM_BUS_ERR("%s: Can't get device info", __func__); goto exit_agg_fab_clks; } if (!node->node_info->is_fab_dev) { struct msm_bus_node_device_type *bus_dev = NULL; bus_dev = node->node_info->bus_device->platform_data; if (node->cur_clk_hz[ctx] >= bus_dev->cur_clk_hz[ctx]) bus_dev->cur_clk_hz[ctx] = node->cur_clk_hz[ctx]; } exit_agg_fab_clks: return ret; }
static int msm_bus_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; }
int msm_bus_commit_data(int *dirty_nodes, int ctx, int num_dirty) { int ret = 0; int i = 0; /* Aggregate the bus clocks */ bus_for_each_dev(&msm_bus_type, NULL, (void *)&ctx, msm_bus_agg_fab_clks); for (i = 0; i < num_dirty; i++) { struct device *node_device = bus_find_device(&msm_bus_type, NULL, (void *)&dirty_nodes[i], msm_bus_device_match_adhoc); ret = flush_bw_data(node_device, ctx); if (ret) MSM_BUS_ERR("%s: Error flushing bw data for node %d", __func__, dirty_nodes[i]); ret = flush_clk_data(node_device, ctx); if (ret) MSM_BUS_ERR("%s: Error flushing clk data for node %d", __func__, dirty_nodes[i]); } kfree(dirty_nodes); /* Aggregate the bus clocks */ bus_for_each_dev(&msm_bus_type, NULL, (void *)&ctx, msm_bus_reset_fab_clks); return ret; }
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 void setup_nr_limits(int curr, int pnode) { struct msm_bus_fabric_device *fabdev = msm_bus_get_fabric_device(GET_FABID(curr)); struct msm_bus_inode_info *info; if (!fabdev) { MSM_BUS_WARN("Fabric Not yet registered. Try again\n"); goto exit_setup_nr_limits; } /* This logic is currently applicable to BIMC masters only */ if (fabdev->id != MSM_BUS_FAB_DEFAULT) { MSM_BUS_ERR("Static limiting of NR masters only for BIMC\n"); goto exit_setup_nr_limits; } info = fabdev->algo->find_node(fabdev, curr); if (!info) { MSM_BUS_ERR("Cannot find node info!\n"); goto exit_setup_nr_limits; } compute_nr_limits(fabdev, pnode); exit_setup_nr_limits: return; }
static int msm_bus_init_clk(struct device *bus_dev, struct msm_bus_node_device_type *pdata) { unsigned int ctx; int ret = 0; struct msm_bus_node_device_type *node_dev = bus_dev->platform_data; for (ctx = 0; ctx < NUM_CTX; ctx++) { if (!IS_ERR_OR_NULL(pdata->clk[ctx].clk)) { node_dev->clk[ctx].clk = pdata->clk[ctx].clk; node_dev->clk[ctx].enable = false; node_dev->clk[ctx].dirty = false; MSM_BUS_ERR("%s: Valid node clk node %d ctx %d", __func__, node_dev->node_info->id, ctx); } } if (!IS_ERR_OR_NULL(pdata->qos_clk.clk)) { node_dev->qos_clk.clk = pdata->qos_clk.clk; node_dev->qos_clk.enable = false; MSM_BUS_ERR("%s: Valid Iface clk node %d", __func__, node_dev->node_info->id); } return ret; }
static int send_rpm_msg(struct device *device) { int ret = 0; int ctx; int rsc_type; struct msm_bus_node_device_type *ndev = device->platform_data; struct msm_rpm_kvp rpm_kvp; if (!ndev) { MSM_BUS_ERR("%s: Error getting node info.", __func__); ret = -ENODEV; goto exit_send_rpm_msg; } rpm_kvp.length = sizeof(uint64_t); rpm_kvp.key = RPM_MASTER_FIELD_BW; for (ctx = MSM_RPM_CTX_ACTIVE_SET; ctx <= MSM_RPM_CTX_SLEEP_SET; ctx++) { if (ctx == MSM_RPM_CTX_ACTIVE_SET) rpm_kvp.data = (uint8_t *)&ndev->node_ab.ab[MSM_RPM_CTX_ACTIVE_SET]; else { rpm_kvp.data = (uint8_t *) &ndev->node_ab.ab[MSM_RPM_CTX_SLEEP_SET]; } if (ndev->node_info->mas_rpm_id != -1) { rsc_type = RPM_BUS_MASTER_REQ; ret = msm_rpm_send_message(ctx, rsc_type, ndev->node_info->mas_rpm_id, &rpm_kvp, 1); if (ret) { MSM_BUS_ERR("%s: Failed to send RPM message:", __func__); MSM_BUS_ERR("%s:Node Id %d RPM id %d", __func__, ndev->node_info->id, ndev->node_info->mas_rpm_id); goto exit_send_rpm_msg; } } if (ndev->node_info->slv_rpm_id != -1) { rsc_type = RPM_BUS_SLAVE_REQ; ret = msm_rpm_send_message(ctx, rsc_type, ndev->node_info->slv_rpm_id, &rpm_kvp, 1); if (ret) { MSM_BUS_ERR("%s: Failed to send RPM message:", __func__); MSM_BUS_ERR("%s: Node Id %d RPM id %d", __func__, ndev->node_info->id, ndev->node_info->slv_rpm_id); goto exit_send_rpm_msg; } } } exit_send_rpm_msg: return ret; }
int msm_bus_update_clks(struct msm_bus_node_device_type *nodedev, int ctx, int **dirty_nodes, int *num_dirty) { int status = 0; struct nodeclk *nodeclk; struct nodeclk *busclk; struct msm_bus_node_device_type *bus_info = NULL; uint64_t req_clk; bus_info = nodedev->node_info->bus_device->platform_data; if (!bus_info) { MSM_BUS_ERR("%s: Unable to find bus device for device %d", __func__, nodedev->node_info->id); status = -ENODEV; goto exit_set_clks; } req_clk = nodedev->cur_clk_hz[ctx]; busclk = &bus_info->clk[ctx]; if (busclk->rate != req_clk) { busclk->rate = req_clk; busclk->dirty = 1; MSM_BUS_DBG("%s: Modifying bus clk %d Rate %llu", __func__, bus_info->node_info->id, req_clk); status = add_dirty_node(dirty_nodes, bus_info->node_info->id, num_dirty); if (status) { MSM_BUS_ERR("%s: Failed to add dirty node %d", __func__, bus_info->node_info->id); goto exit_set_clks; } } req_clk = nodedev->cur_clk_hz[ctx]; nodeclk = &nodedev->clk[ctx]; if (IS_ERR_OR_NULL(nodeclk)) goto exit_set_clks; if (!nodeclk->dirty || (nodeclk->dirty && (nodeclk->rate < req_clk))) { nodeclk->rate = req_clk; nodeclk->dirty = 1; MSM_BUS_DBG("%s: Modifying node clk %d Rate %llu", __func__, nodedev->node_info->id, req_clk); status = add_dirty_node(dirty_nodes, nodedev->node_info->id, num_dirty); if (status) { MSM_BUS_ERR("%s: Failed to add dirty node %d", __func__, nodedev->node_info->id); goto exit_set_clks; } } exit_set_clks: return status; }
static int msm_bus_qos_enable_clk(struct msm_bus_node_device_type *node) { struct msm_bus_node_device_type *bus_node = NULL; long rounded_rate; int ret = 0; int bus_qos_enabled = 0; if (!node) { ret = -ENXIO; goto exit_enable_qos_clk; } bus_node = node->node_info->bus_device->platform_data; if (!bus_node) { ret = -ENXIO; goto exit_enable_qos_clk; } if (!clk_get_rate(bus_node->clk[DUAL_CTX].clk)) { rounded_rate = clk_round_rate(bus_node->clk[DUAL_CTX].clk, 1); ret = setrate_nodeclk(&bus_node->clk[DUAL_CTX], rounded_rate); if (ret) { MSM_BUS_ERR("%s: Failed to set bus clk, node %d", __func__, node->node_info->id); goto exit_enable_qos_clk; } ret = enable_nodeclk(&bus_node->clk[DUAL_CTX]); if (ret) { MSM_BUS_ERR("%s: Failed to enable bus clk, node %d", __func__, node->node_info->id); goto exit_enable_qos_clk; } bus_qos_enabled = 1; } if (!IS_ERR_OR_NULL(node->qos_clk.clk)) { rounded_rate = clk_round_rate(node->qos_clk.clk, 1); ret = setrate_nodeclk(&node->qos_clk, rounded_rate); if (ret) { MSM_BUS_ERR("Failed to set bus clk, node %d", node->node_info->id); goto exit_enable_qos_clk; } ret = enable_nodeclk(&node->qos_clk); if (ret) { MSM_BUS_ERR("Err enable mas qos clk, node %d ret %d", node->node_info->id, ret); goto exit_enable_qos_clk; } } ret = bus_qos_enabled; exit_enable_qos_clk: return ret; }
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_fabric_init(struct device *dev, struct msm_bus_node_device_type *pdata) { struct msm_bus_fab_device_type *fabdev; struct msm_bus_node_device_type *node_dev = NULL; int ret = 0; node_dev = dev->platform_data; if (!node_dev) { MSM_BUS_ERR("%s: Unable to get bus device info" , __func__); ret = -ENXIO; goto exit_fabric_init; } if (node_dev->node_info->virt_dev) { MSM_BUS_ERR("%s: Skip Fab init for virtual device %d", __func__, node_dev->node_info->id); goto exit_fabric_init; } fabdev = devm_kzalloc(dev, sizeof(struct msm_bus_fab_device_type), GFP_KERNEL); if (!fabdev) { MSM_BUS_ERR("Fabric alloc failed\n"); ret = -ENOMEM; goto exit_fabric_init; } node_dev->fabdev = fabdev; fabdev->pqos_base = pdata->fabdev->pqos_base; fabdev->qos_range = pdata->fabdev->qos_range; fabdev->base_offset = pdata->fabdev->base_offset; fabdev->qos_off = pdata->fabdev->qos_off; fabdev->qos_freq = pdata->fabdev->qos_freq; fabdev->bus_type = pdata->fabdev->bus_type; fabdev->bypass_qos_prg = pdata->fabdev->bypass_qos_prg; msm_bus_fab_init_noc_ops(node_dev); fabdev->qos_base = devm_ioremap(dev, fabdev->pqos_base, fabdev->qos_range); if (!fabdev->qos_base) { MSM_BUS_ERR("%s: Error remapping address 0x%zx :bus device %d", __func__, (size_t)fabdev->pqos_base, node_dev->node_info->id); ret = -ENOMEM; goto exit_fabric_init; } /*if (msmbus_coresight_init(pdev)) pr_warn("Coresight support absent for bus: %d\n", pdata->id);*/ exit_fabric_init: return ret; }
int __init msm_bus_device_init_driver(void) { int rc; MSM_BUS_ERR("msm_bus_fabric_init_driver\n"); rc = platform_driver_register(&msm_bus_device_driver); if (rc) { MSM_BUS_ERR("Failed to register bus device driver"); return rc; } return platform_driver_register(&msm_bus_rules_driver); }
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 int msm_bus_setup_dev_conn(struct device *bus_dev, void *data) { struct msm_bus_node_device_type *bus_node = NULL; int ret = 0; int j; bus_node = bus_dev->platform_data; if (!bus_node) { MSM_BUS_ERR("%s: Can't get device info", __func__); ret = -ENODEV; goto exit_setup_dev_conn; } /* Setup parent bus device for this node */ if (!bus_node->node_info->is_fab_dev) { struct device *bus_parent_device = bus_find_device(&msm_bus_type, NULL, (void *)&bus_node->node_info->bus_device_id, msm_bus_device_match_adhoc); if (!bus_parent_device) { MSM_BUS_ERR("%s: Error finding parentdev %d parent %d", __func__, bus_node->node_info->id, bus_node->node_info->bus_device_id); ret = -ENXIO; goto exit_setup_dev_conn; } bus_node->node_info->bus_device = bus_parent_device; } for (j = 0; j < bus_node->node_info->num_connections; j++) { bus_node->node_info->dev_connections[j] = bus_find_device(&msm_bus_type, NULL, (void *)&bus_node->node_info->connections[j], msm_bus_device_match_adhoc); if (!bus_node->node_info->dev_connections[j]) { MSM_BUS_ERR("%s: Error finding conn %d for device %d", __func__, bus_node->node_info->connections[j], bus_node->node_info->id); ret = -ENODEV; goto exit_setup_dev_conn; } } exit_setup_dev_conn: 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; }
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; }
void *msm_bus_realloc_devmem(struct device *dev, void *p, size_t old_size, size_t new_size, gfp_t flags) { void *ret; size_t copy_size = old_size; if (!new_size) { devm_kfree(dev, p); return ZERO_SIZE_PTR; } if (new_size < old_size) copy_size = new_size; ret = devm_kzalloc(dev, new_size, flags); if (!ret) { MSM_BUS_ERR("%s: Error Reallocating memory", __func__); goto exit_realloc_devmem; } memcpy(ret, p, copy_size); devm_kfree(dev, p); exit_realloc_devmem: return ret; }
static int add_dirty_node(int **dirty_nodes, int id, int *num_dirty) { int i; int found = 0; int ret = 0; int *dnode = NULL; for (i = 0; i < *num_dirty; i++) { if ((*dirty_nodes)[i] == id) { found = 1; break; } } if (!found) { (*num_dirty)++; dnode = krealloc(*dirty_nodes, sizeof(int) * (*num_dirty), GFP_KERNEL); if (ZERO_OR_NULL_PTR(dnode)) { MSM_BUS_ERR("%s: Failure allocating dirty nodes array", __func__); ret = -ENOMEM; } else { *dirty_nodes = dnode; (*dirty_nodes)[(*num_dirty) - 1] = id; } } return ret; }
int msm_bus_enable_limiter(struct msm_bus_node_device_type *node_dev, bool enable, uint64_t lim_bw) { int ret = 0; struct msm_bus_node_device_type *bus_node_dev; if (!node_dev) { MSM_BUS_ERR("No device specified"); ret = -ENXIO; goto exit_enable_limiter; } if (!node_dev->ap_owned) { MSM_BUS_ERR("Device is not AP owned %d.", node_dev->node_info->id); ret = -ENXIO; goto exit_enable_limiter; } bus_node_dev = node_dev->node_info->bus_device->platform_data; if (!bus_node_dev) { MSM_BUS_ERR("Unable to get bus device infofor %d", node_dev->node_info->id); ret = -ENXIO; goto exit_enable_limiter; } if (bus_node_dev->fabdev && bus_node_dev->fabdev->noc_ops.limit_mport) { 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_enable_limiter; } bus_node_dev->fabdev->noc_ops.limit_mport( node_dev, bus_node_dev->fabdev->qos_base, bus_node_dev->fabdev->base_offset, bus_node_dev->fabdev->qos_off, bus_node_dev->fabdev->qos_freq, enable, lim_bw); msm_bus_qos_disable_clk(node_dev, ret); } exit_enable_limiter: 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 uint64_t get_avail_bw(struct msm_bus_fabric_device *fabdev) { uint64_t fabclk_rate = 0; int i; uint64_t avail_bw = 0; uint64_t rt_bw = get_rt_bw(); struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev); if (!rt_bw) goto exit_get_avail_bw; for (i = 0; i < NUM_CTX; i++) { uint64_t ctx_rate; ctx_rate = fabric->info.nodeclk[i].rate; fabclk_rate = max(ctx_rate, fabclk_rate); } if (!fabdev->eff_fact || !fabdev->nr_lim_thresh) { MSM_BUS_ERR("Error: Eff-fact %d; nr_thresh %llu", fabdev->eff_fact, fabdev->nr_lim_thresh); return 0; } avail_bw = msm_bus_div64(100, (GET_BIMC_BW(fabclk_rate) * fabdev->eff_fact)); if (avail_bw >= fabdev->nr_lim_thresh) return 0; MSM_BUS_DBG("%s: Total_avail_bw %llu, rt_bw %llu\n", __func__, avail_bw, rt_bw); trace_bus_avail_bw(avail_bw, rt_bw); if (avail_bw < rt_bw) { MSM_BUS_ERR("\n%s: ERROR avail BW %llu < MDP %llu", __func__, avail_bw, rt_bw); avail_bw = 0; goto exit_get_avail_bw; } avail_bw -= rt_bw; exit_get_avail_bw: return avail_bw; }
static int __init msm_bus_init(void) { int retval = 0; retval = bus_register(&msm_bus_type); if (retval) MSM_BUS_ERR("bus_register error! %d\n", retval); return retval; }
/** * msm_bus_fabric_device_register() - Registers a fabric on msm bus * @fabdev: Fabric device to be registered */ int msm_bus_fabric_device_register(struct msm_bus_fabric_device *fabdev) { int ret = 0; fabdev->dev.bus = &msm_bus_type; ret = dev_set_name(&fabdev->dev, fabdev->name); if (ret) { MSM_BUS_ERR("error setting dev name\n"); goto err; } ret = device_register(&fabdev->dev); if (ret < 0) { MSM_BUS_ERR("error registering device%d %s\n", ret, fabdev->name); goto err; } atomic_inc(&num_fab); err: return ret; }
static int setrate_nodeclk(struct nodeclk *nclk, long rate) { int ret = 0; ret = clk_set_rate(nclk->clk, rate); if (ret) MSM_BUS_ERR("%s: failed to setrate clk", __func__); return ret; }
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; }
static int msm_bus_get_iid(int id) { if ((id < SLAVE_ID_KEY && id >= MSM_BUS_MASTER_LAST) || id >= MSM_BUS_SLAVE_LAST) { MSM_BUS_ERR("Cannot get iid. Invalid id %d passed\n", id); return -EINVAL; } return CHECK_ID(((id < SLAVE_ID_KEY) ? master_iids[id] : slave_iids[id - SLAVE_ID_KEY]), id); }
static int msm_bus_board_8064_get_iid(int id) { if ((id < SLAVE_ID_KEY && id >= NMASTERS) || id >= (SLAVE_ID_KEY + NSLAVES)) { MSM_BUS_ERR("Cannot get iid. Invalid id %d passed\n", id); return -EINVAL; } return CHECK_ID(((id < SLAVE_ID_KEY) ? master_iids[id] : slave_iids[id - SLAVE_ID_KEY]), id); }
/** * msm_bus_remote_hw_commit() - Commit the arbitration data to RPM * @fabric: Fabric for which the data should be committed **/ int msm_bus_remote_hw_commit(struct msm_bus_fabric_registration *fab_pdata, void *hw_data, void **cdata) { int ret; bool valid; struct commit_data *dual_cd, *act_cd; void *rpm_data = hw_data; MSM_BUS_DBG("\nReached RPM Commit\n"); dual_cd = (struct commit_data *)cdata[DUAL_CTX]; act_cd = (struct commit_data *)cdata[ACTIVE_CTX]; /* * If the arb data for active set and sleep set is * different, commit both sets. * If the arb data for active set and sleep set is * the same, invalidate the sleep set. */ ret = msm_bus_rpm_compare_cdata(fab_pdata, act_cd, dual_cd); if (!ret) /* Invalidate sleep set.*/ valid = false; else valid = true; ret = msm_bus_rpm_commit_arb(fab_pdata, DUAL_CTX, rpm_data, dual_cd, valid); if (ret) MSM_BUS_ERR("Error comiting fabric:%d in %d ctx\n", fab_pdata->id, DUAL_CTX); valid = true; ret = msm_bus_rpm_commit_arb(fab_pdata, ACTIVE_CTX, rpm_data, act_cd, valid); if (ret) MSM_BUS_ERR("Error comiting fabric:%d in %d ctx\n", fab_pdata->id, ACTIVE_CTX); return ret; }
int msm_bus_board_get_iid(int id) { struct msm_bus_fabric_device *deffab; deffab = msm_bus_get_fabric_device(MSM_BUS_FAB_DEFAULT); if (!deffab) { MSM_BUS_ERR("Error finding default fabric\n"); return -ENXIO; } return deffab->board_algo->get_iid(id); }