Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/tegra: Use IOMMU groups

In order to support IOMMUs more generically and transparently handle the
ARM SMMU on Tegra186, move to using groups instead of devices for domain
attachment. An IOMMU group is a set of devices that share the same IOMMU
domain and is therefore a good match to represent what Tegra DRM needs.

Signed-off-by: Thierry Reding <treding@nvidia.com>

+28 -18
+17 -10
drivers/gpu/drm/tegra/dc.c
··· 1748 1748 static int tegra_dc_init(struct host1x_client *client) 1749 1749 { 1750 1750 struct drm_device *drm = dev_get_drvdata(client->parent); 1751 + struct iommu_group *group = iommu_group_get(client->dev); 1751 1752 unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED; 1752 1753 struct tegra_dc *dc = host1x_client_to_dc(client); 1753 1754 struct tegra_drm *tegra = drm->dev_private; ··· 1760 1759 if (!dc->syncpt) 1761 1760 dev_warn(dc->dev, "failed to allocate syncpoint\n"); 1762 1761 1763 - if (tegra->domain) { 1764 - err = iommu_attach_device(tegra->domain, dc->dev); 1765 - if (err < 0) { 1766 - dev_err(dc->dev, "failed to attach to domain: %d\n", 1767 - err); 1768 - return err; 1762 + if (group && tegra->domain) { 1763 + if (group != tegra->group) { 1764 + err = iommu_attach_group(tegra->domain, group); 1765 + if (err < 0) { 1766 + dev_err(dc->dev, 1767 + "failed to attach to domain: %d\n", 1768 + err); 1769 + return err; 1770 + } 1771 + 1772 + tegra->group = group; 1769 1773 } 1770 1774 1771 1775 dc->domain = tegra->domain; ··· 1831 1825 if (!IS_ERR(primary)) 1832 1826 drm_plane_cleanup(primary); 1833 1827 1834 - if (tegra->domain) { 1835 - iommu_detach_device(tegra->domain, dc->dev); 1828 + if (group && tegra->domain) { 1829 + iommu_detach_group(tegra->domain, group); 1836 1830 dc->domain = NULL; 1837 1831 } 1838 1832 ··· 1841 1835 1842 1836 static int tegra_dc_exit(struct host1x_client *client) 1843 1837 { 1838 + struct iommu_group *group = iommu_group_get(client->dev); 1844 1839 struct tegra_dc *dc = host1x_client_to_dc(client); 1845 1840 int err; 1846 1841 ··· 1853 1846 return err; 1854 1847 } 1855 1848 1856 - if (dc->domain) { 1857 - iommu_detach_device(dc->domain, dc->dev); 1849 + if (group && dc->domain) { 1850 + iommu_detach_group(dc->domain, group); 1858 1851 dc->domain = NULL; 1859 1852 } 1860 1853
+1
drivers/gpu/drm/tegra/drm.h
··· 60 60 struct drm_device *drm; 61 61 62 62 struct iommu_domain *domain; 63 + struct iommu_group *group; 63 64 struct mutex mm_lock; 64 65 struct drm_mm mm; 65 66
+10 -8
drivers/gpu/drm/tegra/vic.c
··· 138 138 static int vic_init(struct host1x_client *client) 139 139 { 140 140 struct tegra_drm_client *drm = host1x_to_drm_client(client); 141 + struct iommu_group *group = iommu_group_get(client->dev); 141 142 struct drm_device *dev = dev_get_drvdata(client->parent); 142 143 struct tegra_drm *tegra = dev->dev_private; 143 144 struct vic *vic = to_vic(drm); 144 145 int err; 145 146 146 - if (tegra->domain) { 147 - err = iommu_attach_device(tegra->domain, vic->dev); 147 + if (group && tegra->domain) { 148 + err = iommu_attach_group(tegra->domain, group); 148 149 if (err < 0) { 149 150 dev_err(vic->dev, "failed to attach to domain: %d\n", 150 151 err); ··· 159 158 vic->falcon.data = tegra; 160 159 err = falcon_load_firmware(&vic->falcon); 161 160 if (err < 0) 162 - goto detach_device; 161 + goto detach; 163 162 } 164 163 165 164 vic->channel = host1x_channel_request(client->dev); 166 165 if (!vic->channel) { 167 166 err = -ENOMEM; 168 - goto detach_device; 167 + goto detach; 169 168 } 170 169 171 170 client->syncpts[0] = host1x_syncpt_request(client, 0); ··· 184 183 host1x_syncpt_free(client->syncpts[0]); 185 184 free_channel: 186 185 host1x_channel_put(vic->channel); 187 - detach_device: 188 - if (tegra->domain) 189 - iommu_detach_device(tegra->domain, vic->dev); 186 + detach: 187 + if (group && tegra->domain) 188 + iommu_detach_group(tegra->domain, group); 190 189 191 190 return err; 192 191 } ··· 194 193 static int vic_exit(struct host1x_client *client) 195 194 { 196 195 struct tegra_drm_client *drm = host1x_to_drm_client(client); 196 + struct iommu_group *group = iommu_group_get(client->dev); 197 197 struct drm_device *dev = dev_get_drvdata(client->parent); 198 198 struct tegra_drm *tegra = dev->dev_private; 199 199 struct vic *vic = to_vic(drm); ··· 208 206 host1x_channel_put(vic->channel); 209 207 210 208 if (vic->domain) { 211 - iommu_detach_device(vic->domain, vic->dev); 209 + iommu_detach_group(vic->domain, group); 212 210 vic->domain = NULL; 213 211 } 214 212