diff options
author | Andy Gross <andy.gross@linaro.org> | 2016-06-03 19:25:23 -0400 |
---|---|---|
committer | Andy Gross <andy.gross@linaro.org> | 2016-06-24 14:33:59 -0400 |
commit | 13e77747800ef71224a12f787ebd26b27c16ff12 (patch) | |
tree | e00cc2b052bb86fdece7a24b78ef9a302a5ec6b3 | |
parent | d0f6fa7ba2d6244e0e7ec32f91903ca398e66bb9 (diff) |
firmware: qcom: scm: Use atomic SCM for cold boot
This patch changes the cold_set_boot_addr function to use atomic SCM
calls. cold_set_boot_addr required adding qcom_scm_call_atomic2 to
support the two arguments going to the smc call. Using atomic removes
the need for memory allocation and instead places all arguments in
registers.
Signed-off-by: Andy Gross <andy.gross@linaro.org>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
Acked-by: Bjorn Andersson <bjorn.andersson@linaro.org>
-rw-r--r-- | drivers/firmware/qcom_scm-32.c | 63 |
1 files changed, 45 insertions, 18 deletions
diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c index 0883292f640f..5be6a123ac70 100644 --- a/drivers/firmware/qcom_scm-32.c +++ b/drivers/firmware/qcom_scm-32.c | |||
@@ -342,6 +342,41 @@ static s32 qcom_scm_call_atomic1(u32 svc, u32 cmd, u32 arg1) | |||
342 | return r0; | 342 | return r0; |
343 | } | 343 | } |
344 | 344 | ||
345 | /** | ||
346 | * qcom_scm_call_atomic2() - Send an atomic SCM command with two arguments | ||
347 | * @svc_id: service identifier | ||
348 | * @cmd_id: command identifier | ||
349 | * @arg1: first argument | ||
350 | * @arg2: second argument | ||
351 | * | ||
352 | * This shall only be used with commands that are guaranteed to be | ||
353 | * uninterruptable, atomic and SMP safe. | ||
354 | */ | ||
355 | static s32 qcom_scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2) | ||
356 | { | ||
357 | int context_id; | ||
358 | |||
359 | register u32 r0 asm("r0") = SCM_ATOMIC(svc, cmd, 2); | ||
360 | register u32 r1 asm("r1") = (u32)&context_id; | ||
361 | register u32 r2 asm("r2") = arg1; | ||
362 | register u32 r3 asm("r3") = arg2; | ||
363 | |||
364 | asm volatile( | ||
365 | __asmeq("%0", "r0") | ||
366 | __asmeq("%1", "r0") | ||
367 | __asmeq("%2", "r1") | ||
368 | __asmeq("%3", "r2") | ||
369 | __asmeq("%4", "r3") | ||
370 | #ifdef REQUIRES_SEC | ||
371 | ".arch_extension sec\n" | ||
372 | #endif | ||
373 | "smc #0 @ switch to secure world\n" | ||
374 | : "=r" (r0) | ||
375 | : "r" (r0), "r" (r1), "r" (r2), "r" (r3) | ||
376 | ); | ||
377 | return r0; | ||
378 | } | ||
379 | |||
345 | u32 qcom_scm_get_version(void) | 380 | u32 qcom_scm_get_version(void) |
346 | { | 381 | { |
347 | int context_id; | 382 | int context_id; |
@@ -378,22 +413,6 @@ u32 qcom_scm_get_version(void) | |||
378 | } | 413 | } |
379 | EXPORT_SYMBOL(qcom_scm_get_version); | 414 | EXPORT_SYMBOL(qcom_scm_get_version); |
380 | 415 | ||
381 | /* | ||
382 | * Set the cold/warm boot address for one of the CPU cores. | ||
383 | */ | ||
384 | static int qcom_scm_set_boot_addr(u32 addr, int flags) | ||
385 | { | ||
386 | struct { | ||
387 | __le32 flags; | ||
388 | __le32 addr; | ||
389 | } cmd; | ||
390 | |||
391 | cmd.addr = cpu_to_le32(addr); | ||
392 | cmd.flags = cpu_to_le32(flags); | ||
393 | return qcom_scm_call(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR, | ||
394 | &cmd, sizeof(cmd), NULL, 0); | ||
395 | } | ||
396 | |||
397 | /** | 416 | /** |
398 | * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus | 417 | * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus |
399 | * @entry: Entry point function for the cpus | 418 | * @entry: Entry point function for the cpus |
@@ -423,7 +442,8 @@ int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) | |||
423 | set_cpu_present(cpu, false); | 442 | set_cpu_present(cpu, false); |
424 | } | 443 | } |
425 | 444 | ||
426 | return qcom_scm_set_boot_addr(virt_to_phys(entry), flags); | 445 | return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR, |
446 | flags, virt_to_phys(entry)); | ||
427 | } | 447 | } |
428 | 448 | ||
429 | /** | 449 | /** |
@@ -439,6 +459,10 @@ int __qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) | |||
439 | int ret; | 459 | int ret; |
440 | int flags = 0; | 460 | int flags = 0; |
441 | int cpu; | 461 | int cpu; |
462 | struct { | ||
463 | __le32 flags; | ||
464 | __le32 addr; | ||
465 | } cmd; | ||
442 | 466 | ||
443 | /* | 467 | /* |
444 | * Reassign only if we are switching from hotplug entry point | 468 | * Reassign only if we are switching from hotplug entry point |
@@ -454,7 +478,10 @@ int __qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) | |||
454 | if (!flags) | 478 | if (!flags) |
455 | return 0; | 479 | return 0; |
456 | 480 | ||
457 | ret = qcom_scm_set_boot_addr(virt_to_phys(entry), flags); | 481 | cmd.addr = cpu_to_le32(virt_to_phys(entry)); |
482 | cmd.flags = cpu_to_le32(flags); | ||
483 | ret = qcom_scm_call(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR, | ||
484 | &cmd, sizeof(cmd), NULL, 0); | ||
458 | if (!ret) { | 485 | if (!ret) { |
459 | for_each_cpu(cpu, cpus) | 486 | for_each_cpu(cpu, cpus) |
460 | qcom_scm_wb[cpu].entry = entry; | 487 | qcom_scm_wb[cpu].entry = entry; |