Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1382709 > unrolled thread
| Started by | Eric Auger <eric.auger@linaro.org> |
|---|---|
| First post | 2016-04-19 19:00 +0200 |
| Last post | 2016-04-22 21:10 +0200 |
| Articles | 17 — 4 participants |
Back to article view | Back to linux.kernel
[PATCH v7 00/10] KVM PCIe/MSI passthrough on ARM/ARM64: kernel part 1/3: iommu changes Eric Auger <eric.auger@linaro.org> - 2016-04-19 19:00 +0200
[PATCH v7 05/10] iommu/dma-reserved-iommu: reserved binding rb-tree and helpers Eric Auger <eric.auger@linaro.org> - 2016-04-19 19:00 +0200
Re: [PATCH v7 05/10] iommu/dma-reserved-iommu: reserved binding rb-tree and helpers Robin Murphy <robin.murphy@arm.com> - 2016-04-20 15:20 +0200
Re: [PATCH v7 05/10] iommu/dma-reserved-iommu: reserved binding rb-tree and helpers Eric Auger <eric.auger@linaro.org> - 2016-04-20 18:30 +0200
Re: [PATCH v7 05/10] iommu/dma-reserved-iommu: reserved binding rb-tree and helpers Robin Murphy <robin.murphy@arm.com> - 2016-04-22 15:10 +0200
[PATCH v7 10/10] iommu/arm-smmu: call iommu_free_reserved_iova_domain on domain destruction Eric Auger <eric.auger@linaro.org> - 2016-04-19 19:00 +0200
Re: [PATCH v7 10/10] iommu/arm-smmu: call iommu_free_reserved_iova_domain on domain destruction Robin Murphy <robin.murphy@arm.com> - 2016-04-20 19:40 +0200
Re: [PATCH v7 10/10] iommu/arm-smmu: call iommu_free_reserved_iova_domain on domain destruction Eric Auger <eric.auger@linaro.org> - 2016-04-21 10:50 +0200
[PATCH v7 09/10] iommu/dma-reserved-iommu: iommu_msi_mapping_translate_msg Eric Auger <eric.auger@linaro.org> - 2016-04-19 19:00 +0200
Re: [PATCH v7 09/10] iommu/dma-reserved-iommu: iommu_msi_mapping_translate_msg Marc Zyngier <marc.zyngier@arm.com> - 2016-04-20 11:40 +0200
Re: [PATCH v7 09/10] iommu/dma-reserved-iommu: iommu_msi_mapping_translate_msg Eric Auger <eric.auger@linaro.org> - 2016-04-20 15:00 +0200
Re: [PATCH v7 09/10] iommu/dma-reserved-iommu: iommu_msi_mapping_translate_msg Robin Murphy <robin.murphy@arm.com> - 2016-04-20 19:30 +0200
Re: [PATCH v7 09/10] iommu/dma-reserved-iommu: iommu_msi_mapping_translate_msg Eric Auger <eric.auger@linaro.org> - 2016-04-21 10:50 +0200
Re: [PATCH v7 00/10] KVM PCIe/MSI passthrough on ARM/ARM64: kernel part 1/3: iommu changes Eric Auger <eric.auger@linaro.org> - 2016-04-21 14:20 +0200
Re: [PATCH v7 00/10] KVM PCIe/MSI passthrough on ARM/ARM64: kernel part 1/3: iommu changes Alex Williamson <alex.williamson@redhat.com> - 2016-04-21 21:40 +0200
Re: [PATCH v7 00/10] KVM PCIe/MSI passthrough on ARM/ARM64: kernel part 1/3: iommu changes Eric Auger <eric.auger@linaro.org> - 2016-04-22 14:40 +0200
Re: [PATCH v7 00/10] KVM PCIe/MSI passthrough on ARM/ARM64: kernel part 1/3: iommu changes Alex Williamson <alex.williamson@redhat.com> - 2016-04-22 21:10 +0200
| From | Eric Auger <eric.auger@linaro.org> |
|---|---|
| Date | 2016-04-19 19:00 +0200 |
| Subject | [PATCH v7 00/10] KVM PCIe/MSI passthrough on ARM/ARM64: kernel part 1/3: iommu changes |
| Message-ID | <rpHah-1sn-3@gated-at.bofh.it> |
This series introduces the dma-reserved-iommu api used to:
- create/destroy an iova domain dedicated to reserved iova bindings
- map/unmap physical addresses onto reserved IOVAs.
- search for an existing reserved iova mapping matching a PA window
- determine whether an msi needs to be iommu mapped
- translate an msi_msg PA address into its IOVA counterpart
Currently reserved IOVAs are meant to map MSI physical doorbells. A single
reserved domain does exit per domain.
Also a new domain attribute is introduced to signal whether the MSI
addresses must be mapped in the IOMMU.
In current usage:
VFIO subsystem is supposed to create/destroy the iommu reserved domain.
The MSI layer is supposed to allocate/free iova mappings
Since several drivers are likely to use the same doorbell, a reference
counting takes place on the bindings. An RB-tree indexed by PA is used
to easily lookup for existing mappings at MSI message composition time.
More details & context can be found at:
http://www.linaro.org/blog/core-dump/kvm-pciemsi-passthrough-armarm64/
Best Regards
Eric
Git: complete series available at
https://git.linaro.org/people/eric.auger/linux.git/shortlog/refs/heads/v4.6-rc4-pcie-passthrough-v7
History:
v6 -> v7:
- fixed known lock bugs and multiple page sized slots matching
(I currently only have a single MSI frame made of a single page)
- reserved_iova_cookie now pointing to a struct that encapsulates the
iova domain handle + protection attribute passed from VFIO (Alex' req)
- 2 new functions exposed: iommu_msi_mapping_translate_msg,
iommu_msi_mapping_desc_to_domain: not sure this is the right location/proto
though
- iommu_put_reserved_iova now takes a phys_addr_t
- everything now is cleanup on iommu_domain destruction
RFC v5 -> patch v6:
- split to ease the review process
- in dma-reserved-api use a spin lock instead of a mutex (reported by
Jean-Philippe)
- revisit iommu_get_reserved_iova API to pass a size parameter upon
Marc's request
- Consistently use the page order passed when creating the iova domain.
- init reserved_binding_list (reported by Julien)
RFC v4 -> RFC v5:
- take into account Thomas' comments on MSI related patches
- split "msi: IOMMU map the doorbell address when needed"
- increase readability and add comments
- fix style issues
- split "iommu: Add DOMAIN_ATTR_MSI_MAPPING attribute"
- platform ITS now advertises IOMMU_CAP_INTR_REMAP
- fix compilation issue with CONFIG_IOMMU API unset
- arm-smmu-v3 now advertises DOMAIN_ATTR_MSI_MAPPING
RFC v3 -> v4:
- Move doorbell mapping/unmapping in msi.c
- fix ref count issue on set_affinity: in case of a change in the address
the previous address is decremented
- doorbell map/unmap now is done on msi composition. Should allow the use
case for platform MSI controllers
- create dma-reserved-iommu.h/c exposing/implementing a new API dedicated
to reserved IOVA management (looking like dma-iommu glue)
- series reordering to ease the review:
- first part is related to IOMMU
- second related to MSI sub-system
- third related to VFIO (except arm-smmu IOMMU_CAP_INTR_REMAP removal)
- expose the number of requested IOVA pages through VFIO_IOMMU_GET_INFO
[this partially addresses Marc's comments on iommu_get/put_single_reserved
size/alignment problematic - which I did not ignore - but I don't know
how much I can do at the moment]
RFC v2 -> RFC v3:
- should fix wrong handling of some CONFIG combinations:
CONFIG_IOVA, CONFIG_IOMMU_API, CONFIG_PCI_MSI_IRQ_DOMAIN
- fix MSI_FLAG_IRQ_REMAPPING setting in GICv3 ITS (although not tested)
PATCH v1 -> RFC v2:
- reverted to RFC since it looks more reasonable ;-) the code is split
between VFIO, IOMMU, MSI controller and I am not sure I did the right
choices. Also API need to be further discussed.
- iova API usage in arm-smmu.c.
- MSI controller natively programs the MSI addr with either the PA or IOVA.
This is not done anymore in vfio-pci driver as suggested by Alex.
- check irq remapping capability of the group
RFC v1 [2] -> PATCH v1:
- use the existing dma map/unmap ioctl interface with a flag to register a
reserved IOVA range. Use the legacy Rb to store this special vfio_dma.
- a single reserved IOVA contiguous region now is allowed
- use of an RB tree indexed by PA to store allocated reserved slots
- use of a vfio_domain iova_domain to manage iova allocation within the
window provided by the userspace
- vfio alloc_map/unmap_free take a vfio_group handle
- vfio_group handle is cached in vfio_pci_device
- add ref counting to bindings
- user modality enabled at the end of the series
Eric Auger (10):
iommu: Add DOMAIN_ATTR_MSI_MAPPING attribute
iommu/arm-smmu: advertise DOMAIN_ATTR_MSI_MAPPING attribute
iommu: introduce a reserved iova cookie
iommu/dma-reserved-iommu: alloc/free_reserved_iova_domain
iommu/dma-reserved-iommu: reserved binding rb-tree and helpers
iommu/dma-reserved-iommu: iommu_get/put_reserved_iova
iommu/dma-reserved-iommu: delete bindings in
iommu_free_reserved_iova_domain
iommu/dma-reserved_iommu: iommu_msi_mapping_desc_to_domain
iommu/dma-reserved-iommu: iommu_msi_mapping_translate_msg
iommu/arm-smmu: call iommu_free_reserved_iova_domain on domain
destruction
drivers/iommu/Kconfig | 8 +
drivers/iommu/Makefile | 1 +
drivers/iommu/arm-smmu-v3.c | 4 +
drivers/iommu/arm-smmu.c | 4 +
drivers/iommu/dma-reserved-iommu.c | 422 +++++++++++++++++++++++++++++++++++++
drivers/iommu/iommu.c | 2 +
include/linux/dma-reserved-iommu.h | 142 +++++++++++++
include/linux/iommu.h | 7 +
8 files changed, 590 insertions(+)
create mode 100644 drivers/iommu/dma-reserved-iommu.c
create mode 100644 include/linux/dma-reserved-iommu.h
--
1.9.1
[toc] | [next] | [standalone]
| From | Eric Auger <eric.auger@linaro.org> |
|---|---|
| Date | 2016-04-19 19:00 +0200 |
| Subject | [PATCH v7 05/10] iommu/dma-reserved-iommu: reserved binding rb-tree and helpers |
| Message-ID | <rpHaj-1sn-29@gated-at.bofh.it> |
| In reply to | #1382709 |
we will need to track which host physical addresses are mapped to
reserved IOVA. In that prospect we introduce a new RB tree indexed
by physical address. This RB tree only is used for reserved IOVA
bindings.
It is expected this RB tree will contain very few bindings. Those
generally correspond to single page mapping one MSI frame (GICv2m
frame or ITS GITS_TRANSLATER frame).
Signed-off-by: Eric Auger <eric.auger@linaro.org>
---
v5 -> v6:
- add comment about @d->reserved_lock to be held
v3 -> v4:
- that code was formerly in "iommu/arm-smmu: add a reserved binding RB tree"
---
drivers/iommu/dma-reserved-iommu.c | 63 ++++++++++++++++++++++++++++++++++++++
1 file changed, 63 insertions(+)
diff --git a/drivers/iommu/dma-reserved-iommu.c b/drivers/iommu/dma-reserved-iommu.c
index 2562af0..f6fa18e 100644
--- a/drivers/iommu/dma-reserved-iommu.c
+++ b/drivers/iommu/dma-reserved-iommu.c
@@ -23,6 +23,69 @@ struct reserved_iova_domain {
int prot; /* iommu protection attributes to be obeyed */
};
+struct iommu_reserved_binding {
+ struct kref kref;
+ struct rb_node node;
+ struct iommu_domain *domain;
+ phys_addr_t addr;
+ dma_addr_t iova;
+ size_t size;
+};
+
+/* Reserved binding RB-tree manipulation */
+
+/* @d->reserved_lock must be held */
+static struct iommu_reserved_binding *find_reserved_binding(
+ struct iommu_domain *d,
+ phys_addr_t start, size_t size)
+{
+ struct rb_node *node = d->reserved_binding_list.rb_node;
+
+ while (node) {
+ struct iommu_reserved_binding *binding =
+ rb_entry(node, struct iommu_reserved_binding, node);
+
+ if (start + size <= binding->addr)
+ node = node->rb_left;
+ else if (start >= binding->addr + binding->size)
+ node = node->rb_right;
+ else
+ return binding;
+ }
+
+ return NULL;
+}
+
+/* @d->reserved_lock must be held */
+static void link_reserved_binding(struct iommu_domain *d,
+ struct iommu_reserved_binding *new)
+{
+ struct rb_node **link = &d->reserved_binding_list.rb_node;
+ struct rb_node *parent = NULL;
+ struct iommu_reserved_binding *binding;
+
+ while (*link) {
+ parent = *link;
+ binding = rb_entry(parent, struct iommu_reserved_binding,
+ node);
+
+ if (new->addr + new->size <= binding->addr)
+ link = &(*link)->rb_left;
+ else
+ link = &(*link)->rb_right;
+ }
+
+ rb_link_node(&new->node, parent, link);
+ rb_insert_color(&new->node, &d->reserved_binding_list);
+}
+
+/* @d->reserved_lock must be held */
+static void unlink_reserved_binding(struct iommu_domain *d,
+ struct iommu_reserved_binding *old)
+{
+ rb_erase(&old->node, &d->reserved_binding_list);
+}
+
int iommu_alloc_reserved_iova_domain(struct iommu_domain *domain,
dma_addr_t iova, size_t size, int prot,
unsigned long order)
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Robin Murphy <robin.murphy@arm.com> |
|---|---|
| Date | 2016-04-20 15:20 +0200 |
| Subject | Re: [PATCH v7 05/10] iommu/dma-reserved-iommu: reserved binding rb-tree and helpers |
| Message-ID | <rq0cV-8rY-1@gated-at.bofh.it> |
| In reply to | #1382710 |
On 19/04/16 17:56, Eric Auger wrote:
> we will need to track which host physical addresses are mapped to
> reserved IOVA. In that prospect we introduce a new RB tree indexed
> by physical address. This RB tree only is used for reserved IOVA
> bindings.
>
> It is expected this RB tree will contain very few bindings.
Sounds like a good reason in favour of using a list, and thus having
rather less code here ;)
> Those
> generally correspond to single page mapping one MSI frame (GICv2m
> frame or ITS GITS_TRANSLATER frame).
>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>
> ---
> v5 -> v6:
> - add comment about @d->reserved_lock to be held
>
> v3 -> v4:
> - that code was formerly in "iommu/arm-smmu: add a reserved binding RB tree"
> ---
> drivers/iommu/dma-reserved-iommu.c | 63 ++++++++++++++++++++++++++++++++++++++
> 1 file changed, 63 insertions(+)
>
> diff --git a/drivers/iommu/dma-reserved-iommu.c b/drivers/iommu/dma-reserved-iommu.c
> index 2562af0..f6fa18e 100644
> --- a/drivers/iommu/dma-reserved-iommu.c
> +++ b/drivers/iommu/dma-reserved-iommu.c
> @@ -23,6 +23,69 @@ struct reserved_iova_domain {
> int prot; /* iommu protection attributes to be obeyed */
> };
>
> +struct iommu_reserved_binding {
> + struct kref kref;
> + struct rb_node node;
> + struct iommu_domain *domain;
Hang on, the tree these are in is already embedded in a domain. Ergo we
can't look them up without first knowing the domain they belong to, so
what purpose does this guy serve?
Robin.
> + phys_addr_t addr;
> + dma_addr_t iova;
> + size_t size;
> +};
> +
> +/* Reserved binding RB-tree manipulation */
> +
> +/* @d->reserved_lock must be held */
> +static struct iommu_reserved_binding *find_reserved_binding(
> + struct iommu_domain *d,
> + phys_addr_t start, size_t size)
> +{
> + struct rb_node *node = d->reserved_binding_list.rb_node;
> +
> + while (node) {
> + struct iommu_reserved_binding *binding =
> + rb_entry(node, struct iommu_reserved_binding, node);
> +
> + if (start + size <= binding->addr)
> + node = node->rb_left;
> + else if (start >= binding->addr + binding->size)
> + node = node->rb_right;
> + else
> + return binding;
> + }
> +
> + return NULL;
> +}
> +
> +/* @d->reserved_lock must be held */
> +static void link_reserved_binding(struct iommu_domain *d,
> + struct iommu_reserved_binding *new)
> +{
> + struct rb_node **link = &d->reserved_binding_list.rb_node;
> + struct rb_node *parent = NULL;
> + struct iommu_reserved_binding *binding;
> +
> + while (*link) {
> + parent = *link;
> + binding = rb_entry(parent, struct iommu_reserved_binding,
> + node);
> +
> + if (new->addr + new->size <= binding->addr)
> + link = &(*link)->rb_left;
> + else
> + link = &(*link)->rb_right;
> + }
> +
> + rb_link_node(&new->node, parent, link);
> + rb_insert_color(&new->node, &d->reserved_binding_list);
> +}
> +
> +/* @d->reserved_lock must be held */
> +static void unlink_reserved_binding(struct iommu_domain *d,
> + struct iommu_reserved_binding *old)
> +{
> + rb_erase(&old->node, &d->reserved_binding_list);
> +}
> +
> int iommu_alloc_reserved_iova_domain(struct iommu_domain *domain,
> dma_addr_t iova, size_t size, int prot,
> unsigned long order)
>
[toc] | [prev] | [next] | [standalone]
| From | Eric Auger <eric.auger@linaro.org> |
|---|---|
| Date | 2016-04-20 18:30 +0200 |
| Subject | Re: [PATCH v7 05/10] iommu/dma-reserved-iommu: reserved binding rb-tree and helpers |
| Message-ID | <rq3aN-2jq-3@gated-at.bofh.it> |
| In reply to | #1383364 |
Robin,
On 04/20/2016 03:12 PM, Robin Murphy wrote:
> On 19/04/16 17:56, Eric Auger wrote:
>> we will need to track which host physical addresses are mapped to
>> reserved IOVA. In that prospect we introduce a new RB tree indexed
>> by physical address. This RB tree only is used for reserved IOVA
>> bindings.
>>
>> It is expected this RB tree will contain very few bindings.
>
> Sounds like a good reason in favour of using a list, and thus having
> rather less code here ;)
OK will move to a simple list.
>
>> Those
>> generally correspond to single page mapping one MSI frame (GICv2m
>> frame or ITS GITS_TRANSLATER frame).
>>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>
>> ---
>> v5 -> v6:
>> - add comment about @d->reserved_lock to be held
>>
>> v3 -> v4:
>> - that code was formerly in "iommu/arm-smmu: add a reserved binding RB
>> tree"
>> ---
>> drivers/iommu/dma-reserved-iommu.c | 63
>> ++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 63 insertions(+)
>>
>> diff --git a/drivers/iommu/dma-reserved-iommu.c
>> b/drivers/iommu/dma-reserved-iommu.c
>> index 2562af0..f6fa18e 100644
>> --- a/drivers/iommu/dma-reserved-iommu.c
>> +++ b/drivers/iommu/dma-reserved-iommu.c
>> @@ -23,6 +23,69 @@ struct reserved_iova_domain {
>> int prot; /* iommu protection attributes to be obeyed */
>> };
>>
>> +struct iommu_reserved_binding {
>> + struct kref kref;
>> + struct rb_node node;
>> + struct iommu_domain *domain;
>
> Hang on, the tree these are in is already embedded in a domain. Ergo we
> can't look them up without first knowing the domain they belong to, so
> what purpose does this guy serve?
this is used on the kref_put. The release function takes a kref; then we
get the container to retrieve the binding and storing the domain here
enables to unlink the node.
Best Regards
Eric
>
> Robin.
>
>> + phys_addr_t addr;
>> + dma_addr_t iova;
>> + size_t size;
>> +};
>> +
>> +/* Reserved binding RB-tree manipulation */
>> +
>> +/* @d->reserved_lock must be held */
>> +static struct iommu_reserved_binding *find_reserved_binding(
>> + struct iommu_domain *d,
>> + phys_addr_t start, size_t size)
>> +{
>> + struct rb_node *node = d->reserved_binding_list.rb_node;
>> +
>> + while (node) {
>> + struct iommu_reserved_binding *binding =
>> + rb_entry(node, struct iommu_reserved_binding, node);
>> +
>> + if (start + size <= binding->addr)
>> + node = node->rb_left;
>> + else if (start >= binding->addr + binding->size)
>> + node = node->rb_right;
>> + else
>> + return binding;
>> + }
>> +
>> + return NULL;
>> +}
>> +
>> +/* @d->reserved_lock must be held */
>> +static void link_reserved_binding(struct iommu_domain *d,
>> + struct iommu_reserved_binding *new)
>> +{
>> + struct rb_node **link = &d->reserved_binding_list.rb_node;
>> + struct rb_node *parent = NULL;
>> + struct iommu_reserved_binding *binding;
>> +
>> + while (*link) {
>> + parent = *link;
>> + binding = rb_entry(parent, struct iommu_reserved_binding,
>> + node);
>> +
>> + if (new->addr + new->size <= binding->addr)
>> + link = &(*link)->rb_left;
>> + else
>> + link = &(*link)->rb_right;
>> + }
>> +
>> + rb_link_node(&new->node, parent, link);
>> + rb_insert_color(&new->node, &d->reserved_binding_list);
>> +}
>> +
>> +/* @d->reserved_lock must be held */
>> +static void unlink_reserved_binding(struct iommu_domain *d,
>> + struct iommu_reserved_binding *old)
>> +{
>> + rb_erase(&old->node, &d->reserved_binding_list);
>> +}
>> +
>> int iommu_alloc_reserved_iova_domain(struct iommu_domain *domain,
>> dma_addr_t iova, size_t size, int prot,
>> unsigned long order)
>>
>
[toc] | [prev] | [next] | [standalone]
| From | Robin Murphy <robin.murphy@arm.com> |
|---|---|
| Date | 2016-04-22 15:10 +0200 |
| Subject | Re: [PATCH v7 05/10] iommu/dma-reserved-iommu: reserved binding rb-tree and helpers |
| Message-ID | <rqJ0n-2pv-31@gated-at.bofh.it> |
| In reply to | #1383549 |
On 20/04/16 17:18, Eric Auger wrote:
> Robin,
> On 04/20/2016 03:12 PM, Robin Murphy wrote:
>> On 19/04/16 17:56, Eric Auger wrote:
>>> we will need to track which host physical addresses are mapped to
>>> reserved IOVA. In that prospect we introduce a new RB tree indexed
>>> by physical address. This RB tree only is used for reserved IOVA
>>> bindings.
>>>
>>> It is expected this RB tree will contain very few bindings.
>>
>> Sounds like a good reason in favour of using a list, and thus having
>> rather less code here ;)
>
> OK will move to a simple list.
>>
>>> Those
>>> generally correspond to single page mapping one MSI frame (GICv2m
>>> frame or ITS GITS_TRANSLATER frame).
>>>
>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>>
>>> ---
>>> v5 -> v6:
>>> - add comment about @d->reserved_lock to be held
>>>
>>> v3 -> v4:
>>> - that code was formerly in "iommu/arm-smmu: add a reserved binding RB
>>> tree"
>>> ---
>>> drivers/iommu/dma-reserved-iommu.c | 63
>>> ++++++++++++++++++++++++++++++++++++++
>>> 1 file changed, 63 insertions(+)
>>>
>>> diff --git a/drivers/iommu/dma-reserved-iommu.c
>>> b/drivers/iommu/dma-reserved-iommu.c
>>> index 2562af0..f6fa18e 100644
>>> --- a/drivers/iommu/dma-reserved-iommu.c
>>> +++ b/drivers/iommu/dma-reserved-iommu.c
>>> @@ -23,6 +23,69 @@ struct reserved_iova_domain {
>>> int prot; /* iommu protection attributes to be obeyed */
>>> };
>>>
>>> +struct iommu_reserved_binding {
>>> + struct kref kref;
>>> + struct rb_node node;
>>> + struct iommu_domain *domain;
>>
>> Hang on, the tree these are in is already embedded in a domain. Ergo we
>> can't look them up without first knowing the domain they belong to, so
>> what purpose does this guy serve?
> this is used on the kref_put. The release function takes a kref; then we
> get the container to retrieve the binding and storing the domain here
> enables to unlink the node.
Ah yes, I see now - that's annoyingly awkward. I think it could possibly
be avoided in the list case (if the kref_put callback just did
list_del_init(), the entry could then be checked for an empty list and
disposed of outside the lock), but I'm not sure whether that's really
worth the fuss. Oh well.
Robin.
> Best Regards
>
> Eric
>>
>> Robin.
>>
>>> + phys_addr_t addr;
>>> + dma_addr_t iova;
>>> + size_t size;
>>> +};
>>> +
>>> +/* Reserved binding RB-tree manipulation */
>>> +
>>> +/* @d->reserved_lock must be held */
>>> +static struct iommu_reserved_binding *find_reserved_binding(
>>> + struct iommu_domain *d,
>>> + phys_addr_t start, size_t size)
>>> +{
>>> + struct rb_node *node = d->reserved_binding_list.rb_node;
>>> +
>>> + while (node) {
>>> + struct iommu_reserved_binding *binding =
>>> + rb_entry(node, struct iommu_reserved_binding, node);
>>> +
>>> + if (start + size <= binding->addr)
>>> + node = node->rb_left;
>>> + else if (start >= binding->addr + binding->size)
>>> + node = node->rb_right;
>>> + else
>>> + return binding;
>>> + }
>>> +
>>> + return NULL;
>>> +}
>>> +
>>> +/* @d->reserved_lock must be held */
>>> +static void link_reserved_binding(struct iommu_domain *d,
>>> + struct iommu_reserved_binding *new)
>>> +{
>>> + struct rb_node **link = &d->reserved_binding_list.rb_node;
>>> + struct rb_node *parent = NULL;
>>> + struct iommu_reserved_binding *binding;
>>> +
>>> + while (*link) {
>>> + parent = *link;
>>> + binding = rb_entry(parent, struct iommu_reserved_binding,
>>> + node);
>>> +
>>> + if (new->addr + new->size <= binding->addr)
>>> + link = &(*link)->rb_left;
>>> + else
>>> + link = &(*link)->rb_right;
>>> + }
>>> +
>>> + rb_link_node(&new->node, parent, link);
>>> + rb_insert_color(&new->node, &d->reserved_binding_list);
>>> +}
>>> +
>>> +/* @d->reserved_lock must be held */
>>> +static void unlink_reserved_binding(struct iommu_domain *d,
>>> + struct iommu_reserved_binding *old)
>>> +{
>>> + rb_erase(&old->node, &d->reserved_binding_list);
>>> +}
>>> +
>>> int iommu_alloc_reserved_iova_domain(struct iommu_domain *domain,
>>> dma_addr_t iova, size_t size, int prot,
>>> unsigned long order)
>>>
>>
>
[toc] | [prev] | [next] | [standalone]
| From | Eric Auger <eric.auger@linaro.org> |
|---|---|
| Date | 2016-04-19 19:00 +0200 |
| Subject | [PATCH v7 10/10] iommu/arm-smmu: call iommu_free_reserved_iova_domain on domain destruction |
| Message-ID | <rpHaj-1sn-31@gated-at.bofh.it> |
| In reply to | #1382709 |
When the domain gets destroyed, let's make sure all reserved iova resources get released. Choice is made to put that call in arm-smmu(-v3).c to do something similar to what was done for iommu_put_dma_cookie. Signed-off-by: Eric Auger <eric.auger@linaro.org> --- v7: new --- drivers/iommu/arm-smmu-v3.c | 2 ++ drivers/iommu/arm-smmu.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index a077a35..afd0dac 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -22,6 +22,7 @@ #include <linux/delay.h> #include <linux/dma-iommu.h> +#include <linux/dma-reserved-iommu.h> #include <linux/err.h> #include <linux/interrupt.h> #include <linux/iommu.h> @@ -1444,6 +1445,7 @@ static void arm_smmu_domain_free(struct iommu_domain *domain) struct arm_smmu_device *smmu = smmu_domain->smmu; iommu_put_dma_cookie(domain); + iommu_free_reserved_iova_domain(domain); free_io_pgtable_ops(smmu_domain->pgtbl_ops); /* Free the CD and ASID, if we allocated them */ diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 8cd7b8a..492339f 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -30,6 +30,7 @@ #include <linux/delay.h> #include <linux/dma-iommu.h> +#include <linux/dma-reserved-iommu.h> #include <linux/dma-mapping.h> #include <linux/err.h> #include <linux/interrupt.h> @@ -1009,6 +1010,7 @@ static void arm_smmu_domain_free(struct iommu_domain *domain) * already been detached. */ iommu_put_dma_cookie(domain); + iommu_free_reserved_iova_domain(domain); arm_smmu_destroy_domain_context(domain); kfree(smmu_domain); } -- 1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Robin Murphy <robin.murphy@arm.com> |
|---|---|
| Date | 2016-04-20 19:40 +0200 |
| Subject | Re: [PATCH v7 10/10] iommu/arm-smmu: call iommu_free_reserved_iova_domain on domain destruction |
| Message-ID | <rq4gy-36L-5@gated-at.bofh.it> |
| In reply to | #1382711 |
On 19/04/16 17:56, Eric Auger wrote: > When the domain gets destroyed, let's make sure all reserved iova > resources get released. > > Choice is made to put that call in arm-smmu(-v3).c to do something similar > to what was done for iommu_put_dma_cookie. > > Signed-off-by: Eric Auger <eric.auger@linaro.org> > > --- > > v7: new > --- > drivers/iommu/arm-smmu-v3.c | 2 ++ > drivers/iommu/arm-smmu.c | 2 ++ > 2 files changed, 4 insertions(+) > > diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c > index a077a35..afd0dac 100644 > --- a/drivers/iommu/arm-smmu-v3.c > +++ b/drivers/iommu/arm-smmu-v3.c > @@ -22,6 +22,7 @@ > > #include <linux/delay.h> > #include <linux/dma-iommu.h> > +#include <linux/dma-reserved-iommu.h> > #include <linux/err.h> > #include <linux/interrupt.h> > #include <linux/iommu.h> > @@ -1444,6 +1445,7 @@ static void arm_smmu_domain_free(struct iommu_domain *domain) > struct arm_smmu_device *smmu = smmu_domain->smmu; > > iommu_put_dma_cookie(domain); > + iommu_free_reserved_iova_domain(domain); Yikes! No, drivers shouldn't be randomly freeing things they didn't allocate - the owner of the domain, who presumably allocated the thing, can call that right _before_ they call iommu_domain_free(). > free_io_pgtable_ops(smmu_domain->pgtbl_ops); > > /* Free the CD and ASID, if we allocated them */ > diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c > index 8cd7b8a..492339f 100644 > --- a/drivers/iommu/arm-smmu.c > +++ b/drivers/iommu/arm-smmu.c > @@ -30,6 +30,7 @@ > > #include <linux/delay.h> > #include <linux/dma-iommu.h> > +#include <linux/dma-reserved-iommu.h> > #include <linux/dma-mapping.h> > #include <linux/err.h> > #include <linux/interrupt.h> > @@ -1009,6 +1010,7 @@ static void arm_smmu_domain_free(struct iommu_domain *domain) > * already been detached. > */ > iommu_put_dma_cookie(domain); > + iommu_free_reserved_iova_domain(domain); ...which has the added bonus of preventing needless duplication everywhere. Robin. > arm_smmu_destroy_domain_context(domain); > kfree(smmu_domain); > } >
[toc] | [prev] | [next] | [standalone]
| From | Eric Auger <eric.auger@linaro.org> |
|---|---|
| Date | 2016-04-21 10:50 +0200 |
| Subject | Re: [PATCH v7 10/10] iommu/arm-smmu: call iommu_free_reserved_iova_domain on domain destruction |
| Message-ID | <rqitc-6j1-33@gated-at.bofh.it> |
| In reply to | #1383581 |
Hi Robin, On 04/20/2016 07:35 PM, Robin Murphy wrote: > On 19/04/16 17:56, Eric Auger wrote: >> When the domain gets destroyed, let's make sure all reserved iova >> resources get released. >> >> Choice is made to put that call in arm-smmu(-v3).c to do something >> similar >> to what was done for iommu_put_dma_cookie. >> >> Signed-off-by: Eric Auger <eric.auger@linaro.org> >> >> --- >> >> v7: new >> --- >> drivers/iommu/arm-smmu-v3.c | 2 ++ >> drivers/iommu/arm-smmu.c | 2 ++ >> 2 files changed, 4 insertions(+) >> >> diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c >> index a077a35..afd0dac 100644 >> --- a/drivers/iommu/arm-smmu-v3.c >> +++ b/drivers/iommu/arm-smmu-v3.c >> @@ -22,6 +22,7 @@ >> >> #include <linux/delay.h> >> #include <linux/dma-iommu.h> >> +#include <linux/dma-reserved-iommu.h> >> #include <linux/err.h> >> #include <linux/interrupt.h> >> #include <linux/iommu.h> >> @@ -1444,6 +1445,7 @@ static void arm_smmu_domain_free(struct >> iommu_domain *domain) >> struct arm_smmu_device *smmu = smmu_domain->smmu; >> >> iommu_put_dma_cookie(domain); >> + iommu_free_reserved_iova_domain(domain); > > Yikes! No, drivers shouldn't be randomly freeing things they didn't > allocate - the owner of the domain, who presumably allocated the thing, > can call that right _before_ they call iommu_domain_free(). OK I move that back to vfio_iommu_type1.c. Thanks Eric > >> free_io_pgtable_ops(smmu_domain->pgtbl_ops); >> >> /* Free the CD and ASID, if we allocated them */ >> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c >> index 8cd7b8a..492339f 100644 >> --- a/drivers/iommu/arm-smmu.c >> +++ b/drivers/iommu/arm-smmu.c >> @@ -30,6 +30,7 @@ >> >> #include <linux/delay.h> >> #include <linux/dma-iommu.h> >> +#include <linux/dma-reserved-iommu.h> >> #include <linux/dma-mapping.h> >> #include <linux/err.h> >> #include <linux/interrupt.h> >> @@ -1009,6 +1010,7 @@ static void arm_smmu_domain_free(struct >> iommu_domain *domain) >> * already been detached. >> */ >> iommu_put_dma_cookie(domain); >> + iommu_free_reserved_iova_domain(domain); > > ...which has the added bonus of preventing needless duplication everywhere. > > Robin. > >> arm_smmu_destroy_domain_context(domain); >> kfree(smmu_domain); >> } >> >
[toc] | [prev] | [next] | [standalone]
| From | Eric Auger <eric.auger@linaro.org> |
|---|---|
| Date | 2016-04-19 19:00 +0200 |
| Subject | [PATCH v7 09/10] iommu/dma-reserved-iommu: iommu_msi_mapping_translate_msg |
| Message-ID | <rpHaj-1sn-35@gated-at.bofh.it> |
| In reply to | #1382709 |
Introduce iommu_msi_mapping_translate_msg whose role consists in
detecting whether the device's MSIs must to be mapped into an IOMMU.
It case it must, the function overrides the MSI msg originally composed
and replaces the doorbell's PA by a pre-allocated and pre-mapped reserved
IOVA. In case the corresponding PA region is not found, the function
returns an error.
This function is likely to be called in some code that cannot sleep. This
is the reason why the allocation/mapping is done separately.
Signed-off-by: Eric Auger <eric.auger@linaro.org>
---
v7: creation
---
drivers/iommu/dma-reserved-iommu.c | 69 ++++++++++++++++++++++++++++++++++++++
include/linux/dma-reserved-iommu.h | 27 +++++++++++++++
2 files changed, 96 insertions(+)
diff --git a/drivers/iommu/dma-reserved-iommu.c b/drivers/iommu/dma-reserved-iommu.c
index 907a17f..603ee45 100644
--- a/drivers/iommu/dma-reserved-iommu.c
+++ b/drivers/iommu/dma-reserved-iommu.c
@@ -18,6 +18,14 @@
#include <linux/iommu.h>
#include <linux/iova.h>
#include <linux/msi.h>
+#include <linux/irq.h>
+
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+#define msg_to_phys_addr(msg) \
+ (((phys_addr_t)((msg)->address_hi) << 32) | (msg)->address_lo)
+#else
+#define msg_to_phys_addr(msg) ((msg)->address_lo)
+#endif
struct reserved_iova_domain {
struct iova_domain *iovad;
@@ -351,3 +359,64 @@ struct iommu_domain *iommu_msi_mapping_desc_to_domain(struct msi_desc *desc)
return d;
}
EXPORT_SYMBOL_GPL(iommu_msi_mapping_desc_to_domain);
+
+static dma_addr_t iommu_find_reserved_iova(struct iommu_domain *domain,
+ phys_addr_t addr, size_t size)
+{
+ unsigned long base_pfn, end_pfn, nb_iommu_pages, order, flags;
+ size_t iommu_page_size, binding_size;
+ struct iommu_reserved_binding *b;
+ phys_addr_t aligned_base, offset;
+ dma_addr_t iova = DMA_ERROR_CODE;
+ struct iova_domain *iovad;
+
+ spin_lock_irqsave(&domain->reserved_lock, flags);
+
+ iovad = (struct iova_domain *)domain->reserved_iova_cookie;
+
+ if (!iovad)
+ goto unlock;
+
+ order = iova_shift(iovad);
+ base_pfn = addr >> order;
+ end_pfn = (addr + size - 1) >> order;
+ aligned_base = base_pfn << order;
+ offset = addr - aligned_base;
+ nb_iommu_pages = end_pfn - base_pfn + 1;
+ iommu_page_size = 1 << order;
+ binding_size = nb_iommu_pages * iommu_page_size;
+
+ b = find_reserved_binding(domain, aligned_base, binding_size);
+ if (b && (b->addr <= aligned_base) &&
+ (aligned_base + binding_size <= b->addr + b->size))
+ iova = b->iova + offset + aligned_base - b->addr;
+unlock:
+ spin_unlock_irqrestore(&domain->reserved_lock, flags);
+ return iova;
+}
+
+int iommu_msi_mapping_translate_msg(struct irq_data *data, struct msi_msg *msg)
+{
+ struct iommu_domain *d;
+ struct msi_desc *desc;
+ dma_addr_t iova;
+
+ desc = irq_data_get_msi_desc(data);
+ if (!desc)
+ return -EINVAL;
+
+ d = iommu_msi_mapping_desc_to_domain(desc);
+ if (!d)
+ return 0;
+
+ iova = iommu_find_reserved_iova(d, msg_to_phys_addr(msg),
+ sizeof(phys_addr_t));
+
+ if (iova == DMA_ERROR_CODE)
+ return -EINVAL;
+
+ msg->address_lo = lower_32_bits(iova);
+ msg->address_hi = upper_32_bits(iova);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iommu_msi_mapping_translate_msg);
diff --git a/include/linux/dma-reserved-iommu.h b/include/linux/dma-reserved-iommu.h
index 8373929..04e1912f 100644
--- a/include/linux/dma-reserved-iommu.h
+++ b/include/linux/dma-reserved-iommu.h
@@ -20,6 +20,8 @@
struct iommu_domain;
struct msi_desc;
+struct irq_data;
+struct msi_msg;
#ifdef CONFIG_IOMMU_DMA_RESERVED
@@ -82,6 +84,25 @@ void iommu_put_reserved_iova(struct iommu_domain *domain, phys_addr_t addr);
*/
struct iommu_domain *iommu_msi_mapping_desc_to_domain(struct msi_desc *desc);
+/**
+ * iommu_msi_mapping_translate_msg: in case the MSI transaction is translated
+ * by an IOMMU, the msg address must be an IOVA instead of a physical address.
+ * This function overwrites the original MSI message containing the doorbell
+ * physical address, result of the primary composition, with the doorbell IOVA.
+ *
+ * The doorbell physical address must be bound previously to an IOVA using
+ * iommu_get_reserved_iova
+ *
+ * @data: irq data handle
+ * @msg: original msi message containing the PA to be overwritten with
+ * the IOVA
+ *
+ * return 0 if the MSI does not need to be mapped or when the PA/IOVA
+ * were successfully swapped; return -EINVAL if the addresses need
+ * to be swapped but not IOMMU binding is found
+ */
+int iommu_msi_mapping_translate_msg(struct irq_data *data, struct msi_msg *msg);
+
#else
static inline int
@@ -111,5 +132,11 @@ iommu_msi_mapping_desc_to_domain(struct msi_desc *desc)
return NULL;
}
+static inline int iommu_msi_mapping_translate_msg(struct irq_data *data,
+ struct msi_msg *msg)
+{
+ return 0;
+}
+
#endif /* CONFIG_IOMMU_DMA_RESERVED */
#endif /* __DMA_RESERVED_IOMMU_H */
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Marc Zyngier <marc.zyngier@arm.com> |
|---|---|
| Date | 2016-04-20 11:40 +0200 |
| Subject | Re: [PATCH v7 09/10] iommu/dma-reserved-iommu: iommu_msi_mapping_translate_msg |
| Message-ID | <rpWM2-5HI-15@gated-at.bofh.it> |
| In reply to | #1382712 |
On 19/04/16 17:56, Eric Auger wrote:
> Introduce iommu_msi_mapping_translate_msg whose role consists in
> detecting whether the device's MSIs must to be mapped into an IOMMU.
> It case it must, the function overrides the MSI msg originally composed
> and replaces the doorbell's PA by a pre-allocated and pre-mapped reserved
> IOVA. In case the corresponding PA region is not found, the function
> returns an error.
>
> This function is likely to be called in some code that cannot sleep. This
> is the reason why the allocation/mapping is done separately.
>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>
> ---
>
> v7: creation
> ---
> drivers/iommu/dma-reserved-iommu.c | 69 ++++++++++++++++++++++++++++++++++++++
> include/linux/dma-reserved-iommu.h | 27 +++++++++++++++
> 2 files changed, 96 insertions(+)
>
> diff --git a/drivers/iommu/dma-reserved-iommu.c b/drivers/iommu/dma-reserved-iommu.c
> index 907a17f..603ee45 100644
> --- a/drivers/iommu/dma-reserved-iommu.c
> +++ b/drivers/iommu/dma-reserved-iommu.c
> @@ -18,6 +18,14 @@
> #include <linux/iommu.h>
> #include <linux/iova.h>
> #include <linux/msi.h>
> +#include <linux/irq.h>
> +
> +#ifdef CONFIG_PHYS_ADDR_T_64BIT
> +#define msg_to_phys_addr(msg) \
> + (((phys_addr_t)((msg)->address_hi) << 32) | (msg)->address_lo)
> +#else
> +#define msg_to_phys_addr(msg) ((msg)->address_lo)
> +#endif
>
> struct reserved_iova_domain {
> struct iova_domain *iovad;
> @@ -351,3 +359,64 @@ struct iommu_domain *iommu_msi_mapping_desc_to_domain(struct msi_desc *desc)
> return d;
> }
> EXPORT_SYMBOL_GPL(iommu_msi_mapping_desc_to_domain);
> +
> +static dma_addr_t iommu_find_reserved_iova(struct iommu_domain *domain,
> + phys_addr_t addr, size_t size)
> +{
> + unsigned long base_pfn, end_pfn, nb_iommu_pages, order, flags;
> + size_t iommu_page_size, binding_size;
> + struct iommu_reserved_binding *b;
> + phys_addr_t aligned_base, offset;
> + dma_addr_t iova = DMA_ERROR_CODE;
> + struct iova_domain *iovad;
> +
> + spin_lock_irqsave(&domain->reserved_lock, flags);
> +
> + iovad = (struct iova_domain *)domain->reserved_iova_cookie;
> +
> + if (!iovad)
> + goto unlock;
> +
> + order = iova_shift(iovad);
> + base_pfn = addr >> order;
> + end_pfn = (addr + size - 1) >> order;
> + aligned_base = base_pfn << order;
> + offset = addr - aligned_base;
> + nb_iommu_pages = end_pfn - base_pfn + 1;
> + iommu_page_size = 1 << order;
> + binding_size = nb_iommu_pages * iommu_page_size;
> +
> + b = find_reserved_binding(domain, aligned_base, binding_size);
> + if (b && (b->addr <= aligned_base) &&
> + (aligned_base + binding_size <= b->addr + b->size))
> + iova = b->iova + offset + aligned_base - b->addr;
> +unlock:
> + spin_unlock_irqrestore(&domain->reserved_lock, flags);
> + return iova;
> +}
> +
> +int iommu_msi_mapping_translate_msg(struct irq_data *data, struct msi_msg *msg)
> +{
I'm really not keen on passing a full irq_data to something that doesn't
really care about it. What this really needs is the device that
generates the MSIs, which makes a lot more sense (you get the device and
the address from the msi_msg).
Or am I getting it wrong?
> + struct iommu_domain *d;
> + struct msi_desc *desc;
> + dma_addr_t iova;
> +
> + desc = irq_data_get_msi_desc(data);
> + if (!desc)
> + return -EINVAL;
> +
> + d = iommu_msi_mapping_desc_to_domain(desc);
> + if (!d)
> + return 0;
> +
> + iova = iommu_find_reserved_iova(d, msg_to_phys_addr(msg),
> + sizeof(phys_addr_t));
> +
> + if (iova == DMA_ERROR_CODE)
> + return -EINVAL;
> +
> + msg->address_lo = lower_32_bits(iova);
> + msg->address_hi = upper_32_bits(iova);
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(iommu_msi_mapping_translate_msg);
> diff --git a/include/linux/dma-reserved-iommu.h b/include/linux/dma-reserved-iommu.h
> index 8373929..04e1912f 100644
> --- a/include/linux/dma-reserved-iommu.h
> +++ b/include/linux/dma-reserved-iommu.h
> @@ -20,6 +20,8 @@
>
> struct iommu_domain;
> struct msi_desc;
> +struct irq_data;
> +struct msi_msg;
>
> #ifdef CONFIG_IOMMU_DMA_RESERVED
>
> @@ -82,6 +84,25 @@ void iommu_put_reserved_iova(struct iommu_domain *domain, phys_addr_t addr);
> */
> struct iommu_domain *iommu_msi_mapping_desc_to_domain(struct msi_desc *desc);
>
> +/**
> + * iommu_msi_mapping_translate_msg: in case the MSI transaction is translated
> + * by an IOMMU, the msg address must be an IOVA instead of a physical address.
> + * This function overwrites the original MSI message containing the doorbell
> + * physical address, result of the primary composition, with the doorbell IOVA.
> + *
> + * The doorbell physical address must be bound previously to an IOVA using
> + * iommu_get_reserved_iova
> + *
> + * @data: irq data handle
> + * @msg: original msi message containing the PA to be overwritten with
> + * the IOVA
> + *
> + * return 0 if the MSI does not need to be mapped or when the PA/IOVA
> + * were successfully swapped; return -EINVAL if the addresses need
> + * to be swapped but not IOMMU binding is found
> + */
> +int iommu_msi_mapping_translate_msg(struct irq_data *data, struct msi_msg *msg);
> +
> #else
>
> static inline int
> @@ -111,5 +132,11 @@ iommu_msi_mapping_desc_to_domain(struct msi_desc *desc)
> return NULL;
> }
>
> +static inline int iommu_msi_mapping_translate_msg(struct irq_data *data,
> + struct msi_msg *msg)
> +{
> + return 0;
> +}
> +
> #endif /* CONFIG_IOMMU_DMA_RESERVED */
> #endif /* __DMA_RESERVED_IOMMU_H */
>
Thanks,
M.
--
Jazz is not dead. It just smells funny...
[toc] | [prev] | [next] | [standalone]
| From | Eric Auger <eric.auger@linaro.org> |
|---|---|
| Date | 2016-04-20 15:00 +0200 |
| Subject | Re: [PATCH v7 09/10] iommu/dma-reserved-iommu: iommu_msi_mapping_translate_msg |
| Message-ID | <rpZTz-834-3@gated-at.bofh.it> |
| In reply to | #1383208 |
On 04/20/2016 11:38 AM, Marc Zyngier wrote:
> On 19/04/16 17:56, Eric Auger wrote:
>> Introduce iommu_msi_mapping_translate_msg whose role consists in
>> detecting whether the device's MSIs must to be mapped into an IOMMU.
>> It case it must, the function overrides the MSI msg originally composed
>> and replaces the doorbell's PA by a pre-allocated and pre-mapped reserved
>> IOVA. In case the corresponding PA region is not found, the function
>> returns an error.
>>
>> This function is likely to be called in some code that cannot sleep. This
>> is the reason why the allocation/mapping is done separately.
>>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>
>> ---
>>
>> v7: creation
>> ---
>> drivers/iommu/dma-reserved-iommu.c | 69 ++++++++++++++++++++++++++++++++++++++
>> include/linux/dma-reserved-iommu.h | 27 +++++++++++++++
>> 2 files changed, 96 insertions(+)
>>
>> diff --git a/drivers/iommu/dma-reserved-iommu.c b/drivers/iommu/dma-reserved-iommu.c
>> index 907a17f..603ee45 100644
>> --- a/drivers/iommu/dma-reserved-iommu.c
>> +++ b/drivers/iommu/dma-reserved-iommu.c
>> @@ -18,6 +18,14 @@
>> #include <linux/iommu.h>
>> #include <linux/iova.h>
>> #include <linux/msi.h>
>> +#include <linux/irq.h>
>> +
>> +#ifdef CONFIG_PHYS_ADDR_T_64BIT
>> +#define msg_to_phys_addr(msg) \
>> + (((phys_addr_t)((msg)->address_hi) << 32) | (msg)->address_lo)
>> +#else
>> +#define msg_to_phys_addr(msg) ((msg)->address_lo)
>> +#endif
>>
>> struct reserved_iova_domain {
>> struct iova_domain *iovad;
>> @@ -351,3 +359,64 @@ struct iommu_domain *iommu_msi_mapping_desc_to_domain(struct msi_desc *desc)
>> return d;
>> }
>> EXPORT_SYMBOL_GPL(iommu_msi_mapping_desc_to_domain);
>> +
>> +static dma_addr_t iommu_find_reserved_iova(struct iommu_domain *domain,
>> + phys_addr_t addr, size_t size)
>> +{
>> + unsigned long base_pfn, end_pfn, nb_iommu_pages, order, flags;
>> + size_t iommu_page_size, binding_size;
>> + struct iommu_reserved_binding *b;
>> + phys_addr_t aligned_base, offset;
>> + dma_addr_t iova = DMA_ERROR_CODE;
>> + struct iova_domain *iovad;
>> +
>> + spin_lock_irqsave(&domain->reserved_lock, flags);
>> +
>> + iovad = (struct iova_domain *)domain->reserved_iova_cookie;
>> +
>> + if (!iovad)
>> + goto unlock;
>> +
>> + order = iova_shift(iovad);
>> + base_pfn = addr >> order;
>> + end_pfn = (addr + size - 1) >> order;
>> + aligned_base = base_pfn << order;
>> + offset = addr - aligned_base;
>> + nb_iommu_pages = end_pfn - base_pfn + 1;
>> + iommu_page_size = 1 << order;
>> + binding_size = nb_iommu_pages * iommu_page_size;
>> +
>> + b = find_reserved_binding(domain, aligned_base, binding_size);
>> + if (b && (b->addr <= aligned_base) &&
>> + (aligned_base + binding_size <= b->addr + b->size))
>> + iova = b->iova + offset + aligned_base - b->addr;
>> +unlock:
>> + spin_unlock_irqrestore(&domain->reserved_lock, flags);
>> + return iova;
>> +}
>> +
>> +int iommu_msi_mapping_translate_msg(struct irq_data *data, struct msi_msg *msg)
>> +{
>
> I'm really not keen on passing a full irq_data to something that doesn't
> really care about it. What this really needs is the device that
> generates the MSIs, which makes a lot more sense (you get the device and
> the address from the msi_msg).
>
> Or am I getting it wrong?
No I have no objection. I eventually decided to keep the irq_data*
parameter to be homegeneous with irq_chip_compose_msi_msg and I found
the function name understandable. However I also understand it looks
weird to get this irq-data incursion in this API
will change into iommu_msi_msg_pa_to_va, as you proposed.
Thank you for your time
Eric
>
>> + struct iommu_domain *d;
>> + struct msi_desc *desc;
>> + dma_addr_t iova;
>> +
>> + desc = irq_data_get_msi_desc(data);
>> + if (!desc)
>> + return -EINVAL;
>> +
>> + d = iommu_msi_mapping_desc_to_domain(desc);
>> + if (!d)
>> + return 0;
>> +
>> + iova = iommu_find_reserved_iova(d, msg_to_phys_addr(msg),
>> + sizeof(phys_addr_t));
>> +
>> + if (iova == DMA_ERROR_CODE)
>> + return -EINVAL;
>> +
>> + msg->address_lo = lower_32_bits(iova);
>> + msg->address_hi = upper_32_bits(iova);
>> + return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(iommu_msi_mapping_translate_msg);
>> diff --git a/include/linux/dma-reserved-iommu.h b/include/linux/dma-reserved-iommu.h
>> index 8373929..04e1912f 100644
>> --- a/include/linux/dma-reserved-iommu.h
>> +++ b/include/linux/dma-reserved-iommu.h
>> @@ -20,6 +20,8 @@
>>
>> struct iommu_domain;
>> struct msi_desc;
>> +struct irq_data;
>> +struct msi_msg;
>>
>> #ifdef CONFIG_IOMMU_DMA_RESERVED
>>
>> @@ -82,6 +84,25 @@ void iommu_put_reserved_iova(struct iommu_domain *domain, phys_addr_t addr);
>> */
>> struct iommu_domain *iommu_msi_mapping_desc_to_domain(struct msi_desc *desc);
>>
>> +/**
>> + * iommu_msi_mapping_translate_msg: in case the MSI transaction is translated
>> + * by an IOMMU, the msg address must be an IOVA instead of a physical address.
>> + * This function overwrites the original MSI message containing the doorbell
>> + * physical address, result of the primary composition, with the doorbell IOVA.
>> + *
>> + * The doorbell physical address must be bound previously to an IOVA using
>> + * iommu_get_reserved_iova
>> + *
>> + * @data: irq data handle
>> + * @msg: original msi message containing the PA to be overwritten with
>> + * the IOVA
>> + *
>> + * return 0 if the MSI does not need to be mapped or when the PA/IOVA
>> + * were successfully swapped; return -EINVAL if the addresses need
>> + * to be swapped but not IOMMU binding is found
>> + */
>> +int iommu_msi_mapping_translate_msg(struct irq_data *data, struct msi_msg *msg);
>> +
>> #else
>>
>> static inline int
>> @@ -111,5 +132,11 @@ iommu_msi_mapping_desc_to_domain(struct msi_desc *desc)
>> return NULL;
>> }
>>
>> +static inline int iommu_msi_mapping_translate_msg(struct irq_data *data,
>> + struct msi_msg *msg)
>> +{
>> + return 0;
>> +}
>> +
>> #endif /* CONFIG_IOMMU_DMA_RESERVED */
>> #endif /* __DMA_RESERVED_IOMMU_H */
>>
>
> Thanks,
>
> M.
>
[toc] | [prev] | [next] | [standalone]
| From | Robin Murphy <robin.murphy@arm.com> |
|---|---|
| Date | 2016-04-20 19:30 +0200 |
| Subject | Re: [PATCH v7 09/10] iommu/dma-reserved-iommu: iommu_msi_mapping_translate_msg |
| Message-ID | <rq46S-33d-15@gated-at.bofh.it> |
| In reply to | #1382712 |
On 19/04/16 17:56, Eric Auger wrote:
> Introduce iommu_msi_mapping_translate_msg whose role consists in
> detecting whether the device's MSIs must to be mapped into an IOMMU.
> It case it must, the function overrides the MSI msg originally composed
> and replaces the doorbell's PA by a pre-allocated and pre-mapped reserved
> IOVA. In case the corresponding PA region is not found, the function
> returns an error.
>
> This function is likely to be called in some code that cannot sleep. This
> is the reason why the allocation/mapping is done separately.
>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>
> ---
>
> v7: creation
> ---
> drivers/iommu/dma-reserved-iommu.c | 69 ++++++++++++++++++++++++++++++++++++++
> include/linux/dma-reserved-iommu.h | 27 +++++++++++++++
> 2 files changed, 96 insertions(+)
>
> diff --git a/drivers/iommu/dma-reserved-iommu.c b/drivers/iommu/dma-reserved-iommu.c
> index 907a17f..603ee45 100644
> --- a/drivers/iommu/dma-reserved-iommu.c
> +++ b/drivers/iommu/dma-reserved-iommu.c
> @@ -18,6 +18,14 @@
> #include <linux/iommu.h>
> #include <linux/iova.h>
> #include <linux/msi.h>
> +#include <linux/irq.h>
> +
> +#ifdef CONFIG_PHYS_ADDR_T_64BIT
> +#define msg_to_phys_addr(msg) \
> + (((phys_addr_t)((msg)->address_hi) << 32) | (msg)->address_lo)
> +#else
> +#define msg_to_phys_addr(msg) ((msg)->address_lo)
> +#endif
>
> struct reserved_iova_domain {
> struct iova_domain *iovad;
> @@ -351,3 +359,64 @@ struct iommu_domain *iommu_msi_mapping_desc_to_domain(struct msi_desc *desc)
> return d;
> }
> EXPORT_SYMBOL_GPL(iommu_msi_mapping_desc_to_domain);
> +
> +static dma_addr_t iommu_find_reserved_iova(struct iommu_domain *domain,
> + phys_addr_t addr, size_t size)
> +{
> + unsigned long base_pfn, end_pfn, nb_iommu_pages, order, flags;
> + size_t iommu_page_size, binding_size;
> + struct iommu_reserved_binding *b;
> + phys_addr_t aligned_base, offset;
> + dma_addr_t iova = DMA_ERROR_CODE;
> + struct iova_domain *iovad;
> +
> + spin_lock_irqsave(&domain->reserved_lock, flags);
> +
> + iovad = (struct iova_domain *)domain->reserved_iova_cookie;
> +
> + if (!iovad)
> + goto unlock;
> +
> + order = iova_shift(iovad);
> + base_pfn = addr >> order;
> + end_pfn = (addr + size - 1) >> order;
> + aligned_base = base_pfn << order;
> + offset = addr - aligned_base;
> + nb_iommu_pages = end_pfn - base_pfn + 1;
> + iommu_page_size = 1 << order;
> + binding_size = nb_iommu_pages * iommu_page_size;
This all looks rather familiar...
> + b = find_reserved_binding(domain, aligned_base, binding_size);
...which implies that at least some of it should be factored into that guy.
> + if (b && (b->addr <= aligned_base) &&
> + (aligned_base + binding_size <= b->addr + b->size))
> + iova = b->iova + offset + aligned_base - b->addr;
> +unlock:
> + spin_unlock_irqrestore(&domain->reserved_lock, flags);
> + return iova;
> +}
> +
> +int iommu_msi_mapping_translate_msg(struct irq_data *data, struct msi_msg *msg)
> +{
> + struct iommu_domain *d;
> + struct msi_desc *desc;
> + dma_addr_t iova;
> +
> + desc = irq_data_get_msi_desc(data);
> + if (!desc)
> + return -EINVAL;
> +
> + d = iommu_msi_mapping_desc_to_domain(desc);
> + if (!d)
> + return 0;
> +
> + iova = iommu_find_reserved_iova(d, msg_to_phys_addr(msg),
> + sizeof(phys_addr_t));
> +
> + if (iova == DMA_ERROR_CODE)
> + return -EINVAL;
> +
> + msg->address_lo = lower_32_bits(iova);
> + msg->address_hi = upper_32_bits(iova);
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(iommu_msi_mapping_translate_msg);
> diff --git a/include/linux/dma-reserved-iommu.h b/include/linux/dma-reserved-iommu.h
> index 8373929..04e1912f 100644
> --- a/include/linux/dma-reserved-iommu.h
> +++ b/include/linux/dma-reserved-iommu.h
> @@ -20,6 +20,8 @@
>
> struct iommu_domain;
> struct msi_desc;
> +struct irq_data;
> +struct msi_msg;
>
> #ifdef CONFIG_IOMMU_DMA_RESERVED
>
> @@ -82,6 +84,25 @@ void iommu_put_reserved_iova(struct iommu_domain *domain, phys_addr_t addr);
> */
> struct iommu_domain *iommu_msi_mapping_desc_to_domain(struct msi_desc *desc);
>
> +/**
> + * iommu_msi_mapping_translate_msg: in case the MSI transaction is translated
> + * by an IOMMU, the msg address must be an IOVA instead of a physical address.
> + * This function overwrites the original MSI message containing the doorbell
> + * physical address, result of the primary composition, with the doorbell IOVA.
> + *
> + * The doorbell physical address must be bound previously to an IOVA using
> + * iommu_get_reserved_iova
> + *
> + * @data: irq data handle
> + * @msg: original msi message containing the PA to be overwritten with
> + * the IOVA
> + *
> + * return 0 if the MSI does not need to be mapped or when the PA/IOVA
> + * were successfully swapped; return -EINVAL if the addresses need
> + * to be swapped but not IOMMU binding is found
> + */
> +int iommu_msi_mapping_translate_msg(struct irq_data *data, struct msi_msg *msg);
> +
> #else
>
> static inline int
> @@ -111,5 +132,11 @@ iommu_msi_mapping_desc_to_domain(struct msi_desc *desc)
> return NULL;
> }
>
> +static inline int iommu_msi_mapping_translate_msg(struct irq_data *data,
> + struct msi_msg *msg)
> +{
> + return 0;
> +}
> +
> #endif /* CONFIG_IOMMU_DMA_RESERVED */
> #endif /* __DMA_RESERVED_IOMMU_H */
>
[toc] | [prev] | [next] | [standalone]
| From | Eric Auger <eric.auger@linaro.org> |
|---|---|
| Date | 2016-04-21 10:50 +0200 |
| Subject | Re: [PATCH v7 09/10] iommu/dma-reserved-iommu: iommu_msi_mapping_translate_msg |
| Message-ID | <rqitc-6j1-43@gated-at.bofh.it> |
| In reply to | #1383579 |
On 04/20/2016 07:28 PM, Robin Murphy wrote:
> On 19/04/16 17:56, Eric Auger wrote:
>> Introduce iommu_msi_mapping_translate_msg whose role consists in
>> detecting whether the device's MSIs must to be mapped into an IOMMU.
>> It case it must, the function overrides the MSI msg originally composed
>> and replaces the doorbell's PA by a pre-allocated and pre-mapped reserved
>> IOVA. In case the corresponding PA region is not found, the function
>> returns an error.
>>
>> This function is likely to be called in some code that cannot sleep. This
>> is the reason why the allocation/mapping is done separately.
>>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>
>> ---
>>
>> v7: creation
>> ---
>> drivers/iommu/dma-reserved-iommu.c | 69
>> ++++++++++++++++++++++++++++++++++++++
>> include/linux/dma-reserved-iommu.h | 27 +++++++++++++++
>> 2 files changed, 96 insertions(+)
>>
>> diff --git a/drivers/iommu/dma-reserved-iommu.c
>> b/drivers/iommu/dma-reserved-iommu.c
>> index 907a17f..603ee45 100644
>> --- a/drivers/iommu/dma-reserved-iommu.c
>> +++ b/drivers/iommu/dma-reserved-iommu.c
>> @@ -18,6 +18,14 @@
>> #include <linux/iommu.h>
>> #include <linux/iova.h>
>> #include <linux/msi.h>
>> +#include <linux/irq.h>
>> +
>> +#ifdef CONFIG_PHYS_ADDR_T_64BIT
>> +#define msg_to_phys_addr(msg) \
>> + (((phys_addr_t)((msg)->address_hi) << 32) | (msg)->address_lo)
>> +#else
>> +#define msg_to_phys_addr(msg) ((msg)->address_lo)
>> +#endif
>>
>> struct reserved_iova_domain {
>> struct iova_domain *iovad;
>> @@ -351,3 +359,64 @@ struct iommu_domain
>> *iommu_msi_mapping_desc_to_domain(struct msi_desc *desc)
>> return d;
>> }
>> EXPORT_SYMBOL_GPL(iommu_msi_mapping_desc_to_domain);
>> +
>> +static dma_addr_t iommu_find_reserved_iova(struct iommu_domain *domain,
>> + phys_addr_t addr, size_t size)
>> +{
>> + unsigned long base_pfn, end_pfn, nb_iommu_pages, order, flags;
>> + size_t iommu_page_size, binding_size;
>> + struct iommu_reserved_binding *b;
>> + phys_addr_t aligned_base, offset;
>> + dma_addr_t iova = DMA_ERROR_CODE;
>> + struct iova_domain *iovad;
>> +
>> + spin_lock_irqsave(&domain->reserved_lock, flags);
>> +
>> + iovad = (struct iova_domain *)domain->reserved_iova_cookie;
>> +
>> + if (!iovad)
>> + goto unlock;
>> +
>> + order = iova_shift(iovad);
>> + base_pfn = addr >> order;
>> + end_pfn = (addr + size - 1) >> order;
>> + aligned_base = base_pfn << order;
>> + offset = addr - aligned_base;
>> + nb_iommu_pages = end_pfn - base_pfn + 1;
>> + iommu_page_size = 1 << order;
>> + binding_size = nb_iommu_pages * iommu_page_size;
>
> This all looks rather familiar...
>
>> + b = find_reserved_binding(domain, aligned_base, binding_size);
>
> ...which implies that at least some of it should be factored into that guy.
ok. Besides, with your compact rewriting proposal, maybe it is not worth
anymore ;-)
Eric
>
>> + if (b && (b->addr <= aligned_base) &&
>> + (aligned_base t + binding_size <= b->addr + b->size))
>> + iova = b->iova + offset + aligned_base - b->addr;
>> +unlock:
>> + spin_unlock_irqrestore(&domain->reserved_lock, flags);
>> + return iova;
>> +}
>> +
>> +int iommu_msi_mapping_translate_msg(struct irq_data *data, struct
>> msi_msg *msg)
>> +{
>> + struct iommu_domain *d;
>> + struct msi_desc *desc;
>> + dma_addr_t iova;
>> +
>> + desc = irq_data_get_msi_desc(data);
>> + if (!desc)
>> + return -EINVAL;
>> +
>> + d = iommu_msi_mapping_desc_to_domain(desc);
>> + if (!d)
>> + return 0;
>> +
>> + iova = iommu_find_reserved_iova(d, msg_to_phys_addr(msg),
>> + sizeof(phys_addr_t));
>> +
>> + if (iova == DMA_ERROR_CODE)
>> + return -EINVAL;
>> +
>> + msg->address_lo = lower_32_bits(iova);
>> + msg->address_hi = upper_32_bits(iova);
>> + return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(iommu_msi_mapping_translate_msg);
>> diff --git a/include/linux/dma-reserved-iommu.h
>> b/include/linux/dma-reserved-iommu.h
>> index 8373929..04e1912f 100644
>> --- a/include/linux/dma-reserved-iommu.h
>> +++ b/include/linux/dma-reserved-iommu.h
>> @@ -20,6 +20,8 @@
>>
>> struct iommu_domain;
>> struct msi_desc;
>> +struct irq_data;
>> +struct msi_msg;
>>
>> #ifdef CONFIG_IOMMU_DMA_RESERVED
>>
>> @@ -82,6 +84,25 @@ void iommu_put_reserved_iova(struct iommu_domain
>> *domain, phys_addr_t addr);
>> */
>> struct iommu_domain *iommu_msi_mapping_desc_to_domain(struct
>> msi_desc *desc);
>>
>> +/**
>> + * iommu_msi_mapping_translate_msg: in case the MSI transaction is
>> translated
>> + * by an IOMMU, the msg address must be an IOVA instead of a physical
>> address.
>> + * This function overwrites the original MSI message containing the
>> doorbell
>> + * physical address, result of the primary composition, with the
>> doorbell IOVA.
>> + *
>> + * The doorbell physical address must be bound previously to an IOVA
>> using
>> + * iommu_get_reserved_iova
>> + *
>> + * @data: irq data handle
>> + * @msg: original msi message containing the PA to be overwritten with
>> + * the IOVA
>> + *
>> + * return 0 if the MSI does not need to be mapped or when the PA/IOVA
>> + * were successfully swapped; return -EINVAL if the addresses need
>> + * to be swapped but not IOMMU binding is found
>> + */
>> +int iommu_msi_mapping_translate_msg(struct irq_data *data, struct
>> msi_msg *msg);
>> +
>> #else
>>
>> static inline int
>> @@ -111,5 +132,11 @@ iommu_msi_mapping_desc_to_domain(struct msi_desc
>> *desc)
>> return NULL;
>> }
>>
>> +static inline int iommu_msi_mapping_translate_msg(struct irq_data *data,
>> + struct msi_msg *msg)
>> +{
>> + return 0;
>> +}
>> +
>> #endif /* CONFIG_IOMMU_DMA_RESERVED */
>> #endif /* __DMA_RESERVED_IOMMU_H */
>>
>
[toc] | [prev] | [next] | [standalone]
| From | Eric Auger <eric.auger@linaro.org> |
|---|---|
| Date | 2016-04-21 14:20 +0200 |
| Subject | Re: [PATCH v7 00/10] KVM PCIe/MSI passthrough on ARM/ARM64: kernel part 1/3: iommu changes |
| Message-ID | <rqlKq-zM-13@gated-at.bofh.it> |
| In reply to | #1382709 |
Hi Alex, Robin, On 04/19/2016 06:56 PM, Eric Auger wrote: > This series introduces the dma-reserved-iommu api used to: > > - create/destroy an iova domain dedicated to reserved iova bindings > - map/unmap physical addresses onto reserved IOVAs. > - search for an existing reserved iova mapping matching a PA window > - determine whether an msi needs to be iommu mapped > - translate an msi_msg PA address into its IOVA counterpart Following Robin's review, I understand one important point we have to clarify is how much this API has to be generic. I agree with Robin on the fact there is quite a lot of duplication between this dma-reserved-iommu implementation and dma-iommu implementation. Maybe we could consider an msi-mapping API implementation upon dma-iommu.c. This implementation would add MSI doorbell binding list management, including, ref counting and locking. We would need to add a map/unmap function taking an iova/pa/size as parameters in current dma-iommu.c An important assumption is that the dma-mapping API and the msi-mapping API must not be used concurrently (be would be trying to use the same cookie to store a different iova_domain). Any thought/suggestion? Best Regards Eric > > Currently reserved IOVAs are meant to map MSI physical doorbells. A single > reserved domain does exit per domain. > > Also a new domain attribute is introduced to signal whether the MSI > addresses must be mapped in the IOMMU. > > In current usage: > VFIO subsystem is supposed to create/destroy the iommu reserved domain. > The MSI layer is supposed to allocate/free iova mappings > > Since several drivers are likely to use the same doorbell, a reference > counting takes place on the bindings. An RB-tree indexed by PA is used > to easily lookup for existing mappings at MSI message composition time. > > More details & context can be found at: > http://www.linaro.org/blog/core-dump/kvm-pciemsi-passthrough-armarm64/ > > Best Regards > > Eric > > Git: complete series available at > https://git.linaro.org/people/eric.auger/linux.git/shortlog/refs/heads/v4.6-rc4-pcie-passthrough-v7 > > History: > > v6 -> v7: > - fixed known lock bugs and multiple page sized slots matching > (I currently only have a single MSI frame made of a single page) > - reserved_iova_cookie now pointing to a struct that encapsulates the > iova domain handle + protection attribute passed from VFIO (Alex' req) > - 2 new functions exposed: iommu_msi_mapping_translate_msg, > iommu_msi_mapping_desc_to_domain: not sure this is the right location/proto > though > - iommu_put_reserved_iova now takes a phys_addr_t > - everything now is cleanup on iommu_domain destruction > > RFC v5 -> patch v6: > - split to ease the review process > - in dma-reserved-api use a spin lock instead of a mutex (reported by > Jean-Philippe) > - revisit iommu_get_reserved_iova API to pass a size parameter upon > Marc's request > - Consistently use the page order passed when creating the iova domain. > - init reserved_binding_list (reported by Julien) > > RFC v4 -> RFC v5: > - take into account Thomas' comments on MSI related patches > - split "msi: IOMMU map the doorbell address when needed" > - increase readability and add comments > - fix style issues > - split "iommu: Add DOMAIN_ATTR_MSI_MAPPING attribute" > - platform ITS now advertises IOMMU_CAP_INTR_REMAP > - fix compilation issue with CONFIG_IOMMU API unset > - arm-smmu-v3 now advertises DOMAIN_ATTR_MSI_MAPPING > > RFC v3 -> v4: > - Move doorbell mapping/unmapping in msi.c > - fix ref count issue on set_affinity: in case of a change in the address > the previous address is decremented > - doorbell map/unmap now is done on msi composition. Should allow the use > case for platform MSI controllers > - create dma-reserved-iommu.h/c exposing/implementing a new API dedicated > to reserved IOVA management (looking like dma-iommu glue) > - series reordering to ease the review: > - first part is related to IOMMU > - second related to MSI sub-system > - third related to VFIO (except arm-smmu IOMMU_CAP_INTR_REMAP removal) > - expose the number of requested IOVA pages through VFIO_IOMMU_GET_INFO > [this partially addresses Marc's comments on iommu_get/put_single_reserved > size/alignment problematic - which I did not ignore - but I don't know > how much I can do at the moment] > > RFC v2 -> RFC v3: > - should fix wrong handling of some CONFIG combinations: > CONFIG_IOVA, CONFIG_IOMMU_API, CONFIG_PCI_MSI_IRQ_DOMAIN > - fix MSI_FLAG_IRQ_REMAPPING setting in GICv3 ITS (although not tested) > > PATCH v1 -> RFC v2: > - reverted to RFC since it looks more reasonable ;-) the code is split > between VFIO, IOMMU, MSI controller and I am not sure I did the right > choices. Also API need to be further discussed. > - iova API usage in arm-smmu.c. > - MSI controller natively programs the MSI addr with either the PA or IOVA. > This is not done anymore in vfio-pci driver as suggested by Alex. > - check irq remapping capability of the group > > RFC v1 [2] -> PATCH v1: > - use the existing dma map/unmap ioctl interface with a flag to register a > reserved IOVA range. Use the legacy Rb to store this special vfio_dma. > - a single reserved IOVA contiguous region now is allowed > - use of an RB tree indexed by PA to store allocated reserved slots > - use of a vfio_domain iova_domain to manage iova allocation within the > window provided by the userspace > - vfio alloc_map/unmap_free take a vfio_group handle > - vfio_group handle is cached in vfio_pci_device > - add ref counting to bindings > - user modality enabled at the end of the series > > > Eric Auger (10): > iommu: Add DOMAIN_ATTR_MSI_MAPPING attribute > iommu/arm-smmu: advertise DOMAIN_ATTR_MSI_MAPPING attribute > iommu: introduce a reserved iova cookie > iommu/dma-reserved-iommu: alloc/free_reserved_iova_domain > iommu/dma-reserved-iommu: reserved binding rb-tree and helpers > iommu/dma-reserved-iommu: iommu_get/put_reserved_iova > iommu/dma-reserved-iommu: delete bindings in > iommu_free_reserved_iova_domain > iommu/dma-reserved_iommu: iommu_msi_mapping_desc_to_domain > iommu/dma-reserved-iommu: iommu_msi_mapping_translate_msg > iommu/arm-smmu: call iommu_free_reserved_iova_domain on domain > destruction > > drivers/iommu/Kconfig | 8 + > drivers/iommu/Makefile | 1 + > drivers/iommu/arm-smmu-v3.c | 4 + > drivers/iommu/arm-smmu.c | 4 + > drivers/iommu/dma-reserved-iommu.c | 422 +++++++++++++++++++++++++++++++++++++ > drivers/iommu/iommu.c | 2 + > include/linux/dma-reserved-iommu.h | 142 +++++++++++++ > include/linux/iommu.h | 7 + > 8 files changed, 590 insertions(+) > create mode 100644 drivers/iommu/dma-reserved-iommu.c > create mode 100644 include/linux/dma-reserved-iommu.h >
[toc] | [prev] | [next] | [standalone]
| From | Alex Williamson <alex.williamson@redhat.com> |
|---|---|
| Date | 2016-04-21 21:40 +0200 |
| Subject | Re: [PATCH v7 00/10] KVM PCIe/MSI passthrough on ARM/ARM64: kernel part 1/3: iommu changes |
| Message-ID | <rqsCe-69j-19@gated-at.bofh.it> |
| In reply to | #1384142 |
On Thu, 21 Apr 2016 14:18:09 +0200
Eric Auger <eric.auger@linaro.org> wrote:
> Hi Alex, Robin,
> On 04/19/2016 06:56 PM, Eric Auger wrote:
> > This series introduces the dma-reserved-iommu api used to:
> >
> > - create/destroy an iova domain dedicated to reserved iova bindings
> > - map/unmap physical addresses onto reserved IOVAs.
> > - search for an existing reserved iova mapping matching a PA window
> > - determine whether an msi needs to be iommu mapped
> > - translate an msi_msg PA address into its IOVA counterpart
>
> Following Robin's review, I understand one important point we have to
> clarify is how much this API has to be generic.
>
> I agree with Robin on the fact there is quite a lot of duplication
> between this dma-reserved-iommu implementation and dma-iommu
> implementation. Maybe we could consider an msi-mapping API
> implementation upon dma-iommu.c. This implementation would add MSI
> doorbell binding list management, including, ref counting and locking.
>
> We would need to add a map/unmap function taking an iova/pa/size as
> parameters in current dma-iommu.c
>
> An important assumption is that the dma-mapping API and the msi-mapping
> API must not be used concurrently (be would be trying to use the same
> cookie to store a different iova_domain).
>
> Any thought/suggestion?
Hi Eric,
I'm not attached to a generic interface, the important part for me is
that if we have an iommu domain with space reserved for MSI, the MSI
setup and allocation code should handle that so we don't need to play
the remapping tricks between vfio-pci and a vfio iommu driver that we
saw in early drafts of this. My first inclination is always to try to
make a generic, re-usable interface, but I apologize if that's led us
astray here and we really do want the more simple, MSI specific
interface.
For the IOMMU API, rather than just a DOMAIN_ATTR_MSI_MAPPING flag,
what about DOMAIN_ATTR_MSI_GEOMETRY with both a get and set attribute?
Maybe something like:
struct iommu_domain_msi_geometry {
dma_addr_t aperture_start;
dma_addr_t aperture_end;
bool fixed; /* or 'programmable' depending on your polarity preference */
};
Calling \get\ on arm would return { 0, 0, false }, indicating it's
programmable, \set\ would allocate the iovad as specified. That would
make it very easy to expand the API to x86 with reporting of the fixed
MSI range and it operates within the existing IOMMU API interfaces.
Thanks,
Alex
[toc] | [prev] | [next] | [standalone]
| From | Eric Auger <eric.auger@linaro.org> |
|---|---|
| Date | 2016-04-22 14:40 +0200 |
| Subject | Re: [PATCH v7 00/10] KVM PCIe/MSI passthrough on ARM/ARM64: kernel part 1/3: iommu changes |
| Message-ID | <rqIxk-1Ux-17@gated-at.bofh.it> |
| In reply to | #1384532 |
Hi Alex,
On 04/21/2016 09:32 PM, Alex Williamson wrote:
> On Thu, 21 Apr 2016 14:18:09 +0200
> Eric Auger <eric.auger@linaro.org> wrote:
>
>> Hi Alex, Robin,
>> On 04/19/2016 06:56 PM, Eric Auger wrote:
>>> This series introduces the dma-reserved-iommu api used to:
>>>
>>> - create/destroy an iova domain dedicated to reserved iova bindings
>>> - map/unmap physical addresses onto reserved IOVAs.
>>> - search for an existing reserved iova mapping matching a PA window
>>> - determine whether an msi needs to be iommu mapped
>>> - translate an msi_msg PA address into its IOVA counterpart
>>
>> Following Robin's review, I understand one important point we have to
>> clarify is how much this API has to be generic.
>>
>> I agree with Robin on the fact there is quite a lot of duplication
>> between this dma-reserved-iommu implementation and dma-iommu
>> implementation. Maybe we could consider an msi-mapping API
>> implementation upon dma-iommu.c. This implementation would add MSI
>> doorbell binding list management, including, ref counting and locking.
>>
>> We would need to add a map/unmap function taking an iova/pa/size as
>> parameters in current dma-iommu.c
>>
>> An important assumption is that the dma-mapping API and the msi-mapping
>> API must not be used concurrently (be would be trying to use the same
>> cookie to store a different iova_domain).
>>
>> Any thought/suggestion?
>
> Hi Eric,
>
> I'm not attached to a generic interface, the important part for me is
> that if we have an iommu domain with space reserved for MSI, the MSI
> setup and allocation code should handle that so we don't need to play
> the remapping tricks between vfio-pci and a vfio iommu driver that we
> saw in early drafts of this. My first inclination is always to try to
> make a generic, re-usable interface, but I apologize if that's led us
> astray here and we really do want the more simple, MSI specific
> interface.
>
> For the IOMMU API, rather than just a DOMAIN_ATTR_MSI_MAPPING flag,
> what about DOMAIN_ATTR_MSI_GEOMETRY with both a get and set attribute?
> Maybe something like:
>
> struct iommu_domain_msi_geometry {
> dma_addr_t aperture_start;
> dma_addr_t aperture_end;
> bool fixed; /* or 'programmable' depending on your polarity preference */
> };
>
> Calling \get\ on arm would return { 0, 0, false }, indicating it's
> programmable, \set\ would allocate the iovad as specified. That would
> make it very easy to expand the API to x86 with reporting of the fixed
> MSI range and it operates within the existing IOMMU API interfaces.
> Thanks,
Yes I would be happy to handle this x86 query requirement. I would be
more inclined to define it at "MSI mapping API" level since the IOMMU
API implementation does not handle iova allocation, as Robin argued as
the beginning. When "MSI MAPPING API" CONFIG is unset I would return
default x86 aperture.
Does it make sense?
Best Regards
Eric
>
> Alex
>
[toc] | [prev] | [next] | [standalone]
| From | Alex Williamson <alex.williamson@redhat.com> |
|---|---|
| Date | 2016-04-22 21:10 +0200 |
| Subject | Re: [PATCH v7 00/10] KVM PCIe/MSI passthrough on ARM/ARM64: kernel part 1/3: iommu changes |
| Message-ID | <rqOCK-75k-27@gated-at.bofh.it> |
| In reply to | #1385125 |
On Fri, 22 Apr 2016 14:31:18 +0200
Eric Auger <eric.auger@linaro.org> wrote:
> Hi Alex,
> On 04/21/2016 09:32 PM, Alex Williamson wrote:
> > On Thu, 21 Apr 2016 14:18:09 +0200
> > Eric Auger <eric.auger@linaro.org> wrote:
> >
> >> Hi Alex, Robin,
> >> On 04/19/2016 06:56 PM, Eric Auger wrote:
> >>> This series introduces the dma-reserved-iommu api used to:
> >>>
> >>> - create/destroy an iova domain dedicated to reserved iova bindings
> >>> - map/unmap physical addresses onto reserved IOVAs.
> >>> - search for an existing reserved iova mapping matching a PA window
> >>> - determine whether an msi needs to be iommu mapped
> >>> - translate an msi_msg PA address into its IOVA counterpart
> >>
> >> Following Robin's review, I understand one important point we have to
> >> clarify is how much this API has to be generic.
> >>
> >> I agree with Robin on the fact there is quite a lot of duplication
> >> between this dma-reserved-iommu implementation and dma-iommu
> >> implementation. Maybe we could consider an msi-mapping API
> >> implementation upon dma-iommu.c. This implementation would add MSI
> >> doorbell binding list management, including, ref counting and locking.
> >>
> >> We would need to add a map/unmap function taking an iova/pa/size as
> >> parameters in current dma-iommu.c
> >>
> >> An important assumption is that the dma-mapping API and the msi-mapping
> >> API must not be used concurrently (be would be trying to use the same
> >> cookie to store a different iova_domain).
> >>
> >> Any thought/suggestion?
> >
> > Hi Eric,
> >
> > I'm not attached to a generic interface, the important part for me is
> > that if we have an iommu domain with space reserved for MSI, the MSI
> > setup and allocation code should handle that so we don't need to play
> > the remapping tricks between vfio-pci and a vfio iommu driver that we
> > saw in early drafts of this. My first inclination is always to try to
> > make a generic, re-usable interface, but I apologize if that's led us
> > astray here and we really do want the more simple, MSI specific
> > interface.
> >
> > For the IOMMU API, rather than just a DOMAIN_ATTR_MSI_MAPPING flag,
> > what about DOMAIN_ATTR_MSI_GEOMETRY with both a get and set attribute?
> > Maybe something like:
> >
> > struct iommu_domain_msi_geometry {
> > dma_addr_t aperture_start;
> > dma_addr_t aperture_end;
> > bool fixed; /* or 'programmable' depending on your polarity preference */
> > };
> >
> > Calling \get\ on arm would return { 0, 0, false }, indicating it's
> > programmable, \set\ would allocate the iovad as specified. That would
> > make it very easy to expand the API to x86 with reporting of the fixed
> > MSI range and it operates within the existing IOMMU API interfaces.
> > Thanks,
> Yes I would be happy to handle this x86 query requirement. I would be
> more inclined to define it at "MSI mapping API" level since the IOMMU
> API implementation does not handle iova allocation, as Robin argued as
> the beginning. When "MSI MAPPING API" CONFIG is unset I would return
> default x86 aperture.
>
> Does it make sense?
It's not entirely clear to me if x86 would be participating in this MSI
mapping API given the implicit handling within iommu/irq-remapping.
It might make sense if x86 iommus simply left a gap in their existing
geometry reporting through the iommu api. I guess we'll see in your
next draft ;) Thanks,
Alex
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web