diff options
author | Jonathan Marek <jonathan@marek.ca> | 2018-11-14 17:08:04 -0500 |
---|---|---|
committer | Rob Clark <robdclark@gmail.com> | 2018-12-11 13:07:10 -0500 |
commit | c2052a4e5c99f7edcb0283e6e12b2fb6975b7353 (patch) | |
tree | 2c1b7d32227e42b3d757d3cce7b6a5af1fbdad4a | |
parent | d1d9d0e1724d6a7123b4280fdf6630ae70f96c9c (diff) |
drm/msm: implement a2xx mmu
A2XX has its own very simple MMU.
Added a msm_use_mmu() function because we can't rely on iommu_present to
decide to use MMU or not.
Signed-off-by: Jonathan Marek <jonathan@marek.ca>
Signed-off-by: Rob Clark <robdclark@gmail.com>
-rw-r--r-- | drivers/gpu/drm/msm/Makefile | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/adreno/a2xx_gpu.c | 50 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/adreno/adreno_device.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/adreno/adreno_gpu.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_drv.c | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_drv.h | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_gem.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_gem_vma.c | 23 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_gpu.c | 31 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_gpummu.c | 123 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_mmu.h | 3 |
11 files changed, 242 insertions, 20 deletions
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 61e76f87a5a1..1b26c410599d 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile | |||
@@ -93,7 +93,8 @@ msm-y := \ | |||
93 | msm_rd.o \ | 93 | msm_rd.o \ |
94 | msm_ringbuffer.o \ | 94 | msm_ringbuffer.o \ |
95 | msm_submitqueue.o \ | 95 | msm_submitqueue.o \ |
96 | msm_gpu_tracepoints.o | 96 | msm_gpu_tracepoints.o \ |
97 | msm_gpummu.o | ||
97 | 98 | ||
98 | msm-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o \ | 99 | msm-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o \ |
99 | disp/dpu1/dpu_dbg.o | 100 | disp/dpu1/dpu_dbg.o |
diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c index 5eddcf14eeb9..1f83bc18d500 100644 --- a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c | |||
@@ -2,6 +2,8 @@ | |||
2 | /* Copyright (c) 2018 The Linux Foundation. All rights reserved. */ | 2 | /* Copyright (c) 2018 The Linux Foundation. All rights reserved. */ |
3 | 3 | ||
4 | #include "a2xx_gpu.h" | 4 | #include "a2xx_gpu.h" |
5 | #include "msm_gem.h" | ||
6 | #include "msm_mmu.h" | ||
5 | 7 | ||
6 | extern bool hang_debug; | 8 | extern bool hang_debug; |
7 | 9 | ||
@@ -58,9 +60,12 @@ static bool a2xx_me_init(struct msm_gpu *gpu) | |||
58 | static int a2xx_hw_init(struct msm_gpu *gpu) | 60 | static int a2xx_hw_init(struct msm_gpu *gpu) |
59 | { | 61 | { |
60 | struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); | 62 | struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); |
63 | dma_addr_t pt_base, tran_error; | ||
61 | uint32_t *ptr, len; | 64 | uint32_t *ptr, len; |
62 | int i, ret; | 65 | int i, ret; |
63 | 66 | ||
67 | msm_gpummu_params(gpu->aspace->mmu, &pt_base, &tran_error); | ||
68 | |||
64 | DBG("%s", gpu->name); | 69 | DBG("%s", gpu->name); |
65 | 70 | ||
66 | /* halt ME to avoid ucode upload issues on a20x */ | 71 | /* halt ME to avoid ucode upload issues on a20x */ |
@@ -80,9 +85,34 @@ static int a2xx_hw_init(struct msm_gpu *gpu) | |||
80 | /* note: kgsl uses 0x0000ffff for a20x */ | 85 | /* note: kgsl uses 0x0000ffff for a20x */ |
81 | gpu_write(gpu, REG_A2XX_RBBM_CNTL, 0x00004442); | 86 | gpu_write(gpu, REG_A2XX_RBBM_CNTL, 0x00004442); |
82 | 87 | ||
83 | gpu_write(gpu, REG_A2XX_MH_MMU_CONFIG, 0); | 88 | /* MPU: physical range */ |
84 | gpu_write(gpu, REG_A2XX_MH_MMU_MPU_BASE, 0); | 89 | gpu_write(gpu, REG_A2XX_MH_MMU_MPU_BASE, 0x00000000); |
85 | gpu_write(gpu, REG_A2XX_MH_MMU_MPU_END, 0xfffff000); | 90 | gpu_write(gpu, REG_A2XX_MH_MMU_MPU_END, 0xfffff000); |
91 | |||
92 | gpu_write(gpu, REG_A2XX_MH_MMU_CONFIG, A2XX_MH_MMU_CONFIG_MMU_ENABLE | | ||
93 | A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR(BEH_TRAN_RNG) | | ||
94 | A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR(BEH_TRAN_RNG) | | ||
95 | A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR(BEH_TRAN_RNG) | | ||
96 | A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR(BEH_TRAN_RNG) | | ||
97 | A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR(BEH_TRAN_RNG) | | ||
98 | A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR(BEH_TRAN_RNG) | | ||
99 | A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR(BEH_TRAN_RNG) | | ||
100 | A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR(BEH_TRAN_RNG) | | ||
101 | A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR(BEH_TRAN_RNG) | | ||
102 | A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR(BEH_TRAN_RNG) | | ||
103 | A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR(BEH_TRAN_RNG)); | ||
104 | |||
105 | /* same as parameters in adreno_gpu */ | ||
106 | gpu_write(gpu, REG_A2XX_MH_MMU_VA_RANGE, SZ_16M | | ||
107 | A2XX_MH_MMU_VA_RANGE_NUM_64KB_REGIONS(0xfff)); | ||
108 | |||
109 | gpu_write(gpu, REG_A2XX_MH_MMU_PT_BASE, pt_base); | ||
110 | gpu_write(gpu, REG_A2XX_MH_MMU_TRAN_ERROR, tran_error); | ||
111 | |||
112 | gpu_write(gpu, REG_A2XX_MH_MMU_INVALIDATE, | ||
113 | A2XX_MH_MMU_INVALIDATE_INVALIDATE_ALL | | ||
114 | A2XX_MH_MMU_INVALIDATE_INVALIDATE_TC); | ||
115 | |||
86 | gpu_write(gpu, REG_A2XX_MH_ARBITER_CONFIG, | 116 | gpu_write(gpu, REG_A2XX_MH_ARBITER_CONFIG, |
87 | A2XX_MH_ARBITER_CONFIG_SAME_PAGE_LIMIT(16) | | 117 | A2XX_MH_ARBITER_CONFIG_SAME_PAGE_LIMIT(16) | |
88 | A2XX_MH_ARBITER_CONFIG_L1_ARB_ENABLE | | 118 | A2XX_MH_ARBITER_CONFIG_L1_ARB_ENABLE | |
@@ -109,9 +139,21 @@ static int a2xx_hw_init(struct msm_gpu *gpu) | |||
109 | /* note: gsl doesn't set this */ | 139 | /* note: gsl doesn't set this */ |
110 | gpu_write(gpu, REG_A2XX_RBBM_DEBUG, 0x00080000); | 140 | gpu_write(gpu, REG_A2XX_RBBM_DEBUG, 0x00080000); |
111 | 141 | ||
112 | gpu_write(gpu, REG_A2XX_RBBM_INT_CNTL, 0); | 142 | gpu_write(gpu, REG_A2XX_RBBM_INT_CNTL, |
113 | gpu_write(gpu, REG_AXXX_CP_INT_CNTL, 0x80000000); /* RB INT */ | 143 | A2XX_RBBM_INT_CNTL_RDERR_INT_MASK); |
144 | gpu_write(gpu, REG_AXXX_CP_INT_CNTL, | ||
145 | AXXX_CP_INT_CNTL_T0_PACKET_IN_IB_MASK | | ||
146 | AXXX_CP_INT_CNTL_OPCODE_ERROR_MASK | | ||
147 | AXXX_CP_INT_CNTL_PROTECTED_MODE_ERROR_MASK | | ||
148 | AXXX_CP_INT_CNTL_RESERVED_BIT_ERROR_MASK | | ||
149 | AXXX_CP_INT_CNTL_IB_ERROR_MASK | | ||
150 | AXXX_CP_INT_CNTL_IB1_INT_MASK | | ||
151 | AXXX_CP_INT_CNTL_RB_INT_MASK); | ||
114 | gpu_write(gpu, REG_A2XX_SQ_INT_CNTL, 0); | 152 | gpu_write(gpu, REG_A2XX_SQ_INT_CNTL, 0); |
153 | gpu_write(gpu, REG_A2XX_MH_INTERRUPT_MASK, | ||
154 | A2XX_MH_INTERRUPT_MASK_AXI_READ_ERROR | | ||
155 | A2XX_MH_INTERRUPT_MASK_AXI_WRITE_ERROR | | ||
156 | A2XX_MH_INTERRUPT_MASK_MMU_PAGE_FAULT); | ||
115 | 157 | ||
116 | for (i = 3; i <= 5; i++) | 158 | for (i = 3; i <= 5; i++) |
117 | if ((SZ_16K << i) == adreno_gpu->gmem) | 159 | if ((SZ_16K << i) == adreno_gpu->gmem) |
diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index adc442f736a2..473433f574f9 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c | |||
@@ -307,6 +307,7 @@ static int adreno_bind(struct device *dev, struct device *master, void *data) | |||
307 | static struct adreno_platform_config config = {}; | 307 | static struct adreno_platform_config config = {}; |
308 | const struct adreno_info *info; | 308 | const struct adreno_info *info; |
309 | struct drm_device *drm = dev_get_drvdata(master); | 309 | struct drm_device *drm = dev_get_drvdata(master); |
310 | struct msm_drm_private *priv = drm->dev_private; | ||
310 | struct msm_gpu *gpu; | 311 | struct msm_gpu *gpu; |
311 | int ret; | 312 | int ret; |
312 | 313 | ||
@@ -329,6 +330,8 @@ static int adreno_bind(struct device *dev, struct device *master, void *data) | |||
329 | DBG("Found GPU: %u.%u.%u.%u", config.rev.core, config.rev.major, | 330 | DBG("Found GPU: %u.%u.%u.%u", config.rev.core, config.rev.major, |
330 | config.rev.minor, config.rev.patchid); | 331 | config.rev.minor, config.rev.patchid); |
331 | 332 | ||
333 | priv->is_a2xx = config.rev.core == 2; | ||
334 | |||
332 | gpu = info->init(drm); | 335 | gpu = info->init(drm); |
333 | if (IS_ERR(gpu)) { | 336 | if (IS_ERR(gpu)) { |
334 | dev_warn(drm->dev, "failed to load adreno gpu\n"); | 337 | dev_warn(drm->dev, "failed to load adreno gpu\n"); |
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 9ab67dd1bcd3..2e4372ef17a3 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c | |||
@@ -769,6 +769,9 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, | |||
769 | 769 | ||
770 | adreno_gpu_config.va_start = SZ_16M; | 770 | adreno_gpu_config.va_start = SZ_16M; |
771 | adreno_gpu_config.va_end = 0xffffffff; | 771 | adreno_gpu_config.va_end = 0xffffffff; |
772 | /* maximum range of a2xx mmu */ | ||
773 | if (adreno_is_a2xx(adreno_gpu)) | ||
774 | adreno_gpu_config.va_end = SZ_16M + 0xfff * SZ_64K; | ||
772 | 775 | ||
773 | adreno_gpu_config.nr_rings = nr_rings; | 776 | adreno_gpu_config.nr_rings = nr_rings; |
774 | 777 | ||
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 7661ca71fca6..ae3d6b440bcc 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include "msm_gem.h" | 26 | #include "msm_gem.h" |
27 | #include "msm_gpu.h" | 27 | #include "msm_gpu.h" |
28 | #include "msm_kms.h" | 28 | #include "msm_kms.h" |
29 | #include "adreno/adreno_gpu.h" | ||
29 | 30 | ||
30 | 31 | ||
31 | /* | 32 | /* |
@@ -361,6 +362,14 @@ static int get_mdp_ver(struct platform_device *pdev) | |||
361 | 362 | ||
362 | #include <linux/of_address.h> | 363 | #include <linux/of_address.h> |
363 | 364 | ||
365 | bool msm_use_mmu(struct drm_device *dev) | ||
366 | { | ||
367 | struct msm_drm_private *priv = dev->dev_private; | ||
368 | |||
369 | /* a2xx comes with its own MMU */ | ||
370 | return priv->is_a2xx || iommu_present(&platform_bus_type); | ||
371 | } | ||
372 | |||
364 | static int msm_init_vram(struct drm_device *dev) | 373 | static int msm_init_vram(struct drm_device *dev) |
365 | { | 374 | { |
366 | struct msm_drm_private *priv = dev->dev_private; | 375 | struct msm_drm_private *priv = dev->dev_private; |
@@ -399,7 +408,7 @@ static int msm_init_vram(struct drm_device *dev) | |||
399 | * Grab the entire CMA chunk carved out in early startup in | 408 | * Grab the entire CMA chunk carved out in early startup in |
400 | * mach-msm: | 409 | * mach-msm: |
401 | */ | 410 | */ |
402 | } else if (!iommu_present(&platform_bus_type)) { | 411 | } else if (!msm_use_mmu(dev)) { |
403 | DRM_INFO("using %s VRAM carveout\n", vram); | 412 | DRM_INFO("using %s VRAM carveout\n", vram); |
404 | size = memparse(vram, NULL); | 413 | size = memparse(vram, NULL); |
405 | } | 414 | } |
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 71a03ce21da5..9cd6a96c6bf2 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h | |||
@@ -179,6 +179,8 @@ struct msm_drm_private { | |||
179 | /* when we have more than one 'msm_gpu' these need to be an array: */ | 179 | /* when we have more than one 'msm_gpu' these need to be an array: */ |
180 | struct msm_gpu *gpu; | 180 | struct msm_gpu *gpu; |
181 | struct msm_file_private *lastctx; | 181 | struct msm_file_private *lastctx; |
182 | /* gpu is only set on open(), but we need this info earlier */ | ||
183 | bool is_a2xx; | ||
182 | 184 | ||
183 | struct drm_fb_helper *fbdev; | 185 | struct drm_fb_helper *fbdev; |
184 | 186 | ||
@@ -258,9 +260,15 @@ struct msm_gem_address_space * | |||
258 | msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, | 260 | msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, |
259 | const char *name); | 261 | const char *name); |
260 | 262 | ||
263 | struct msm_gem_address_space * | ||
264 | msm_gem_address_space_create_a2xx(struct device *dev, struct msm_gpu *gpu, | ||
265 | const char *name, uint64_t va_start, uint64_t va_end); | ||
266 | |||
261 | int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu); | 267 | int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu); |
262 | void msm_unregister_mmu(struct drm_device *dev, struct msm_mmu *mmu); | 268 | void msm_unregister_mmu(struct drm_device *dev, struct msm_mmu *mmu); |
263 | 269 | ||
270 | bool msm_use_mmu(struct drm_device *dev); | ||
271 | |||
264 | void msm_gem_submit_free(struct msm_gem_submit *submit); | 272 | void msm_gem_submit_free(struct msm_gem_submit *submit); |
265 | int msm_ioctl_gem_submit(struct drm_device *dev, void *data, | 273 | int msm_ioctl_gem_submit(struct drm_device *dev, void *data, |
266 | struct drm_file *file); | 274 | struct drm_file *file); |
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 38b7f4e9e7ff..51a95da694d8 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c | |||
@@ -975,7 +975,7 @@ static struct drm_gem_object *_msm_gem_new(struct drm_device *dev, | |||
975 | 975 | ||
976 | size = PAGE_ALIGN(size); | 976 | size = PAGE_ALIGN(size); |
977 | 977 | ||
978 | if (!iommu_present(&platform_bus_type)) | 978 | if (!msm_use_mmu(dev)) |
979 | use_vram = true; | 979 | use_vram = true; |
980 | else if ((flags & (MSM_BO_STOLEN | MSM_BO_SCANOUT)) && priv->vram.size) | 980 | else if ((flags & (MSM_BO_STOLEN | MSM_BO_SCANOUT)) && priv->vram.size) |
981 | use_vram = true; | 981 | use_vram = true; |
@@ -1052,7 +1052,7 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev, | |||
1052 | int ret, npages; | 1052 | int ret, npages; |
1053 | 1053 | ||
1054 | /* if we don't have IOMMU, don't bother pretending we can import: */ | 1054 | /* if we don't have IOMMU, don't bother pretending we can import: */ |
1055 | if (!iommu_present(&platform_bus_type)) { | 1055 | if (!msm_use_mmu(dev)) { |
1056 | DRM_DEV_ERROR(dev->dev, "cannot import without IOMMU\n"); | 1056 | DRM_DEV_ERROR(dev->dev, "cannot import without IOMMU\n"); |
1057 | return ERR_PTR(-EINVAL); | 1057 | return ERR_PTR(-EINVAL); |
1058 | } | 1058 | } |
diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index ee46d8321b05..557360788084 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c | |||
@@ -159,3 +159,26 @@ msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, | |||
159 | 159 | ||
160 | return aspace; | 160 | return aspace; |
161 | } | 161 | } |
162 | |||
163 | struct msm_gem_address_space * | ||
164 | msm_gem_address_space_create_a2xx(struct device *dev, struct msm_gpu *gpu, | ||
165 | const char *name, uint64_t va_start, uint64_t va_end) | ||
166 | { | ||
167 | struct msm_gem_address_space *aspace; | ||
168 | u64 size = va_end - va_start; | ||
169 | |||
170 | aspace = kzalloc(sizeof(*aspace), GFP_KERNEL); | ||
171 | if (!aspace) | ||
172 | return ERR_PTR(-ENOMEM); | ||
173 | |||
174 | spin_lock_init(&aspace->lock); | ||
175 | aspace->name = name; | ||
176 | aspace->mmu = msm_gpummu_new(dev, gpu); | ||
177 | |||
178 | drm_mm_init(&aspace->mm, (va_start >> PAGE_SHIFT), | ||
179 | size >> PAGE_SHIFT); | ||
180 | |||
181 | kref_init(&aspace->kref); | ||
182 | |||
183 | return aspace; | ||
184 | } | ||
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index c3909ba75b12..6e079a83bd36 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include "msm_mmu.h" | 20 | #include "msm_mmu.h" |
21 | #include "msm_fence.h" | 21 | #include "msm_fence.h" |
22 | #include "msm_gpu_trace.h" | 22 | #include "msm_gpu_trace.h" |
23 | #include "adreno/adreno_gpu.h" | ||
23 | 24 | ||
24 | #include <generated/utsrelease.h> | 25 | #include <generated/utsrelease.h> |
25 | #include <linux/string_helpers.h> | 26 | #include <linux/string_helpers.h> |
@@ -822,7 +823,6 @@ static struct msm_gem_address_space * | |||
822 | msm_gpu_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev, | 823 | msm_gpu_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev, |
823 | uint64_t va_start, uint64_t va_end) | 824 | uint64_t va_start, uint64_t va_end) |
824 | { | 825 | { |
825 | struct iommu_domain *iommu; | ||
826 | struct msm_gem_address_space *aspace; | 826 | struct msm_gem_address_space *aspace; |
827 | int ret; | 827 | int ret; |
828 | 828 | ||
@@ -831,20 +831,27 @@ msm_gpu_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev, | |||
831 | * and have separate page tables per context. For now, to keep things | 831 | * and have separate page tables per context. For now, to keep things |
832 | * simple and to get something working, just use a single address space: | 832 | * simple and to get something working, just use a single address space: |
833 | */ | 833 | */ |
834 | iommu = iommu_domain_alloc(&platform_bus_type); | 834 | if (!adreno_is_a2xx(to_adreno_gpu(gpu))) { |
835 | if (!iommu) | 835 | struct iommu_domain *iommu = iommu_domain_alloc(&platform_bus_type); |
836 | return NULL; | 836 | if (!iommu) |
837 | 837 | return NULL; | |
838 | iommu->geometry.aperture_start = va_start; | 838 | |
839 | iommu->geometry.aperture_end = va_end; | 839 | iommu->geometry.aperture_start = va_start; |
840 | 840 | iommu->geometry.aperture_end = va_end; | |
841 | DRM_DEV_INFO(gpu->dev->dev, "%s: using IOMMU\n", gpu->name); | 841 | |
842 | DRM_DEV_INFO(gpu->dev->dev, "%s: using IOMMU\n", gpu->name); | ||
843 | |||
844 | aspace = msm_gem_address_space_create(&pdev->dev, iommu, "gpu"); | ||
845 | if (IS_ERR(aspace)) | ||
846 | iommu_domain_free(iommu); | ||
847 | } else { | ||
848 | aspace = msm_gem_address_space_create_a2xx(&pdev->dev, gpu, "gpu", | ||
849 | va_start, va_end); | ||
850 | } | ||
842 | 851 | ||
843 | aspace = msm_gem_address_space_create(&pdev->dev, iommu, "gpu"); | ||
844 | if (IS_ERR(aspace)) { | 852 | if (IS_ERR(aspace)) { |
845 | DRM_DEV_ERROR(gpu->dev->dev, "failed to init iommu: %ld\n", | 853 | DRM_DEV_ERROR(gpu->dev->dev, "failed to init mmu: %ld\n", |
846 | PTR_ERR(aspace)); | 854 | PTR_ERR(aspace)); |
847 | iommu_domain_free(iommu); | ||
848 | return ERR_CAST(aspace); | 855 | return ERR_CAST(aspace); |
849 | } | 856 | } |
850 | 857 | ||
diff --git a/drivers/gpu/drm/msm/msm_gpummu.c b/drivers/gpu/drm/msm/msm_gpummu.c new file mode 100644 index 000000000000..27312b553dd8 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_gpummu.c | |||
@@ -0,0 +1,123 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* Copyright (c) 2018 The Linux Foundation. All rights reserved. */ | ||
3 | |||
4 | #include "msm_drv.h" | ||
5 | #include "msm_mmu.h" | ||
6 | #include "adreno/adreno_gpu.h" | ||
7 | #include "adreno/a2xx.xml.h" | ||
8 | |||
9 | struct msm_gpummu { | ||
10 | struct msm_mmu base; | ||
11 | struct msm_gpu *gpu; | ||
12 | dma_addr_t pt_base; | ||
13 | uint32_t *table; | ||
14 | }; | ||
15 | #define to_msm_gpummu(x) container_of(x, struct msm_gpummu, base) | ||
16 | |||
17 | #define GPUMMU_VA_START SZ_16M | ||
18 | #define GPUMMU_VA_RANGE (0xfff * SZ_64K) | ||
19 | #define GPUMMU_PAGE_SIZE SZ_4K | ||
20 | #define TABLE_SIZE (sizeof(uint32_t) * GPUMMU_VA_RANGE / GPUMMU_PAGE_SIZE) | ||
21 | |||
22 | static int msm_gpummu_attach(struct msm_mmu *mmu, const char * const *names, | ||
23 | int cnt) | ||
24 | { | ||
25 | return 0; | ||
26 | } | ||
27 | |||
28 | static void msm_gpummu_detach(struct msm_mmu *mmu, const char * const *names, | ||
29 | int cnt) | ||
30 | { | ||
31 | } | ||
32 | |||
33 | static int msm_gpummu_map(struct msm_mmu *mmu, uint64_t iova, | ||
34 | struct sg_table *sgt, unsigned len, int prot) | ||
35 | { | ||
36 | struct msm_gpummu *gpummu = to_msm_gpummu(mmu); | ||
37 | unsigned idx = (iova - GPUMMU_VA_START) / GPUMMU_PAGE_SIZE; | ||
38 | struct scatterlist *sg; | ||
39 | unsigned prot_bits = 0; | ||
40 | unsigned i, j; | ||
41 | |||
42 | if (prot & IOMMU_WRITE) | ||
43 | prot_bits |= 1; | ||
44 | if (prot & IOMMU_READ) | ||
45 | prot_bits |= 2; | ||
46 | |||
47 | for_each_sg(sgt->sgl, sg, sgt->nents, i) { | ||
48 | dma_addr_t addr = sg->dma_address; | ||
49 | for (j = 0; j < sg->length / GPUMMU_PAGE_SIZE; j++, idx++) { | ||
50 | gpummu->table[idx] = addr | prot_bits; | ||
51 | addr += GPUMMU_PAGE_SIZE; | ||
52 | } | ||
53 | } | ||
54 | |||
55 | /* we can improve by deferring flush for multiple map() */ | ||
56 | gpu_write(gpummu->gpu, REG_A2XX_MH_MMU_INVALIDATE, | ||
57 | A2XX_MH_MMU_INVALIDATE_INVALIDATE_ALL | | ||
58 | A2XX_MH_MMU_INVALIDATE_INVALIDATE_TC); | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static int msm_gpummu_unmap(struct msm_mmu *mmu, uint64_t iova, unsigned len) | ||
63 | { | ||
64 | struct msm_gpummu *gpummu = to_msm_gpummu(mmu); | ||
65 | unsigned idx = (iova - GPUMMU_VA_START) / GPUMMU_PAGE_SIZE; | ||
66 | unsigned i; | ||
67 | |||
68 | for (i = 0; i < len / GPUMMU_PAGE_SIZE; i++, idx++) | ||
69 | gpummu->table[idx] = 0; | ||
70 | |||
71 | gpu_write(gpummu->gpu, REG_A2XX_MH_MMU_INVALIDATE, | ||
72 | A2XX_MH_MMU_INVALIDATE_INVALIDATE_ALL | | ||
73 | A2XX_MH_MMU_INVALIDATE_INVALIDATE_TC); | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static void msm_gpummu_destroy(struct msm_mmu *mmu) | ||
78 | { | ||
79 | struct msm_gpummu *gpummu = to_msm_gpummu(mmu); | ||
80 | |||
81 | dma_free_attrs(mmu->dev, TABLE_SIZE, gpummu->table, gpummu->pt_base, | ||
82 | DMA_ATTR_FORCE_CONTIGUOUS); | ||
83 | |||
84 | kfree(gpummu); | ||
85 | } | ||
86 | |||
87 | static const struct msm_mmu_funcs funcs = { | ||
88 | .attach = msm_gpummu_attach, | ||
89 | .detach = msm_gpummu_detach, | ||
90 | .map = msm_gpummu_map, | ||
91 | .unmap = msm_gpummu_unmap, | ||
92 | .destroy = msm_gpummu_destroy, | ||
93 | }; | ||
94 | |||
95 | struct msm_mmu *msm_gpummu_new(struct device *dev, struct msm_gpu *gpu) | ||
96 | { | ||
97 | struct msm_gpummu *gpummu; | ||
98 | |||
99 | gpummu = kzalloc(sizeof(*gpummu), GFP_KERNEL); | ||
100 | if (!gpummu) | ||
101 | return ERR_PTR(-ENOMEM); | ||
102 | |||
103 | gpummu->table = dma_alloc_attrs(dev, TABLE_SIZE + 32, &gpummu->pt_base, | ||
104 | GFP_KERNEL | __GFP_ZERO, DMA_ATTR_FORCE_CONTIGUOUS); | ||
105 | if (!gpummu->table) { | ||
106 | kfree(gpummu); | ||
107 | return ERR_PTR(-ENOMEM); | ||
108 | } | ||
109 | |||
110 | gpummu->gpu = gpu; | ||
111 | msm_mmu_init(&gpummu->base, dev, &funcs); | ||
112 | |||
113 | return &gpummu->base; | ||
114 | } | ||
115 | |||
116 | void msm_gpummu_params(struct msm_mmu *mmu, dma_addr_t *pt_base, | ||
117 | dma_addr_t *tran_error) | ||
118 | { | ||
119 | dma_addr_t base = to_msm_gpummu(mmu)->pt_base; | ||
120 | |||
121 | *pt_base = base; | ||
122 | *tran_error = base + TABLE_SIZE; /* 32-byte aligned */ | ||
123 | } | ||
diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index 94c0b83d8026..d21b26604d0b 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h | |||
@@ -53,4 +53,7 @@ static inline void msm_mmu_set_fault_handler(struct msm_mmu *mmu, void *arg, | |||
53 | mmu->handler = handler; | 53 | mmu->handler = handler; |
54 | } | 54 | } |
55 | 55 | ||
56 | void msm_gpummu_params(struct msm_mmu *mmu, dma_addr_t *pt_base, | ||
57 | dma_addr_t *tran_error); | ||
58 | |||
56 | #endif /* __MSM_MMU_H__ */ | 59 | #endif /* __MSM_MMU_H__ */ |