Loading drivers/firmware/qcom_scm-64.c +315 −8 Original line number Diff line number Diff line Loading @@ -71,6 +71,83 @@ static DEFINE_MUTEX(qcom_scm_lock); #define SMCCC_FIRST_REG_IDX 2 #define SMCCC_LAST_REG_IDX (SMCCC_FIRST_REG_IDX + SMCCC_N_REG_ARGS - 1) #define LEGACY_FUNCNUM(s, c) (((s) << 10) | ((c) & 0x3ff)) /** * struct legacy_command - one SCM command buffer * @len: total available memory for command and response * @buf_offset: start of command buffer * @resp_hdr_offset: start of response buffer * @id: command to be executed * @buf: buffer returned from legacy_get_command_buffer() * * An SCM command is laid out in memory as follows: * * ------------------- <--- struct legacy_command * | command header | * ------------------- <--- legacy_get_command_buffer() * | command buffer | * ------------------- <--- struct legacy_response and * | response header | legacy_command_to_response() * ------------------- <--- legacy_get_response_buffer() * | response buffer | * ------------------- * * There can be arbitrary padding between the headers and buffers so * you should always use the appropriate qcom_scm_get_*_buffer() routines * to access the buffers in a safe manner. */ struct legacy_command { __le32 len; __le32 buf_offset; __le32 resp_hdr_offset; __le32 id; __le32 buf[0]; }; /** * struct legacy_response - one SCM response buffer * @len: total available memory for response * @buf_offset: start of response data relative to start of legacy_response * @is_complete: indicates if the command has finished processing */ struct legacy_response { __le32 len; __le32 buf_offset; __le32 is_complete; }; #define LEGACY_ATOMIC_N_REG_ARGS 5 #define LEGACY_ATOMIC_FIRST_REG_IDX 2 #define LEGACY_CLASS_REGISTER (0x2 << 8) #define LEGACY_MASK_IRQS BIT(5) #define LEGACY_ATOMIC(svc, cmd, n) ((LEGACY_FUNCNUM(svc, cmd) << 12) | \ LEGACY_CLASS_REGISTER | \ LEGACY_MASK_IRQS | \ (n & 0xf)) #define QCOM_SCM_FLAG_COLDBOOT_CPU0 0x00 #define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01 #define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08 #define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20 #define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04 #define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02 #define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10 #define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40 struct qcom_scm_entry { int flag; void *entry; }; static struct qcom_scm_entry qcom_scm_wb[] = { { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 }, { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 }, { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 }, { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 }, }; static void __qcom_scm_call_do_quirk(const struct arm_smccc_args *smc, struct arm_smccc_res *res) { Loading @@ -90,7 +167,7 @@ static void __qcom_scm_call_do_quirk(const struct arm_smccc_args *smc, } while (res->a0 == QCOM_SCM_INTERRUPTED); } static int ___qcom_scm_call_smccc(struct device *dev, static int qcom_scm_call_smccc(struct device *dev, struct qcom_scm_desc *desc, bool atomic) { int arglen = desc->arginfo & 0xf; Loading Loading @@ -176,6 +253,169 @@ static int ___qcom_scm_call_smccc(struct device *dev, return res.a0 ? qcom_scm_remap_error(res.a0) : 0; } /** * legacy_command_to_response() - Get a pointer to a legacy_response * @cmd: command * * Returns a pointer to a response for a command. */ static inline struct legacy_response *legacy_command_to_response( const struct legacy_command *cmd) { return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset); } /** * legacy_get_command_buffer() - Get a pointer to a command buffer * @cmd: command * * Returns a pointer to the command buffer of a command. */ static inline void *legacy_get_command_buffer(const struct legacy_command *cmd) { return (void *)cmd->buf; } /** * legacy_get_response_buffer() - Get a pointer to a response buffer * @rsp: response * * Returns a pointer to a response buffer of a response. */ static inline void *legacy_get_response_buffer( const struct legacy_response *rsp) { return (void *)rsp + le32_to_cpu(rsp->buf_offset); } static void __qcom_scm_call_do(const struct arm_smccc_args *smc, struct arm_smccc_res *res) { do { arm_smccc_smc(smc->a[0], smc->a[1], smc->a[2], smc->a[3], smc->a[4], smc->a[5], smc->a[6], smc->a[7], res); } while (res->a0 == QCOM_SCM_INTERRUPTED); } /** * qcom_scm_call_legacy() - Send an SCM command * @dev: struct device * @svc_id: service identifier * @cmd_id: command identifier * @cmd_buf: command buffer * @cmd_len: length of the command buffer * @resp_buf: response buffer * @resp_len: length of the response buffer * * Sends a command to the SCM and waits for the command to finish processing. * * A note on cache maintenance: * Note that any buffers that are expected to be accessed by the secure world * must be flushed before invoking qcom_scm_call and invalidated in the cache * immediately after qcom_scm_call returns. Cache maintenance on the command * and response buffers is taken care of by qcom_scm_call; however, callers are * responsible for any other cached buffers passed over to the secure world. */ static int qcom_scm_call_legacy(struct device *dev, struct qcom_scm_desc *desc) { int arglen = desc->arginfo & 0xf; int ret = 0, context_id; size_t i; struct legacy_command *cmd; struct legacy_response *rsp; struct arm_smccc_args smc = {{0}}; struct arm_smccc_res res; const size_t cmd_len = arglen * sizeof(__le32); const size_t resp_len = MAX_QCOM_SCM_RETS * sizeof(__le32); size_t alloc_len = sizeof(*cmd) + cmd_len + sizeof(*rsp) + resp_len; dma_addr_t cmd_phys; __le32 *arg_buf; __le32 *res_buf; cmd = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL); if (!cmd) return -ENOMEM; cmd->len = cpu_to_le32(alloc_len); cmd->buf_offset = cpu_to_le32(sizeof(*cmd)); cmd->resp_hdr_offset = cpu_to_le32(sizeof(*cmd) + cmd_len); cmd->id = cpu_to_le32(LEGACY_FUNCNUM(desc->svc, desc->cmd)); arg_buf = legacy_get_command_buffer(cmd); for (i = 0; i < arglen; i++) arg_buf[i] = cpu_to_le32(desc->args[i]); rsp = legacy_command_to_response(cmd); cmd_phys = dma_map_single(dev, cmd, alloc_len, DMA_TO_DEVICE); if (dma_mapping_error(dev, cmd_phys)) { kfree(cmd); return -ENOMEM; } smc.a[0] = 1; smc.a[1] = (unsigned long)&context_id; smc.a[2] = cmd_phys; mutex_lock(&qcom_scm_lock); __qcom_scm_call_do(&smc, &res); if (res.a0 < 0) ret = qcom_scm_remap_error(res.a0); mutex_unlock(&qcom_scm_lock); if (ret) goto out; do { dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len, sizeof(*rsp), DMA_FROM_DEVICE); } while (!rsp->is_complete); dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len + le32_to_cpu(rsp->buf_offset), resp_len, DMA_FROM_DEVICE); res_buf = legacy_get_response_buffer(rsp); for (i = 0; i < MAX_QCOM_SCM_RETS; i++) desc->res[i] = le32_to_cpu(res_buf[i]); out: dma_unmap_single(dev, cmd_phys, alloc_len, DMA_TO_DEVICE); kfree(cmd); return ret; } /** * qcom_scm_call_atomic_legacy() - Send an atomic SCM command with up to * 5 arguments and 3 return values * * This shall only be used with commands that are guaranteed to be * uninterruptable, atomic and SMP safe. */ static int qcom_scm_call_atomic_legacy(struct device *dev, struct qcom_scm_desc *desc) { int context_id; struct arm_smccc_args smc = {{0}}; struct arm_smccc_res res; size_t i, arglen = desc->arginfo & 0xf; BUG_ON(arglen > LEGACY_ATOMIC_N_REG_ARGS); smc.a[0] = LEGACY_ATOMIC(desc->svc, desc->cmd, arglen); smc.a[1] = (unsigned long)&context_id; for (i = 0; i < arglen; i++) smc.a[i + LEGACY_ATOMIC_FIRST_REG_IDX] = desc->args[i]; arm_smccc_smc(smc.a[0], smc.a[1], smc.a[2], smc.a[3], smc.a[4], smc.a[5], smc.a[6], smc.a[7], &res); desc->res[0] = res.a1; desc->res[1] = res.a2; desc->res[2] = res.a3; return res.a0; } /** * qcom_scm_call() - Invoke a syscall in the secure world * @dev: device Loading @@ -189,7 +429,7 @@ static int ___qcom_scm_call_smccc(struct device *dev, static int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc) { might_sleep(); return ___qcom_scm_call_smccc(dev, desc, false); return qcom_scm_call_smccc(dev, desc, false); } /** Loading @@ -205,7 +445,7 @@ static int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc) */ static int qcom_scm_call_atomic(struct device *dev, struct qcom_scm_desc *desc) { return ___qcom_scm_call_smccc(dev, desc, true); return qcom_scm_call_smccc(dev, desc, true); } /** Loading @@ -219,7 +459,35 @@ static int qcom_scm_call_atomic(struct device *dev, struct qcom_scm_desc *desc) int __qcom_scm_set_cold_boot_addr(struct device *dev, void *entry, const cpumask_t *cpus) { return -ENOTSUPP; int flags = 0; int cpu; int scm_cb_flags[] = { QCOM_SCM_FLAG_COLDBOOT_CPU0, QCOM_SCM_FLAG_COLDBOOT_CPU1, QCOM_SCM_FLAG_COLDBOOT_CPU2, QCOM_SCM_FLAG_COLDBOOT_CPU3, }; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_BOOT, .cmd = QCOM_SCM_BOOT_SET_ADDR, .owner = ARM_SMCCC_OWNER_SIP, }; if (!cpus || (cpus && cpumask_empty(cpus))) return -EINVAL; for_each_cpu(cpu, cpus) { if (cpu < ARRAY_SIZE(scm_cb_flags)) flags |= scm_cb_flags[cpu]; else set_cpu_present(cpu, false); } desc.args[0] = flags; desc.args[1] = virt_to_phys(entry); desc.arginfo = QCOM_SCM_ARGS(2); return qcom_scm_call_atomic(dev, &desc); } /** Loading @@ -234,7 +502,37 @@ int __qcom_scm_set_cold_boot_addr(struct device *dev, void *entry, int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry, const cpumask_t *cpus) { return -ENOTSUPP; int ret; int flags = 0; int cpu; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_BOOT, .cmd = QCOM_SCM_BOOT_SET_ADDR, }; /* * Reassign only if we are switching from hotplug entry point * to cpuidle entry point or vice versa. */ for_each_cpu(cpu, cpus) { if (entry == qcom_scm_wb[cpu].entry) continue; flags |= qcom_scm_wb[cpu].flag; } /* No change in entry function */ if (!flags) return 0; desc.args[0] = virt_to_phys(entry); desc.args[1] = flags; ret = qcom_scm_call(dev, &desc); if (!ret) { for_each_cpu(cpu, cpus) qcom_scm_wb[cpu].entry = entry; } return ret; } /** Loading @@ -247,6 +545,15 @@ int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry, */ void __qcom_scm_cpu_power_down(struct device *dev, u32 flags) { struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_BOOT, .cmd = QCOM_SCM_BOOT_TERMINATE_PC, .args[0] = flags & QCOM_SCM_FLUSH_FLAG_MASK, .arginfo = QCOM_SCM_ARGS(1), .owner = ARM_SMCCC_OWNER_SIP, }; qcom_scm_call_atomic(dev, &desc); } int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id) Loading Loading @@ -279,7 +586,7 @@ int __qcom_scm_set_dload_mode(struct device *dev, bool enable) desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0; desc.arginfo = QCOM_SCM_ARGS(2); return qcom_scm_call(dev, &desc); return qcom_scm_call_atomic(dev, &desc); } bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral) Loading Loading @@ -403,7 +710,7 @@ int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr, desc.args[0] = addr; desc.arginfo = QCOM_SCM_ARGS(1); ret = qcom_scm_call(dev, &desc); ret = qcom_scm_call_atomic(dev, &desc); if (ret >= 0) *val = desc.res[0]; Loading @@ -422,7 +729,7 @@ int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val) desc.args[1] = val; desc.arginfo = QCOM_SCM_ARGS(2); return qcom_scm_call(dev, &desc); return qcom_scm_call_atomic(dev, &desc); } int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id) Loading Loading
drivers/firmware/qcom_scm-64.c +315 −8 Original line number Diff line number Diff line Loading @@ -71,6 +71,83 @@ static DEFINE_MUTEX(qcom_scm_lock); #define SMCCC_FIRST_REG_IDX 2 #define SMCCC_LAST_REG_IDX (SMCCC_FIRST_REG_IDX + SMCCC_N_REG_ARGS - 1) #define LEGACY_FUNCNUM(s, c) (((s) << 10) | ((c) & 0x3ff)) /** * struct legacy_command - one SCM command buffer * @len: total available memory for command and response * @buf_offset: start of command buffer * @resp_hdr_offset: start of response buffer * @id: command to be executed * @buf: buffer returned from legacy_get_command_buffer() * * An SCM command is laid out in memory as follows: * * ------------------- <--- struct legacy_command * | command header | * ------------------- <--- legacy_get_command_buffer() * | command buffer | * ------------------- <--- struct legacy_response and * | response header | legacy_command_to_response() * ------------------- <--- legacy_get_response_buffer() * | response buffer | * ------------------- * * There can be arbitrary padding between the headers and buffers so * you should always use the appropriate qcom_scm_get_*_buffer() routines * to access the buffers in a safe manner. */ struct legacy_command { __le32 len; __le32 buf_offset; __le32 resp_hdr_offset; __le32 id; __le32 buf[0]; }; /** * struct legacy_response - one SCM response buffer * @len: total available memory for response * @buf_offset: start of response data relative to start of legacy_response * @is_complete: indicates if the command has finished processing */ struct legacy_response { __le32 len; __le32 buf_offset; __le32 is_complete; }; #define LEGACY_ATOMIC_N_REG_ARGS 5 #define LEGACY_ATOMIC_FIRST_REG_IDX 2 #define LEGACY_CLASS_REGISTER (0x2 << 8) #define LEGACY_MASK_IRQS BIT(5) #define LEGACY_ATOMIC(svc, cmd, n) ((LEGACY_FUNCNUM(svc, cmd) << 12) | \ LEGACY_CLASS_REGISTER | \ LEGACY_MASK_IRQS | \ (n & 0xf)) #define QCOM_SCM_FLAG_COLDBOOT_CPU0 0x00 #define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01 #define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08 #define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20 #define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04 #define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02 #define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10 #define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40 struct qcom_scm_entry { int flag; void *entry; }; static struct qcom_scm_entry qcom_scm_wb[] = { { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 }, { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 }, { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 }, { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 }, }; static void __qcom_scm_call_do_quirk(const struct arm_smccc_args *smc, struct arm_smccc_res *res) { Loading @@ -90,7 +167,7 @@ static void __qcom_scm_call_do_quirk(const struct arm_smccc_args *smc, } while (res->a0 == QCOM_SCM_INTERRUPTED); } static int ___qcom_scm_call_smccc(struct device *dev, static int qcom_scm_call_smccc(struct device *dev, struct qcom_scm_desc *desc, bool atomic) { int arglen = desc->arginfo & 0xf; Loading Loading @@ -176,6 +253,169 @@ static int ___qcom_scm_call_smccc(struct device *dev, return res.a0 ? qcom_scm_remap_error(res.a0) : 0; } /** * legacy_command_to_response() - Get a pointer to a legacy_response * @cmd: command * * Returns a pointer to a response for a command. */ static inline struct legacy_response *legacy_command_to_response( const struct legacy_command *cmd) { return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset); } /** * legacy_get_command_buffer() - Get a pointer to a command buffer * @cmd: command * * Returns a pointer to the command buffer of a command. */ static inline void *legacy_get_command_buffer(const struct legacy_command *cmd) { return (void *)cmd->buf; } /** * legacy_get_response_buffer() - Get a pointer to a response buffer * @rsp: response * * Returns a pointer to a response buffer of a response. */ static inline void *legacy_get_response_buffer( const struct legacy_response *rsp) { return (void *)rsp + le32_to_cpu(rsp->buf_offset); } static void __qcom_scm_call_do(const struct arm_smccc_args *smc, struct arm_smccc_res *res) { do { arm_smccc_smc(smc->a[0], smc->a[1], smc->a[2], smc->a[3], smc->a[4], smc->a[5], smc->a[6], smc->a[7], res); } while (res->a0 == QCOM_SCM_INTERRUPTED); } /** * qcom_scm_call_legacy() - Send an SCM command * @dev: struct device * @svc_id: service identifier * @cmd_id: command identifier * @cmd_buf: command buffer * @cmd_len: length of the command buffer * @resp_buf: response buffer * @resp_len: length of the response buffer * * Sends a command to the SCM and waits for the command to finish processing. * * A note on cache maintenance: * Note that any buffers that are expected to be accessed by the secure world * must be flushed before invoking qcom_scm_call and invalidated in the cache * immediately after qcom_scm_call returns. Cache maintenance on the command * and response buffers is taken care of by qcom_scm_call; however, callers are * responsible for any other cached buffers passed over to the secure world. */ static int qcom_scm_call_legacy(struct device *dev, struct qcom_scm_desc *desc) { int arglen = desc->arginfo & 0xf; int ret = 0, context_id; size_t i; struct legacy_command *cmd; struct legacy_response *rsp; struct arm_smccc_args smc = {{0}}; struct arm_smccc_res res; const size_t cmd_len = arglen * sizeof(__le32); const size_t resp_len = MAX_QCOM_SCM_RETS * sizeof(__le32); size_t alloc_len = sizeof(*cmd) + cmd_len + sizeof(*rsp) + resp_len; dma_addr_t cmd_phys; __le32 *arg_buf; __le32 *res_buf; cmd = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL); if (!cmd) return -ENOMEM; cmd->len = cpu_to_le32(alloc_len); cmd->buf_offset = cpu_to_le32(sizeof(*cmd)); cmd->resp_hdr_offset = cpu_to_le32(sizeof(*cmd) + cmd_len); cmd->id = cpu_to_le32(LEGACY_FUNCNUM(desc->svc, desc->cmd)); arg_buf = legacy_get_command_buffer(cmd); for (i = 0; i < arglen; i++) arg_buf[i] = cpu_to_le32(desc->args[i]); rsp = legacy_command_to_response(cmd); cmd_phys = dma_map_single(dev, cmd, alloc_len, DMA_TO_DEVICE); if (dma_mapping_error(dev, cmd_phys)) { kfree(cmd); return -ENOMEM; } smc.a[0] = 1; smc.a[1] = (unsigned long)&context_id; smc.a[2] = cmd_phys; mutex_lock(&qcom_scm_lock); __qcom_scm_call_do(&smc, &res); if (res.a0 < 0) ret = qcom_scm_remap_error(res.a0); mutex_unlock(&qcom_scm_lock); if (ret) goto out; do { dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len, sizeof(*rsp), DMA_FROM_DEVICE); } while (!rsp->is_complete); dma_sync_single_for_cpu(dev, cmd_phys + sizeof(*cmd) + cmd_len + le32_to_cpu(rsp->buf_offset), resp_len, DMA_FROM_DEVICE); res_buf = legacy_get_response_buffer(rsp); for (i = 0; i < MAX_QCOM_SCM_RETS; i++) desc->res[i] = le32_to_cpu(res_buf[i]); out: dma_unmap_single(dev, cmd_phys, alloc_len, DMA_TO_DEVICE); kfree(cmd); return ret; } /** * qcom_scm_call_atomic_legacy() - Send an atomic SCM command with up to * 5 arguments and 3 return values * * This shall only be used with commands that are guaranteed to be * uninterruptable, atomic and SMP safe. */ static int qcom_scm_call_atomic_legacy(struct device *dev, struct qcom_scm_desc *desc) { int context_id; struct arm_smccc_args smc = {{0}}; struct arm_smccc_res res; size_t i, arglen = desc->arginfo & 0xf; BUG_ON(arglen > LEGACY_ATOMIC_N_REG_ARGS); smc.a[0] = LEGACY_ATOMIC(desc->svc, desc->cmd, arglen); smc.a[1] = (unsigned long)&context_id; for (i = 0; i < arglen; i++) smc.a[i + LEGACY_ATOMIC_FIRST_REG_IDX] = desc->args[i]; arm_smccc_smc(smc.a[0], smc.a[1], smc.a[2], smc.a[3], smc.a[4], smc.a[5], smc.a[6], smc.a[7], &res); desc->res[0] = res.a1; desc->res[1] = res.a2; desc->res[2] = res.a3; return res.a0; } /** * qcom_scm_call() - Invoke a syscall in the secure world * @dev: device Loading @@ -189,7 +429,7 @@ static int ___qcom_scm_call_smccc(struct device *dev, static int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc) { might_sleep(); return ___qcom_scm_call_smccc(dev, desc, false); return qcom_scm_call_smccc(dev, desc, false); } /** Loading @@ -205,7 +445,7 @@ static int qcom_scm_call(struct device *dev, struct qcom_scm_desc *desc) */ static int qcom_scm_call_atomic(struct device *dev, struct qcom_scm_desc *desc) { return ___qcom_scm_call_smccc(dev, desc, true); return qcom_scm_call_smccc(dev, desc, true); } /** Loading @@ -219,7 +459,35 @@ static int qcom_scm_call_atomic(struct device *dev, struct qcom_scm_desc *desc) int __qcom_scm_set_cold_boot_addr(struct device *dev, void *entry, const cpumask_t *cpus) { return -ENOTSUPP; int flags = 0; int cpu; int scm_cb_flags[] = { QCOM_SCM_FLAG_COLDBOOT_CPU0, QCOM_SCM_FLAG_COLDBOOT_CPU1, QCOM_SCM_FLAG_COLDBOOT_CPU2, QCOM_SCM_FLAG_COLDBOOT_CPU3, }; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_BOOT, .cmd = QCOM_SCM_BOOT_SET_ADDR, .owner = ARM_SMCCC_OWNER_SIP, }; if (!cpus || (cpus && cpumask_empty(cpus))) return -EINVAL; for_each_cpu(cpu, cpus) { if (cpu < ARRAY_SIZE(scm_cb_flags)) flags |= scm_cb_flags[cpu]; else set_cpu_present(cpu, false); } desc.args[0] = flags; desc.args[1] = virt_to_phys(entry); desc.arginfo = QCOM_SCM_ARGS(2); return qcom_scm_call_atomic(dev, &desc); } /** Loading @@ -234,7 +502,37 @@ int __qcom_scm_set_cold_boot_addr(struct device *dev, void *entry, int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry, const cpumask_t *cpus) { return -ENOTSUPP; int ret; int flags = 0; int cpu; struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_BOOT, .cmd = QCOM_SCM_BOOT_SET_ADDR, }; /* * Reassign only if we are switching from hotplug entry point * to cpuidle entry point or vice versa. */ for_each_cpu(cpu, cpus) { if (entry == qcom_scm_wb[cpu].entry) continue; flags |= qcom_scm_wb[cpu].flag; } /* No change in entry function */ if (!flags) return 0; desc.args[0] = virt_to_phys(entry); desc.args[1] = flags; ret = qcom_scm_call(dev, &desc); if (!ret) { for_each_cpu(cpu, cpus) qcom_scm_wb[cpu].entry = entry; } return ret; } /** Loading @@ -247,6 +545,15 @@ int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry, */ void __qcom_scm_cpu_power_down(struct device *dev, u32 flags) { struct qcom_scm_desc desc = { .svc = QCOM_SCM_SVC_BOOT, .cmd = QCOM_SCM_BOOT_TERMINATE_PC, .args[0] = flags & QCOM_SCM_FLUSH_FLAG_MASK, .arginfo = QCOM_SCM_ARGS(1), .owner = ARM_SMCCC_OWNER_SIP, }; qcom_scm_call_atomic(dev, &desc); } int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id) Loading Loading @@ -279,7 +586,7 @@ int __qcom_scm_set_dload_mode(struct device *dev, bool enable) desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0; desc.arginfo = QCOM_SCM_ARGS(2); return qcom_scm_call(dev, &desc); return qcom_scm_call_atomic(dev, &desc); } bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral) Loading Loading @@ -403,7 +710,7 @@ int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr, desc.args[0] = addr; desc.arginfo = QCOM_SCM_ARGS(1); ret = qcom_scm_call(dev, &desc); ret = qcom_scm_call_atomic(dev, &desc); if (ret >= 0) *val = desc.res[0]; Loading @@ -422,7 +729,7 @@ int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val) desc.args[1] = val; desc.arginfo = QCOM_SCM_ARGS(2); return qcom_scm_call(dev, &desc); return qcom_scm_call_atomic(dev, &desc); } int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id) Loading