hc
2023-03-21 4b55d97acc464242bcd6a8ae77b8ff37c22dec58
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/* exynos_drm_iommu.c
 *
 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
 * Author: Inki Dae <inki.dae@samsung.com>
 *
 * This program is free software; you can redistribute  it and/or modify it
 * under  the terms of  the GNU General  Public License as published by the
 * Free Software Foundation;  either version 2 of the  License, or (at your
 * option) any later version.
 */
 
#include <drm/drmP.h>
#include <drm/exynos_drm.h>
 
#include <linux/dma-mapping.h>
#include <linux/iommu.h>
 
#include "exynos_drm_drv.h"
#include "exynos_drm_iommu.h"
 
static inline int configure_dma_max_seg_size(struct device *dev)
{
   if (!dev->dma_parms)
       dev->dma_parms = kzalloc(sizeof(*dev->dma_parms), GFP_KERNEL);
   if (!dev->dma_parms)
       return -ENOMEM;
 
   dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
   return 0;
}
 
static inline void clear_dma_max_seg_size(struct device *dev)
{
   kfree(dev->dma_parms);
   dev->dma_parms = NULL;
}
 
/*
 * drm_create_iommu_mapping - create a mapping structure
 *
 * @drm_dev: DRM device
 */
int drm_create_iommu_mapping(struct drm_device *drm_dev)
{
   struct exynos_drm_private *priv = drm_dev->dev_private;
 
   return __exynos_iommu_create_mapping(priv, EXYNOS_DEV_ADDR_START,
                        EXYNOS_DEV_ADDR_SIZE);
}
 
/*
 * drm_release_iommu_mapping - release iommu mapping structure
 *
 * @drm_dev: DRM device
 */
void drm_release_iommu_mapping(struct drm_device *drm_dev)
{
   struct exynos_drm_private *priv = drm_dev->dev_private;
 
   __exynos_iommu_release_mapping(priv);
}
 
/*
 * drm_iommu_attach_device- attach device to iommu mapping
 *
 * @drm_dev: DRM device
 * @subdrv_dev: device to be attach
 *
 * This function should be called by sub drivers to attach it to iommu
 * mapping.
 */
int drm_iommu_attach_device(struct drm_device *drm_dev,
               struct device *subdrv_dev)
{
   struct exynos_drm_private *priv = drm_dev->dev_private;
   int ret;
 
   if (get_dma_ops(priv->dma_dev) != get_dma_ops(subdrv_dev)) {
       DRM_ERROR("Device %s lacks support for IOMMU\n",
             dev_name(subdrv_dev));
       return -EINVAL;
   }
 
   ret = configure_dma_max_seg_size(subdrv_dev);
   if (ret)
       return ret;
 
   ret = __exynos_iommu_attach(priv, subdrv_dev);
   if (ret)
       clear_dma_max_seg_size(subdrv_dev);
 
   return 0;
}
 
/*
 * drm_iommu_detach_device -detach device address space mapping from device
 *
 * @drm_dev: DRM device
 * @subdrv_dev: device to be detached
 *
 * This function should be called by sub drivers to detach it from iommu
 * mapping
 */
void drm_iommu_detach_device(struct drm_device *drm_dev,
               struct device *subdrv_dev)
{
   struct exynos_drm_private *priv = drm_dev->dev_private;
 
   __exynos_iommu_detach(priv, subdrv_dev);
   clear_dma_max_seg_size(subdrv_dev);
}