Hi,
This series convert reservation of Loongson64 Logic PIO into DeviceTree based
method.
It can be used to replace Huacai's
"MIPS: Loongson64: Reserve legacy MMIO space according to bridge type".
Thanks.
v2:
- Address Rob and Huacai's review comments.
Jiaxun Yang (5):
of_address: Add bus type match for pci ranges parser
MIPS: Loongson64: Process ISA Node in DeviceTree
MIPS: Loongson64: Enlarge IO_SPACE_LIMIT
MIPS: Loongson64: DTS: Fix ISA range for RS780E PCH
MIPS: Loongson64: Add ISA node for LS7A PCH
arch/mips/boot/dts/loongson/ls7a-pch.dtsi | 7 ++
arch/mips/boot/dts/loongson/rs780e-pch.dtsi | 2 +-
arch/mips/include/asm/io.h | 3 +-
.../mips/include/asm/mach-loongson64/spaces.h | 3 +-
arch/mips/loongson64/init.c | 88 +++++++++++++------
drivers/of/address.c | 27 +++---
include/linux/of_address.h | 5 ++
7 files changed, 94 insertions(+), 41 deletions(-)
--
2.28.0.rc1
So the parser can be used to parse range property of ISA bus.
As they're all using PCI-like method of range property, there is no need
start a new parser.
Signed-off-by: Jiaxun Yang <[email protected]>
--
v2: Drop useless check, fix some na for bus_addr
add define of of_range_parser_init according to
Rob's suggestion.
---
drivers/of/address.c | 27 +++++++++++++++------------
include/linux/of_address.h | 5 +++++
2 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 8eea3f6e29a4..7406636cea87 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -698,9 +698,10 @@ static int parser_init(struct of_pci_range_parser *parser,
parser->node = node;
parser->pna = of_n_addr_cells(node);
- parser->na = of_bus_n_addr_cells(node);
- parser->ns = of_bus_n_size_cells(node);
parser->dma = !strcmp(name, "dma-ranges");
+ parser->bus = of_match_bus(node);
+
+ parser->bus->count_cells(parser->node, &parser->na, &parser->ns);
parser->range = of_get_property(node, name, &rlen);
if (parser->range == NULL)
@@ -732,6 +733,7 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
int na = parser->na;
int ns = parser->ns;
int np = parser->pna + na + ns;
+ int busflag_na = 0;
if (!range)
return NULL;
@@ -739,12 +741,14 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
if (!parser->range || parser->range + np > parser->end)
return NULL;
- if (parser->na == 3)
- range->flags = of_bus_pci_get_flags(parser->range);
- else
- range->flags = 0;
+ range->flags = parser->bus->get_flags(parser->range);
+
+ /* PCI and ISA have a extra cell for resource flags */
+ if (strcmp(parser->bus->name, "pci") ||
+ strcmp(parser->bus->name, "isa"))
+ busflag_na = 1;
- range->pci_addr = of_read_number(parser->range, na);
+ range->bus_addr = of_read_number(parser->range + busflag_na, na - busflag_na);
if (parser->dma)
range->cpu_addr = of_translate_dma_address(parser->node,
@@ -759,11 +763,10 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
/* Now consume following elements while they are contiguous */
while (parser->range + np <= parser->end) {
u32 flags = 0;
- u64 pci_addr, cpu_addr, size;
+ u64 bus_addr, cpu_addr, size;
- if (parser->na == 3)
- flags = of_bus_pci_get_flags(parser->range);
- pci_addr = of_read_number(parser->range, na);
+ flags = parser->bus->get_flags(parser->range);
+ bus_addr = of_read_number(parser->range + busflag_na, na - busflag_na);
if (parser->dma)
cpu_addr = of_translate_dma_address(parser->node,
parser->range + na);
@@ -774,7 +777,7 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
if (flags != range->flags)
break;
- if (pci_addr != range->pci_addr + range->size ||
+ if (bus_addr != range->bus_addr + range->size ||
cpu_addr != range->cpu_addr + range->size)
break;
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index 763022ed3456..3e8d6489cbf1 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -6,8 +6,11 @@
#include <linux/of.h>
#include <linux/io.h>
+struct of_bus;
+
struct of_pci_range_parser {
struct device_node *node;
+ struct of_bus *bus;
const __be32 *range;
const __be32 *end;
int na;
@@ -53,6 +56,7 @@ extern const __be32 *of_get_address(struct device_node *dev, int index,
extern int of_pci_range_parser_init(struct of_pci_range_parser *parser,
struct device_node *node);
+#define of_range_parser_init of_pci_range_parser_init
extern int of_pci_dma_range_parser_init(struct of_pci_range_parser *parser,
struct device_node *node);
extern struct of_pci_range *of_pci_range_parser_one(
@@ -83,6 +87,7 @@ static inline int of_pci_range_parser_init(struct of_pci_range_parser *parser,
{
return -ENOSYS;
}
+#define of_range_parser_init of_pci_range_parser_init
static inline int of_pci_dma_range_parser_init(struct of_pci_range_parser *parser,
struct device_node *node)
--
2.28.0.rc1
Previously, we're hardcoding resserved ISA I/O Space in code, now
we're processing reverved I/O via DeviceTree directly. Using the ranges
property to determine the size and address of reserved I/O space.
Signed-off-by: Jiaxun Yang <[email protected]>
--
v2: Use range_parser instead of pci_range_parser
---
arch/mips/loongson64/init.c | 88 ++++++++++++++++++++++++++-----------
1 file changed, 63 insertions(+), 25 deletions(-)
diff --git a/arch/mips/loongson64/init.c b/arch/mips/loongson64/init.c
index 59ddadace83f..67e95193758e 100644
--- a/arch/mips/loongson64/init.c
+++ b/arch/mips/loongson64/init.c
@@ -7,6 +7,8 @@
#include <linux/irqchip.h>
#include <linux/logic_pio.h>
#include <linux/memblock.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
#include <asm/bootinfo.h>
#include <asm/traps.h>
#include <asm/smp-ops.h>
@@ -63,41 +65,77 @@ void __init prom_free_prom_memory(void)
{
}
-static __init void reserve_pio_range(void)
+static int __init add_legacy_isa_io(struct fwnode_handle *fwnode, resource_size_t hw_start,
+ resource_size_t size)
{
+ int ret = 0;
struct logic_pio_hwaddr *range;
+ unsigned long vaddr;
range = kzalloc(sizeof(*range), GFP_ATOMIC);
if (!range)
- return;
+ return -ENOMEM;
- range->fwnode = &of_root->fwnode;
- range->size = MMIO_LOWER_RESERVED;
- range->hw_start = LOONGSON_PCIIO_BASE;
+ range->fwnode = fwnode;
+ range->size = size;
+ range->hw_start = hw_start;
range->flags = LOGIC_PIO_CPU_MMIO;
- if (logic_pio_register_range(range)) {
- pr_err("Failed to reserve PIO range for legacy ISA\n");
- goto free_range;
+ ret = logic_pio_register_range(range);
+ if (ret) {
+ kfree(range);
+ return ret;
+ }
+
+ /* Legacy ISA must placed at the start of PCI_IOBASE */
+ if (range->io_start != 0) {
+ logic_pio_unregister_range(range);
+ kfree(range);
+ return -EINVAL;
}
- if (WARN(range->io_start != 0,
- "Reserved PIO range does not start from 0\n"))
- goto unregister;
-
- /*
- * i8259 would access I/O space, so mapping must be done here.
- * Please remove it when all drivers can be managed by logic_pio.
- */
- ioremap_page_range(PCI_IOBASE, PCI_IOBASE + MMIO_LOWER_RESERVED,
- LOONGSON_PCIIO_BASE,
- pgprot_device(PAGE_KERNEL));
-
- return;
-unregister:
- logic_pio_unregister_range(range);
-free_range:
- kfree(range);
+ vaddr = PCI_IOBASE + range->io_start;
+
+ ioremap_page_range(vaddr, vaddr + size, hw_start, pgprot_device(PAGE_KERNEL));
+
+ return 0;
+}
+
+static __init void reserve_pio_range(void)
+{
+ struct device_node *np;
+
+ for_each_node_by_name(np, "isa") {
+ struct of_range range;
+ struct of_range_parser parser;
+
+ pr_info("ISA Bridge: %pOF\n", np);
+
+ if (of_range_parser_init(&parser, np)) {
+ pr_info("Failed to parse resources.\n");
+ break;
+ }
+
+ for_each_of_range(&parser, &range) {
+ switch (range.flags & IORESOURCE_TYPE_BITS) {
+ case IORESOURCE_IO:
+ pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
+ range.cpu_addr,
+ range.cpu_addr + range.size - 1,
+ range.bus_addr);
+ if (add_legacy_isa_io(&np->fwnode, range.cpu_addr + range.bus_addr,
+ range.size))
+ pr_warn("Failed to reserve legacy IO in Logic PIO\n");
+ break;
+ case IORESOURCE_MEM:
+ pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx\n",
+ range.cpu_addr,
+ range.cpu_addr + range.size - 1,
+ range.bus_addr);
+ break;
+ }
+ }
+ }
}
void __init arch_init_irq(void)
--
2.28.0.rc1
Ranges should express the actual physical address on bus.
Signed-off-by: Jiaxun Yang <[email protected]>
---
arch/mips/boot/dts/loongson/rs780e-pch.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/mips/boot/dts/loongson/rs780e-pch.dtsi b/arch/mips/boot/dts/loongson/rs780e-pch.dtsi
index d4c803d74036..99174b52dfb8 100644
--- a/arch/mips/boot/dts/loongson/rs780e-pch.dtsi
+++ b/arch/mips/boot/dts/loongson/rs780e-pch.dtsi
@@ -25,7 +25,7 @@ isa {
compatible = "isa";
#address-cells = <2>;
#size-cells = <1>;
- ranges = <1 0 0 0 0x4000>;
+ ranges = <1 0 0 0x18000000 0x4000>;
rtc0: rtc@70 {
compatible = "motorola,mc146818";
--
2.28.0.rc1
It can be very big on LS7A PCH systems.
Signed-off-by: Jiaxun Yang <[email protected]>
---
arch/mips/include/asm/io.h | 3 ++-
arch/mips/include/asm/mach-loongson64/spaces.h | 3 +--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h
index 346fffd9e972..0072489325fa 100644
--- a/arch/mips/include/asm/io.h
+++ b/arch/mips/include/asm/io.h
@@ -50,8 +50,9 @@
# define __relaxed_ioswabq ioswabq
/* ioswab[bwlq], __mem_ioswab[bwlq] are defined in mangle-port.h */
-
+#ifndef IO_SPACE_LIMIT
#define IO_SPACE_LIMIT 0xffff
+#endif
/*
* On MIPS I/O ports are memory mapped, so we access them using normal
diff --git a/arch/mips/include/asm/mach-loongson64/spaces.h b/arch/mips/include/asm/mach-loongson64/spaces.h
index 3de0ac9d8829..fa5ea4ee8b6c 100644
--- a/arch/mips/include/asm/mach-loongson64/spaces.h
+++ b/arch/mips/include/asm/mach-loongson64/spaces.h
@@ -11,8 +11,7 @@
#define PCI_IOSIZE SZ_16M
#define MAP_BASE (PCI_IOBASE + PCI_IOSIZE)
-/* Reserved at the start of PCI_IOBASE for legacy drivers */
-#define MMIO_LOWER_RESERVED 0x10000
+#define IO_SPACE_LIMIT PCI_IOSIZE
#include <asm/mach-generic/spaces.h>
#endif
--
2.28.0.rc1
Although currently we're not enabling any ISA device in devicetree,
but this node is required to express the ranges of address reserved
for ISA.
Signed-off-by: Jiaxun Yang <[email protected]>
---
arch/mips/boot/dts/loongson/ls7a-pch.dtsi | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/mips/boot/dts/loongson/ls7a-pch.dtsi b/arch/mips/boot/dts/loongson/ls7a-pch.dtsi
index 1c286bb8c703..e574a062dfae 100644
--- a/arch/mips/boot/dts/loongson/ls7a-pch.dtsi
+++ b/arch/mips/boot/dts/loongson/ls7a-pch.dtsi
@@ -367,5 +367,12 @@ pci_bridge@14,0 {
interrupt-map = <0 0 0 0 &pic 39 IRQ_TYPE_LEVEL_HIGH>;
};
};
+
+ isa {
+ compatible = "isa";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges = <1 0 0 0x18000000 0x20000>;
+ };
};
};
--
2.28.0.rc1
?? 2020/7/21 ????10:17, Jiaxun Yang ะด??:
> It can be very big on LS7A PCH systems.
>
> Signed-off-by: Jiaxun Yang <[email protected]>
> ---
> arch/mips/include/asm/io.h | 3 ++-
> arch/mips/include/asm/mach-loongson64/spaces.h | 3 +--
> 2 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h
> index 346fffd9e972..0072489325fa 100644
> --- a/arch/mips/include/asm/io.h
> +++ b/arch/mips/include/asm/io.h
> @@ -50,8 +50,9 @@
> # define __relaxed_ioswabq ioswabq
>
> /* ioswab[bwlq], __mem_ioswab[bwlq] are defined in mangle-port.h */
> -
> +#ifndef IO_SPACE_LIMIT
> #define IO_SPACE_LIMIT 0xffff
> +#endif
>
> /*
> * On MIPS I/O ports are memory mapped, so we access them using normal
> diff --git a/arch/mips/include/asm/mach-loongson64/spaces.h b/arch/mips/include/asm/mach-loongson64/spaces.h
> index 3de0ac9d8829..fa5ea4ee8b6c 100644
> --- a/arch/mips/include/asm/mach-loongson64/spaces.h
> +++ b/arch/mips/include/asm/mach-loongson64/spaces.h
> @@ -11,8 +11,7 @@
> #define PCI_IOSIZE SZ_16M
> #define MAP_BASE (PCI_IOBASE + PCI_IOSIZE)
>
> -/* Reserved at the start of PCI_IOBASE for legacy drivers */
> -#define MMIO_LOWER_RESERVED 0x10000
> +#define IO_SPACE_LIMIT PCI_IOSIZE
Oops, it should be (PCI_IOSIZE - 1), will fix in next revision.
Sorry for the noise.
Thanks.
- Jiaxun
>
> #include <asm/mach-generic/spaces.h>
> #endif
On Tue, Jul 21, 2020 at 10:17:31PM +0800, Jiaxun Yang wrote:
> It can be very big on LS7A PCH systems.
>
> Signed-off-by: Jiaxun Yang <[email protected]>
> ---
> arch/mips/include/asm/io.h | 3 ++-
> arch/mips/include/asm/mach-loongson64/spaces.h | 3 +--
> 2 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h
> index 346fffd9e972..0072489325fa 100644
> --- a/arch/mips/include/asm/io.h
> +++ b/arch/mips/include/asm/io.h
> @@ -50,8 +50,9 @@
> # define __relaxed_ioswabq ioswabq
>
> /* ioswab[bwlq], __mem_ioswab[bwlq] are defined in mangle-port.h */
> -
> +#ifndef IO_SPACE_LIMIT
> #define IO_SPACE_LIMIT 0xffff
> +#endif
please move this to include/asm/mach-generic/spaces.h
Thomas.
--
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea. [ RFC1925, 2.3 ]
On Tue, Jul 21, 2020 at 8:18 AM Jiaxun Yang <[email protected]> wrote:
>
> So the parser can be used to parse range property of ISA bus.
>
> As they're all using PCI-like method of range property, there is no need
> start a new parser.
>
> Signed-off-by: Jiaxun Yang <[email protected]>
>
> --
> v2: Drop useless check, fix some na for bus_addr
> add define of of_range_parser_init according to
> Rob's suggestion.
> ---
> drivers/of/address.c | 27 +++++++++++++++------------
> include/linux/of_address.h | 5 +++++
> 2 files changed, 20 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/of/address.c b/drivers/of/address.c
> index 8eea3f6e29a4..7406636cea87 100644
> --- a/drivers/of/address.c
> +++ b/drivers/of/address.c
> @@ -698,9 +698,10 @@ static int parser_init(struct of_pci_range_parser *parser,
>
> parser->node = node;
> parser->pna = of_n_addr_cells(node);
> - parser->na = of_bus_n_addr_cells(node);
> - parser->ns = of_bus_n_size_cells(node);
> parser->dma = !strcmp(name, "dma-ranges");
> + parser->bus = of_match_bus(node);
> +
> + parser->bus->count_cells(parser->node, &parser->na, &parser->ns);
>
> parser->range = of_get_property(node, name, &rlen);
> if (parser->range == NULL)
> @@ -732,6 +733,7 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
> int na = parser->na;
> int ns = parser->ns;
> int np = parser->pna + na + ns;
> + int busflag_na = 0;
>
> if (!range)
> return NULL;
> @@ -739,12 +741,14 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
> if (!parser->range || parser->range + np > parser->end)
> return NULL;
>
> - if (parser->na == 3)
> - range->flags = of_bus_pci_get_flags(parser->range);
> - else
> - range->flags = 0;
> + range->flags = parser->bus->get_flags(parser->range);
> +
> + /* PCI and ISA have a extra cell for resource flags */
> + if (strcmp(parser->bus->name, "pci") ||
> + strcmp(parser->bus->name, "isa"))
> + busflag_na = 1;
This should be abstracted out. Probably the easiest is to add a
'has_flags' boolean to the of_bus struct.
>
> - range->pci_addr = of_read_number(parser->range, na);
> + range->bus_addr = of_read_number(parser->range + busflag_na, na - busflag_na);
>
> if (parser->dma)
> range->cpu_addr = of_translate_dma_address(parser->node,
> @@ -759,11 +763,10 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
> /* Now consume following elements while they are contiguous */
> while (parser->range + np <= parser->end) {
> u32 flags = 0;
> - u64 pci_addr, cpu_addr, size;
> + u64 bus_addr, cpu_addr, size;
>
> - if (parser->na == 3)
> - flags = of_bus_pci_get_flags(parser->range);
> - pci_addr = of_read_number(parser->range, na);
> + flags = parser->bus->get_flags(parser->range);
> + bus_addr = of_read_number(parser->range + busflag_na, na - busflag_na);
> if (parser->dma)
> cpu_addr = of_translate_dma_address(parser->node,
> parser->range + na);
> @@ -774,7 +777,7 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
>
> if (flags != range->flags)
> break;
> - if (pci_addr != range->pci_addr + range->size ||
> + if (bus_addr != range->bus_addr + range->size ||
> cpu_addr != range->cpu_addr + range->size)
> break;
>
> diff --git a/include/linux/of_address.h b/include/linux/of_address.h
> index 763022ed3456..3e8d6489cbf1 100644
> --- a/include/linux/of_address.h
> +++ b/include/linux/of_address.h
> @@ -6,8 +6,11 @@
> #include <linux/of.h>
> #include <linux/io.h>
>
> +struct of_bus;
> +
> struct of_pci_range_parser {
> struct device_node *node;
> + struct of_bus *bus;
> const __be32 *range;
> const __be32 *end;
> int na;
> @@ -53,6 +56,7 @@ extern const __be32 *of_get_address(struct device_node *dev, int index,
>
> extern int of_pci_range_parser_init(struct of_pci_range_parser *parser,
> struct device_node *node);
> +#define of_range_parser_init of_pci_range_parser_init
> extern int of_pci_dma_range_parser_init(struct of_pci_range_parser *parser,
> struct device_node *node);
> extern struct of_pci_range *of_pci_range_parser_one(
> @@ -83,6 +87,7 @@ static inline int of_pci_range_parser_init(struct of_pci_range_parser *parser,
> {
> return -ENOSYS;
> }
> +#define of_range_parser_init of_pci_range_parser_init
No need for 2 defines. Move this outside of the ifdef like the others.