aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Gross <andy.gross@linaro.org>2016-06-03 19:25:23 -0400
committerAndy Gross <andy.gross@linaro.org>2016-06-24 14:33:59 -0400
commit13e77747800ef71224a12f787ebd26b27c16ff12 (patch)
treee00cc2b052bb86fdece7a24b78ef9a302a5ec6b3
parentd0f6fa7ba2d6244e0e7ec32f91903ca398e66bb9 (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.c63
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 */
355static 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
345u32 qcom_scm_get_version(void) 380u32 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}
379EXPORT_SYMBOL(qcom_scm_get_version); 414EXPORT_SYMBOL(qcom_scm_get_version);
380 415
381/*
382 * Set the cold/warm boot address for one of the CPU cores.
383 */
384static 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;