mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 19:29:37 +00:00
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>
This commit is contained in:
parent
41c3068cc2
commit
bc8828bd08
3 changed files with 28 additions and 18 deletions
|
@ -1748,6 +1748,7 @@ static irqreturn_t tegra_dc_irq(int irq, void *data)
|
|||
static int tegra_dc_init(struct host1x_client *client)
|
||||
{
|
||||
struct drm_device *drm = dev_get_drvdata(client->parent);
|
||||
struct iommu_group *group = iommu_group_get(client->dev);
|
||||
unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;
|
||||
struct tegra_dc *dc = host1x_client_to_dc(client);
|
||||
struct tegra_drm *tegra = drm->dev_private;
|
||||
|
@ -1759,12 +1760,17 @@ static int tegra_dc_init(struct host1x_client *client)
|
|||
if (!dc->syncpt)
|
||||
dev_warn(dc->dev, "failed to allocate syncpoint\n");
|
||||
|
||||
if (tegra->domain) {
|
||||
err = iommu_attach_device(tegra->domain, dc->dev);
|
||||
if (err < 0) {
|
||||
dev_err(dc->dev, "failed to attach to domain: %d\n",
|
||||
err);
|
||||
return err;
|
||||
if (group && tegra->domain) {
|
||||
if (group != tegra->group) {
|
||||
err = iommu_attach_group(tegra->domain, group);
|
||||
if (err < 0) {
|
||||
dev_err(dc->dev,
|
||||
"failed to attach to domain: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
tegra->group = group;
|
||||
}
|
||||
|
||||
dc->domain = tegra->domain;
|
||||
|
@ -1825,8 +1831,8 @@ static int tegra_dc_init(struct host1x_client *client)
|
|||
if (!IS_ERR(primary))
|
||||
drm_plane_cleanup(primary);
|
||||
|
||||
if (tegra->domain) {
|
||||
iommu_detach_device(tegra->domain, dc->dev);
|
||||
if (group && tegra->domain) {
|
||||
iommu_detach_group(tegra->domain, group);
|
||||
dc->domain = NULL;
|
||||
}
|
||||
|
||||
|
@ -1835,6 +1841,7 @@ static int tegra_dc_init(struct host1x_client *client)
|
|||
|
||||
static int tegra_dc_exit(struct host1x_client *client)
|
||||
{
|
||||
struct iommu_group *group = iommu_group_get(client->dev);
|
||||
struct tegra_dc *dc = host1x_client_to_dc(client);
|
||||
int err;
|
||||
|
||||
|
@ -1846,8 +1853,8 @@ static int tegra_dc_exit(struct host1x_client *client)
|
|||
return err;
|
||||
}
|
||||
|
||||
if (dc->domain) {
|
||||
iommu_detach_device(dc->domain, dc->dev);
|
||||
if (group && dc->domain) {
|
||||
iommu_detach_group(dc->domain, group);
|
||||
dc->domain = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ struct tegra_drm {
|
|||
struct drm_device *drm;
|
||||
|
||||
struct iommu_domain *domain;
|
||||
struct iommu_group *group;
|
||||
struct mutex mm_lock;
|
||||
struct drm_mm mm;
|
||||
|
||||
|
|
|
@ -138,13 +138,14 @@ static const struct falcon_ops vic_falcon_ops = {
|
|||
static int vic_init(struct host1x_client *client)
|
||||
{
|
||||
struct tegra_drm_client *drm = host1x_to_drm_client(client);
|
||||
struct iommu_group *group = iommu_group_get(client->dev);
|
||||
struct drm_device *dev = dev_get_drvdata(client->parent);
|
||||
struct tegra_drm *tegra = dev->dev_private;
|
||||
struct vic *vic = to_vic(drm);
|
||||
int err;
|
||||
|
||||
if (tegra->domain) {
|
||||
err = iommu_attach_device(tegra->domain, vic->dev);
|
||||
if (group && tegra->domain) {
|
||||
err = iommu_attach_group(tegra->domain, group);
|
||||
if (err < 0) {
|
||||
dev_err(vic->dev, "failed to attach to domain: %d\n",
|
||||
err);
|
||||
|
@ -158,13 +159,13 @@ static int vic_init(struct host1x_client *client)
|
|||
vic->falcon.data = tegra;
|
||||
err = falcon_load_firmware(&vic->falcon);
|
||||
if (err < 0)
|
||||
goto detach_device;
|
||||
goto detach;
|
||||
}
|
||||
|
||||
vic->channel = host1x_channel_request(client->dev);
|
||||
if (!vic->channel) {
|
||||
err = -ENOMEM;
|
||||
goto detach_device;
|
||||
goto detach;
|
||||
}
|
||||
|
||||
client->syncpts[0] = host1x_syncpt_request(client, 0);
|
||||
|
@ -183,9 +184,9 @@ static int vic_init(struct host1x_client *client)
|
|||
host1x_syncpt_free(client->syncpts[0]);
|
||||
free_channel:
|
||||
host1x_channel_put(vic->channel);
|
||||
detach_device:
|
||||
if (tegra->domain)
|
||||
iommu_detach_device(tegra->domain, vic->dev);
|
||||
detach:
|
||||
if (group && tegra->domain)
|
||||
iommu_detach_group(tegra->domain, group);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -193,6 +194,7 @@ static int vic_init(struct host1x_client *client)
|
|||
static int vic_exit(struct host1x_client *client)
|
||||
{
|
||||
struct tegra_drm_client *drm = host1x_to_drm_client(client);
|
||||
struct iommu_group *group = iommu_group_get(client->dev);
|
||||
struct drm_device *dev = dev_get_drvdata(client->parent);
|
||||
struct tegra_drm *tegra = dev->dev_private;
|
||||
struct vic *vic = to_vic(drm);
|
||||
|
@ -206,7 +208,7 @@ static int vic_exit(struct host1x_client *client)
|
|||
host1x_channel_put(vic->channel);
|
||||
|
||||
if (vic->domain) {
|
||||
iommu_detach_device(vic->domain, vic->dev);
|
||||
iommu_detach_group(vic->domain, group);
|
||||
vic->domain = NULL;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue