Skip to content

Commit 07dc367

Browse files
mszyprowdaeinki
authored andcommitted
drm/exynos: Fix cleanup of IOMMU related objects
Store the IOMMU mapping created by the device core of each Exynos DRM sub-device and restore it when the Exynos DRM driver is unbound. This fixes IOMMU initialization failure for the second time when a deferred probe is triggered from the bind() callback of master's compound DRM driver. This also fixes the following issue found using kmemleak detector: unreferenced object 0xc2137640 (size 64): comm "swapper/0", pid 1, jiffies 4294937900 (age 3127.400s) hex dump (first 32 bytes): 50 a3 14 c2 80 a2 14 c2 01 00 00 00 20 00 00 00 P........... ... 00 10 00 00 00 80 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<3acd268d>] arch_setup_dma_ops+0x4c/0x104 [<9f7d2cce>] of_dma_configure+0x19c/0x3a4 [<ba07704b>] really_probe+0xb0/0x47c [<4f510e4f>] driver_probe_device+0x78/0x1c4 [<7481a0cf>] device_driver_attach+0x58/0x60 [<0ff8f5c1>] __driver_attach+0xb8/0x158 [<86006144>] bus_for_each_dev+0x74/0xb4 [<10159dca>] bus_add_driver+0x1c0/0x200 [<8a265265>] driver_register+0x74/0x108 [<e0f3451a>] exynos_drm_init+0xb0/0x134 [<db3fc7ba>] do_one_initcall+0x90/0x458 [<6da35917>] kernel_init_freeable+0x188/0x200 [<db3f74d4>] kernel_init+0x8/0x110 [<1f3cddf9>] ret_from_fork+0x14/0x20 [<8cd12507>] 0x0 unreferenced object 0xc214a280 (size 128): comm "swapper/0", pid 1, jiffies 4294937900 (age 3127.400s) hex dump (first 32 bytes): 00 a0 ec ed 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<3acd268d>] arch_setup_dma_ops+0x4c/0x104 [<9f7d2cce>] of_dma_configure+0x19c/0x3a4 [<ba07704b>] really_probe+0xb0/0x47c [<4f510e4f>] driver_probe_device+0x78/0x1c4 [<7481a0cf>] device_driver_attach+0x58/0x60 [<0ff8f5c1>] __driver_attach+0xb8/0x158 [<86006144>] bus_for_each_dev+0x74/0xb4 [<10159dca>] bus_add_driver+0x1c0/0x200 [<8a265265>] driver_register+0x74/0x108 [<e0f3451a>] exynos_drm_init+0xb0/0x134 [<db3fc7ba>] do_one_initcall+0x90/0x458 [<6da35917>] kernel_init_freeable+0x188/0x200 [<db3f74d4>] kernel_init+0x8/0x110 [<1f3cddf9>] ret_from_fork+0x14/0x20 [<8cd12507>] 0x0 unreferenced object 0xedeca000 (size 4096): comm "swapper/0", pid 1, jiffies 4294937900 (age 3127.400s) hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<3acd268d>] arch_setup_dma_ops+0x4c/0x104 [<9f7d2cce>] of_dma_configure+0x19c/0x3a4 [<ba07704b>] really_probe+0xb0/0x47c [<4f510e4f>] driver_probe_device+0x78/0x1c4 [<7481a0cf>] device_driver_attach+0x58/0x60 [<0ff8f5c1>] __driver_attach+0xb8/0x158 [<86006144>] bus_for_each_dev+0x74/0xb4 [<10159dca>] bus_add_driver+0x1c0/0x200 [<8a265265>] driver_register+0x74/0x108 [<e0f3451a>] exynos_drm_init+0xb0/0x134 [<db3fc7ba>] do_one_initcall+0x90/0x458 [<6da35917>] kernel_init_freeable+0x188/0x200 [<db3f74d4>] kernel_init+0x8/0x110 [<1f3cddf9>] ret_from_fork+0x14/0x20 [<8cd12507>] 0x0 unreferenced object 0xc214a300 (size 128): comm "swapper/0", pid 1, jiffies 4294937900 (age 3127.400s) hex dump (first 32 bytes): 00 a3 14 c2 00 a3 14 c2 00 40 18 c2 00 80 18 c2 .........@...... 02 00 02 00 ad 4e ad de ff ff ff ff ff ff ff ff .....N.......... backtrace: [<08cbd8bc>] iommu_domain_alloc+0x24/0x50 [<b835abee>] arm_iommu_create_mapping+0xe4/0x134 [<3acd268d>] arch_setup_dma_ops+0x4c/0x104 [<9f7d2cce>] of_dma_configure+0x19c/0x3a4 [<ba07704b>] really_probe+0xb0/0x47c [<4f510e4f>] driver_probe_device+0x78/0x1c4 [<7481a0cf>] device_driver_attach+0x58/0x60 [<0ff8f5c1>] __driver_attach+0xb8/0x158 [<86006144>] bus_for_each_dev+0x74/0xb4 [<10159dca>] bus_add_driver+0x1c0/0x200 [<8a265265>] driver_register+0x74/0x108 [<e0f3451a>] exynos_drm_init+0xb0/0x134 [<db3fc7ba>] do_one_initcall+0x90/0x458 [<6da35917>] kernel_init_freeable+0x188/0x200 [<db3f74d4>] kernel_init+0x8/0x110 [<1f3cddf9>] ret_from_fork+0x14/0x20 Signed-off-by: Marek Szyprowski <[email protected]> Reviewed-by: Lukasz Luba <[email protected]> Signed-off-by: Inki Dae <[email protected]>
1 parent 513dc79 commit 07dc367

11 files changed

+53
-29
lines changed

drivers/gpu/drm/exynos/exynos5433_drm_decon.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ static const char * const decon_clks_name[] = {
5555
struct decon_context {
5656
struct device *dev;
5757
struct drm_device *drm_dev;
58+
void *dma_priv;
5859
struct exynos_drm_crtc *crtc;
5960
struct exynos_drm_plane planes[WINDOWS_NR];
6061
struct exynos_drm_plane_config configs[WINDOWS_NR];
@@ -644,7 +645,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
644645

645646
decon_clear_channels(ctx->crtc);
646647

647-
return exynos_drm_register_dma(drm_dev, dev);
648+
return exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv);
648649
}
649650

650651
static void decon_unbind(struct device *dev, struct device *master, void *data)
@@ -654,7 +655,7 @@ static void decon_unbind(struct device *dev, struct device *master, void *data)
654655
decon_atomic_disable(ctx->crtc);
655656

656657
/* detach this sub driver from iommu mapping if supported. */
657-
exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev);
658+
exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev, &ctx->dma_priv);
658659
}
659660

660661
static const struct component_ops decon_component_ops = {

drivers/gpu/drm/exynos/exynos7_drm_decon.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
struct decon_context {
4141
struct device *dev;
4242
struct drm_device *drm_dev;
43+
void *dma_priv;
4344
struct exynos_drm_crtc *crtc;
4445
struct exynos_drm_plane planes[WINDOWS_NR];
4546
struct exynos_drm_plane_config configs[WINDOWS_NR];
@@ -127,13 +128,13 @@ static int decon_ctx_initialize(struct decon_context *ctx,
127128

128129
decon_clear_channels(ctx->crtc);
129130

130-
return exynos_drm_register_dma(drm_dev, ctx->dev);
131+
return exynos_drm_register_dma(drm_dev, ctx->dev, &ctx->dma_priv);
131132
}
132133

133134
static void decon_ctx_remove(struct decon_context *ctx)
134135
{
135136
/* detach this sub driver from iommu mapping if supported. */
136-
exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev);
137+
exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev, &ctx->dma_priv);
137138
}
138139

139140
static u32 decon_calc_clkdiv(struct decon_context *ctx,

drivers/gpu/drm/exynos/exynos_drm_dma.c

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ static inline void clear_dma_max_seg_size(struct device *dev)
5858
* mapping.
5959
*/
6060
static int drm_iommu_attach_device(struct drm_device *drm_dev,
61-
struct device *subdrv_dev)
61+
struct device *subdrv_dev, void **dma_priv)
6262
{
6363
struct exynos_drm_private *priv = drm_dev->dev_private;
6464
int ret;
@@ -74,7 +74,14 @@ static int drm_iommu_attach_device(struct drm_device *drm_dev,
7474
return ret;
7575

7676
if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
77-
if (to_dma_iommu_mapping(subdrv_dev))
77+
/*
78+
* Keep the original DMA mapping of the sub-device and
79+
* restore it on Exynos DRM detach, otherwise the DMA
80+
* framework considers it as IOMMU-less during the next
81+
* probe (in case of deferred probe or modular build)
82+
*/
83+
*dma_priv = to_dma_iommu_mapping(subdrv_dev);
84+
if (*dma_priv)
7885
arm_iommu_detach_device(subdrv_dev);
7986

8087
ret = arm_iommu_attach_device(subdrv_dev, priv->mapping);
@@ -98,19 +105,21 @@ static int drm_iommu_attach_device(struct drm_device *drm_dev,
98105
* mapping
99106
*/
100107
static void drm_iommu_detach_device(struct drm_device *drm_dev,
101-
struct device *subdrv_dev)
108+
struct device *subdrv_dev, void **dma_priv)
102109
{
103110
struct exynos_drm_private *priv = drm_dev->dev_private;
104111

105-
if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU))
112+
if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
106113
arm_iommu_detach_device(subdrv_dev);
107-
else if (IS_ENABLED(CONFIG_IOMMU_DMA))
114+
arm_iommu_attach_device(subdrv_dev, *dma_priv);
115+
} else if (IS_ENABLED(CONFIG_IOMMU_DMA))
108116
iommu_detach_device(priv->mapping, subdrv_dev);
109117

110118
clear_dma_max_seg_size(subdrv_dev);
111119
}
112120

113-
int exynos_drm_register_dma(struct drm_device *drm, struct device *dev)
121+
int exynos_drm_register_dma(struct drm_device *drm, struct device *dev,
122+
void **dma_priv)
114123
{
115124
struct exynos_drm_private *priv = drm->dev_private;
116125

@@ -137,13 +146,14 @@ int exynos_drm_register_dma(struct drm_device *drm, struct device *dev)
137146
priv->mapping = mapping;
138147
}
139148

140-
return drm_iommu_attach_device(drm, dev);
149+
return drm_iommu_attach_device(drm, dev, dma_priv);
141150
}
142151

143-
void exynos_drm_unregister_dma(struct drm_device *drm, struct device *dev)
152+
void exynos_drm_unregister_dma(struct drm_device *drm, struct device *dev,
153+
void **dma_priv)
144154
{
145155
if (IS_ENABLED(CONFIG_EXYNOS_IOMMU))
146-
drm_iommu_detach_device(drm, dev);
156+
drm_iommu_detach_device(drm, dev, dma_priv);
147157
}
148158

149159
void exynos_drm_cleanup_dma(struct drm_device *drm)

drivers/gpu/drm/exynos/exynos_drm_drv.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,10 @@ static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
223223
return priv->mapping ? true : false;
224224
}
225225

226-
int exynos_drm_register_dma(struct drm_device *drm, struct device *dev);
227-
void exynos_drm_unregister_dma(struct drm_device *drm, struct device *dev);
226+
int exynos_drm_register_dma(struct drm_device *drm, struct device *dev,
227+
void **dma_priv);
228+
void exynos_drm_unregister_dma(struct drm_device *drm, struct device *dev,
229+
void **dma_priv);
228230
void exynos_drm_cleanup_dma(struct drm_device *drm);
229231

230232
#ifdef CONFIG_DRM_EXYNOS_DPI

drivers/gpu/drm/exynos/exynos_drm_fimc.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ struct fimc_scaler {
9797
struct fimc_context {
9898
struct exynos_drm_ipp ipp;
9999
struct drm_device *drm_dev;
100+
void *dma_priv;
100101
struct device *dev;
101102
struct exynos_drm_ipp_task *task;
102103
struct exynos_drm_ipp_formats *formats;
@@ -1133,7 +1134,7 @@ static int fimc_bind(struct device *dev, struct device *master, void *data)
11331134

11341135
ctx->drm_dev = drm_dev;
11351136
ipp->drm_dev = drm_dev;
1136-
exynos_drm_register_dma(drm_dev, dev);
1137+
exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv);
11371138

11381139
exynos_drm_ipp_register(dev, ipp, &ipp_funcs,
11391140
DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
@@ -1153,7 +1154,7 @@ static void fimc_unbind(struct device *dev, struct device *master,
11531154
struct exynos_drm_ipp *ipp = &ctx->ipp;
11541155

11551156
exynos_drm_ipp_unregister(dev, ipp);
1156-
exynos_drm_unregister_dma(drm_dev, dev);
1157+
exynos_drm_unregister_dma(drm_dev, dev, &ctx->dma_priv);
11571158
}
11581159

11591160
static const struct component_ops fimc_component_ops = {

drivers/gpu/drm/exynos/exynos_drm_fimd.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ static struct fimd_driver_data exynos5420_fimd_driver_data = {
167167
struct fimd_context {
168168
struct device *dev;
169169
struct drm_device *drm_dev;
170+
void *dma_priv;
170171
struct exynos_drm_crtc *crtc;
171172
struct exynos_drm_plane planes[WINDOWS_NR];
172173
struct exynos_drm_plane_config configs[WINDOWS_NR];
@@ -1090,7 +1091,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
10901091
if (is_drm_iommu_supported(drm_dev))
10911092
fimd_clear_channels(ctx->crtc);
10921093

1093-
return exynos_drm_register_dma(drm_dev, dev);
1094+
return exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv);
10941095
}
10951096

10961097
static void fimd_unbind(struct device *dev, struct device *master,
@@ -1100,7 +1101,7 @@ static void fimd_unbind(struct device *dev, struct device *master,
11001101

11011102
fimd_atomic_disable(ctx->crtc);
11021103

1103-
exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev);
1104+
exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev, &ctx->dma_priv);
11041105

11051106
if (ctx->encoder)
11061107
exynos_dpi_remove(ctx->encoder);

drivers/gpu/drm/exynos/exynos_drm_g2d.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ struct g2d_runqueue_node {
232232

233233
struct g2d_data {
234234
struct device *dev;
235+
void *dma_priv;
235236
struct clk *gate_clk;
236237
void __iomem *regs;
237238
int irq;
@@ -1409,7 +1410,7 @@ static int g2d_bind(struct device *dev, struct device *master, void *data)
14091410
return ret;
14101411
}
14111412

1412-
ret = exynos_drm_register_dma(drm_dev, dev);
1413+
ret = exynos_drm_register_dma(drm_dev, dev, &g2d->dma_priv);
14131414
if (ret < 0) {
14141415
dev_err(dev, "failed to enable iommu.\n");
14151416
g2d_fini_cmdlist(g2d);
@@ -1434,7 +1435,7 @@ static void g2d_unbind(struct device *dev, struct device *master, void *data)
14341435
priv->g2d_dev = NULL;
14351436

14361437
cancel_work_sync(&g2d->runqueue_work);
1437-
exynos_drm_unregister_dma(g2d->drm_dev, dev);
1438+
exynos_drm_unregister_dma(g2d->drm_dev, dev, &g2d->dma_priv);
14381439
}
14391440

14401441
static const struct component_ops g2d_component_ops = {

drivers/gpu/drm/exynos/exynos_drm_gsc.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ struct gsc_scaler {
9797
struct gsc_context {
9898
struct exynos_drm_ipp ipp;
9999
struct drm_device *drm_dev;
100+
void *dma_priv;
100101
struct device *dev;
101102
struct exynos_drm_ipp_task *task;
102103
struct exynos_drm_ipp_formats *formats;
@@ -1169,7 +1170,7 @@ static int gsc_bind(struct device *dev, struct device *master, void *data)
11691170

11701171
ctx->drm_dev = drm_dev;
11711172
ctx->drm_dev = drm_dev;
1172-
exynos_drm_register_dma(drm_dev, dev);
1173+
exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv);
11731174

11741175
exynos_drm_ipp_register(dev, ipp, &ipp_funcs,
11751176
DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
@@ -1189,7 +1190,7 @@ static void gsc_unbind(struct device *dev, struct device *master,
11891190
struct exynos_drm_ipp *ipp = &ctx->ipp;
11901191

11911192
exynos_drm_ipp_unregister(dev, ipp);
1192-
exynos_drm_unregister_dma(drm_dev, dev);
1193+
exynos_drm_unregister_dma(drm_dev, dev, &ctx->dma_priv);
11931194
}
11941195

11951196
static const struct component_ops gsc_component_ops = {

drivers/gpu/drm/exynos/exynos_drm_rotator.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ struct rot_variant {
5656
struct rot_context {
5757
struct exynos_drm_ipp ipp;
5858
struct drm_device *drm_dev;
59+
void *dma_priv;
5960
struct device *dev;
6061
void __iomem *regs;
6162
struct clk *clock;
@@ -243,7 +244,7 @@ static int rotator_bind(struct device *dev, struct device *master, void *data)
243244

244245
rot->drm_dev = drm_dev;
245246
ipp->drm_dev = drm_dev;
246-
exynos_drm_register_dma(drm_dev, dev);
247+
exynos_drm_register_dma(drm_dev, dev, &rot->dma_priv);
247248

248249
exynos_drm_ipp_register(dev, ipp, &ipp_funcs,
249250
DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE,
@@ -261,7 +262,7 @@ static void rotator_unbind(struct device *dev, struct device *master,
261262
struct exynos_drm_ipp *ipp = &rot->ipp;
262263

263264
exynos_drm_ipp_unregister(dev, ipp);
264-
exynos_drm_unregister_dma(rot->drm_dev, rot->dev);
265+
exynos_drm_unregister_dma(rot->drm_dev, rot->dev, &rot->dma_priv);
265266
}
266267

267268
static const struct component_ops rotator_component_ops = {

drivers/gpu/drm/exynos/exynos_drm_scaler.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct scaler_data {
3939
struct scaler_context {
4040
struct exynos_drm_ipp ipp;
4141
struct drm_device *drm_dev;
42+
void *dma_priv;
4243
struct device *dev;
4344
void __iomem *regs;
4445
struct clk *clock[SCALER_MAX_CLK];
@@ -450,7 +451,7 @@ static int scaler_bind(struct device *dev, struct device *master, void *data)
450451

451452
scaler->drm_dev = drm_dev;
452453
ipp->drm_dev = drm_dev;
453-
exynos_drm_register_dma(drm_dev, dev);
454+
exynos_drm_register_dma(drm_dev, dev, &scaler->dma_priv);
454455

455456
exynos_drm_ipp_register(dev, ipp, &ipp_funcs,
456457
DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
@@ -470,7 +471,8 @@ static void scaler_unbind(struct device *dev, struct device *master,
470471
struct exynos_drm_ipp *ipp = &scaler->ipp;
471472

472473
exynos_drm_ipp_unregister(dev, ipp);
473-
exynos_drm_unregister_dma(scaler->drm_dev, scaler->dev);
474+
exynos_drm_unregister_dma(scaler->drm_dev, scaler->dev,
475+
&scaler->dma_priv);
474476
}
475477

476478
static const struct component_ops scaler_component_ops = {

0 commit comments

Comments
 (0)