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_mas_init(struct msm_bus_bimc_info *binfo, struct msm_bus_inode_info *info) { struct msm_bus_bimc_qos_mode *qmode; qmode = kzalloc(sizeof(struct msm_bus_bimc_qos_mode), GFP_KERNEL); if (!qmode) { MSM_BUS_WARN("Couldn't alloc prio data for node: %d\n", info->node_info->id); return -ENOMEM; } info->hw_data = (void *)qmode; /** * If the master supports dual configuration, * configure registers for both modes */ if (info->node_info->dual_conf) bimc_init_mas_reg(binfo, info, qmode, info->node_info->mode_thresh); else if (info->node_info->nr_lim) init_health_regs(binfo, info, qmode, BIMC_QOS_MODE_LIMITER); bimc_init_mas_reg(binfo, info, qmode, info->node_info->mode); return 0; }
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; }
int msm_bus_device_match(struct device *dev, void* id) { struct msm_bus_fabric_device *fabdev = to_msm_bus_fabric_device(dev); if (!fabdev) { MSM_BUS_WARN("Fabric %p returning 0\n", fabdev); return 0; } return (fabdev->id == (int)id); }
/* This function uses shift operations to divide 64 bit value for higher * efficiency. The divisor expected are number of ports or bus-width. * These are expected to be 1, 2, 4, 8, 16 and 32 in most cases. * * To account for exception to the above divisor values, the standard * do_div function is used. * */ uint64_t msm_bus_div64(unsigned int w, uint64_t bw) { uint64_t *b = &bw; if ((bw > 0) && (bw < w)) return 1; switch (w) { case 0: MSM_BUS_WARN("AXI: Divide by 0 attempted\n"); case 1: return bw; case 2: return (bw >> 1); case 4: return (bw >> 2); case 8: return (bw >> 3); case 16: return (bw >> 4); case 32: return (bw >> 5); } do_div(*b, w); return *b; }
/** * update_path() - Update the path with the bandwidth and clock values, as * requested by the client. * * @curr: Current source node, as specified in the client vector (master) * @pnode: The first-hop node on the path, stored in the internal client struct * @req_clk: Requested clock value from the vector * @req_bw: Requested bandwidth value from the vector * @curr_clk: Current clock frequency * @curr_bw: Currently allocated bandwidth * * This function updates the nodes on the path calculated using getpath(), with * clock and bandwidth values. The sum of bandwidths, and the max of clock * frequencies is calculated at each node on the path. Commit data to be sent * to RPM for each master and slave is also calculated here. */ static int update_path(int curr, int pnode, unsigned long req_clk, unsigned long req_bw, unsigned long curr_clk, unsigned long curr_bw, unsigned int ctx, unsigned int cl_active_flag) { int index, ret = 0; struct msm_bus_inode_info *info; int next_pnode; long int add_bw = req_bw - curr_bw; unsigned bwsum = 0; unsigned req_clk_hz, curr_clk_hz, bwsum_hz; int *master_tiers; struct msm_bus_fabric_device *fabdev = msm_bus_get_fabric_device (GET_FABID(curr)); MSM_BUS_DBG("args: %d %d %d %lu %lu %lu %lu %u\n", curr, GET_NODE(pnode), GET_INDEX(pnode), req_clk, req_bw, curr_clk, curr_bw, ctx); index = GET_INDEX(pnode); MSM_BUS_DBG("Client passed index :%d\n", index); info = fabdev->algo->find_node(fabdev, curr); if (!info) { MSM_BUS_ERR("Cannot find node info!\n"); return -ENXIO; } info->link_info.sel_bw = &info->link_info.bw[ctx]; info->link_info.sel_clk = &info->link_info.clk[ctx]; *info->link_info.sel_bw += add_bw; info->pnode[index].sel_bw = &info->pnode[index].bw[ctx]; /** * To select the right clock, AND the context with * client active flag. */ info->pnode[index].sel_clk = &info->pnode[index].clk[ctx & cl_active_flag]; *info->pnode[index].sel_bw += add_bw; info->link_info.num_tiers = info->node_info->num_tiers; info->link_info.tier = info->node_info->tier; master_tiers = info->node_info->tier; 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; } MSM_BUS_DBG("id: %d\n", info->node_info->priv_id); /* find next node and index */ next_pnode = info->pnode[index].next; curr = GET_NODE(next_pnode); index = GET_INDEX(next_pnode); MSM_BUS_DBG("id:%d, next: %d\n", info-> node_info->priv_id, curr); /* Get hop */ /* check if we are here as gateway, or does the hop belong to * this fabric */ 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; } hop->link_info.sel_bw = &hop->link_info.bw[ctx]; hop->link_info.sel_clk = &hop->link_info.clk[ctx]; *hop->link_info.sel_bw += add_bw; hop->pnode[index].sel_bw = &hop->pnode[index].bw[ctx]; hop->pnode[index].sel_clk = &hop->pnode[index].clk[ctx & cl_active_flag]; if (!hop->node_info->buswidth) { MSM_BUS_WARN("No bus width found. Using default\n"); hop->node_info->buswidth = 8; } *hop->pnode[index].sel_clk = BW_TO_CLK_FREQ_HZ(hop->node_info-> buswidth, req_clk); *hop->pnode[index].sel_bw += add_bw; MSM_BUS_DBG("fabric: %d slave: %d, slave-width: %d info: %d\n", fabdev->id, hop->node_info->priv_id, hop->node_info-> buswidth, info->node_info->priv_id); /* Update Bandwidth */ fabdev->algo->update_bw(fabdev, hop, info, add_bw, master_tiers, ctx); bwsum = (uint16_t)*hop->link_info.sel_bw; /* Update Fabric clocks */ curr_clk_hz = BW_TO_CLK_FREQ_HZ(hop->node_info->buswidth, curr_clk); req_clk_hz = BW_TO_CLK_FREQ_HZ(hop->node_info->buswidth, req_clk); bwsum_hz = BW_TO_CLK_FREQ_HZ(hop->node_info->buswidth, bwsum); MSM_BUS_DBG("Calling update-clks: curr_hz: %lu, req_hz: %lu," " bw_hz %u\n", curr_clk, req_clk, bwsum_hz); ret = fabdev->algo->update_clks(fabdev, hop, index, curr_clk_hz, req_clk_hz, bwsum_hz, SEL_FAB_CLK, ctx, cl_active_flag); if (ret) MSM_BUS_WARN("Failed to update clk\n"); info = hop; } while (GET_NODE(info->pnode[index].next) != info->node_info->priv_id); /* Update BW, clk after exiting the loop for the last one */ if (!info) { MSM_BUS_ERR("Cannot find node info!\n"); return -ENXIO; } /* Update slave clocks */ ret = fabdev->algo->update_clks(fabdev, info, index, curr_clk_hz, req_clk_hz, bwsum_hz, SEL_SLAVE_CLK, ctx, cl_active_flag); if (ret) MSM_BUS_ERR("Failed to update clk\n"); return ret; }
/** * getpath() - Finds the path from the topology between src and dest * @src: Source. This is the master from which the request originates * @dest: Destination. This is the slave to which we're trying to reach * * Function returns: next_pnode_id. The higher 16 bits of the next_pnode_id * represent the src id of the next node on path. The lower 16 bits of the * next_pnode_id represent the "index", which is the next entry in the array * of pnodes for that node to fill in clk and bw values. This is created using * CREATE_PNODE_ID. The return value is stored in ret_pnode, and this is added * to the list of path nodes. * * This function recursively finds the path by updating the src to the * closest possible node to dest. */ static int getpath(int src, int dest) { int pnode_num = -1, i; struct msm_bus_fabnodeinfo *fabnodeinfo; struct msm_bus_fabric_device *fabdev; int next_pnode_id = -1; struct msm_bus_inode_info *info = NULL; int _src = src/FABRIC_ID_KEY; int _dst = dest/FABRIC_ID_KEY; int ret_pnode = -1; int fabid = GET_FABID(src); /* Find the location of fabric for the src */ MSM_BUS_DBG("%d --> %d\n", src, dest); fabdev = msm_bus_get_fabric_device(fabid); if (!fabdev) { MSM_BUS_WARN("Fabric Not yet registered. Try again\n"); return -ENXIO; } /* Are we there yet? */ if (src == dest) { info = fabdev->algo->find_node(fabdev, src); if (ZERO_OR_NULL_PTR(info)) { MSM_BUS_ERR("Node %d not found\n", dest); return -ENXIO; } for (i = 0; i <= info->num_pnodes; i++) { if (info->pnode[i].next == -2) { MSM_BUS_DBG("src = dst Reusing pnode for" " info: %d at index: %d\n", info->node_info->priv_id, i); next_pnode_id = CREATE_PNODE_ID(src, i); info->pnode[i].clk[DUAL_CTX] = 0; info->pnode[i].bw[DUAL_CTX] = 0; info->pnode[i].next = next_pnode_id; MSM_BUS_DBG("returning: %d, %d\n", GET_NODE (next_pnode_id), GET_INDEX(next_pnode_id)); return next_pnode_id; } } next_pnode_id = CREATE_PNODE_ID(src, (info->num_pnodes + 1)); pnode_num = add_path_node(info, next_pnode_id); if (pnode_num < 0) { MSM_BUS_ERR("Error adding path node\n"); return -ENXIO; } MSM_BUS_DBG("returning: %d, %d\n", GET_NODE(next_pnode_id), GET_INDEX(next_pnode_id)); return next_pnode_id; } else if (_src == _dst) { /* * src and dest belong to same fabric, find the destination * from the radix tree */ info = fabdev->algo->find_node(fabdev, dest); if (ZERO_OR_NULL_PTR(info)) { MSM_BUS_ERR("Node %d not found\n", dest); return -ENXIO; } ret_pnode = getpath(info->node_info->priv_id, dest); next_pnode_id = ret_pnode; } else { /* find the dest fabric */ int trynextgw = true; struct list_head *gateways = fabdev->algo->get_gw_list(fabdev); list_for_each_entry(fabnodeinfo, gateways, list) { /* see if the destination is at a connected fabric */ if (_dst == (fabnodeinfo->info->node_info->priv_id / FABRIC_ID_KEY)) { /* Found the fab on which the device exists */ info = fabnodeinfo->info; trynextgw = false; ret_pnode = getpath(info->node_info->priv_id, dest); pnode_num = add_path_node(info, ret_pnode); if (pnode_num < 0) { MSM_BUS_ERR("Error adding path node\n"); return -ENXIO; } next_pnode_id = CREATE_PNODE_ID( info->node_info->priv_id, pnode_num); break; } } /* find the gateway */ if (trynextgw) { gateways = fabdev->algo->get_gw_list(fabdev); list_for_each_entry(fabnodeinfo, gateways, list) { struct msm_bus_fabric_device *gwfab = msm_bus_get_fabric_device(fabnodeinfo-> info->node_info->priv_id); if (!gwfab->visited) { MSM_BUS_DBG("VISITED ID: %d\n", gwfab->id); gwfab->visited = true; info = fabnodeinfo->info; ret_pnode = getpath(info-> node_info->priv_id, dest); pnode_num = add_path_node(info, ret_pnode); if (pnode_num < 0) { MSM_BUS_ERR("Malloc failure in" " adding path node\n"); return -ENXIO; } next_pnode_id = CREATE_PNODE_ID( info->node_info->priv_id, pnode_num); break; } } if (next_pnode_id < 0) return -ENXIO; } } if (!IS_NODE(src)) { MSM_BUS_DBG("Returning next_pnode_id:%d[%d]\n", GET_NODE( next_pnode_id), GET_INDEX(next_pnode_id)); return next_pnode_id; } info = fabdev->algo->find_node(fabdev, src); if (!info) { MSM_BUS_ERR("Node info not found.\n"); return -ENXIO; } pnode_num = add_path_node(info, next_pnode_id); MSM_BUS_DBG(" Last: %d[%d] = (%d, %d)\n", src, info->num_pnodes, GET_NODE(next_pnode_id), GET_INDEX(next_pnode_id)); MSM_BUS_DBG("returning: %d, %d\n", src, pnode_num); return CREATE_PNODE_ID(src, pnode_num); }
/** * update_path() - Update the path with the bandwidth and clock values, as * requested by the client. * * @curr: Current source node, as specified in the client vector (master) * @pnode: The first-hop node on the path, stored in the internal client struct * @req_clk: Requested clock value from the vector * @req_bw: Requested bandwidth value from the vector * @curr_clk: Current clock frequency * @curr_bw: Currently allocated bandwidth * * This function updates the nodes on the path calculated using getpath(), with * clock and bandwidth values. The sum of bandwidths, and the max of clock * frequencies is calculated at each node on the path. Commit data to be sent * to RPM for each master and slave is also calculated here. */ static int update_path(int curr, int pnode, uint64_t req_clk, uint64_t req_bw, uint64_t curr_clk, uint64_t curr_bw, unsigned int ctx, unsigned int cl_active_flag) { int index, ret = 0; struct msm_bus_inode_info *info; int next_pnode; int64_t add_bw = req_bw - curr_bw; uint64_t bwsum = 0; uint64_t req_clk_hz, curr_clk_hz, bwsum_hz; int *master_tiers; struct msm_bus_fabric_device *fabdev = msm_bus_get_fabric_device (GET_FABID(curr)); if (!fabdev) { MSM_BUS_ERR("Bus device for bus ID: %d not found!\n", GET_FABID(curr)); return -ENXIO; } MSM_BUS_DBG("args: %d %d %d %llu %llu %llu %llu %u\n", curr, GET_NODE(pnode), GET_INDEX(pnode), req_clk, req_bw, curr_clk, curr_bw, ctx); index = GET_INDEX(pnode); MSM_BUS_DBG("Client passed index :%d\n", index); info = fabdev->algo->find_node(fabdev, curr); if (!info) { MSM_BUS_ERR("Cannot find node info!\n"); return -ENXIO; } #ifndef CONFIG_BW_LIMITER_FIX /** * If master supports dual configuration, check if * the configuration needs to be changed based on * incoming requests */ if (info->node_info->dual_conf) fabdev->algo->config_master(fabdev, info, req_clk, req_bw); #endif info->link_info.sel_bw = &info->link_info.bw[ctx]; info->link_info.sel_clk = &info->link_info.clk[ctx]; *info->link_info.sel_bw += add_bw; info->pnode[index].sel_bw = &info->pnode[index].bw[ctx]; /** * To select the right clock, AND the context with * client active flag. */ info->pnode[index].sel_clk = &info->pnode[index].clk[ctx & cl_active_flag]; *info->pnode[index].sel_bw += add_bw; #ifdef CONFIG_BW_LIMITER_FIX *info->pnode[index].sel_clk = req_clk; /** * If master supports dual configuration, check if * the configuration needs to be changed based on * incoming requests */ if (info->node_info->dual_conf) { uint64_t node_maxib = 0; node_maxib = get_node_maxib(info); fabdev->algo->config_master(fabdev, info, node_maxib, req_bw); } #endif info->link_info.num_tiers = info->node_info->num_tiers; info->link_info.tier = info->node_info->tier; master_tiers = info->node_info->tier; 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; } MSM_BUS_DBG("id: %d\n", info->node_info->priv_id); /* find next node and index */ next_pnode = info->pnode[index].next; curr = GET_NODE(next_pnode); index = GET_INDEX(next_pnode); MSM_BUS_DBG("id:%d, next: %d\n", info-> node_info->priv_id, curr); /* Get hop */ /* check if we are here as gateway, or does the hop belong to * this fabric */ 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; } hop->link_info.sel_bw = &hop->link_info.bw[ctx]; hop->link_info.sel_clk = &hop->link_info.clk[ctx]; *hop->link_info.sel_bw += add_bw; hop->pnode[index].sel_bw = &hop->pnode[index].bw[ctx]; hop->pnode[index].sel_clk = &hop->pnode[index].clk[ctx & cl_active_flag]; if (!hop->node_info->buswidth) { MSM_BUS_WARN("No bus width found. Using default\n"); hop->node_info->buswidth = 8; } *hop->pnode[index].sel_clk = BW_TO_CLK_FREQ_HZ(hop->node_info-> buswidth, req_clk); *hop->pnode[index].sel_bw += add_bw; MSM_BUS_DBG("fabric: %d slave: %d, slave-width: %d info: %d\n", fabdev->id, hop->node_info->priv_id, hop->node_info-> buswidth, info->node_info->priv_id); /* Update Bandwidth */ fabdev->algo->update_bw(fabdev, hop, info, add_bw, master_tiers, ctx); bwsum = *hop->link_info.sel_bw; /* Update Fabric clocks */ curr_clk_hz = BW_TO_CLK_FREQ_HZ(hop->node_info->buswidth, curr_clk); req_clk_hz = BW_TO_CLK_FREQ_HZ(hop->node_info->buswidth, req_clk); bwsum_hz = BW_TO_CLK_FREQ_HZ(hop->node_info->buswidth, bwsum); /* Account for multiple channels if any */ if (hop->node_info->num_sports > 1) bwsum_hz = msm_bus_div64(hop->node_info->num_sports, bwsum_hz); MSM_BUS_DBG("AXI: Hop: %d, ports: %d, bwsum_hz: %llu\n", hop->node_info->id, hop->node_info->num_sports, bwsum_hz); MSM_BUS_DBG("up-clk: curr_hz: %llu, req_hz: %llu, bw_hz %llu\n", curr_clk, req_clk, bwsum_hz); ret = fabdev->algo->update_clks(fabdev, hop, index, curr_clk_hz, req_clk_hz, bwsum_hz, SEL_FAB_CLK, ctx, cl_active_flag); if (ret) MSM_BUS_WARN("Failed to update clk\n"); info = hop; } while (GET_NODE(info->pnode[index].next) != info->node_info->priv_id); /* Update BW, clk after exiting the loop for the last one */ if (!info) { MSM_BUS_ERR("Cannot find node info!\n"); return -ENXIO; } /* Update slave clocks */ ret = fabdev->algo->update_clks(fabdev, info, index, curr_clk_hz, req_clk_hz, bwsum_hz, SEL_SLAVE_CLK, ctx, cl_active_flag); if (ret) MSM_BUS_ERR("Failed to update clk\n"); 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 qcom_msm_bus_req req = { .key = key, }; int ret = 0; if (ctx == ACTIVE_CTX) ctx = QCOM_SMD_RPM_ACTIVE_STATE; else if (ctx == DUAL_CTX) ctx = QCOM_SMD_RPM_SLEEP_STATE; #if 0 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; } #endif if (valid) { req.value = hw_info->bw; req.nbytes = sizeof(uint64_t); #if 0 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)); #endif } else { req.value = 0; req.nbytes = 0; #if 0 /* 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; } #endif } #if 0 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); #endif ret = qcom_rpm_bus_send_message(ctx, rsc_type, hw_info->hw_id, &req); return ret; }