From: Eric Auger <eric.auger@redhat.com> To: eric.auger.pro@gmail.com, eric.auger@redhat.com, iommu@lists.linux-foundation.org, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu, joro@8bytes.org, alex.williamson@redhat.com, jacob.jun.pan@linux.intel.com, yi.l.liu@linux.intel.com, jean-philippe.brucker@arm.com, will.deacon@arm.com, robin.murphy@arm.com Cc: kevin.tian@intel.com, ashok.raj@intel.com, marc.zyngier@arm.com, christoffer.dall@arm.com, peter.maydell@linaro.org, vincent.stehle@arm.com Subject: [PATCH v5 11/22] iommu/arm-smmu-v3: Maintain a SID->device structure Date: Fri, 15 Mar 2019 17:08:55 +0100 [thread overview] Message-ID: <20190315160906.12900-12-eric.auger@redhat.com> (raw) In-Reply-To: <20190315160906.12900-1-eric.auger@redhat.com> From: Jean-Philippe Brucker <jean-philippe.brucker@arm.com> When handling faults from the event or PRI queue, we need to find the struct device associated to a SID. Add a rb_tree to keep track of SIDs. Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com> --- drivers/iommu/arm-smmu-v3.c | 136 ++++++++++++++++++++++++++++++++++-- 1 file changed, 132 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index ff998c967a0a..21d027695181 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -588,6 +588,16 @@ struct arm_smmu_device { /* IOMMU core code handle */ struct iommu_device iommu; + + struct rb_root streams; + struct mutex streams_mutex; + +}; + +struct arm_smmu_stream { + u32 id; + struct arm_smmu_master_data *master; + struct rb_node node; }; /* SMMU private data for each master */ @@ -597,6 +607,7 @@ struct arm_smmu_master_data { struct arm_smmu_domain *domain; struct list_head list; /* domain->devices */ + struct arm_smmu_stream *streams; struct device *dev; }; @@ -1243,6 +1254,32 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid) return 0; } +__maybe_unused +static struct arm_smmu_master_data * +arm_smmu_find_master(struct arm_smmu_device *smmu, u32 sid) +{ + struct rb_node *node; + struct arm_smmu_stream *stream; + struct arm_smmu_master_data *master = NULL; + + mutex_lock(&smmu->streams_mutex); + node = smmu->streams.rb_node; + while (node) { + stream = rb_entry(node, struct arm_smmu_stream, node); + if (stream->id < sid) { + node = node->rb_right; + } else if (stream->id > sid) { + node = node->rb_left; + } else { + master = stream->master; + break; + } + } + mutex_unlock(&smmu->streams_mutex); + + return master; +} + /* IRQ and event handlers */ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev) { @@ -1881,6 +1918,71 @@ static bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid) return sid < limit; } +static int arm_smmu_insert_master(struct arm_smmu_device *smmu, + struct arm_smmu_master_data *master) +{ + int i; + int ret = 0; + struct arm_smmu_stream *new_stream, *cur_stream; + struct rb_node **new_node, *parent_node = NULL; + struct iommu_fwspec *fwspec = master->dev->iommu_fwspec; + + master->streams = kcalloc(fwspec->num_ids, + sizeof(struct arm_smmu_stream), GFP_KERNEL); + if (!master->streams) + return -ENOMEM; + + mutex_lock(&smmu->streams_mutex); + for (i = 0; i < fwspec->num_ids && !ret; i++) { + new_stream = &master->streams[i]; + new_stream->id = fwspec->ids[i]; + new_stream->master = master; + + new_node = &(smmu->streams.rb_node); + while (*new_node) { + cur_stream = rb_entry(*new_node, struct arm_smmu_stream, + node); + parent_node = *new_node; + if (cur_stream->id > new_stream->id) { + new_node = &((*new_node)->rb_left); + } else if (cur_stream->id < new_stream->id) { + new_node = &((*new_node)->rb_right); + } else { + dev_warn(master->dev, + "stream %u already in tree\n", + cur_stream->id); + ret = -EINVAL; + break; + } + } + + if (!ret) { + rb_link_node(&new_stream->node, parent_node, new_node); + rb_insert_color(&new_stream->node, &smmu->streams); + } + } + mutex_unlock(&smmu->streams_mutex); + + return ret; +} + +static void arm_smmu_remove_master(struct arm_smmu_device *smmu, + struct arm_smmu_master_data *master) +{ + int i; + struct iommu_fwspec *fwspec = master->dev->iommu_fwspec; + + if (!master->streams) + return; + + mutex_lock(&smmu->streams_mutex); + for (i = 0; i < fwspec->num_ids; i++) + rb_erase(&master->streams[i].node, &smmu->streams); + mutex_unlock(&smmu->streams_mutex); + + kfree(master->streams); +} + static struct iommu_ops arm_smmu_ops; static int arm_smmu_add_device(struct device *dev) @@ -1929,13 +2031,35 @@ static int arm_smmu_add_device(struct device *dev) } } + ret = iommu_device_link(&smmu->iommu, dev); + if (ret) + goto err_free_master; + + ret = arm_smmu_insert_master(smmu, master); + if (ret) + goto err_unlink; + group = iommu_group_get_for_dev(dev); - if (!IS_ERR(group)) { - iommu_group_put(group); - iommu_device_link(&smmu->iommu, dev); + if (IS_ERR(group)) { + ret = PTR_ERR(group); + goto err_remove_master; } - return PTR_ERR_OR_ZERO(group); + iommu_group_put(group); + + return 0; + +err_remove_master: + arm_smmu_remove_master(smmu, master); + +err_unlink: + iommu_device_unlink(&smmu->iommu, dev); + +err_free_master: + kfree(master); + fwspec->iommu_priv = NULL; + + return ret; } static void arm_smmu_remove_device(struct device *dev) @@ -1952,6 +2076,7 @@ static void arm_smmu_remove_device(struct device *dev) if (master && master->ste.assigned) arm_smmu_detach_dev(dev); iommu_group_remove_device(dev); + arm_smmu_remove_master(smmu, master); iommu_device_unlink(&smmu->iommu, dev); kfree(master); iommu_fwspec_free(dev); @@ -2265,6 +2390,9 @@ static int arm_smmu_init_structures(struct arm_smmu_device *smmu) { int ret; + mutex_init(&smmu->streams_mutex); + smmu->streams = RB_ROOT; + ret = arm_smmu_init_queues(smmu); if (ret) return ret; -- 2.20.1
WARNING: multiple messages have this Message-ID (diff)
From: Eric Auger <eric.auger-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> To: eric.auger.pro-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org, eric.auger-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, kvm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, kvmarm-FPEHb7Xf0XXUo1n7N8X6UoWGPAHP3yOg@public.gmane.org, joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org, alex.williamson-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org, jacob.jun.pan-VuQAYsv1563Yd54FQh9/CA@public.gmane.org, yi.l.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org, jean-philippe.brucker-5wv7dgnIgG8@public.gmane.org, will.deacon-5wv7dgnIgG8@public.gmane.org, robin.murphy-5wv7dgnIgG8@public.gmane.org Cc: peter.maydell-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org, kevin.tian-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org, vincent.stehle-5wv7dgnIgG8@public.gmane.org, ashok.raj-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org, marc.zyngier-5wv7dgnIgG8@public.gmane.org, christoffer.dall-5wv7dgnIgG8@public.gmane.org Subject: [PATCH v5 11/22] iommu/arm-smmu-v3: Maintain a SID->device structure Date: Fri, 15 Mar 2019 17:08:55 +0100 [thread overview] Message-ID: <20190315160906.12900-12-eric.auger@redhat.com> (raw) In-Reply-To: <20190315160906.12900-1-eric.auger-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> From: Jean-Philippe Brucker <jean-philippe.brucker-5wv7dgnIgG8@public.gmane.org> When handling faults from the event or PRI queue, we need to find the struct device associated to a SID. Add a rb_tree to keep track of SIDs. Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker-5wv7dgnIgG8@public.gmane.org> --- drivers/iommu/arm-smmu-v3.c | 136 ++++++++++++++++++++++++++++++++++-- 1 file changed, 132 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index ff998c967a0a..21d027695181 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -588,6 +588,16 @@ struct arm_smmu_device { /* IOMMU core code handle */ struct iommu_device iommu; + + struct rb_root streams; + struct mutex streams_mutex; + +}; + +struct arm_smmu_stream { + u32 id; + struct arm_smmu_master_data *master; + struct rb_node node; }; /* SMMU private data for each master */ @@ -597,6 +607,7 @@ struct arm_smmu_master_data { struct arm_smmu_domain *domain; struct list_head list; /* domain->devices */ + struct arm_smmu_stream *streams; struct device *dev; }; @@ -1243,6 +1254,32 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid) return 0; } +__maybe_unused +static struct arm_smmu_master_data * +arm_smmu_find_master(struct arm_smmu_device *smmu, u32 sid) +{ + struct rb_node *node; + struct arm_smmu_stream *stream; + struct arm_smmu_master_data *master = NULL; + + mutex_lock(&smmu->streams_mutex); + node = smmu->streams.rb_node; + while (node) { + stream = rb_entry(node, struct arm_smmu_stream, node); + if (stream->id < sid) { + node = node->rb_right; + } else if (stream->id > sid) { + node = node->rb_left; + } else { + master = stream->master; + break; + } + } + mutex_unlock(&smmu->streams_mutex); + + return master; +} + /* IRQ and event handlers */ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev) { @@ -1881,6 +1918,71 @@ static bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid) return sid < limit; } +static int arm_smmu_insert_master(struct arm_smmu_device *smmu, + struct arm_smmu_master_data *master) +{ + int i; + int ret = 0; + struct arm_smmu_stream *new_stream, *cur_stream; + struct rb_node **new_node, *parent_node = NULL; + struct iommu_fwspec *fwspec = master->dev->iommu_fwspec; + + master->streams = kcalloc(fwspec->num_ids, + sizeof(struct arm_smmu_stream), GFP_KERNEL); + if (!master->streams) + return -ENOMEM; + + mutex_lock(&smmu->streams_mutex); + for (i = 0; i < fwspec->num_ids && !ret; i++) { + new_stream = &master->streams[i]; + new_stream->id = fwspec->ids[i]; + new_stream->master = master; + + new_node = &(smmu->streams.rb_node); + while (*new_node) { + cur_stream = rb_entry(*new_node, struct arm_smmu_stream, + node); + parent_node = *new_node; + if (cur_stream->id > new_stream->id) { + new_node = &((*new_node)->rb_left); + } else if (cur_stream->id < new_stream->id) { + new_node = &((*new_node)->rb_right); + } else { + dev_warn(master->dev, + "stream %u already in tree\n", + cur_stream->id); + ret = -EINVAL; + break; + } + } + + if (!ret) { + rb_link_node(&new_stream->node, parent_node, new_node); + rb_insert_color(&new_stream->node, &smmu->streams); + } + } + mutex_unlock(&smmu->streams_mutex); + + return ret; +} + +static void arm_smmu_remove_master(struct arm_smmu_device *smmu, + struct arm_smmu_master_data *master) +{ + int i; + struct iommu_fwspec *fwspec = master->dev->iommu_fwspec; + + if (!master->streams) + return; + + mutex_lock(&smmu->streams_mutex); + for (i = 0; i < fwspec->num_ids; i++) + rb_erase(&master->streams[i].node, &smmu->streams); + mutex_unlock(&smmu->streams_mutex); + + kfree(master->streams); +} + static struct iommu_ops arm_smmu_ops; static int arm_smmu_add_device(struct device *dev) @@ -1929,13 +2031,35 @@ static int arm_smmu_add_device(struct device *dev) } } + ret = iommu_device_link(&smmu->iommu, dev); + if (ret) + goto err_free_master; + + ret = arm_smmu_insert_master(smmu, master); + if (ret) + goto err_unlink; + group = iommu_group_get_for_dev(dev); - if (!IS_ERR(group)) { - iommu_group_put(group); - iommu_device_link(&smmu->iommu, dev); + if (IS_ERR(group)) { + ret = PTR_ERR(group); + goto err_remove_master; } - return PTR_ERR_OR_ZERO(group); + iommu_group_put(group); + + return 0; + +err_remove_master: + arm_smmu_remove_master(smmu, master); + +err_unlink: + iommu_device_unlink(&smmu->iommu, dev); + +err_free_master: + kfree(master); + fwspec->iommu_priv = NULL; + + return ret; } static void arm_smmu_remove_device(struct device *dev) @@ -1952,6 +2076,7 @@ static void arm_smmu_remove_device(struct device *dev) if (master && master->ste.assigned) arm_smmu_detach_dev(dev); iommu_group_remove_device(dev); + arm_smmu_remove_master(smmu, master); iommu_device_unlink(&smmu->iommu, dev); kfree(master); iommu_fwspec_free(dev); @@ -2265,6 +2390,9 @@ static int arm_smmu_init_structures(struct arm_smmu_device *smmu) { int ret; + mutex_init(&smmu->streams_mutex); + smmu->streams = RB_ROOT; + ret = arm_smmu_init_queues(smmu); if (ret) return ret; -- 2.20.1
next prev parent reply other threads:[~2019-03-15 16:10 UTC|newest] Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top 2019-03-15 16:08 [PATCH v5 00/22] SMMUv3 Nested Stage Setup Eric Auger 2019-03-15 16:08 ` Eric Auger 2019-03-15 16:08 ` [PATCH v5 01/22] driver core: add per device iommu param Eric Auger 2019-03-15 16:08 ` Eric Auger 2019-03-15 16:08 ` [PATCH v5 02/22] iommu: introduce device fault data Eric Auger 2019-03-15 16:08 ` Eric Auger 2019-03-15 16:08 ` [PATCH v5 03/22] iommu: introduce device fault report API Eric Auger 2019-03-15 16:08 ` [PATCH v5 04/22] iommu: Introduce attach/detach_pasid_table API Eric Auger 2019-03-15 16:08 ` Eric Auger 2019-03-15 16:08 ` [PATCH v5 05/22] iommu: Introduce cache_invalidate API Eric Auger 2019-03-15 18:37 ` Jacob Pan 2019-03-17 16:43 ` Auger Eric 2019-03-17 16:43 ` Auger Eric 2019-03-18 11:01 ` Jean-Philippe Brucker 2019-03-18 11:01 ` Jean-Philippe Brucker 2019-03-18 11:01 ` Jean-Philippe Brucker 2019-03-18 12:44 ` Auger Eric 2019-03-18 12:44 ` Auger Eric 2019-03-18 12:44 ` Auger Eric 2019-03-15 16:08 ` [PATCH v5 06/22] iommu: Introduce bind/unbind_guest_msi Eric Auger 2019-03-15 16:08 ` Eric Auger 2019-03-15 16:08 ` [PATCH v5 07/22] vfio: VFIO_IOMMU_ATTACH/DETACH_PASID_TABLE Eric Auger 2019-03-15 16:08 ` Eric Auger 2019-03-15 16:08 ` [PATCH v5 08/22] vfio: VFIO_IOMMU_CACHE_INVALIDATE Eric Auger 2019-03-15 16:08 ` [PATCH v5 09/22] vfio: VFIO_IOMMU_BIND/UNBIND_MSI Eric Auger 2019-03-15 16:08 ` [PATCH v5 10/22] iommu/arm-smmu-v3: Link domains and devices Eric Auger 2019-03-15 16:08 ` Eric Auger [this message] 2019-03-15 16:08 ` [PATCH v5 11/22] iommu/arm-smmu-v3: Maintain a SID->device structure Eric Auger 2019-03-15 16:08 ` [PATCH v5 12/22] iommu/smmuv3: Get prepared for nested stage support Eric Auger 2019-03-15 16:08 ` Eric Auger 2019-03-15 16:08 ` [PATCH v5 13/22] iommu/smmuv3: Implement attach/detach_pasid_table Eric Auger 2019-03-15 16:08 ` [PATCH v5 14/22] iommu/smmuv3: Implement cache_invalidate Eric Auger 2019-03-15 16:08 ` Eric Auger 2019-03-15 16:08 ` [PATCH v5 15/22] dma-iommu: Implement NESTED_MSI cookie Eric Auger 2019-03-15 16:09 ` [PATCH v5 16/22] iommu/smmuv3: Implement bind/unbind_guest_msi Eric Auger 2019-03-15 16:09 ` [PATCH v5 17/22] iommu/smmuv3: Report non recoverable faults Eric Auger 2019-03-15 16:09 ` [PATCH v5 18/22] vfio-pci: Add a new VFIO_REGION_TYPE_NESTED region type Eric Auger 2019-03-15 16:09 ` [PATCH v5 19/22] vfio-pci: Register an iommu fault handler Eric Auger 2019-03-15 16:09 ` [PATCH v5 20/22] vfio_pci: Allow to mmap the fault queue Eric Auger 2019-03-15 16:09 ` Eric Auger 2019-03-15 16:09 ` [PATCH v5 21/22] vfio-pci: Add VFIO_PCI_DMA_FAULT_IRQ_INDEX Eric Auger 2019-03-15 16:09 ` Eric Auger 2019-03-15 16:09 ` [PATCH v5 22/22] vfio: Document nested stage control Eric Auger 2019-03-15 16:09 ` Eric Auger
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20190315160906.12900-12-eric.auger@redhat.com \ --to=eric.auger@redhat.com \ --cc=alex.williamson@redhat.com \ --cc=ashok.raj@intel.com \ --cc=christoffer.dall@arm.com \ --cc=eric.auger.pro@gmail.com \ --cc=iommu@lists.linux-foundation.org \ --cc=jacob.jun.pan@linux.intel.com \ --cc=jean-philippe.brucker@arm.com \ --cc=joro@8bytes.org \ --cc=kevin.tian@intel.com \ --cc=kvm@vger.kernel.org \ --cc=kvmarm@lists.cs.columbia.edu \ --cc=linux-kernel@vger.kernel.org \ --cc=marc.zyngier@arm.com \ --cc=peter.maydell@linaro.org \ --cc=robin.murphy@arm.com \ --cc=vincent.stehle@arm.com \ --cc=will.deacon@arm.com \ --cc=yi.l.liu@linux.intel.com \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.