Skip to content

Commit

Permalink
drm/tegra: Refactor IOMMU attach/detach
Browse files Browse the repository at this point in the history
Attaching to and detaching from an IOMMU uses the same code sequence in
every driver, so factor it out into separate helpers.

Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
  • Loading branch information
thierryreding committed May 17, 2018
1 parent 230630b commit 0c407de
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 83 deletions.
42 changes: 7 additions & 35 deletions drivers/gpu/drm/tegra/dc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1837,21 +1837,11 @@ static int tegra_dc_init(struct host1x_client *client)
if (!dc->syncpt)
dev_warn(dc->dev, "failed to allocate syncpoint\n");

if (tegra->domain) {
dc->group = iommu_group_get(client->dev);

if (dc->group && dc->group != tegra->group) {
err = iommu_attach_group(tegra->domain, dc->group);
if (err < 0) {
dev_err(dc->dev,
"failed to attach to domain: %d\n",
err);
iommu_group_put(dc->group);
return err;
}

tegra->group = dc->group;
}
dc->group = host1x_client_iommu_attach(client, true);
if (IS_ERR(dc->group)) {
err = PTR_ERR(dc->group);
dev_err(client->dev, "failed to attach to domain: %d\n", err);
return err;
}

if (dc->soc->wgrps)
Expand Down Expand Up @@ -1916,25 +1906,15 @@ static int tegra_dc_init(struct host1x_client *client)
if (!IS_ERR(primary))
drm_plane_cleanup(primary);

if (dc->group) {
if (dc->group == tegra->group) {
iommu_detach_group(tegra->domain, dc->group);
tegra->group = NULL;
}

iommu_group_put(dc->group);
}

host1x_client_iommu_detach(client, dc->group);
host1x_syncpt_free(dc->syncpt);

return err;
}

static int tegra_dc_exit(struct host1x_client *client)
{
struct drm_device *drm = dev_get_drvdata(client->parent);
struct tegra_dc *dc = host1x_client_to_dc(client);
struct tegra_drm *tegra = drm->dev_private;
int err;

devm_free_irq(dc->dev, dc->irq, dc);
Expand All @@ -1945,15 +1925,7 @@ static int tegra_dc_exit(struct host1x_client *client)
return err;
}

if (dc->group) {
if (dc->group == tegra->group) {
iommu_detach_group(tegra->domain, dc->group);
tegra->group = NULL;
}

iommu_group_put(dc->group);
}

host1x_client_iommu_detach(client, dc->group);
host1x_syncpt_free(dc->syncpt);

return 0;
Expand Down
46 changes: 46 additions & 0 deletions drivers/gpu/drm/tegra/drm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1114,6 +1114,52 @@ int tegra_drm_unregister_client(struct tegra_drm *tegra,
return 0;
}

struct iommu_group *host1x_client_iommu_attach(struct host1x_client *client,
bool shared)
{
struct drm_device *drm = dev_get_drvdata(client->parent);
struct tegra_drm *tegra = drm->dev_private;
struct iommu_group *group = NULL;
int err;

if (tegra->domain) {
group = iommu_group_get(client->dev);
if (!group) {
dev_err(client->dev, "failed to get IOMMU group\n");
return ERR_PTR(-ENODEV);
}

if (!shared || (shared && (group != tegra->group))) {
err = iommu_attach_group(tegra->domain, group);
if (err < 0) {
iommu_group_put(group);
return ERR_PTR(err);
}

if (shared && !tegra->group)
tegra->group = group;
}
}

return group;
}

void host1x_client_iommu_detach(struct host1x_client *client,
struct iommu_group *group)
{
struct drm_device *drm = dev_get_drvdata(client->parent);
struct tegra_drm *tegra = drm->dev_private;

if (group) {
if (group == tegra->group) {
iommu_detach_group(tegra->domain, group);
tegra->group = NULL;
}

iommu_group_put(group);
}
}

void *tegra_drm_alloc(struct tegra_drm *tegra, size_t size, dma_addr_t *dma)
{
struct iova *alloc;
Expand Down
4 changes: 4 additions & 0 deletions drivers/gpu/drm/tegra/drm.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ int tegra_drm_register_client(struct tegra_drm *tegra,
struct tegra_drm_client *client);
int tegra_drm_unregister_client(struct tegra_drm *tegra,
struct tegra_drm_client *client);
struct iommu_group *host1x_client_iommu_attach(struct host1x_client *client,
bool shared);
void host1x_client_iommu_detach(struct host1x_client *client,
struct iommu_group *group);

int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm);
int tegra_drm_exit(struct tegra_drm *tegra);
Expand Down
32 changes: 8 additions & 24 deletions drivers/gpu/drm/tegra/gr2d.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ static int gr2d_init(struct host1x_client *client)
struct tegra_drm_client *drm = host1x_to_drm_client(client);
struct drm_device *dev = dev_get_drvdata(client->parent);
unsigned long flags = HOST1X_SYNCPT_HAS_BASE;
struct tegra_drm *tegra = dev->dev_private;
struct gr2d *gr2d = to_gr2d(drm);
int err;

Expand All @@ -47,22 +46,14 @@ static int gr2d_init(struct host1x_client *client)
goto put;
}

if (tegra->domain) {
gr2d->group = iommu_group_get(client->dev);

if (gr2d->group) {
err = iommu_attach_group(tegra->domain, gr2d->group);
if (err < 0) {
dev_err(client->dev,
"failed to attach to domain: %d\n",
err);
iommu_group_put(gr2d->group);
goto free;
}
}
gr2d->group = host1x_client_iommu_attach(client, false);
if (IS_ERR(gr2d->group)) {
err = PTR_ERR(gr2d->group);
dev_err(client->dev, "failed to attach to domain: %d\n", err);
goto free;
}

err = tegra_drm_register_client(tegra, drm);
err = tegra_drm_register_client(dev->dev_private, drm);
if (err < 0) {
dev_err(client->dev, "failed to register client: %d\n", err);
goto detach;
Expand All @@ -71,10 +62,7 @@ static int gr2d_init(struct host1x_client *client)
return 0;

detach:
if (gr2d->group) {
iommu_detach_group(tegra->domain, gr2d->group);
iommu_group_put(gr2d->group);
}
host1x_client_iommu_detach(client, gr2d->group);
free:
host1x_syncpt_free(client->syncpts[0]);
put:
Expand All @@ -94,14 +82,10 @@ static int gr2d_exit(struct host1x_client *client)
if (err < 0)
return err;

host1x_client_iommu_detach(client, gr2d->group);
host1x_syncpt_free(client->syncpts[0]);
host1x_channel_put(gr2d->channel);

if (gr2d->group) {
iommu_detach_group(tegra->domain, gr2d->group);
iommu_group_put(gr2d->group);
}

return 0;
}

Expand Down
31 changes: 7 additions & 24 deletions drivers/gpu/drm/tegra/gr3d.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ static int gr3d_init(struct host1x_client *client)
struct tegra_drm_client *drm = host1x_to_drm_client(client);
struct drm_device *dev = dev_get_drvdata(client->parent);
unsigned long flags = HOST1X_SYNCPT_HAS_BASE;
struct tegra_drm *tegra = dev->dev_private;
struct gr3d *gr3d = to_gr3d(drm);
int err;

Expand All @@ -57,19 +56,11 @@ static int gr3d_init(struct host1x_client *client)
goto put;
}

if (tegra->domain) {
gr3d->group = iommu_group_get(client->dev);

if (gr3d->group) {
err = iommu_attach_group(tegra->domain, gr3d->group);
if (err < 0) {
dev_err(client->dev,
"failed to attach to domain: %d\n",
err);
iommu_group_put(gr3d->group);
goto free;
}
}
gr3d->group = host1x_client_iommu_attach(client, false);
if (IS_ERR(gr3d->group)) {
err = PTR_ERR(gr3d->group);
dev_err(client->dev, "failed to attach to domain: %d\n", err);
goto free;
}

err = tegra_drm_register_client(dev->dev_private, drm);
Expand All @@ -81,10 +72,7 @@ static int gr3d_init(struct host1x_client *client)
return 0;

detach:
if (gr3d->group) {
iommu_detach_group(tegra->domain, gr3d->group);
iommu_group_put(gr3d->group);
}
host1x_client_iommu_detach(client, gr3d->group);
free:
host1x_syncpt_free(client->syncpts[0]);
put:
Expand All @@ -96,22 +84,17 @@ static int gr3d_exit(struct host1x_client *client)
{
struct tegra_drm_client *drm = host1x_to_drm_client(client);
struct drm_device *dev = dev_get_drvdata(client->parent);
struct tegra_drm *tegra = dev->dev_private;
struct gr3d *gr3d = to_gr3d(drm);
int err;

err = tegra_drm_unregister_client(dev->dev_private, drm);
if (err < 0)
return err;

host1x_client_iommu_detach(client, gr3d->group);
host1x_syncpt_free(client->syncpts[0]);
host1x_channel_put(gr3d->channel);

if (gr3d->group) {
iommu_detach_group(tegra->domain, gr3d->group);
iommu_group_put(gr3d->group);
}

return 0;
}

Expand Down

0 comments on commit 0c407de

Please sign in to comment.