Loading drivers/soc/qcom/rpmh-rsc.c +29 −22 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "%s " fmt, KBUILD_MODNAME Loading Loading @@ -66,6 +66,13 @@ #define RSC_PDC_DRV_DATA 0x38 #define RSC_PDC_DATA_OFFSET 0x08 #define ACCL_TYPE(addr) ((addr >> 16) & 0xF) #define NR_ACCL_TYPES 3 static const char * const accl_str[] = { "", "", "", "CLK", "VREG", "BUS", }; bool rpmh_standalone; static struct rsc_drv *__rsc_drv[2]; static int __rsc_count; Loading Loading @@ -630,11 +637,10 @@ static struct tcs_group *get_tcs_from_index(struct rsc_drv *drv, int tcs_id) return NULL; } static void print_tcs_info(struct rsc_drv *drv, int tcs_id) static void print_tcs_info(struct rsc_drv *drv, int tcs_id, unsigned long *accl) { struct tcs_group *tcs_grp = get_tcs_from_index(drv, tcs_id); const struct tcs_request *req = get_req_from_tcs(drv, tcs_id); struct tcs_cmd *cmd; unsigned long cmds_enabled; u32 addr, data, msgid, sts, irq_sts; bool in_use = test_bit(tcs_id, drv->tcs_in_use); Loading @@ -658,29 +664,17 @@ static void print_tcs_info(struct rsc_drv *drv, int tcs_id) tcs_id, sts ? "IDLE" : "BUSY", data, (irq_sts & BIT(tcs_id)) ? "COMPLETED" : "PENDING"); for (i = 0; i < req->num_cmds; i++) { cmd = &req->cmds[i]; pr_warn("\tREQ=%d [addr=0x%x data=0x%x wait=0x%x]\n", i, cmd->addr, cmd->data, cmd->wait); if (i < MAX_CMDS_PER_TCS) { addr = read_tcs_reg(drv, RSC_DRV_CMD_ADDR, tcs_id, i); data = read_tcs_reg(drv, RSC_DRV_CMD_DATA, tcs_id, i); msgid = read_tcs_reg(drv, RSC_DRV_CMD_MSGID, tcs_id, i); sts = read_tcs_reg(drv, RSC_DRV_CMD_STATUS, tcs_id, i); pr_warn("\tCMD=%d [addr=0x%x data=0x%x hdr=0x%x sts=0x%x enabled=%ld]\n", i, addr, data, msgid, sts, (cmds_enabled & BIT(i))); } } for_each_set_bit_from(i, &cmds_enabled, MAX_CMDS_PER_TCS) { for_each_set_bit(i, &cmds_enabled, MAX_CMDS_PER_TCS) { addr = read_tcs_reg(drv, RSC_DRV_CMD_ADDR, tcs_id, i); data = read_tcs_reg(drv, RSC_DRV_CMD_DATA, tcs_id, i); msgid = read_tcs_reg(drv, RSC_DRV_CMD_MSGID, tcs_id, i); sts = read_tcs_reg(drv, RSC_DRV_CMD_STATUS, tcs_id, i); pr_warn("\tCMD=%d [addr=0x%x data=0x%x hdr=0x%x sts=0x%x enabled=1]\n", i, addr, data, msgid, sts); if (!(sts & CMD_STATUS_ISSUED)) continue; if (!(sts & CMD_STATUS_COMPL)) *accl |= BIT(ACCL_TYPE(addr)); } } Loading @@ -690,6 +684,8 @@ void rpmh_rsc_debug(struct rsc_drv *drv) bool irq_sts; int i; int busy = 0; unsigned long accl = 0; char str[20] = ""; pr_warn("RSC:%s\n", drv->name); Loading @@ -697,7 +693,7 @@ void rpmh_rsc_debug(struct rsc_drv *drv) if (!test_bit(i, drv->tcs_in_use)) continue; busy++; print_tcs_info(drv, i); print_tcs_info(drv, i, &accl); } if (!rsc_irq_data) { Loading @@ -709,6 +705,17 @@ void rpmh_rsc_debug(struct rsc_drv *drv) pr_warn("HW IRQ %lu is %s at GIC\n", rsc_irq_data->hwirq, irq_sts ? "PENDING" : "NOT PENDING"); for_each_set_bit(i, &accl, ARRAY_SIZE(accl_str)) { strlcat(str, accl_str[i], sizeof(str)); strlcat(str, " ", sizeof(str)); } if (busy && !irq_sts) pr_warn("ERROR:Accelerator(s) { %s } at AOSS did not respond\n", str); else if (irq_sts) pr_warn("ERROR:Possible lockup in Linux\n"); /* * The TCS(s) are busy waiting, we have no way to recover from this. * If this debug function is called, we assume it's because timeout Loading drivers/soc/qcom/rpmh.c +21 −13 Original line number Diff line number Diff line Loading @@ -117,6 +117,7 @@ void rpmh_tx_done(const struct tcs_request *msg, int r) struct rpmh_request *rpm_msg = container_of(msg, struct rpmh_request, msg); struct completion *compl = rpm_msg->completion; bool free = rpm_msg->needs_free; rpm_msg->err = r; Loading @@ -131,7 +132,7 @@ void rpmh_tx_done(const struct tcs_request *msg, int r) complete(compl); exit: if (rpm_msg->needs_free) if (free) kfree(rpm_msg); } Loading Loading @@ -400,11 +401,12 @@ int rpmh_write_batch(const struct device *dev, enum rpmh_state state, { struct batch_cache_req *req; struct rpmh_request *rpm_msgs; DECLARE_COMPLETION_ONSTACK(compl); struct completion *compls; struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev); unsigned long time_left; int count = 0; int ret, i, j; int ret, i; void *ptr; if (!cmd || !n) return -EINVAL; Loading @@ -421,10 +423,15 @@ int rpmh_write_batch(const struct device *dev, enum rpmh_state state, if (!count) return -EINVAL; req = kzalloc(sizeof(*req) + count * sizeof(req->rpm_msgs[0]), ptr = kzalloc(sizeof(*req) + count * (sizeof(req->rpm_msgs[0]) + sizeof(*compls)), GFP_ATOMIC); if (!req) if (!ptr) return -ENOMEM; req = ptr; compls = ptr + sizeof(*req) + count * sizeof(*rpm_msgs); req->count = count; rpm_msgs = req->rpm_msgs; Loading @@ -439,25 +446,26 @@ int rpmh_write_batch(const struct device *dev, enum rpmh_state state, } for (i = 0; i < count; i++) { rpm_msgs[i].completion = &compl; struct completion *compl = &compls[i]; init_completion(compl); rpm_msgs[i].completion = compl; ret = rpmh_rsc_send_data(ctrlr_to_drv(ctrlr), &rpm_msgs[i].msg); if (ret) { pr_err("Error(%d) sending RPMH message addr=%#x\n", ret, rpm_msgs[i].msg.cmds[0].addr); for (j = i; j < count; j++) rpmh_tx_done(&rpm_msgs[j].msg, ret); break; } } time_left = RPMH_TIMEOUT_MS; for (i = 0; i < count; i++) { time_left = wait_for_completion_timeout(&compl, time_left); while (i--) { time_left = wait_for_completion_timeout(&compls[i], time_left); if (!time_left) { /* * Better hope they never finish because they'll signal * the completion on our stack and that's bad once * we've returned from the function. * the completion that we're going to free once * we've returned from this function. */ rpmh_rsc_debug(ctrlr_to_drv(ctrlr)); ret = -ETIMEDOUT; Loading @@ -466,7 +474,7 @@ int rpmh_write_batch(const struct device *dev, enum rpmh_state state, } exit: kfree(req); kfree(ptr); return ret; } Loading Loading
drivers/soc/qcom/rpmh-rsc.c +29 −22 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "%s " fmt, KBUILD_MODNAME Loading Loading @@ -66,6 +66,13 @@ #define RSC_PDC_DRV_DATA 0x38 #define RSC_PDC_DATA_OFFSET 0x08 #define ACCL_TYPE(addr) ((addr >> 16) & 0xF) #define NR_ACCL_TYPES 3 static const char * const accl_str[] = { "", "", "", "CLK", "VREG", "BUS", }; bool rpmh_standalone; static struct rsc_drv *__rsc_drv[2]; static int __rsc_count; Loading Loading @@ -630,11 +637,10 @@ static struct tcs_group *get_tcs_from_index(struct rsc_drv *drv, int tcs_id) return NULL; } static void print_tcs_info(struct rsc_drv *drv, int tcs_id) static void print_tcs_info(struct rsc_drv *drv, int tcs_id, unsigned long *accl) { struct tcs_group *tcs_grp = get_tcs_from_index(drv, tcs_id); const struct tcs_request *req = get_req_from_tcs(drv, tcs_id); struct tcs_cmd *cmd; unsigned long cmds_enabled; u32 addr, data, msgid, sts, irq_sts; bool in_use = test_bit(tcs_id, drv->tcs_in_use); Loading @@ -658,29 +664,17 @@ static void print_tcs_info(struct rsc_drv *drv, int tcs_id) tcs_id, sts ? "IDLE" : "BUSY", data, (irq_sts & BIT(tcs_id)) ? "COMPLETED" : "PENDING"); for (i = 0; i < req->num_cmds; i++) { cmd = &req->cmds[i]; pr_warn("\tREQ=%d [addr=0x%x data=0x%x wait=0x%x]\n", i, cmd->addr, cmd->data, cmd->wait); if (i < MAX_CMDS_PER_TCS) { addr = read_tcs_reg(drv, RSC_DRV_CMD_ADDR, tcs_id, i); data = read_tcs_reg(drv, RSC_DRV_CMD_DATA, tcs_id, i); msgid = read_tcs_reg(drv, RSC_DRV_CMD_MSGID, tcs_id, i); sts = read_tcs_reg(drv, RSC_DRV_CMD_STATUS, tcs_id, i); pr_warn("\tCMD=%d [addr=0x%x data=0x%x hdr=0x%x sts=0x%x enabled=%ld]\n", i, addr, data, msgid, sts, (cmds_enabled & BIT(i))); } } for_each_set_bit_from(i, &cmds_enabled, MAX_CMDS_PER_TCS) { for_each_set_bit(i, &cmds_enabled, MAX_CMDS_PER_TCS) { addr = read_tcs_reg(drv, RSC_DRV_CMD_ADDR, tcs_id, i); data = read_tcs_reg(drv, RSC_DRV_CMD_DATA, tcs_id, i); msgid = read_tcs_reg(drv, RSC_DRV_CMD_MSGID, tcs_id, i); sts = read_tcs_reg(drv, RSC_DRV_CMD_STATUS, tcs_id, i); pr_warn("\tCMD=%d [addr=0x%x data=0x%x hdr=0x%x sts=0x%x enabled=1]\n", i, addr, data, msgid, sts); if (!(sts & CMD_STATUS_ISSUED)) continue; if (!(sts & CMD_STATUS_COMPL)) *accl |= BIT(ACCL_TYPE(addr)); } } Loading @@ -690,6 +684,8 @@ void rpmh_rsc_debug(struct rsc_drv *drv) bool irq_sts; int i; int busy = 0; unsigned long accl = 0; char str[20] = ""; pr_warn("RSC:%s\n", drv->name); Loading @@ -697,7 +693,7 @@ void rpmh_rsc_debug(struct rsc_drv *drv) if (!test_bit(i, drv->tcs_in_use)) continue; busy++; print_tcs_info(drv, i); print_tcs_info(drv, i, &accl); } if (!rsc_irq_data) { Loading @@ -709,6 +705,17 @@ void rpmh_rsc_debug(struct rsc_drv *drv) pr_warn("HW IRQ %lu is %s at GIC\n", rsc_irq_data->hwirq, irq_sts ? "PENDING" : "NOT PENDING"); for_each_set_bit(i, &accl, ARRAY_SIZE(accl_str)) { strlcat(str, accl_str[i], sizeof(str)); strlcat(str, " ", sizeof(str)); } if (busy && !irq_sts) pr_warn("ERROR:Accelerator(s) { %s } at AOSS did not respond\n", str); else if (irq_sts) pr_warn("ERROR:Possible lockup in Linux\n"); /* * The TCS(s) are busy waiting, we have no way to recover from this. * If this debug function is called, we assume it's because timeout Loading
drivers/soc/qcom/rpmh.c +21 −13 Original line number Diff line number Diff line Loading @@ -117,6 +117,7 @@ void rpmh_tx_done(const struct tcs_request *msg, int r) struct rpmh_request *rpm_msg = container_of(msg, struct rpmh_request, msg); struct completion *compl = rpm_msg->completion; bool free = rpm_msg->needs_free; rpm_msg->err = r; Loading @@ -131,7 +132,7 @@ void rpmh_tx_done(const struct tcs_request *msg, int r) complete(compl); exit: if (rpm_msg->needs_free) if (free) kfree(rpm_msg); } Loading Loading @@ -400,11 +401,12 @@ int rpmh_write_batch(const struct device *dev, enum rpmh_state state, { struct batch_cache_req *req; struct rpmh_request *rpm_msgs; DECLARE_COMPLETION_ONSTACK(compl); struct completion *compls; struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev); unsigned long time_left; int count = 0; int ret, i, j; int ret, i; void *ptr; if (!cmd || !n) return -EINVAL; Loading @@ -421,10 +423,15 @@ int rpmh_write_batch(const struct device *dev, enum rpmh_state state, if (!count) return -EINVAL; req = kzalloc(sizeof(*req) + count * sizeof(req->rpm_msgs[0]), ptr = kzalloc(sizeof(*req) + count * (sizeof(req->rpm_msgs[0]) + sizeof(*compls)), GFP_ATOMIC); if (!req) if (!ptr) return -ENOMEM; req = ptr; compls = ptr + sizeof(*req) + count * sizeof(*rpm_msgs); req->count = count; rpm_msgs = req->rpm_msgs; Loading @@ -439,25 +446,26 @@ int rpmh_write_batch(const struct device *dev, enum rpmh_state state, } for (i = 0; i < count; i++) { rpm_msgs[i].completion = &compl; struct completion *compl = &compls[i]; init_completion(compl); rpm_msgs[i].completion = compl; ret = rpmh_rsc_send_data(ctrlr_to_drv(ctrlr), &rpm_msgs[i].msg); if (ret) { pr_err("Error(%d) sending RPMH message addr=%#x\n", ret, rpm_msgs[i].msg.cmds[0].addr); for (j = i; j < count; j++) rpmh_tx_done(&rpm_msgs[j].msg, ret); break; } } time_left = RPMH_TIMEOUT_MS; for (i = 0; i < count; i++) { time_left = wait_for_completion_timeout(&compl, time_left); while (i--) { time_left = wait_for_completion_timeout(&compls[i], time_left); if (!time_left) { /* * Better hope they never finish because they'll signal * the completion on our stack and that's bad once * we've returned from the function. * the completion that we're going to free once * we've returned from this function. */ rpmh_rsc_debug(ctrlr_to_drv(ctrlr)); ret = -ETIMEDOUT; Loading @@ -466,7 +474,7 @@ int rpmh_write_batch(const struct device *dev, enum rpmh_state state, } exit: kfree(req); kfree(ptr); return ret; } Loading