Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1647143 > unrolled thread

[PATCH v7 0/3] PCI/IOMMU: Reserve IOVAs for PCI inbound memory

Started byOza Pawandeep <oza.oza@broadcom.com>
First post2017-05-22 18:50 +0200
Last post2017-05-23 07:10 +0200
Articles 5 — 3 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v7 0/3] PCI/IOMMU: Reserve IOVAs for PCI inbound memory Oza Pawandeep <oza.oza@broadcom.com> - 2017-05-22 18:50 +0200
    [PATCH v7 3/3] IOMMU/PCI: Reserve IOVA for inbound memory for PCI masters Oza Pawandeep <oza.oza@broadcom.com> - 2017-05-22 18:50 +0200
    [PATCH v7 2/3] PCI: Add support for PCI inbound windows resources Oza Pawandeep <oza.oza@broadcom.com> - 2017-05-22 18:50 +0200
    Re: [PATCH v7 0/3] PCI/IOMMU: Reserve IOVAs for PCI inbound memory Alex Williamson <alex.williamson@redhat.com> - 2017-05-22 21:20 +0200
      Re: [PATCH v7 0/3] PCI/IOMMU: Reserve IOVAs for PCI inbound memory Oza Oza <oza.oza@broadcom.com> - 2017-05-23 07:10 +0200

#1647143 — [PATCH v7 0/3] PCI/IOMMU: Reserve IOVAs for PCI inbound memory

FromOza Pawandeep <oza.oza@broadcom.com>
Date2017-05-22 18:50 +0200
Subject[PATCH v7 0/3] PCI/IOMMU: Reserve IOVAs for PCI inbound memory
Message-ID<tJYGR-86U-7@gated-at.bofh.it>
iproc based PCI RC and Stingray SOC has limitaiton of addressing only 512GB
memory at once.

IOVA allocation honors device's coherent_dma_mask/dma_mask.
In PCI case, current code honors DMA mask set by EP, there is no
concept of PCI host bridge dma-mask,  should be there and hence
could truly reflect the limitation of PCI host bridge.

However assuming Linux takes care of largest possible dma_mask, still the
limitation could exist, because of the way memory banks are implemented.

for e.g. memory banks:
<0x00000000 0x80000000 0x0 0x80000000>, /* 2G @ 2G */
<0x00000008 0x80000000 0x3 0x80000000>, /* 14G @ 34G */
<0x00000090 0x00000000 0x4 0x00000000>, /* 16G @ 576G */
<0x000000a0 0x00000000 0x4 0x00000000>; /* 16G @ 640G */

When run User space (SPDK) which internally uses vfio in order to access
PCI EndPoint directly.

Vfio uses huge-pages which could come from 640G/0x000000a0. 
And the way vfio maps the hugepage is to have phys addr as iova,
and ends up calling VFIO_IOMMU_MAP_DMA ends up calling iommu_map,
inturn arm_lpae_map mapping iovas out of range.

So the way kernel allocates IOVA (where it honours device dma_mask) and
the way userspace gets IOVA is different.

dma-ranges = <0x43000000 0x00 0x00 0x00 0x00 0x80 0x00>; will not work.

Instead we have to go for scattered dma-ranges leaving holes.
Hence, we have to reserve IOVA allocations for inbound memory.
The patch-set caters to only addressing IOVA allocation problem.

Changes since v7:
- Robin's comment addressed
where he wanted to remove depedency between IOMMU and OF layer.
- Bjorn Helgaas's comments addressed.

Changes since v6:
- Robin's comments addressed.

Changes since v5:
Changes since v4:
Changes since v3:
Changes since v2:
- minor changes, redudant checkes removed
- removed internal review

Changes since v1:
- address Rob's comments.
- Add a get_dma_ranges() function to of_bus struct..
- Convert existing contents of of_dma_get_range function to
  of_bus_default_dma_get_ranges and adding that to the
  default of_bus struct.
- Make of_dma_get_range call of_bus_match() and then bus->get_dma_ranges.


Oza Pawandeep (3):
  OF/PCI: expose inbound memory interface to PCI RC drivers.
  IOMMU/PCI: reserve IOVA for inbound memory for PCI masters
  PCI: add support for inbound windows resources

 drivers/iommu/dma-iommu.c | 44 ++++++++++++++++++++--
 drivers/of/of_pci.c       | 96 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/pci/probe.c       | 30 +++++++++++++--
 include/linux/of_pci.h    |  7 ++++
 include/linux/pci.h       |  1 +
 5 files changed, 170 insertions(+), 8 deletions(-)

-- 
1.9.1

[toc] | [next] | [standalone]


#1647145 — [PATCH v7 3/3] IOMMU/PCI: Reserve IOVA for inbound memory for PCI masters

FromOza Pawandeep <oza.oza@broadcom.com>
Date2017-05-22 18:50 +0200
Subject[PATCH v7 3/3] IOMMU/PCI: Reserve IOVA for inbound memory for PCI masters
Message-ID<tJYGR-86U-15@gated-at.bofh.it>
In reply to#1647143
This patch reserves the inbound memory holes for PCI masters.
ARM64 based SOCs may have scattered memory banks.
For e.g as iproc based SOC has

<0x00000000 0x80000000 0x0 0x80000000>, /* 2G @ 2G */
<0x00000008 0x80000000 0x3 0x80000000>, /* 14G @ 34G */
<0x00000090 0x00000000 0x4 0x00000000>, /* 16G @ 576G */
<0x000000a0 0x00000000 0x4 0x00000000>; /* 16G @ 640G */

But incoming PCI transaction addressing capability is limited
by host bridge, for example if max incoming window capability
is 512 GB, then 0x00000090 and 0x000000a0 will fall beyond it.

To address this problem, iommu has to avoid allocating IOVA which
are reserved. 

Which in turn does not allocate IOVA if it falls into hole.
and the holes should be reserved before any of the IOVA allocations
can happen.

Signed-off-by: Oza Pawandeep <oza.oza@broadcom.com>

diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 8348f366..efe3d07 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -171,16 +171,15 @@ void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list)
 {
 	struct pci_host_bridge *bridge;
 	struct resource_entry *window;
+	struct iommu_resv_region *region;
+	phys_addr_t start, end;
+	size_t length;
 
 	if (!dev_is_pci(dev))
 		return;
 
 	bridge = pci_find_host_bridge(to_pci_dev(dev)->bus);
 	resource_list_for_each_entry(window, &bridge->windows) {
-		struct iommu_resv_region *region;
-		phys_addr_t start;
-		size_t length;
-
 		if (resource_type(window->res) != IORESOURCE_MEM)
 			continue;
 
@@ -193,6 +192,43 @@ void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list)
 
 		list_add_tail(&region->list, list);
 	}
+
+	/* PCI inbound memory reservation. */
+	start = length = 0;
+	resource_list_for_each_entry(window, &bridge->inbound_windows) {
+		end = window->res->start - window->offset;
+
+		if (start > end) {
+			/* multiple ranges assumed sorted. */
+			pr_warn("PCI: failed to reserve iovas\n");
+			return;
+		}
+
+		if (start != end) {
+			length = end - start - 1;
+			region = iommu_alloc_resv_region(start, length, 0,
+				IOMMU_RESV_RESERVED);
+			if (!region)
+				return;
+
+			list_add_tail(&region->list, list);
+		}
+
+		start += end + length + 1;
+	}
+	/*
+	 * the last dma-range should honour based on the
+	 * 32/64-bit dma addresses.
+	 */
+	if ((start) && (start < DMA_BIT_MASK(sizeof(dma_addr_t) * 8))) {
+		length = DMA_BIT_MASK((sizeof(dma_addr_t) * 8)) - 1;
+		region = iommu_alloc_resv_region(start, length, 0,
+			IOMMU_RESV_RESERVED);
+		if (!region)
+			return;
+
+		list_add_tail(&region->list, list);
+	}
 }
 EXPORT_SYMBOL(iommu_dma_get_resv_regions);
 
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1647150 — [PATCH v7 2/3] PCI: Add support for PCI inbound windows resources

FromOza Pawandeep <oza.oza@broadcom.com>
Date2017-05-22 18:50 +0200
Subject[PATCH v7 2/3] PCI: Add support for PCI inbound windows resources
Message-ID<tJYGS-86U-27@gated-at.bofh.it>
In reply to#1647143
This patch adds support for inbound memory window
for PCI RC drivers.

It defines new function pci_create_root_bus2 which
takes inbound resources as an argument and fills in the
memory resource to PCI internal host bridge structure
as inbound_windows.

Legacy RC driver could continue to use pci_create_root_bus,
but any RC driver who wants to reseve IOVAS for their
inbound memory holes, should use new API pci_create_root_bus2.

Signed-off-by: Oza Pawandeep <oza.oza@broadcom.com>

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 19c8950..a95b9bb 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -531,6 +531,7 @@ struct pci_host_bridge *pci_alloc_host_bridge(size_t priv)
 		return NULL;
 
 	INIT_LIST_HEAD(&bridge->windows);
+	INIT_LIST_HEAD(&bridge->inbound_windows);
 
 	return bridge;
 }
@@ -726,6 +727,7 @@ int pci_register_host_bridge(struct pci_host_bridge *bridge)
 	struct pci_bus *bus, *b;
 	resource_size_t offset;
 	LIST_HEAD(resources);
+	LIST_HEAD(inbound_resources);
 	struct resource *res;
 	char addr[64], *fmt;
 	const char *name;
@@ -739,6 +741,8 @@ int pci_register_host_bridge(struct pci_host_bridge *bridge)
 
 	/* temporarily move resources off the list */
 	list_splice_init(&bridge->windows, &resources);
+	list_splice_init(&bridge->inbound_windows, &inbound_resources);
+
 	bus->sysdata = bridge->sysdata;
 	bus->msi = bridge->msi;
 	bus->ops = bridge->ops;
@@ -794,6 +798,10 @@ int pci_register_host_bridge(struct pci_host_bridge *bridge)
 	else
 		pr_info("PCI host bridge to bus %s\n", name);
 
+	/* Add inbound mem resource. */
+	resource_list_for_each_entry_safe(window, n, &inbound_resources)
+		list_move_tail(&window->node, &bridge->inbound_windows);
+
 	/* Add initial resources to the bus */
 	resource_list_for_each_entry_safe(window, n, &resources) {
 		list_move_tail(&window->node, &bridge->windows);
@@ -2300,7 +2308,8 @@ void __weak pcibios_remove_bus(struct pci_bus *bus)
 
 static struct pci_bus *pci_create_root_bus_msi(struct device *parent,
 		int bus, struct pci_ops *ops, void *sysdata,
-		struct list_head *resources, struct msi_controller *msi)
+		struct list_head *resources, struct list_head *in_res,
+		struct msi_controller *msi)
 {
 	int error;
 	struct pci_host_bridge *bridge;
@@ -2313,6 +2322,9 @@ static struct pci_bus *pci_create_root_bus_msi(struct device *parent,
 	bridge->dev.release = pci_release_host_bridge_dev;
 
 	list_splice_init(resources, &bridge->windows);
+	if (in_res)
+		list_splice_init(in_res, &bridge->inbound_windows);
+
 	bridge->sysdata = sysdata;
 	bridge->busnr = bus;
 	bridge->ops = ops;
@@ -2329,11 +2341,20 @@ static struct pci_bus *pci_create_root_bus_msi(struct device *parent,
 	return NULL;
 }
 
+struct pci_bus *pci_create_root_bus2(struct device *parent, int bus,
+		struct pci_ops *ops, void *sysdata, struct list_head *resources,
+		struct list_head *in_res)
+{
+	return pci_create_root_bus_msi(parent, bus, ops, sysdata,
+				       resources, in_res, NULL);
+}
+EXPORT_SYMBOL_GPL(pci_create_root_bus2);
+
 struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
 		struct pci_ops *ops, void *sysdata, struct list_head *resources)
 {
-	return pci_create_root_bus_msi(parent, bus, ops, sysdata, resources,
-				       NULL);
+	return pci_create_root_bus_msi(parent, bus, ops, sysdata,
+				       resources, NULL, NULL);
 }
 EXPORT_SYMBOL_GPL(pci_create_root_bus);
 
@@ -2415,7 +2436,8 @@ struct pci_bus *pci_scan_root_bus_msi(struct device *parent, int bus,
 			break;
 		}
 
-	b = pci_create_root_bus_msi(parent, bus, ops, sysdata, resources, msi);
+	b = pci_create_root_bus_msi(parent, bus, ops, sysdata,
+				    resources, NULL, msi);
 	if (!b)
 		return NULL;
 
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 33c2b0b..d2df107 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -432,6 +432,7 @@ struct pci_host_bridge {
 	void *sysdata;
 	int busnr;
 	struct list_head windows;	/* resource_entry */
+	struct list_head inbound_windows;	/* inbound memory */
 	void (*release_fn)(struct pci_host_bridge *);
 	void *release_data;
 	struct msi_controller *msi;
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1647285

FromAlex Williamson <alex.williamson@redhat.com>
Date2017-05-22 21:20 +0200
Message-ID<tK122-1cI-21@gated-at.bofh.it>
In reply to#1647143
On Mon, 22 May 2017 22:09:39 +0530
Oza Pawandeep <oza.oza@broadcom.com> wrote:

> iproc based PCI RC and Stingray SOC has limitaiton of addressing only 512GB
> memory at once.
> 
> IOVA allocation honors device's coherent_dma_mask/dma_mask.
> In PCI case, current code honors DMA mask set by EP, there is no
> concept of PCI host bridge dma-mask,  should be there and hence
> could truly reflect the limitation of PCI host bridge.
> 
> However assuming Linux takes care of largest possible dma_mask, still the
> limitation could exist, because of the way memory banks are implemented.
> 
> for e.g. memory banks:
> <0x00000000 0x80000000 0x0 0x80000000>, /* 2G @ 2G */
> <0x00000008 0x80000000 0x3 0x80000000>, /* 14G @ 34G */
> <0x00000090 0x00000000 0x4 0x00000000>, /* 16G @ 576G */
> <0x000000a0 0x00000000 0x4 0x00000000>; /* 16G @ 640G */
> 
> When run User space (SPDK) which internally uses vfio in order to access
> PCI EndPoint directly.
> 
> Vfio uses huge-pages which could come from 640G/0x000000a0. 
> And the way vfio maps the hugepage is to have phys addr as iova,
> and ends up calling VFIO_IOMMU_MAP_DMA ends up calling iommu_map,
> inturn arm_lpae_map mapping iovas out of range.
> 
> So the way kernel allocates IOVA (where it honours device dma_mask) and
> the way userspace gets IOVA is different.
> 
> dma-ranges = <0x43000000 0x00 0x00 0x00 0x00 0x80 0x00>; will not work.
> 
> Instead we have to go for scattered dma-ranges leaving holes.
> Hence, we have to reserve IOVA allocations for inbound memory.
> The patch-set caters to only addressing IOVA allocation problem.


The description here confuses me, with vfio the user owns the iova
allocation problem.  Mappings are only identity mapped if the user
chooses to do so.  The dma_mask of the device is set by the driver and
only relevant to the DMA-API.  vfio is a meta-driver and doesn't know
the dma_mask of any particular device, that's the user's job.  Is the
net result of what's happening here for the vfio case simply to expose
extra reserved regions in sysfs, which the user can then consume to
craft a compatible iova?  Thanks,

Alex

> 
> Changes since v7:
> - Robin's comment addressed
> where he wanted to remove depedency between IOMMU and OF layer.
> - Bjorn Helgaas's comments addressed.
> 
> Changes since v6:
> - Robin's comments addressed.
> 
> Changes since v5:
> Changes since v4:
> Changes since v3:
> Changes since v2:
> - minor changes, redudant checkes removed
> - removed internal review
> 
> Changes since v1:
> - address Rob's comments.
> - Add a get_dma_ranges() function to of_bus struct..
> - Convert existing contents of of_dma_get_range function to
>   of_bus_default_dma_get_ranges and adding that to the
>   default of_bus struct.
> - Make of_dma_get_range call of_bus_match() and then bus->get_dma_ranges.
> 
> 
> Oza Pawandeep (3):
>   OF/PCI: expose inbound memory interface to PCI RC drivers.
>   IOMMU/PCI: reserve IOVA for inbound memory for PCI masters
>   PCI: add support for inbound windows resources
> 
>  drivers/iommu/dma-iommu.c | 44 ++++++++++++++++++++--
>  drivers/of/of_pci.c       | 96 +++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/pci/probe.c       | 30 +++++++++++++--
>  include/linux/of_pci.h    |  7 ++++
>  include/linux/pci.h       |  1 +
>  5 files changed, 170 insertions(+), 8 deletions(-)
> 

[toc] | [prev] | [next] | [standalone]


#1647632

FromOza Oza <oza.oza@broadcom.com>
Date2017-05-23 07:10 +0200
Message-ID<tKaeZ-77l-9@gated-at.bofh.it>
In reply to#1647285
On Tue, May 23, 2017 at 12:48 AM, Alex Williamson
<alex.williamson@redhat.com> wrote:
> On Mon, 22 May 2017 22:09:39 +0530
> Oza Pawandeep <oza.oza@broadcom.com> wrote:
>
>> iproc based PCI RC and Stingray SOC has limitaiton of addressing only 512GB
>> memory at once.
>>
>> IOVA allocation honors device's coherent_dma_mask/dma_mask.
>> In PCI case, current code honors DMA mask set by EP, there is no
>> concept of PCI host bridge dma-mask,  should be there and hence
>> could truly reflect the limitation of PCI host bridge.
>>
>> However assuming Linux takes care of largest possible dma_mask, still the
>> limitation could exist, because of the way memory banks are implemented.
>>
>> for e.g. memory banks:
>> <0x00000000 0x80000000 0x0 0x80000000>, /* 2G @ 2G */
>> <0x00000008 0x80000000 0x3 0x80000000>, /* 14G @ 34G */
>> <0x00000090 0x00000000 0x4 0x00000000>, /* 16G @ 576G */
>> <0x000000a0 0x00000000 0x4 0x00000000>; /* 16G @ 640G */
>>
>> When run User space (SPDK) which internally uses vfio in order to access
>> PCI EndPoint directly.
>>
>> Vfio uses huge-pages which could come from 640G/0x000000a0.
>> And the way vfio maps the hugepage is to have phys addr as iova,
>> and ends up calling VFIO_IOMMU_MAP_DMA ends up calling iommu_map,
>> inturn arm_lpae_map mapping iovas out of range.
>>
>> So the way kernel allocates IOVA (where it honours device dma_mask) and
>> the way userspace gets IOVA is different.
>>
>> dma-ranges = <0x43000000 0x00 0x00 0x00 0x00 0x80 0x00>; will not work.
>>
>> Instead we have to go for scattered dma-ranges leaving holes.
>> Hence, we have to reserve IOVA allocations for inbound memory.
>> The patch-set caters to only addressing IOVA allocation problem.
>
>
> The description here confuses me, with vfio the user owns the iova
> allocation problem.  Mappings are only identity mapped if the user
> chooses to do so.  The dma_mask of the device is set by the driver and
> only relevant to the DMA-API.  vfio is a meta-driver and doesn't know
> the dma_mask of any particular device, that's the user's job.  Is the
> net result of what's happening here for the vfio case simply to expose
> extra reserved regions in sysfs, which the user can then consume to
> craft a compatible iova?  Thanks,
>
> Alex

Hi Alex,

this is not a VFIO problem, the reason I have mentioned VFIO because,
wanted to bring problem
statement as a whole (which includes both kernel space and user space).
The way SPDK pipeline is set, yes mapping are identity mapped, and
whatever user space passes down IOVA,
VFIO use is as is. which is fine and expected.

But the problem is, user space physical memory (hugepages)  reside
high enough in
memory, which could be beyond PCI RC's capability.

Again, this is not VFIO's problem, neither is of user-space.
In-fact both have nothing to do with dma-mask as well.
My reference of dma-mask was for Linux IOMMU framework (not for VFIO)

Regards,
Oza.
>
>>
>> Changes since v7:
>> - Robin's comment addressed
>> where he wanted to remove depedency between IOMMU and OF layer.
>> - Bjorn Helgaas's comments addressed.
>>
>> Changes since v6:
>> - Robin's comments addressed.
>>
>> Changes since v5:
>> Changes since v4:
>> Changes since v3:
>> Changes since v2:
>> - minor changes, redudant checkes removed
>> - removed internal review
>>
>> Changes since v1:
>> - address Rob's comments.
>> - Add a get_dma_ranges() function to of_bus struct..
>> - Convert existing contents of of_dma_get_range function to
>>   of_bus_default_dma_get_ranges and adding that to the
>>   default of_bus struct.
>> - Make of_dma_get_range call of_bus_match() and then bus->get_dma_ranges.
>>
>>
>> Oza Pawandeep (3):
>>   OF/PCI: expose inbound memory interface to PCI RC drivers.
>>   IOMMU/PCI: reserve IOVA for inbound memory for PCI masters
>>   PCI: add support for inbound windows resources
>>
>>  drivers/iommu/dma-iommu.c | 44 ++++++++++++++++++++--
>>  drivers/of/of_pci.c       | 96 +++++++++++++++++++++++++++++++++++++++++++++++
>>  drivers/pci/probe.c       | 30 +++++++++++++--
>>  include/linux/of_pci.h    |  7 ++++
>>  include/linux/pci.h       |  1 +
>>  5 files changed, 170 insertions(+), 8 deletions(-)
>>
>

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web