Message ID | 20180504133707.22451-4-thierry.reding@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 04.05.2018 16:37, Thierry Reding wrote: > From: Thierry Reding <treding@nvidia.com> > > Attaching to and detaching from an IOMMU uses the same code sequence in > every driver, so factor it out into separate helpers. > > Signed-off-by: Thierry Reding <treding@nvidia.com> > --- > drivers/gpu/drm/tegra/dc.c | 42 ++++++------------------------------ > drivers/gpu/drm/tegra/drm.c | 42 ++++++++++++++++++++++++++++++++++++ > drivers/gpu/drm/tegra/drm.h | 4 ++++ > drivers/gpu/drm/tegra/gr2d.c | 32 +++++++-------------------- > drivers/gpu/drm/tegra/gr3d.c | 31 ++++++-------------------- > 5 files changed, 68 insertions(+), 83 deletions(-) > > diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c > index c843f11043db..3e7ec3937346 100644 > --- a/drivers/gpu/drm/tegra/dc.c > +++ b/drivers/gpu/drm/tegra/dc.c > @@ -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) > @@ -1916,15 +1906,7 @@ 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; > @@ -1932,9 +1914,7 @@ static int tegra_dc_init(struct host1x_client *client) > > 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); > @@ -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; > diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c > index 7afe2f635f74..bc1008305e1e 100644 > --- a/drivers/gpu/drm/tegra/drm.c > +++ b/drivers/gpu/drm/tegra/drm.c > @@ -1114,6 +1114,48 @@ 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 && (!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; > diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h > index 4f41aaec8530..fe263cf58f34 100644 > --- a/drivers/gpu/drm/tegra/drm.h > +++ b/drivers/gpu/drm/tegra/drm.h > @@ -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); > diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c > index 0b42e99da8ad..2cd0f66c8aa9 100644 > --- a/drivers/gpu/drm/tegra/gr2d.c > +++ b/drivers/gpu/drm/tegra/gr2d.c > @@ -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; > > @@ -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; > @@ -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: > @@ -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; > } > > diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c > index e129f1afff33..98e3c67d0fb5 100644 > --- a/drivers/gpu/drm/tegra/gr3d.c > +++ b/drivers/gpu/drm/tegra/gr3d.c > @@ -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; > > @@ -56,19 +55,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); > @@ -80,10 +71,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: > @@ -95,7 +83,6 @@ 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; > > @@ -103,14 +90,10 @@ static int gr3d_exit(struct host1x_client *client) > 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; > } > > Reviewed-by: Dmitry Osipenko <digetx@gmail.com> Though I'd prefer to have tegra->group renamed, maybe to 'shared_dc_group'.
On Fri, May 04, 2018 at 05:23:42PM +0300, Dmitry Osipenko wrote: > On 04.05.2018 16:37, Thierry Reding wrote: > > From: Thierry Reding <treding@nvidia.com> > > > > Attaching to and detaching from an IOMMU uses the same code sequence in > > every driver, so factor it out into separate helpers. > > > > Signed-off-by: Thierry Reding <treding@nvidia.com> > > --- > > drivers/gpu/drm/tegra/dc.c | 42 ++++++------------------------------ > > drivers/gpu/drm/tegra/drm.c | 42 ++++++++++++++++++++++++++++++++++++ > > drivers/gpu/drm/tegra/drm.h | 4 ++++ > > drivers/gpu/drm/tegra/gr2d.c | 32 +++++++-------------------- > > drivers/gpu/drm/tegra/gr3d.c | 31 ++++++-------------------- > > 5 files changed, 68 insertions(+), 83 deletions(-) > > > > diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c > > index c843f11043db..3e7ec3937346 100644 > > --- a/drivers/gpu/drm/tegra/dc.c > > +++ b/drivers/gpu/drm/tegra/dc.c > > @@ -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) > > @@ -1916,15 +1906,7 @@ 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; > > @@ -1932,9 +1914,7 @@ static int tegra_dc_init(struct host1x_client *client) > > > > 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); > > @@ -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; > > diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c > > index 7afe2f635f74..bc1008305e1e 100644 > > --- a/drivers/gpu/drm/tegra/drm.c > > +++ b/drivers/gpu/drm/tegra/drm.c > > @@ -1114,6 +1114,48 @@ 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 && (!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; > > diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h > > index 4f41aaec8530..fe263cf58f34 100644 > > --- a/drivers/gpu/drm/tegra/drm.h > > +++ b/drivers/gpu/drm/tegra/drm.h > > @@ -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); > > diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c > > index 0b42e99da8ad..2cd0f66c8aa9 100644 > > --- a/drivers/gpu/drm/tegra/gr2d.c > > +++ b/drivers/gpu/drm/tegra/gr2d.c > > @@ -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; > > > > @@ -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; > > @@ -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: > > @@ -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; > > } > > > > diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c > > index e129f1afff33..98e3c67d0fb5 100644 > > --- a/drivers/gpu/drm/tegra/gr3d.c > > +++ b/drivers/gpu/drm/tegra/gr3d.c > > @@ -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; > > > > @@ -56,19 +55,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); > > @@ -80,10 +71,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: > > @@ -95,7 +83,6 @@ 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; > > > > @@ -103,14 +90,10 @@ static int gr3d_exit(struct host1x_client *client) > > 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; > > } > > > > > > Reviewed-by: Dmitry Osipenko <digetx@gmail.com> > > Though I'd prefer to have tegra->group renamed, maybe to 'shared_dc_group'. tegra->group doesn't bother me at all. I think just the fact that it's in struct tegra_drm implies that it is shared. It's also declared closely to all the other "shared" variables, so I think that makes it pretty clear. If there were other IOMMU groups I'd agree that renaming it would be good to clarify the purpose. But as it is, I think there's no need for that. Thanks for the review! Thierry
On 04.05.2018 18:10, Thierry Reding wrote: > On Fri, May 04, 2018 at 05:23:42PM +0300, Dmitry Osipenko wrote: >> On 04.05.2018 16:37, Thierry Reding wrote: >>> From: Thierry Reding <treding@nvidia.com> >>> >>> Attaching to and detaching from an IOMMU uses the same code sequence in >>> every driver, so factor it out into separate helpers. >>> >>> Signed-off-by: Thierry Reding <treding@nvidia.com> >>> --- >>> drivers/gpu/drm/tegra/dc.c | 42 ++++++------------------------------ >>> drivers/gpu/drm/tegra/drm.c | 42 ++++++++++++++++++++++++++++++++++++ >>> drivers/gpu/drm/tegra/drm.h | 4 ++++ >>> drivers/gpu/drm/tegra/gr2d.c | 32 +++++++-------------------- >>> drivers/gpu/drm/tegra/gr3d.c | 31 ++++++-------------------- >>> 5 files changed, 68 insertions(+), 83 deletions(-) >>> >>> diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c >>> index c843f11043db..3e7ec3937346 100644 >>> --- a/drivers/gpu/drm/tegra/dc.c >>> +++ b/drivers/gpu/drm/tegra/dc.c >>> @@ -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) >>> @@ -1916,15 +1906,7 @@ 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; >>> @@ -1932,9 +1914,7 @@ static int tegra_dc_init(struct host1x_client *client) >>> >>> 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); >>> @@ -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; >>> diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c >>> index 7afe2f635f74..bc1008305e1e 100644 >>> --- a/drivers/gpu/drm/tegra/drm.c >>> +++ b/drivers/gpu/drm/tegra/drm.c >>> @@ -1114,6 +1114,48 @@ 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 && (!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; >>> diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h >>> index 4f41aaec8530..fe263cf58f34 100644 >>> --- a/drivers/gpu/drm/tegra/drm.h >>> +++ b/drivers/gpu/drm/tegra/drm.h >>> @@ -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); >>> diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c >>> index 0b42e99da8ad..2cd0f66c8aa9 100644 >>> --- a/drivers/gpu/drm/tegra/gr2d.c >>> +++ b/drivers/gpu/drm/tegra/gr2d.c >>> @@ -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; >>> >>> @@ -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; >>> @@ -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: >>> @@ -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; >>> } >>> >>> diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c >>> index e129f1afff33..98e3c67d0fb5 100644 >>> --- a/drivers/gpu/drm/tegra/gr3d.c >>> +++ b/drivers/gpu/drm/tegra/gr3d.c >>> @@ -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; >>> >>> @@ -56,19 +55,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); >>> @@ -80,10 +71,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: >>> @@ -95,7 +83,6 @@ 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; >>> >>> @@ -103,14 +90,10 @@ static int gr3d_exit(struct host1x_client *client) >>> 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; >>> } >>> >>> >> >> Reviewed-by: Dmitry Osipenko <digetx@gmail.com> >> >> Though I'd prefer to have tegra->group renamed, maybe to 'shared_dc_group'. > > tegra->group doesn't bother me at all. I think just the fact that it's > in struct tegra_drm implies that it is shared. It's also declared > closely to all the other "shared" variables, so I think that makes it > pretty clear. If there were other IOMMU groups I'd agree that renaming > it would be good to clarify the purpose. But as it is, I think there's > no need for that. > > Thanks for the review! Well, okay. On the other hand IOMMU API should handle re-attaching from a different device and then that shared group isn't needed at all. Does that re-attaching cause any problems right now? If yes, maybe it's worth fixing the root of the problem rather than trying to workaround it.
On Fri, May 04, 2018 at 06:17:45PM +0300, Dmitry Osipenko wrote: > On 04.05.2018 18:10, Thierry Reding wrote: > > On Fri, May 04, 2018 at 05:23:42PM +0300, Dmitry Osipenko wrote: > >> On 04.05.2018 16:37, Thierry Reding wrote: > >>> From: Thierry Reding <treding@nvidia.com> > >>> > >>> Attaching to and detaching from an IOMMU uses the same code sequence in > >>> every driver, so factor it out into separate helpers. > >>> > >>> Signed-off-by: Thierry Reding <treding@nvidia.com> > >>> --- > >>> drivers/gpu/drm/tegra/dc.c | 42 ++++++------------------------------ > >>> drivers/gpu/drm/tegra/drm.c | 42 ++++++++++++++++++++++++++++++++++++ > >>> drivers/gpu/drm/tegra/drm.h | 4 ++++ > >>> drivers/gpu/drm/tegra/gr2d.c | 32 +++++++-------------------- > >>> drivers/gpu/drm/tegra/gr3d.c | 31 ++++++-------------------- > >>> 5 files changed, 68 insertions(+), 83 deletions(-) > >>> > >>> diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c > >>> index c843f11043db..3e7ec3937346 100644 > >>> --- a/drivers/gpu/drm/tegra/dc.c > >>> +++ b/drivers/gpu/drm/tegra/dc.c > >>> @@ -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) > >>> @@ -1916,15 +1906,7 @@ 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; > >>> @@ -1932,9 +1914,7 @@ static int tegra_dc_init(struct host1x_client *client) > >>> > >>> 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); > >>> @@ -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; > >>> diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c > >>> index 7afe2f635f74..bc1008305e1e 100644 > >>> --- a/drivers/gpu/drm/tegra/drm.c > >>> +++ b/drivers/gpu/drm/tegra/drm.c > >>> @@ -1114,6 +1114,48 @@ 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 && (!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; > >>> diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h > >>> index 4f41aaec8530..fe263cf58f34 100644 > >>> --- a/drivers/gpu/drm/tegra/drm.h > >>> +++ b/drivers/gpu/drm/tegra/drm.h > >>> @@ -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); > >>> diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c > >>> index 0b42e99da8ad..2cd0f66c8aa9 100644 > >>> --- a/drivers/gpu/drm/tegra/gr2d.c > >>> +++ b/drivers/gpu/drm/tegra/gr2d.c > >>> @@ -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; > >>> > >>> @@ -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; > >>> @@ -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: > >>> @@ -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; > >>> } > >>> > >>> diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c > >>> index e129f1afff33..98e3c67d0fb5 100644 > >>> --- a/drivers/gpu/drm/tegra/gr3d.c > >>> +++ b/drivers/gpu/drm/tegra/gr3d.c > >>> @@ -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; > >>> > >>> @@ -56,19 +55,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); > >>> @@ -80,10 +71,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: > >>> @@ -95,7 +83,6 @@ 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; > >>> > >>> @@ -103,14 +90,10 @@ static int gr3d_exit(struct host1x_client *client) > >>> 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; > >>> } > >>> > >>> > >> > >> Reviewed-by: Dmitry Osipenko <digetx@gmail.com> > >> > >> Though I'd prefer to have tegra->group renamed, maybe to 'shared_dc_group'. > > > > tegra->group doesn't bother me at all. I think just the fact that it's > > in struct tegra_drm implies that it is shared. It's also declared > > closely to all the other "shared" variables, so I think that makes it > > pretty clear. If there were other IOMMU groups I'd agree that renaming > > it would be good to clarify the purpose. But as it is, I think there's > > no need for that. > > > > Thanks for the review! > > Well, okay. On the other hand IOMMU API should handle re-attaching from a > different device and then that shared group isn't needed at all. Does that > re-attaching cause any problems right now? If yes, maybe it's worth fixing the > root of the problem rather than trying to workaround it. Agreed. I've got that on my TODO list somewhere, let me bump that up a little. Thierry
On 04.05.2018 16:37, Thierry Reding wrote: > From: Thierry Reding <treding@nvidia.com> > > Attaching to and detaching from an IOMMU uses the same code sequence in > every driver, so factor it out into separate helpers. > > Signed-off-by: Thierry Reding <treding@nvidia.com> > --- > drivers/gpu/drm/tegra/dc.c | 42 ++++++------------------------------ > drivers/gpu/drm/tegra/drm.c | 42 ++++++++++++++++++++++++++++++++++++ > drivers/gpu/drm/tegra/drm.h | 4 ++++ > drivers/gpu/drm/tegra/gr2d.c | 32 +++++++-------------------- > drivers/gpu/drm/tegra/gr3d.c | 31 ++++++-------------------- > 5 files changed, 68 insertions(+), 83 deletions(-) > > diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c > index c843f11043db..3e7ec3937346 100644 > --- a/drivers/gpu/drm/tegra/dc.c > +++ b/drivers/gpu/drm/tegra/dc.c > @@ -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) > @@ -1916,15 +1906,7 @@ 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; > @@ -1932,9 +1914,7 @@ static int tegra_dc_init(struct host1x_client *client) > > 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); > @@ -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; > diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c > index 7afe2f635f74..bc1008305e1e 100644 > --- a/drivers/gpu/drm/tegra/drm.c > +++ b/drivers/gpu/drm/tegra/drm.c > @@ -1114,6 +1114,48 @@ 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 && (!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; Nit: Probably it doesn't make much sense to have devices unattached to BO's AS, what about to error out here or at least display a error/warning message? @@ -1796,7 +1796,12 @@ struct iommu_group *host1x_client_iommu_attach(struct host1x_client *client, if (tegra->domain) { group = iommu_group_get(client->dev); - if (group && (!shared || (shared && (group != tegra->group)))) { + if (!group) { + dev_err(client->dev, "Failed to get IOMMU group\n"); + return ERR_PTR(-EINVAL); + } + + if (!shared || group != tegra->group) { err = iommu_attach_group(tegra->domain, group); if (err < 0) { iommu_group_put(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; > diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h > index 4f41aaec8530..fe263cf58f34 100644 > --- a/drivers/gpu/drm/tegra/drm.h > +++ b/drivers/gpu/drm/tegra/drm.h > @@ -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); > diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c > index 0b42e99da8ad..2cd0f66c8aa9 100644 > --- a/drivers/gpu/drm/tegra/gr2d.c > +++ b/drivers/gpu/drm/tegra/gr2d.c > @@ -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; > > @@ -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; > @@ -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: > @@ -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; > } > > diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c > index e129f1afff33..98e3c67d0fb5 100644 > --- a/drivers/gpu/drm/tegra/gr3d.c > +++ b/drivers/gpu/drm/tegra/gr3d.c > @@ -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; > > @@ -56,19 +55,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); > @@ -80,10 +71,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: > @@ -95,7 +83,6 @@ 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; > > @@ -103,14 +90,10 @@ static int gr3d_exit(struct host1x_client *client) > 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; > } > >
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index c843f11043db..3e7ec3937346 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -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) @@ -1916,15 +1906,7 @@ 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; @@ -1932,9 +1914,7 @@ static int tegra_dc_init(struct host1x_client *client) 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); @@ -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; diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 7afe2f635f74..bc1008305e1e 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -1114,6 +1114,48 @@ 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 && (!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; diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 4f41aaec8530..fe263cf58f34 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -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); diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c index 0b42e99da8ad..2cd0f66c8aa9 100644 --- a/drivers/gpu/drm/tegra/gr2d.c +++ b/drivers/gpu/drm/tegra/gr2d.c @@ -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; @@ -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; @@ -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: @@ -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; } diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c index e129f1afff33..98e3c67d0fb5 100644 --- a/drivers/gpu/drm/tegra/gr3d.c +++ b/drivers/gpu/drm/tegra/gr3d.c @@ -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; @@ -56,19 +55,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); @@ -80,10 +71,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: @@ -95,7 +83,6 @@ 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; @@ -103,14 +90,10 @@ static int gr3d_exit(struct host1x_client *client) 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; }