aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJordan Crouse <jcrouse@codeaurora.org>2017-05-17 10:45:29 -0400
committerRob Clark <robdclark@gmail.com>2017-06-16 11:15:31 -0400
commit7c65817e6d38fad8ed4ae8632b3615980a2197b4 (patch)
tree97f1c8a2326fba7614f3191a6fba6661f7933049
parent925344ccc91d7a7fd84cab2dece1c34bbd86fd8c (diff)
drm/msm: gpu: Enable zap shader for A5XX
The A5XX GPU powers on in "secure" mode. In secure mode the GPU can only render to buffers that are marked as secure and inaccessible to the kernel and user through a series of hardware protections. In practice secure mode is used to draw things like a UI on a secure video frame. In order to switch out of secure mode the GPU executes a special shader that clears out the GMEM and other sensitve registers and then writes a register. Because the kernel can't be trusted the shader binary is signed and verified and programmed by the secure world. To do this we need to read the MDT header and the segments from the firmware location and put them in memory and present them for approval. For targets without secure support there is an out: if the secure world doesn't support secure then there are no hardware protections and we can freely write the SECVID_TRUST register from the CPU. We don't have 100% confidence that we can query the secure capabilities at run time but we have enough calls that need to go right to give us some confidence that we're at least doing something useful. Of course if we guess wrong you trigger a permissions violation which usually ends up in a system crash but thats a problem that shows up immediately. [v2: use child device per Bjorn] [v3: use generic MDT loader per Bjorn] [v4: use managed dma functions and ifdefs for the MDT loader] [v5: Add depends for QCOM_MDT_LOADER] Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Acked-by: Bjorn Andersson <bjorn.andersson@linaro.org> [robclark: fix Kconfig to use select instead of depends + #if IS_ENABLED()] Signed-off-by: Rob Clark <robdclark@gmail.com>
-rw-r--r--drivers/gpu/drm/msm/Kconfig1
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_gpu.c180
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_gpu.h2
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_device.c1
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.h1
5 files changed, 183 insertions, 2 deletions
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 0a31cd6d01ce..b638d192ce5e 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -5,6 +5,7 @@ config DRM_MSM
5 depends on ARCH_QCOM || (ARM && COMPILE_TEST) 5 depends on ARCH_QCOM || (ARM && COMPILE_TEST)
6 depends on OF && COMMON_CLK 6 depends on OF && COMMON_CLK
7 depends on MMU 7 depends on MMU
8 select QCOM_MDT_LOADER
8 select REGULATOR 9 select REGULATOR
9 select DRM_KMS_HELPER 10 select DRM_KMS_HELPER
10 select DRM_PANEL 11 select DRM_PANEL
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index 31a9bceed32c..67fd6bf2a25f 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -11,6 +11,12 @@
11 * 11 *
12 */ 12 */
13 13
14#include <linux/types.h>
15#include <linux/cpumask.h>
16#include <linux/qcom_scm.h>
17#include <linux/dma-mapping.h>
18#include <linux/of_reserved_mem.h>
19#include <linux/soc/qcom/mdt_loader.h>
14#include "msm_gem.h" 20#include "msm_gem.h"
15#include "msm_mmu.h" 21#include "msm_mmu.h"
16#include "a5xx_gpu.h" 22#include "a5xx_gpu.h"
@@ -18,6 +24,62 @@
18extern bool hang_debug; 24extern bool hang_debug;
19static void a5xx_dump(struct msm_gpu *gpu); 25static void a5xx_dump(struct msm_gpu *gpu);
20 26
27#define GPU_PAS_ID 13
28
29#if IS_ENABLED(CONFIG_QCOM_MDT_LOADER)
30
31static int zap_shader_load_mdt(struct device *dev, const char *fwname)
32{
33 const struct firmware *fw;
34 phys_addr_t mem_phys;
35 ssize_t mem_size;
36 void *mem_region = NULL;
37 int ret;
38
39 /* Request the MDT file for the firmware */
40 ret = request_firmware(&fw, fwname, dev);
41 if (ret) {
42 DRM_DEV_ERROR(dev, "Unable to load %s\n", fwname);
43 return ret;
44 }
45
46 /* Figure out how much memory we need */
47 mem_size = qcom_mdt_get_size(fw);
48 if (mem_size < 0) {
49 ret = mem_size;
50 goto out;
51 }
52
53 /* Allocate memory for the firmware image */
54 mem_region = dmam_alloc_coherent(dev, mem_size, &mem_phys, GFP_KERNEL);
55 if (!mem_region) {
56 ret = -ENOMEM;
57 goto out;
58 }
59
60 /* Load the rest of the MDT */
61 ret = qcom_mdt_load(dev, fw, fwname, GPU_PAS_ID, mem_region, mem_phys,
62 mem_size);
63 if (ret)
64 goto out;
65
66 /* Send the image to the secure world */
67 ret = qcom_scm_pas_auth_and_reset(GPU_PAS_ID);
68 if (ret)
69 DRM_DEV_ERROR(dev, "Unable to authorize the image\n");
70
71out:
72 release_firmware(fw);
73
74 return ret;
75}
76#else
77static int zap_shader_load_mdt(struct device *dev, const char *fwname)
78{
79 return -ENODEV;
80}
81#endif
82
21static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, 83static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
22 struct msm_file_private *ctx) 84 struct msm_file_private *ctx)
23{ 85{
@@ -304,6 +366,98 @@ static int a5xx_ucode_init(struct msm_gpu *gpu)
304 return 0; 366 return 0;
305} 367}
306 368
369#define SCM_GPU_ZAP_SHADER_RESUME 0
370
371static int a5xx_zap_shader_resume(struct msm_gpu *gpu)
372{
373 int ret;
374
375 ret = qcom_scm_set_remote_state(SCM_GPU_ZAP_SHADER_RESUME, GPU_PAS_ID);
376 if (ret)
377 DRM_ERROR("%s: zap-shader resume failed: %d\n",
378 gpu->name, ret);
379
380 return ret;
381}
382
383/* Set up a child device to "own" the zap shader */
384static int a5xx_zap_shader_dev_init(struct device *parent, struct device *dev)
385{
386 struct device_node *node;
387 int ret;
388
389 if (dev->parent)
390 return 0;
391
392 /* Find the sub-node for the zap shader */
393 node = of_get_child_by_name(parent->of_node, "zap-shader");
394 if (!node) {
395 DRM_DEV_ERROR(parent, "zap-shader not found in device tree\n");
396 return -ENODEV;
397 }
398
399 dev->parent = parent;
400 dev->of_node = node;
401 dev_set_name(dev, "adreno_zap_shader");
402
403 ret = device_register(dev);
404 if (ret) {
405 DRM_DEV_ERROR(parent, "Couldn't register zap shader device\n");
406 goto out;
407 }
408
409 ret = of_reserved_mem_device_init(dev);
410 if (ret) {
411 DRM_DEV_ERROR(parent, "Unable to set up the reserved memory\n");
412 device_unregister(dev);
413 }
414
415out:
416 if (ret)
417 dev->parent = NULL;
418
419 return ret;
420}
421
422static int a5xx_zap_shader_init(struct msm_gpu *gpu)
423{
424 static bool loaded;
425 struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
426 struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
427 struct platform_device *pdev = a5xx_gpu->pdev;
428 int ret;
429
430 /*
431 * If the zap shader is already loaded into memory we just need to kick
432 * the remote processor to reinitialize it
433 */
434 if (loaded)
435 return a5xx_zap_shader_resume(gpu);
436
437 /* We need SCM to be able to load the firmware */
438 if (!qcom_scm_is_available()) {
439 DRM_DEV_ERROR(&pdev->dev, "SCM is not available\n");
440 return -EPROBE_DEFER;
441 }
442
443 /* Each GPU has a target specific zap shader firmware name to use */
444 if (!adreno_gpu->info->zapfw) {
445 DRM_DEV_ERROR(&pdev->dev,
446 "Zap shader firmware file not specified for this target\n");
447 return -ENODEV;
448 }
449
450 ret = a5xx_zap_shader_dev_init(&pdev->dev, &a5xx_gpu->zap_dev);
451
452 if (!ret)
453 ret = zap_shader_load_mdt(&a5xx_gpu->zap_dev,
454 adreno_gpu->info->zapfw);
455
456 loaded = !ret;
457
458 return ret;
459}
460
307#define A5XX_INT_MASK (A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR | \ 461#define A5XX_INT_MASK (A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR | \
308 A5XX_RBBM_INT_0_MASK_RBBM_TRANSFER_TIMEOUT | \ 462 A5XX_RBBM_INT_0_MASK_RBBM_TRANSFER_TIMEOUT | \
309 A5XX_RBBM_INT_0_MASK_RBBM_ME_MS_TIMEOUT | \ 463 A5XX_RBBM_INT_0_MASK_RBBM_ME_MS_TIMEOUT | \
@@ -488,8 +642,27 @@ static int a5xx_hw_init(struct msm_gpu *gpu)
488 return -EINVAL; 642 return -EINVAL;
489 } 643 }
490 644
491 /* Put the GPU into unsecure mode */ 645 /*
492 gpu_write(gpu, REG_A5XX_RBBM_SECVID_TRUST_CNTL, 0x0); 646 * Try to load a zap shader into the secure world. If successful
647 * we can use the CP to switch out of secure mode. If not then we
648 * have no resource but to try to switch ourselves out manually. If we
649 * guessed wrong then access to the RBBM_SECVID_TRUST_CNTL register will
650 * be blocked and a permissions violation will soon follow.
651 */
652 ret = a5xx_zap_shader_init(gpu);
653 if (!ret) {
654 OUT_PKT7(gpu->rb, CP_SET_SECURE_MODE, 1);
655 OUT_RING(gpu->rb, 0x00000000);
656
657 gpu->funcs->flush(gpu);
658 if (!gpu->funcs->idle(gpu))
659 return -EINVAL;
660 } else {
661 /* Print a warning so if we die, we know why */
662 dev_warn_once(gpu->dev->dev,
663 "Zap shader not enabled - using SECVID_TRUST_CNTL instead\n");
664 gpu_write(gpu, REG_A5XX_RBBM_SECVID_TRUST_CNTL, 0x0);
665 }
493 666
494 return 0; 667 return 0;
495} 668}
@@ -521,6 +694,9 @@ static void a5xx_destroy(struct msm_gpu *gpu)
521 694
522 DBG("%s", gpu->name); 695 DBG("%s", gpu->name);
523 696
697 if (a5xx_gpu->zap_dev.parent)
698 device_unregister(&a5xx_gpu->zap_dev);
699
524 if (a5xx_gpu->pm4_bo) { 700 if (a5xx_gpu->pm4_bo) {
525 if (a5xx_gpu->pm4_iova) 701 if (a5xx_gpu->pm4_iova)
526 msm_gem_put_iova(a5xx_gpu->pm4_bo, gpu->id); 702 msm_gem_put_iova(a5xx_gpu->pm4_bo, gpu->id);
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h
index 1590f845d554..78408f56660e 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h
@@ -36,6 +36,8 @@ struct a5xx_gpu {
36 uint32_t gpmu_dwords; 36 uint32_t gpmu_dwords;
37 37
38 uint32_t lm_leakage; 38 uint32_t lm_leakage;
39
40 struct device zap_dev;
39}; 41};
40 42
41#define to_a5xx_gpu(x) container_of(x, struct a5xx_gpu, base) 43#define to_a5xx_gpu(x) container_of(x, struct a5xx_gpu, base)
diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
index c0fa5d1c75ff..b7bd6d393215 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_device.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
@@ -86,6 +86,7 @@ static const struct adreno_info gpulist[] = {
86 ADRENO_QUIRK_FAULT_DETECT_MASK, 86 ADRENO_QUIRK_FAULT_DETECT_MASK,
87 .init = a5xx_gpu_init, 87 .init = a5xx_gpu_init,
88 .gpmufw = "a530v3_gpmu.fw2", 88 .gpmufw = "a530v3_gpmu.fw2",
89 .zapfw = "a530_zap.mdt",
89 }, 90 },
90}; 91};
91 92
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index fb4831f9f80b..12b1483625f8 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -77,6 +77,7 @@ struct adreno_info {
77 uint32_t gmem; 77 uint32_t gmem;
78 enum adreno_quirks quirks; 78 enum adreno_quirks quirks;
79 struct msm_gpu *(*init)(struct drm_device *dev); 79 struct msm_gpu *(*init)(struct drm_device *dev);
80 const char *zapfw;
80}; 81};
81 82
82const struct adreno_info *adreno_info(struct adreno_rev rev); 83const struct adreno_info *adreno_info(struct adreno_rev rev);