Linux-Devicetree Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH 1/7] of/address: Move range parser code out of CONFIG_PCI
       [not found] <20200214224322.20030-1-robh@kernel.org>
@ 2020-02-14 22:43 ` Rob Herring
  2020-02-14 22:43 ` [PATCH 2/7] microblaze: Drop using struct of_pci_range.pci_space field Rob Herring
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 7+ messages in thread
From: Rob Herring @ 2020-02-14 22:43 UTC (permalink / raw)
  To: devicetree, Frank Rowand
  Cc: linux-kernel, Linus Walleij, Robin Murphy, Christoph Hellwig,
	Arnd Bergmann, Benjamin Herrenschmidt, linuxppc-dev,
	Michael Ellerman, Michal Simek, Paul Mackerras

In preparation to make the range parsing code work for non-PCI buses,
move the parsing functions out from the CONFIG_PCI #ifdef.

Signed-off-by: Rob Herring <robh@kernel.org>
---
 drivers/of/address.c | 215 ++++++++++++++++++++++---------------------
 1 file changed, 109 insertions(+), 106 deletions(-)

diff --git a/drivers/of/address.c b/drivers/of/address.c
index e8a39c3ec4d4..846045a48395 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -100,6 +100,28 @@ static unsigned int of_bus_default_get_flags(const __be32 *addr)
 	return IORESOURCE_MEM;
 }
 
+static unsigned int of_bus_pci_get_flags(const __be32 *addr)
+{
+	unsigned int flags = 0;
+	u32 w = be32_to_cpup(addr);
+
+	if (!IS_ENABLED(CONFIG_PCI))
+		return 0;
+
+	switch((w >> 24) & 0x03) {
+	case 0x01:
+		flags |= IORESOURCE_IO;
+		break;
+	case 0x02: /* 32 bits */
+	case 0x03: /* 64 bits */
+		flags |= IORESOURCE_MEM;
+		break;
+	}
+	if (w & 0x40000000)
+		flags |= IORESOURCE_PREFETCH;
+	return flags;
+}
+
 #ifdef CONFIG_PCI
 /*
  * PCI bus specific translator
@@ -125,25 +147,6 @@ static void of_bus_pci_count_cells(struct device_node *np,
 		*sizec = 2;
 }
 
-static unsigned int of_bus_pci_get_flags(const __be32 *addr)
-{
-	unsigned int flags = 0;
-	u32 w = be32_to_cpup(addr);
-
-	switch((w >> 24) & 0x03) {
-	case 0x01:
-		flags |= IORESOURCE_IO;
-		break;
-	case 0x02: /* 32 bits */
-	case 0x03: /* 64 bits */
-		flags |= IORESOURCE_MEM;
-		break;
-	}
-	if (w & 0x40000000)
-		flags |= IORESOURCE_PREFETCH;
-	return flags;
-}
-
 static u64 of_bus_pci_map(__be32 *addr, const __be32 *range, int na, int ns,
 		int pna)
 {
@@ -234,93 +237,6 @@ int of_pci_address_to_resource(struct device_node *dev, int bar,
 }
 EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
 
-static int parser_init(struct of_pci_range_parser *parser,
-			struct device_node *node, const char *name)
-{
-	const int na = 3, ns = 2;
-	int rlen;
-
-	parser->node = node;
-	parser->pna = of_n_addr_cells(node);
-	parser->np = parser->pna + na + ns;
-	parser->dma = !strcmp(name, "dma-ranges");
-
-	parser->range = of_get_property(node, name, &rlen);
-	if (parser->range == NULL)
-		return -ENOENT;
-
-	parser->end = parser->range + rlen / sizeof(__be32);
-
-	return 0;
-}
-
-int of_pci_range_parser_init(struct of_pci_range_parser *parser,
-				struct device_node *node)
-{
-	return parser_init(parser, node, "ranges");
-}
-EXPORT_SYMBOL_GPL(of_pci_range_parser_init);
-
-int of_pci_dma_range_parser_init(struct of_pci_range_parser *parser,
-				struct device_node *node)
-{
-	return parser_init(parser, node, "dma-ranges");
-}
-EXPORT_SYMBOL_GPL(of_pci_dma_range_parser_init);
-
-struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
-						struct of_pci_range *range)
-{
-	const int na = 3, ns = 2;
-
-	if (!range)
-		return NULL;
-
-	if (!parser->range || parser->range + parser->np > parser->end)
-		return NULL;
-
-	range->pci_space = be32_to_cpup(parser->range);
-	range->flags = of_bus_pci_get_flags(parser->range);
-	range->pci_addr = of_read_number(parser->range + 1, ns);
-	if (parser->dma)
-		range->cpu_addr = of_translate_dma_address(parser->node,
-				parser->range + na);
-	else
-		range->cpu_addr = of_translate_address(parser->node,
-				parser->range + na);
-	range->size = of_read_number(parser->range + parser->pna + na, ns);
-
-	parser->range += parser->np;
-
-	/* Now consume following elements while they are contiguous */
-	while (parser->range + parser->np <= parser->end) {
-		u32 flags;
-		u64 pci_addr, cpu_addr, size;
-
-		flags = of_bus_pci_get_flags(parser->range);
-		pci_addr = of_read_number(parser->range + 1, ns);
-		if (parser->dma)
-			cpu_addr = of_translate_dma_address(parser->node,
-					parser->range + na);
-		else
-			cpu_addr = of_translate_address(parser->node,
-					parser->range + na);
-		size = of_read_number(parser->range + parser->pna + na, ns);
-
-		if (flags != range->flags)
-			break;
-		if (pci_addr != range->pci_addr + range->size ||
-		    cpu_addr != range->cpu_addr + range->size)
-			break;
-
-		range->size += size;
-		parser->range += parser->np;
-	}
-
-	return range;
-}
-EXPORT_SYMBOL_GPL(of_pci_range_parser_one);
-
 /*
  * of_pci_range_to_resource - Create a resource from an of_pci_range
  * @range:	the PCI range that describes the resource
@@ -775,6 +691,93 @@ const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,
 }
 EXPORT_SYMBOL(of_get_address);
 
+static int parser_init(struct of_pci_range_parser *parser,
+			struct device_node *node, const char *name)
+{
+	const int na = 3, ns = 2;
+	int rlen;
+
+	parser->node = node;
+	parser->pna = of_n_addr_cells(node);
+	parser->np = parser->pna + na + ns;
+	parser->dma = !strcmp(name, "dma-ranges");
+
+	parser->range = of_get_property(node, name, &rlen);
+	if (parser->range == NULL)
+		return -ENOENT;
+
+	parser->end = parser->range + rlen / sizeof(__be32);
+
+	return 0;
+}
+
+int of_pci_range_parser_init(struct of_pci_range_parser *parser,
+				struct device_node *node)
+{
+	return parser_init(parser, node, "ranges");
+}
+EXPORT_SYMBOL_GPL(of_pci_range_parser_init);
+
+int of_pci_dma_range_parser_init(struct of_pci_range_parser *parser,
+				struct device_node *node)
+{
+	return parser_init(parser, node, "dma-ranges");
+}
+EXPORT_SYMBOL_GPL(of_pci_dma_range_parser_init);
+
+struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
+						struct of_pci_range *range)
+{
+	const int na = 3, ns = 2;
+
+	if (!range)
+		return NULL;
+
+	if (!parser->range || parser->range + parser->np > parser->end)
+		return NULL;
+
+	range->pci_space = be32_to_cpup(parser->range);
+	range->flags = of_bus_pci_get_flags(parser->range);
+	range->pci_addr = of_read_number(parser->range + 1, ns);
+	if (parser->dma)
+		range->cpu_addr = of_translate_dma_address(parser->node,
+				parser->range + na);
+	else
+		range->cpu_addr = of_translate_address(parser->node,
+				parser->range + na);
+	range->size = of_read_number(parser->range + parser->pna + na, ns);
+
+	parser->range += parser->np;
+
+	/* Now consume following elements while they are contiguous */
+	while (parser->range + parser->np <= parser->end) {
+		u32 flags;
+		u64 pci_addr, cpu_addr, size;
+
+		flags = of_bus_pci_get_flags(parser->range);
+		pci_addr = of_read_number(parser->range + 1, ns);
+		if (parser->dma)
+			cpu_addr = of_translate_dma_address(parser->node,
+					parser->range + na);
+		else
+			cpu_addr = of_translate_address(parser->node,
+					parser->range + na);
+		size = of_read_number(parser->range + parser->pna + na, ns);
+
+		if (flags != range->flags)
+			break;
+		if (pci_addr != range->pci_addr + range->size ||
+		    cpu_addr != range->cpu_addr + range->size)
+			break;
+
+		range->size += size;
+		parser->range += parser->np;
+	}
+
+	return range;
+}
+EXPORT_SYMBOL_GPL(of_pci_range_parser_one);
+
 static u64 of_translate_ioport(struct device_node *dev, const __be32 *in_addr,
 			u64 size)
 {
-- 
2.20.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 2/7] microblaze: Drop using struct of_pci_range.pci_space field
       [not found] <20200214224322.20030-1-robh@kernel.org>
  2020-02-14 22:43 ` [PATCH 1/7] of/address: Move range parser code out of CONFIG_PCI Rob Herring
@ 2020-02-14 22:43 ` Rob Herring
  2020-02-14 22:43 ` [PATCH 3/7] powerpc: " Rob Herring
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 7+ messages in thread
From: Rob Herring @ 2020-02-14 22:43 UTC (permalink / raw)
  To: devicetree, Frank Rowand
  Cc: linux-kernel, Linus Walleij, Robin Murphy, Christoph Hellwig,
	Arnd Bergmann, Benjamin Herrenschmidt, linuxppc-dev,
	Michael Ellerman, Michal Simek, Paul Mackerras

Let's use the struct of_pci_range.flags field instead so we can remove
the pci_space field.

Just drop the debug prints as there's plenty of debug output in
drivers/of/address.c which can be enabled.

Cc: Michal Simek <monstr@monstr.eu>
Signed-off-by: Rob Herring <robh@kernel.org>
---
 arch/microblaze/pci/pci-common.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index 58cc4965bd3e..60a58c0015f2 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -433,10 +433,6 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
 	pr_debug("Parsing ranges property...\n");
 	for_each_of_pci_range(&parser, &range) {
 		/* Read next ranges element */
-		pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
-				range.pci_space, range.pci_addr);
-		pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
-					range.cpu_addr, range.size);
 
 		/* If we failed translation or got a zero-sized region
 		 * (some FW try to feed us with non sensical zero sized regions
@@ -486,7 +482,7 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
 			pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
 				range.cpu_addr, range.cpu_addr + range.size - 1,
 				range.pci_addr,
-				(range.pci_space & 0x40000000) ?
+				(range.flags & IORESOURCE_PREFETCH) ?
 				"Prefetch" : "");
 
 			/* We support only 3 memory ranges */
@@ -1121,4 +1117,3 @@ int early_find_capability(struct pci_controller *hose, int bus, int devfn,
 {
 	return pci_bus_find_capability(fake_pci_bus(hose, bus), devfn, cap);
 }
-
-- 
2.20.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 3/7] powerpc: Drop using struct of_pci_range.pci_space field
       [not found] <20200214224322.20030-1-robh@kernel.org>
  2020-02-14 22:43 ` [PATCH 1/7] of/address: Move range parser code out of CONFIG_PCI Rob Herring
  2020-02-14 22:43 ` [PATCH 2/7] microblaze: Drop using struct of_pci_range.pci_space field Rob Herring
@ 2020-02-14 22:43 ` " Rob Herring
  2020-02-14 22:43 ` [PATCH 4/7] of: Drop " Rob Herring
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 7+ messages in thread
From: Rob Herring @ 2020-02-14 22:43 UTC (permalink / raw)
  To: devicetree, Frank Rowand
  Cc: linux-kernel, Linus Walleij, Robin Murphy, Christoph Hellwig,
	Arnd Bergmann, Benjamin Herrenschmidt, linuxppc-dev,
	Michael Ellerman, Michal Simek, Paul Mackerras

Let's use the struct of_pci_range.flags field instead so we can remove
the pci_space field.

Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: linuxppc-dev@lists.ozlabs.org
Signed-off-by: Rob Herring <robh@kernel.org>
---
 arch/powerpc/kernel/pci-common.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index c6c03416a151..d0074ad73aa3 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -728,7 +728,7 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
 			       " MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
 			       range.cpu_addr, range.cpu_addr + range.size - 1,
 			       range.pci_addr,
-			       (range.pci_space & 0x40000000) ?
+			       (range.flags & IORESOURCE_PREFETCH) ?
 			       "Prefetch" : "");
 
 			/* We support only 3 memory ranges */
-- 
2.20.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 4/7] of: Drop struct of_pci_range.pci_space field
       [not found] <20200214224322.20030-1-robh@kernel.org>
                   ` (2 preceding siblings ...)
  2020-02-14 22:43 ` [PATCH 3/7] powerpc: " Rob Herring
@ 2020-02-14 22:43 ` " Rob Herring
  2020-02-14 22:43 ` [PATCH 5/7] of/address: Rework of_pci_range parsing for non-PCI buses Rob Herring
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 7+ messages in thread
From: Rob Herring @ 2020-02-14 22:43 UTC (permalink / raw)
  To: devicetree, Frank Rowand
  Cc: linux-kernel, Linus Walleij, Robin Murphy, Christoph Hellwig,
	Arnd Bergmann, Benjamin Herrenschmidt, linuxppc-dev,
	Michael Ellerman, Michal Simek, Paul Mackerras

There's no more users of struct of_pci_range.pci_space field, so remove it.

Signed-off-by: Rob Herring <robh@kernel.org>
---
 drivers/of/address.c       | 1 -
 include/linux/of_address.h | 1 -
 2 files changed, 2 deletions(-)

diff --git a/drivers/of/address.c b/drivers/of/address.c
index 846045a48395..5d608d7c10d6 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -736,7 +736,6 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
 	if (!parser->range || parser->range + parser->np > parser->end)
 		return NULL;
 
-	range->pci_space = be32_to_cpup(parser->range);
 	range->flags = of_bus_pci_get_flags(parser->range);
 	range->pci_addr = of_read_number(parser->range + 1, ns);
 	if (parser->dma)
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index eac7ab109df4..8d12bf18e80b 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -16,7 +16,6 @@ struct of_pci_range_parser {
 };
 
 struct of_pci_range {
-	u32 pci_space;
 	u64 pci_addr;
 	u64 cpu_addr;
 	u64 size;
-- 
2.20.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 5/7] of/address: Rework of_pci_range parsing for non-PCI buses
       [not found] <20200214224322.20030-1-robh@kernel.org>
                   ` (3 preceding siblings ...)
  2020-02-14 22:43 ` [PATCH 4/7] of: Drop " Rob Herring
@ 2020-02-14 22:43 ` Rob Herring
  2020-02-14 22:43 ` [PATCH 6/7] of/address: use range parser for of_dma_get_range Rob Herring
  2020-02-14 22:43 ` [PATCH 7/7] of/address: Support multiple 'dma-ranges' entries Rob Herring
  6 siblings, 0 replies; 7+ messages in thread
From: Rob Herring @ 2020-02-14 22:43 UTC (permalink / raw)
  To: devicetree, Frank Rowand
  Cc: linux-kernel, Linus Walleij, Robin Murphy, Christoph Hellwig,
	Arnd Bergmann, Benjamin Herrenschmidt, linuxppc-dev,
	Michael Ellerman, Michal Simek, Paul Mackerras

The only PCI specific part of of_pci_range_parser_one() is the handling
of the 3rd address cell. Rework it to work on regular 1 and 2 cell
addresses.

Use defines and a union to avoid a treewide renaming of the parsing
helpers and struct.

Signed-off-by: Rob Herring <robh@kernel.org>
---
 drivers/of/address.c       | 33 +++++++++++++++++++++------------
 include/linux/of_address.h | 12 +++++++++---
 2 files changed, 30 insertions(+), 15 deletions(-)

diff --git a/drivers/of/address.c b/drivers/of/address.c
index 5d608d7c10d6..6d33f849f114 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -694,12 +694,12 @@ EXPORT_SYMBOL(of_get_address);
 static int parser_init(struct of_pci_range_parser *parser,
 			struct device_node *node, const char *name)
 {
-	const int na = 3, ns = 2;
 	int rlen;
 
 	parser->node = node;
 	parser->pna = of_n_addr_cells(node);
-	parser->np = parser->pna + na + ns;
+	parser->na = of_bus_n_addr_cells(node);
+	parser->ns = of_bus_n_size_cells(node);
 	parser->dma = !strcmp(name, "dma-ranges");
 
 	parser->range = of_get_property(node, name, &rlen);
@@ -724,20 +724,28 @@ int of_pci_dma_range_parser_init(struct of_pci_range_parser *parser,
 	return parser_init(parser, node, "dma-ranges");
 }
 EXPORT_SYMBOL_GPL(of_pci_dma_range_parser_init);
+#define of_dma_range_parser_init of_pci_dma_range_parser_init
 
 struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
 						struct of_pci_range *range)
 {
-	const int na = 3, ns = 2;
+	int na = parser->na;
+	int ns = parser->ns;
+	int np = parser->pna + na + ns;
 
 	if (!range)
 		return NULL;
 
-	if (!parser->range || parser->range + parser->np > parser->end)
+	if (!parser->range || parser->range + np > parser->end)
 		return NULL;
 
-	range->flags = of_bus_pci_get_flags(parser->range);
-	range->pci_addr = of_read_number(parser->range + 1, ns);
+	if (parser->na == 3)
+		range->flags = of_bus_pci_get_flags(parser->range);
+	else
+		range->flags = 0;
+
+	range->pci_addr = of_read_number(parser->range, na);
+
 	if (parser->dma)
 		range->cpu_addr = of_translate_dma_address(parser->node,
 				parser->range + na);
@@ -746,15 +754,16 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
 				parser->range + na);
 	range->size = of_read_number(parser->range + parser->pna + na, ns);
 
-	parser->range += parser->np;
+	parser->range += np;
 
 	/* Now consume following elements while they are contiguous */
-	while (parser->range + parser->np <= parser->end) {
-		u32 flags;
+	while (parser->range + np <= parser->end) {
+		u32 flags = 0;
 		u64 pci_addr, cpu_addr, size;
 
-		flags = of_bus_pci_get_flags(parser->range);
-		pci_addr = of_read_number(parser->range + 1, ns);
+		if (parser->na == 3)
+			flags = of_bus_pci_get_flags(parser->range);
+		pci_addr = of_read_number(parser->range, na);
 		if (parser->dma)
 			cpu_addr = of_translate_dma_address(parser->node,
 					parser->range + na);
@@ -770,7 +779,7 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
 			break;
 
 		range->size += size;
-		parser->range += parser->np;
+		parser->range += np;
 	}
 
 	return range;
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index 8d12bf18e80b..763022ed3456 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -10,20 +10,27 @@ struct of_pci_range_parser {
 	struct device_node *node;
 	const __be32 *range;
 	const __be32 *end;
-	int np;
+	int na;
+	int ns;
 	int pna;
 	bool dma;
 };
+#define of_range_parser of_pci_range_parser
 
 struct of_pci_range {
-	u64 pci_addr;
+	union {
+		u64 pci_addr;
+		u64 bus_addr;
+	};
 	u64 cpu_addr;
 	u64 size;
 	u32 flags;
 };
+#define of_range of_pci_range
 
 #define for_each_of_pci_range(parser, range) \
 	for (; of_pci_range_parser_one(parser, range);)
+#define for_each_of_range for_each_of_pci_range
 
 /* Translate a DMA address from device space to CPU space */
 extern u64 of_translate_dma_address(struct device_node *dev,
@@ -142,4 +149,3 @@ static inline int of_pci_range_to_resource(struct of_pci_range *range,
 #endif /* CONFIG_OF_ADDRESS && CONFIG_PCI */
 
 #endif /* __OF_ADDRESS_H */
-
-- 
2.20.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 6/7] of/address: use range parser for of_dma_get_range
       [not found] <20200214224322.20030-1-robh@kernel.org>
                   ` (4 preceding siblings ...)
  2020-02-14 22:43 ` [PATCH 5/7] of/address: Rework of_pci_range parsing for non-PCI buses Rob Herring
@ 2020-02-14 22:43 ` Rob Herring
  2020-02-14 22:43 ` [PATCH 7/7] of/address: Support multiple 'dma-ranges' entries Rob Herring
  6 siblings, 0 replies; 7+ messages in thread
From: Rob Herring @ 2020-02-14 22:43 UTC (permalink / raw)
  To: devicetree, Frank Rowand
  Cc: linux-kernel, Linus Walleij, Robin Murphy, Christoph Hellwig,
	Arnd Bergmann, Benjamin Herrenschmidt, linuxppc-dev,
	Michael Ellerman, Michal Simek, Paul Mackerras

of_dma_get_range() does the same ranges parsing as
of_pci_range_parser_one(), so let's refactor of_dma_get_range() to use
it instead.

This commit is no functional change. Subsequent commits will parse more
than the 1st dma-ranges entry.

Signed-off-by: Rob Herring <robh@kernel.org>
---
 drivers/of/address.c | 38 +++++++++++++-------------------------
 1 file changed, 13 insertions(+), 25 deletions(-)

diff --git a/drivers/of/address.c b/drivers/of/address.c
index 6d33f849f114..a2c45812a50e 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -939,10 +939,11 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz
 {
 	struct device_node *node = of_node_get(np);
 	const __be32 *ranges = NULL;
-	int len, naddr, nsize, pna;
+	int len;
 	int ret = 0;
 	bool found_dma_ranges = false;
-	u64 dmaaddr;
+	struct of_range_parser parser;
+	struct of_range range;
 
 	while (node) {
 		ranges = of_get_property(node, "dma-ranges", &len);
@@ -967,33 +968,20 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz
 		goto out;
 	}
 
-	naddr = of_bus_n_addr_cells(node);
-	nsize = of_bus_n_size_cells(node);
-	pna = of_n_addr_cells(node);
-	if ((len / sizeof(__be32)) % (pna + naddr + nsize)) {
-		ret = -EINVAL;
-		goto out;
-	}
+	of_dma_range_parser_init(&parser, node);
+
+	for_each_of_range(&parser, &range) {
+		pr_debug("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n",
+			 range.bus_addr, range.cpu_addr, range.size);
+
+		*dma_addr = range.bus_addr;
+		*paddr = range.cpu_addr;
+		*size = range.size;
 
-	/* dma-ranges format:
-	 * DMA addr	: naddr cells
-	 * CPU addr	: pna cells
-	 * size		: nsize cells
-	 */
-	dmaaddr = of_read_number(ranges, naddr);
-	*paddr = of_translate_dma_address(node, ranges + naddr);
-	if (*paddr == OF_BAD_ADDR) {
-		pr_err("translation of DMA address(%llx) to CPU address failed node(%pOF)\n",
-		       dmaaddr, np);
-		ret = -EINVAL;
 		goto out;
 	}
-	*dma_addr = dmaaddr;
-
-	*size = of_read_number(ranges + naddr + pna, nsize);
 
-	pr_debug("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n",
-		 *dma_addr, *paddr, *size);
+	pr_err("translation of DMA ranges failed on node(%pOF)\n", np);
 
 out:
 	of_node_put(node);
-- 
2.20.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 7/7] of/address: Support multiple 'dma-ranges' entries
       [not found] <20200214224322.20030-1-robh@kernel.org>
                   ` (5 preceding siblings ...)
  2020-02-14 22:43 ` [PATCH 6/7] of/address: use range parser for of_dma_get_range Rob Herring
@ 2020-02-14 22:43 ` Rob Herring
  6 siblings, 0 replies; 7+ messages in thread
From: Rob Herring @ 2020-02-14 22:43 UTC (permalink / raw)
  To: devicetree, Frank Rowand
  Cc: linux-kernel, Linus Walleij, Robin Murphy, Christoph Hellwig,
	Arnd Bergmann, Benjamin Herrenschmidt, linuxppc-dev,
	Michael Ellerman, Michal Simek, Paul Mackerras

Currently, the DMA offset and mask for a device are set based only on the
first 'dma-ranges' entry. We should really be using all the entries. The
kernel doesn't yet support multiple offsets and sizes, so the best we can
do is to find the biggest size for a single offset. The algorithm is
copied from acpi_dma_get_range().

If there's different offsets from the first entry, then we warn and
continue. It really should be an error, but this will likely break
existing DTs.

Signed-off-by: Rob Herring <robh@kernel.org>
---
 drivers/of/address.c | 28 ++++++++++++++++++++++++----
 1 file changed, 24 insertions(+), 4 deletions(-)

diff --git a/drivers/of/address.c b/drivers/of/address.c
index a2c45812a50e..8eea3f6e29a4 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -944,6 +944,7 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz
 	bool found_dma_ranges = false;
 	struct of_range_parser parser;
 	struct of_range range;
+	u64 dma_start = U64_MAX, dma_end = 0, dma_offset = 0;
 
 	while (node) {
 		ranges = of_get_property(node, "dma-ranges", &len);
@@ -974,14 +975,33 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz
 		pr_debug("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n",
 			 range.bus_addr, range.cpu_addr, range.size);
 
-		*dma_addr = range.bus_addr;
-		*paddr = range.cpu_addr;
-		*size = range.size;
+		if (dma_offset && range.cpu_addr - range.bus_addr != dma_offset) {
+			pr_warn("Can't handle multiple dma-ranges with different offsets on node(%pOF)\n", node);
+			/* Don't error out as we'd break some existing DTs */
+			continue;
+		}
+		dma_offset = range.cpu_addr - range.bus_addr;
+
+		/* Take lower and upper limits */
+		if (range.bus_addr < dma_start)
+			dma_start = range.bus_addr;
+		if (range.bus_addr + range.size > dma_end)
+			dma_end = range.bus_addr + range.size;
+	}
 
+	if (dma_start >= dma_end) {
+		ret = -EINVAL;
+		pr_debug("Invalid DMA ranges configuration on node(%pOF)\n",
+			 node);
 		goto out;
 	}
 
-	pr_err("translation of DMA ranges failed on node(%pOF)\n", np);
+	*dma_addr = dma_start;
+	*size = dma_end - dma_start;
+	*paddr = dma_start + dma_offset;
+
+	pr_debug("final: dma_addr(%llx) cpu_addr(%llx) size(%llx)\n",
+		 *dma_addr, *paddr, *size);
 
 out:
 	of_node_put(node);
-- 
2.20.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, back to index

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20200214224322.20030-1-robh@kernel.org>
2020-02-14 22:43 ` [PATCH 1/7] of/address: Move range parser code out of CONFIG_PCI Rob Herring
2020-02-14 22:43 ` [PATCH 2/7] microblaze: Drop using struct of_pci_range.pci_space field Rob Herring
2020-02-14 22:43 ` [PATCH 3/7] powerpc: " Rob Herring
2020-02-14 22:43 ` [PATCH 4/7] of: Drop " Rob Herring
2020-02-14 22:43 ` [PATCH 5/7] of/address: Rework of_pci_range parsing for non-PCI buses Rob Herring
2020-02-14 22:43 ` [PATCH 6/7] of/address: use range parser for of_dma_get_range Rob Herring
2020-02-14 22:43 ` [PATCH 7/7] of/address: Support multiple 'dma-ranges' entries Rob Herring

Linux-Devicetree Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-devicetree/0 linux-devicetree/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-devicetree linux-devicetree/ https://lore.kernel.org/linux-devicetree \
		devicetree@vger.kernel.org
	public-inbox-index linux-devicetree

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-devicetree


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git