From: Thierry Reding treding@nvidia.com
Some cleanups and minor improvements, nothing exciting here. However, these prepare the way for some larger rework that will convert explicit IOMMU API usage to the DMA API, which optionally can be backed by an IOMMU.
Thierry
Thierry Reding (14): gpu: host1x: Do not limit DMA segment size gpu: host1x: Remove gratuitous blank line gpu: host1x: Explicitly initialize host1x_info structures gpu: host1x: Request channels for clients, not devices drm/tegra: Inherit device DMA parameters from host1x drm/tegra: Use DRM_DEBUG_DRIVER for driver messages drm/tegra: vic: Skip stream ID programming without IOMMU drm/tegra: vic: Inherit DMA mask from host1x drm/tegra: vic: Use common IOMMU attach/detach code drm/tegra: Move IOMMU group into host1x client drm/tegra: gem: Rename paddr -> iova drm/tegra: gem: Use dma_get_sgtable() drm/tegra: gem: Always map SG tables for DMA-BUFs drm/tegra: gem: Use sg_alloc_table_from_pages()
drivers/gpu/drm/tegra/dc.c | 24 +++++++++++------ drivers/gpu/drm/tegra/dc.h | 2 -- drivers/gpu/drm/tegra/drm.c | 30 ++++++++++----------- drivers/gpu/drm/tegra/drm.h | 6 ++--- drivers/gpu/drm/tegra/fb.c | 4 +-- drivers/gpu/drm/tegra/gem.c | 37 +++++++++++--------------- drivers/gpu/drm/tegra/gem.h | 2 +- drivers/gpu/drm/tegra/gr2d.c | 12 ++++----- drivers/gpu/drm/tegra/gr3d.c | 12 ++++----- drivers/gpu/drm/tegra/hub.c | 2 +- drivers/gpu/drm/tegra/vic.c | 51 ++++++++++++++++++++---------------- drivers/gpu/host1x/bus.c | 2 +- drivers/gpu/host1x/channel.c | 13 ++++----- drivers/gpu/host1x/channel.h | 1 + drivers/gpu/host1x/dev.c | 12 +++++++++ drivers/gpu/host1x/intr.c | 1 - include/linux/host1x.h | 4 ++- 17 files changed, 114 insertions(+), 101 deletions(-)
From: Thierry Reding treding@nvidia.com
None of the host1x clients have any limitations on the DMA segment size, so don't pretend that they do.
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/host1x/bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c index 742aa9ff21b8..2c8559ff3481 100644 --- a/drivers/gpu/host1x/bus.c +++ b/drivers/gpu/host1x/bus.c @@ -445,7 +445,7 @@ static int host1x_device_add(struct host1x *host1x, of_dma_configure(&device->dev, host1x->dev->of_node, true);
device->dev.dma_parms = &device->dma_parms; - dma_set_max_seg_size(&device->dev, SZ_4M); + dma_set_max_seg_size(&device->dev, UINT_MAX);
err = host1x_device_parse_dt(device, driver); if (err < 0) {
From: Thierry Reding treding@nvidia.com
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/host1x/intr.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/drivers/gpu/host1x/intr.c b/drivers/gpu/host1x/intr.c index 26f3c741d085..9245add23b5d 100644 --- a/drivers/gpu/host1x/intr.c +++ b/drivers/gpu/host1x/intr.c @@ -105,7 +105,6 @@ static void action_submit_complete(struct host1x_waitlist *waiter) /* Add nr_completed to trace */ trace_host1x_channel_submit_complete(dev_name(channel->dev), waiter->count, waiter->thresh); - }
static void action_wakeup(struct host1x_waitlist *waiter)
From: Thierry Reding treding@nvidia.com
It's technically not required to explicitly initialize the fields that will be zero by default, but it's easier to read these structures if they are all initialized uniformly.
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/host1x/dev.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 5a3f797240d4..e8ab4d0c5091 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -77,6 +77,9 @@ static const struct host1x_info host1x01_info = { .init = host1x01_init, .sync_offset = 0x3000, .dma_mask = DMA_BIT_MASK(32), + .has_hypervisor = false, + .num_sid_entries = 0, + .sid_table = NULL, };
static const struct host1x_info host1x02_info = { @@ -87,6 +90,9 @@ static const struct host1x_info host1x02_info = { .init = host1x02_init, .sync_offset = 0x3000, .dma_mask = DMA_BIT_MASK(32), + .has_hypervisor = false, + .num_sid_entries = 0, + .sid_table = NULL, };
static const struct host1x_info host1x04_info = { @@ -97,6 +103,9 @@ static const struct host1x_info host1x04_info = { .init = host1x04_init, .sync_offset = 0x2100, .dma_mask = DMA_BIT_MASK(34), + .has_hypervisor = false, + .num_sid_entries = 0, + .sid_table = NULL, };
static const struct host1x_info host1x05_info = { @@ -107,6 +116,9 @@ static const struct host1x_info host1x05_info = { .init = host1x05_init, .sync_offset = 0x2100, .dma_mask = DMA_BIT_MASK(34), + .has_hypervisor = false, + .num_sid_entries = 0, + .sid_table = NULL, };
static const struct host1x_sid_entry tegra186_sid_table[] = {
From: Thierry Reding treding@nvidia.com
A struct device doesn't carry much information that a channel might be interested in, but the client very much does. Request channels for the clients rather than their parent devices and store a pointer to them in order to have that information available when needed.
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/tegra/gr2d.c | 2 +- drivers/gpu/drm/tegra/gr3d.c | 2 +- drivers/gpu/drm/tegra/vic.c | 2 +- drivers/gpu/host1x/channel.c | 13 +++++++------ drivers/gpu/host1x/channel.h | 1 + include/linux/host1x.h | 2 +- 6 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c index 641299cc85b8..3cbb4a029c41 100644 --- a/drivers/gpu/drm/tegra/gr2d.c +++ b/drivers/gpu/drm/tegra/gr2d.c @@ -40,7 +40,7 @@ static int gr2d_init(struct host1x_client *client) struct gr2d *gr2d = to_gr2d(drm); int err;
- gr2d->channel = host1x_channel_request(client->dev); + gr2d->channel = host1x_channel_request(client); if (!gr2d->channel) return -ENOMEM;
diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c index 8b9a35b1cbb3..87a386134cc4 100644 --- a/drivers/gpu/drm/tegra/gr3d.c +++ b/drivers/gpu/drm/tegra/gr3d.c @@ -49,7 +49,7 @@ static int gr3d_init(struct host1x_client *client) struct gr3d *gr3d = to_gr3d(drm); int err;
- gr3d->channel = host1x_channel_request(client->dev); + gr3d->channel = host1x_channel_request(client); if (!gr3d->channel) return -ENOMEM;
diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c index cd0399fd8c63..c97a61c877af 100644 --- a/drivers/gpu/drm/tegra/vic.c +++ b/drivers/gpu/drm/tegra/vic.c @@ -198,7 +198,7 @@ static int vic_init(struct host1x_client *client) vic->domain = tegra->domain; }
- vic->channel = host1x_channel_request(client->dev); + vic->channel = host1x_channel_request(client); if (!vic->channel) { err = -ENOMEM; goto detach; diff --git a/drivers/gpu/host1x/channel.c b/drivers/gpu/host1x/channel.c index 1436295aa450..4cd212bb570d 100644 --- a/drivers/gpu/host1x/channel.c +++ b/drivers/gpu/host1x/channel.c @@ -115,14 +115,14 @@ static struct host1x_channel *acquire_unused_channel(struct host1x *host)
/** * host1x_channel_request() - Allocate a channel - * @device: Host1x unit this channel will be used to send commands to + * @client: Host1x client this channel will be used to send commands to * - * Allocates a new host1x channel for @device. May return NULL if CDMA + * Allocates a new host1x channel for @client. May return NULL if CDMA * initialization fails. */ -struct host1x_channel *host1x_channel_request(struct device *dev) +struct host1x_channel *host1x_channel_request(struct host1x_client *client) { - struct host1x *host = dev_get_drvdata(dev->parent); + struct host1x *host = dev_get_drvdata(client->dev->parent); struct host1x_channel_list *chlist = &host->channel_list; struct host1x_channel *channel; int err; @@ -133,7 +133,8 @@ struct host1x_channel *host1x_channel_request(struct device *dev)
kref_init(&channel->refcount); mutex_init(&channel->submitlock); - channel->dev = dev; + channel->client = client; + channel->dev = client->dev;
err = host1x_hw_channel_init(host, channel, channel->id); if (err < 0) @@ -148,7 +149,7 @@ struct host1x_channel *host1x_channel_request(struct device *dev) fail: clear_bit(channel->id, chlist->allocated_channels);
- dev_err(dev, "failed to initialize channel\n"); + dev_err(client->dev, "failed to initialize channel\n");
return NULL; } diff --git a/drivers/gpu/host1x/channel.h b/drivers/gpu/host1x/channel.h index 4fd694834f74..39044ff6c3aa 100644 --- a/drivers/gpu/host1x/channel.h +++ b/drivers/gpu/host1x/channel.h @@ -26,6 +26,7 @@ struct host1x_channel { unsigned int id; struct mutex submitlock; void __iomem *regs; + struct host1x_client *client; struct device *dev; struct host1x_cdma cdma; }; diff --git a/include/linux/host1x.h b/include/linux/host1x.h index e6eea45e1154..4396cd566a33 100644 --- a/include/linux/host1x.h +++ b/include/linux/host1x.h @@ -158,7 +158,7 @@ u32 host1x_syncpt_base_id(struct host1x_syncpt_base *base); struct host1x_channel; struct host1x_job;
-struct host1x_channel *host1x_channel_request(struct device *dev); +struct host1x_channel *host1x_channel_request(struct host1x_client *client); struct host1x_channel *host1x_channel_get(struct host1x_channel *channel); void host1x_channel_put(struct host1x_channel *channel); int host1x_job_submit(struct host1x_job *job);
From: Thierry Reding treding@nvidia.com
The display controllers and VIC don't have any limitations on the DMA segment size. Inherit the DMA parameters from the parent device, which also doesn't have any such limitations.
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/tegra/dc.c | 9 +++++++++ drivers/gpu/drm/tegra/vic.c | 9 +++++++++ 2 files changed, 18 insertions(+)
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index fbf57bc3cdab..f7f7984bb749 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -2074,6 +2074,12 @@ static int tegra_dc_init(struct host1x_client *client) goto cleanup; }
+ /* + * Inherit the DMA parameters (such as maximum segment size) from the + * parent device. + */ + client->dev->dma_parms = client->parent->dma_parms; + return 0;
cleanup: @@ -2097,6 +2103,9 @@ static int tegra_dc_exit(struct host1x_client *client) if (!tegra_dc_has_window_groups(dc)) return 0;
+ /* avoid a dangling pointer just in case this disappears */ + client->dev->dma_parms = NULL; + devm_free_irq(dc->dev, dc->irq, dc);
err = tegra_dc_rgb_exit(dc); diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c index c97a61c877af..8d98b0cfc47b 100644 --- a/drivers/gpu/drm/tegra/vic.c +++ b/drivers/gpu/drm/tegra/vic.c @@ -214,6 +214,12 @@ static int vic_init(struct host1x_client *client) if (err < 0) goto free_syncpt;
+ /* + * Inherit the DMA parameters (such as maximum segment size) from the + * parent device. + */ + client->dev->dma_parms = client->parent->dma_parms; + return 0;
free_syncpt: @@ -236,6 +242,9 @@ static int vic_exit(struct host1x_client *client) struct vic *vic = to_vic(drm); int err;
+ /* avoid a dangling pointer just in case this disappears */ + client->dev->dma_parms = NULL; + err = tegra_drm_unregister_client(tegra, drm); if (err < 0) return err;
From: Thierry Reding treding@nvidia.com
The driver-specific messages should use the DRM_UT_DRIVER category so that they can be properly filtered.
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/tegra/drm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index bc7cc32140f8..498d22a65616 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -163,10 +163,10 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags) drm_mm_init(&tegra->mm, gem_start, gem_end - gem_start + 1); mutex_init(&tegra->mm_lock);
- DRM_DEBUG("IOMMU apertures:\n"); - DRM_DEBUG(" GEM: %#llx-%#llx\n", gem_start, gem_end); - DRM_DEBUG(" Carveout: %#llx-%#llx\n", carveout_start, - carveout_end); + DRM_DEBUG_DRIVER("IOMMU apertures:\n"); + DRM_DEBUG_DRIVER(" GEM: %#llx-%#llx\n", gem_start, gem_end); + DRM_DEBUG_DRIVER(" Carveout: %#llx-%#llx\n", carveout_start, + carveout_end); }
if (tegra->hub) {
From: Thierry Reding treding@nvidia.com
If VIC is not behind an IOMMU, don't touch any of the registers related to stream ID programming.
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/tegra/vic.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c index 8d98b0cfc47b..748798f2cdc8 100644 --- a/drivers/gpu/drm/tegra/vic.c +++ b/drivers/gpu/drm/tegra/vic.c @@ -97,6 +97,9 @@ static int vic_runtime_suspend(struct device *dev)
static int vic_boot(struct vic *vic) { +#ifdef CONFIG_IOMMU_API + struct iommu_fwspec *spec = dev_iommu_fwspec_get(vic->dev); +#endif u32 fce_ucode_size, fce_bin_data_offset; void *hdr; int err = 0; @@ -105,15 +108,14 @@ static int vic_boot(struct vic *vic) return 0;
#ifdef CONFIG_IOMMU_API - if (vic->config->supports_sid) { - struct iommu_fwspec *spec = dev_iommu_fwspec_get(vic->dev); + if (vic->config->supports_sid && spec) { u32 value;
value = TRANSCFG_ATT(1, TRANSCFG_SID_FALCON) | TRANSCFG_ATT(0, TRANSCFG_SID_HW); vic_writel(vic, value, VIC_TFBIF_TRANSCFG);
- if (spec && spec->num_ids > 0) { + if (spec->num_ids > 0) { value = spec->ids[0] & 0xffff;
vic_writel(vic, value, VIC_THI_STREAMID0);
From: Thierry Reding treding@nvidia.com
VIC, just like all other host1x clients, has the same addressing range as its parent host1x device. Inherit the DMA mask to reflect that.
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/tegra/vic.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c index 748798f2cdc8..d60e479cde92 100644 --- a/drivers/gpu/drm/tegra/vic.c +++ b/drivers/gpu/drm/tegra/vic.c @@ -385,6 +385,13 @@ static int vic_probe(struct platform_device *pdev) struct vic *vic; int err;
+ /* inherit DMA mask from host1x parent */ + err = dma_coerce_mask_and_coherent(dev, *dev->parent->dma_mask); + if (err < 0) { + dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err); + return err; + } + vic = devm_kzalloc(dev, sizeof(*vic), GFP_KERNEL); if (!vic) return -ENOMEM;
From: Thierry Reding treding@nvidia.com
Reuse common code to attach to or detach from an IOMMU domain.
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/tegra/vic.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c index d60e479cde92..e4b17c7ce708 100644 --- a/drivers/gpu/drm/tegra/vic.c +++ b/drivers/gpu/drm/tegra/vic.c @@ -34,7 +34,7 @@ struct vic { void __iomem *regs; struct tegra_drm_client client; struct host1x_channel *channel; - struct iommu_domain *domain; + struct iommu_group *group; struct device *dev; struct clk *clk; struct reset_control *rst; @@ -183,21 +183,16 @@ 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 (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); - return err; - } - - vic->domain = tegra->domain; + vic->group = host1x_client_iommu_attach(client, false); + if (IS_ERR(vic->group)) { + err = PTR_ERR(vic->group); + dev_err(vic->dev, "failed to attach to domain: %d\n", err); + return err; }
vic->channel = host1x_channel_request(client); @@ -229,8 +224,7 @@ static int vic_init(struct host1x_client *client) free_channel: host1x_channel_put(vic->channel); detach: - if (group && tegra->domain) - iommu_detach_group(tegra->domain, group); + host1x_client_iommu_detach(client, vic->group);
return err; } @@ -238,7 +232,6 @@ 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); @@ -253,11 +246,7 @@ static int vic_exit(struct host1x_client *client)
host1x_syncpt_free(client->syncpts[0]); host1x_channel_put(vic->channel); - - if (vic->domain) { - iommu_detach_group(vic->domain, group); - vic->domain = NULL; - } + host1x_client_iommu_detach(client, vic->group);
return 0; }
From: Thierry Reding treding@nvidia.com
Handling of the IOMMU group attachment is common to all clients, so move the group into the client to simplify code.
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/tegra/dc.c | 9 ++++----- drivers/gpu/drm/tegra/dc.h | 2 -- drivers/gpu/drm/tegra/drm.c | 22 +++++++++++----------- drivers/gpu/drm/tegra/drm.h | 6 ++---- drivers/gpu/drm/tegra/gr2d.c | 10 ++++------ drivers/gpu/drm/tegra/gr3d.c | 10 ++++------ drivers/gpu/drm/tegra/vic.c | 10 ++++------ include/linux/host1x.h | 2 ++ 8 files changed, 31 insertions(+), 40 deletions(-)
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index f7f7984bb749..3ac535bd99ca 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -2014,9 +2014,8 @@ static int tegra_dc_init(struct host1x_client *client) if (!dc->syncpt) dev_warn(dc->dev, "failed to allocate syncpoint\n");
- dc->group = host1x_client_iommu_attach(client, true); - if (IS_ERR(dc->group)) { - err = PTR_ERR(dc->group); + err = host1x_client_iommu_attach(client, true); + if (err < 0) { dev_err(client->dev, "failed to attach to domain: %d\n", err); return err; } @@ -2089,7 +2088,7 @@ static int tegra_dc_init(struct host1x_client *client) if (!IS_ERR(primary)) drm_plane_cleanup(primary);
- host1x_client_iommu_detach(client, dc->group); + host1x_client_iommu_detach(client); host1x_syncpt_free(dc->syncpt);
return err; @@ -2114,7 +2113,7 @@ static int tegra_dc_exit(struct host1x_client *client) return err; }
- host1x_client_iommu_detach(client, dc->group); + host1x_client_iommu_detach(client); host1x_syncpt_free(dc->syncpt);
return 0; diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index 0c4d17851f47..3d8ddccd758f 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h @@ -90,8 +90,6 @@ struct tegra_dc { struct drm_info_list *debugfs_files;
const struct tegra_dc_soc_info *soc; - - struct iommu_group *group; };
static inline struct tegra_dc * diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 498d22a65616..b74362cb63eb 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -1068,8 +1068,7 @@ int tegra_drm_unregister_client(struct tegra_drm *tegra, return 0; }
-struct iommu_group *host1x_client_iommu_attach(struct host1x_client *client, - bool shared) +int 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; @@ -1080,7 +1079,7 @@ struct iommu_group *host1x_client_iommu_attach(struct host1x_client *client, group = iommu_group_get(client->dev); if (!group) { dev_err(client->dev, "failed to get IOMMU group\n"); - return ERR_PTR(-ENODEV); + return -ENODEV; }
if (!shared || (shared && (group != tegra->group))) { @@ -1095,7 +1094,7 @@ struct iommu_group *host1x_client_iommu_attach(struct host1x_client *client, err = iommu_attach_group(tegra->domain, group); if (err < 0) { iommu_group_put(group); - return ERR_PTR(err); + return err; }
if (shared && !tegra->group) @@ -1103,22 +1102,23 @@ struct iommu_group *host1x_client_iommu_attach(struct host1x_client *client, } }
- return group; + client->group = group; + + return 0; }
-void host1x_client_iommu_detach(struct host1x_client *client, - struct iommu_group *group) +void host1x_client_iommu_detach(struct host1x_client *client) { 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); + if (client->group) { + if (client->group == tegra->group) { + iommu_detach_group(tegra->domain, client->group); tegra->group = NULL; }
- iommu_group_put(group); + iommu_group_put(client->group); } }
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 29911eff9ceb..6a06d636e930 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -100,10 +100,8 @@ 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 host1x_client_iommu_attach(struct host1x_client *client, bool shared); +void host1x_client_iommu_detach(struct host1x_client *client);
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 3cbb4a029c41..5d5af9a05c18 100644 --- a/drivers/gpu/drm/tegra/gr2d.c +++ b/drivers/gpu/drm/tegra/gr2d.c @@ -17,7 +17,6 @@ struct gr2d_soc { };
struct gr2d { - struct iommu_group *group; struct tegra_drm_client client; struct host1x_channel *channel; struct clk *clk; @@ -51,9 +50,8 @@ static int gr2d_init(struct host1x_client *client) goto put; }
- gr2d->group = host1x_client_iommu_attach(client, false); - if (IS_ERR(gr2d->group)) { - err = PTR_ERR(gr2d->group); + err = host1x_client_iommu_attach(client, false); + if (err < 0) { dev_err(client->dev, "failed to attach to domain: %d\n", err); goto free; } @@ -67,7 +65,7 @@ static int gr2d_init(struct host1x_client *client) return 0;
detach: - host1x_client_iommu_detach(client, gr2d->group); + host1x_client_iommu_detach(client); free: host1x_syncpt_free(client->syncpts[0]); put: @@ -87,7 +85,7 @@ static int gr2d_exit(struct host1x_client *client) if (err < 0) return err;
- host1x_client_iommu_detach(client, gr2d->group); + host1x_client_iommu_detach(client); host1x_syncpt_free(client->syncpts[0]); host1x_channel_put(gr2d->channel);
diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c index 87a386134cc4..c249a6bd8d51 100644 --- a/drivers/gpu/drm/tegra/gr3d.c +++ b/drivers/gpu/drm/tegra/gr3d.c @@ -23,7 +23,6 @@ struct gr3d_soc { };
struct gr3d { - struct iommu_group *group; struct tegra_drm_client client; struct host1x_channel *channel; struct clk *clk_secondary; @@ -60,9 +59,8 @@ static int gr3d_init(struct host1x_client *client) goto put; }
- gr3d->group = host1x_client_iommu_attach(client, false); - if (IS_ERR(gr3d->group)) { - err = PTR_ERR(gr3d->group); + err = host1x_client_iommu_attach(client, false); + if (err < 0) { dev_err(client->dev, "failed to attach to domain: %d\n", err); goto free; } @@ -76,7 +74,7 @@ static int gr3d_init(struct host1x_client *client) return 0;
detach: - host1x_client_iommu_detach(client, gr3d->group); + host1x_client_iommu_detach(client); free: host1x_syncpt_free(client->syncpts[0]); put: @@ -95,7 +93,7 @@ static int gr3d_exit(struct host1x_client *client) if (err < 0) return err;
- host1x_client_iommu_detach(client, gr3d->group); + host1x_client_iommu_detach(client); host1x_syncpt_free(client->syncpts[0]); host1x_channel_put(gr3d->channel);
diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c index e4b17c7ce708..d34b1ada422c 100644 --- a/drivers/gpu/drm/tegra/vic.c +++ b/drivers/gpu/drm/tegra/vic.c @@ -34,7 +34,6 @@ struct vic { void __iomem *regs; struct tegra_drm_client client; struct host1x_channel *channel; - struct iommu_group *group; struct device *dev; struct clk *clk; struct reset_control *rst; @@ -188,9 +187,8 @@ static int vic_init(struct host1x_client *client) struct vic *vic = to_vic(drm); int err;
- vic->group = host1x_client_iommu_attach(client, false); - if (IS_ERR(vic->group)) { - err = PTR_ERR(vic->group); + err = host1x_client_iommu_attach(client, false); + if (err < 0) { dev_err(vic->dev, "failed to attach to domain: %d\n", err); return err; } @@ -224,7 +222,7 @@ static int vic_init(struct host1x_client *client) free_channel: host1x_channel_put(vic->channel); detach: - host1x_client_iommu_detach(client, vic->group); + host1x_client_iommu_detach(client);
return err; } @@ -246,7 +244,7 @@ static int vic_exit(struct host1x_client *client)
host1x_syncpt_free(client->syncpts[0]); host1x_channel_put(vic->channel); - host1x_client_iommu_detach(client, vic->group); + host1x_client_iommu_detach(client);
return 0; } diff --git a/include/linux/host1x.h b/include/linux/host1x.h index 4396cd566a33..8b2d1a4bf7b1 100644 --- a/include/linux/host1x.h +++ b/include/linux/host1x.h @@ -18,6 +18,7 @@ enum host1x_class { };
struct host1x_client; +struct iommu_group;
/** * struct host1x_client_ops - host1x client operations @@ -44,6 +45,7 @@ struct host1x_client { struct list_head list; struct device *parent; struct device *dev; + struct iommu_group *group;
const struct host1x_client_ops *ops;
14.10.2019 15:50, Thierry Reding пишет:
From: Thierry Reding treding@nvidia.com
Handling of the IOMMU group attachment is common to all clients, so move the group into the client to simplify code.
Signed-off-by: Thierry Reding treding@nvidia.com
drivers/gpu/drm/tegra/dc.c | 9 ++++----- drivers/gpu/drm/tegra/dc.h | 2 -- drivers/gpu/drm/tegra/drm.c | 22 +++++++++++----------- drivers/gpu/drm/tegra/drm.h | 6 ++---- drivers/gpu/drm/tegra/gr2d.c | 10 ++++------ drivers/gpu/drm/tegra/gr3d.c | 10 ++++------ drivers/gpu/drm/tegra/vic.c | 10 ++++------ include/linux/host1x.h | 2 ++ 8 files changed, 31 insertions(+), 40 deletions(-)
Hello Thierry,
Is there any chance that you could pick up these patches [0] and rebase yours series on top of them?
[0] https://patchwork.ozlabs.org/project/linux-tegra/list/?series=115608
16.10.2019 18:33, Dmitry Osipenko пишет:
14.10.2019 15:50, Thierry Reding пишет:
From: Thierry Reding treding@nvidia.com
Handling of the IOMMU group attachment is common to all clients, so move the group into the client to simplify code.
Signed-off-by: Thierry Reding treding@nvidia.com
drivers/gpu/drm/tegra/dc.c | 9 ++++----- drivers/gpu/drm/tegra/dc.h | 2 -- drivers/gpu/drm/tegra/drm.c | 22 +++++++++++----------- drivers/gpu/drm/tegra/drm.h | 6 ++---- drivers/gpu/drm/tegra/gr2d.c | 10 ++++------ drivers/gpu/drm/tegra/gr3d.c | 10 ++++------ drivers/gpu/drm/tegra/vic.c | 10 ++++------ include/linux/host1x.h | 2 ++ 8 files changed, 31 insertions(+), 40 deletions(-)
Hello Thierry,
Is there any chance that you could pick up these patches [0] and rebase yours series on top of them?
[0] https://patchwork.ozlabs.org/project/linux-tegra/list/?series=115608
I want to clarify that the reason of my request is that "Fix 2d and 3d clients detaching from IOMMU domain" patch won't be backportable if I'll rebase my patches on top this series and it looks to me that it won't be the least to fix the bug.
From: Thierry Reding treding@nvidia.com
The address can refer to either physical memory or IO virtual memory. If referring to IO virtual memory, there will always be an associated physical memory address. Rename this variable to "iova" to clarify in all cases that this is the IO virtual memory, which in the absence of an IOMMU is identical to the physical address.
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/tegra/dc.c | 6 +++--- drivers/gpu/drm/tegra/fb.c | 4 ++-- drivers/gpu/drm/tegra/gem.c | 18 +++++++++--------- drivers/gpu/drm/tegra/gem.h | 2 +- drivers/gpu/drm/tegra/hub.c | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 3ac535bd99ca..54966f538141 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -717,7 +717,7 @@ static void tegra_plane_atomic_update(struct drm_plane *plane, for (i = 0; i < fb->format->num_planes; i++) { struct tegra_bo *bo = tegra_fb_get_plane(fb, i);
- window.base[i] = bo->paddr + fb->offsets[i]; + window.base[i] = bo->iova + fb->offsets[i];
/* * Tegra uses a shared stride for UV planes. Framebuffers are @@ -869,11 +869,11 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane, return; }
- value |= (bo->paddr >> 10) & 0x3fffff; + value |= (bo->iova >> 10) & 0x3fffff; tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR);
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - value = (bo->paddr >> 32) & 0x3; + value = (bo->iova >> 32) & 0x3; tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR_HI); #endif
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index e34325c83d28..7cea89f29a5c 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -269,10 +269,10 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper, } }
- drm->mode_config.fb_base = (resource_size_t)bo->paddr; + drm->mode_config.fb_base = (resource_size_t)bo->iova; info->screen_base = (void __iomem *)bo->vaddr + offset; info->screen_size = size; - info->fix.smem_start = (unsigned long)(bo->paddr + offset); + info->fix.smem_start = (unsigned long)(bo->iova + offset); info->fix.smem_len = size;
return 0; diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index fb7667c8dd4c..7412e23500d1 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -33,7 +33,7 @@ static dma_addr_t tegra_bo_pin(struct host1x_bo *bo, struct sg_table **sgt)
*sgt = obj->sgt;
- return obj->paddr; + return obj->iova; }
static void tegra_bo_unpin(struct host1x_bo *bo, struct sg_table *sgt) @@ -133,9 +133,9 @@ static int tegra_bo_iommu_map(struct tegra_drm *tegra, struct tegra_bo *bo) goto unlock; }
- bo->paddr = bo->mm->start; + bo->iova = bo->mm->start;
- bo->size = iommu_map_sg(tegra->domain, bo->paddr, bo->sgt->sgl, + bo->size = iommu_map_sg(tegra->domain, bo->iova, bo->sgt->sgl, bo->sgt->nents, prot); if (!bo->size) { dev_err(tegra->drm->dev, "failed to map buffer\n"); @@ -161,7 +161,7 @@ static int tegra_bo_iommu_unmap(struct tegra_drm *tegra, struct tegra_bo *bo) return 0;
mutex_lock(&tegra->mm_lock); - iommu_unmap(tegra->domain, bo->paddr, bo->size); + iommu_unmap(tegra->domain, bo->iova, bo->size); drm_mm_remove_node(bo->mm); mutex_unlock(&tegra->mm_lock);
@@ -209,7 +209,7 @@ static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo) sg_free_table(bo->sgt); kfree(bo->sgt); } else if (bo->vaddr) { - dma_free_wc(drm->dev, bo->gem.size, bo->vaddr, bo->paddr); + dma_free_wc(drm->dev, bo->gem.size, bo->vaddr, bo->iova); } }
@@ -264,7 +264,7 @@ static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo) } else { size_t size = bo->gem.size;
- bo->vaddr = dma_alloc_wc(drm->dev, size, &bo->paddr, + bo->vaddr = dma_alloc_wc(drm->dev, size, &bo->iova, GFP_KERNEL | __GFP_NOWARN); if (!bo->vaddr) { dev_err(drm->dev, @@ -365,7 +365,7 @@ static struct tegra_bo *tegra_bo_import(struct drm_device *drm, goto detach; }
- bo->paddr = sg_dma_address(bo->sgt->sgl); + bo->iova = sg_dma_address(bo->sgt->sgl); }
bo->gem.import_attach = attach; @@ -461,7 +461,7 @@ int __tegra_gem_mmap(struct drm_gem_object *gem, struct vm_area_struct *vma) vma->vm_flags &= ~VM_PFNMAP; vma->vm_pgoff = 0;
- err = dma_mmap_wc(gem->dev->dev, vma, bo->vaddr, bo->paddr, + err = dma_mmap_wc(gem->dev->dev, vma, bo->vaddr, bo->iova, gem->size); if (err < 0) { drm_gem_vm_close(vma); @@ -523,7 +523,7 @@ tegra_gem_prime_map_dma_buf(struct dma_buf_attachment *attach, if (sg_alloc_table(sgt, 1, GFP_KERNEL)) goto free;
- sg_dma_address(sgt->sgl) = bo->paddr; + sg_dma_address(sgt->sgl) = bo->iova; sg_dma_len(sgt->sgl) = gem->size; }
diff --git a/drivers/gpu/drm/tegra/gem.h b/drivers/gpu/drm/tegra/gem.h index 83ffb1e14ca3..fafb5724499b 100644 --- a/drivers/gpu/drm/tegra/gem.h +++ b/drivers/gpu/drm/tegra/gem.h @@ -31,7 +31,7 @@ struct tegra_bo { struct host1x_bo base; unsigned long flags; struct sg_table *sgt; - dma_addr_t paddr; + dma_addr_t iova; void *vaddr;
struct drm_mm_node *mm; diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c index 839b49c40e51..104115e42190 100644 --- a/drivers/gpu/drm/tegra/hub.c +++ b/drivers/gpu/drm/tegra/hub.c @@ -457,7 +457,7 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane, tegra_plane_writel(p, 0, DC_WINBUF_CDE_CONTROL);
bo = tegra_fb_get_plane(fb, 0); - base = bo->paddr; + base = bo->iova;
tegra_plane_writel(p, state->format, DC_WIN_COLOR_DEPTH); tegra_plane_writel(p, 0, DC_WIN_PRECOMP_WGRP_PARAMS);
From: Thierry Reding treding@nvidia.com
Rather than manually creating an SG table in an incorrect way, let the standard dma_get_sgtable() function do it.
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/tegra/gem.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index 7412e23500d1..3345cce14662 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -520,11 +520,9 @@ tegra_gem_prime_map_dma_buf(struct dma_buf_attachment *attach, if (dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir) == 0) goto free; } else { - if (sg_alloc_table(sgt, 1, GFP_KERNEL)) + if (dma_get_sgtable(attach->dev, sgt, bo->vaddr, bo->iova, + gem->size) < 0) goto free; - - sg_dma_address(sgt->sgl) = bo->iova; - sg_dma_len(sgt->sgl) = gem->size; }
return sgt;
From: Thierry Reding treding@nvidia.com
When an importer wants to map a DMA-BUF, make sure to always actually map it, irrespective of whether the buffer is contiguous or not.
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/tegra/gem.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index 3345cce14662..00701cadaceb 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -516,15 +516,15 @@ tegra_gem_prime_map_dma_buf(struct dma_buf_attachment *attach,
for_each_sg(sgt->sgl, sg, bo->num_pages, i) sg_set_page(sg, bo->pages[i], PAGE_SIZE, 0); - - if (dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir) == 0) - goto free; } else { if (dma_get_sgtable(attach->dev, sgt, bo->vaddr, bo->iova, gem->size) < 0) goto free; }
+ if (dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir) == 0) + goto free; + return sgt;
free:
From: Thierry Reding treding@nvidia.com
Instead of manually creating the SG table for a discontiguous buffer, use the existing sg_alloc_table_from_pages(). Note that this is not safe to be used with the ARM DMA/IOMMU integration code because that will not ensure that the whole buffer is mapped contiguously. Depending on the size of the individual entries the mapping may end up containing holes to ensure alignment.
However, we only ever use these buffers with explicit IOMMU API usage and know how to avoid these holes.
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/tegra/gem.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index 00701cadaceb..d2f88cc3134f 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -508,14 +508,9 @@ tegra_gem_prime_map_dma_buf(struct dma_buf_attachment *attach, return NULL;
if (bo->pages) { - struct scatterlist *sg; - unsigned int i; - - if (sg_alloc_table(sgt, bo->num_pages, GFP_KERNEL)) + if (sg_alloc_table_from_pages(sgt, bo->pages, bo->num_pages, + 0, gem->size, GFP_KERNEL) < 0) goto free; - - for_each_sg(sgt->sgl, sg, bo->num_pages, i) - sg_set_page(sg, bo->pages[i], PAGE_SIZE, 0); } else { if (dma_get_sgtable(attach->dev, sgt, bo->vaddr, bo->iova, gem->size) < 0)
dri-devel@lists.freedesktop.org