|
7 | 7 | #include <linux/irqchip.h>
|
8 | 8 | #include <linux/logic_pio.h>
|
9 | 9 | #include <linux/memblock.h>
|
| 10 | +#include <linux/of.h> |
| 11 | +#include <linux/of_address.h> |
10 | 12 | #include <asm/bootinfo.h>
|
11 | 13 | #include <asm/traps.h>
|
12 | 14 | #include <asm/smp-ops.h>
|
@@ -63,41 +65,76 @@ void __init prom_free_prom_memory(void)
|
63 | 65 | {
|
64 | 66 | }
|
65 | 67 |
|
66 |
| -static __init void reserve_pio_range(void) |
| 68 | +static int __init add_legacy_isa_io(struct fwnode_handle *fwnode, resource_size_t hw_start, |
| 69 | + resource_size_t size) |
67 | 70 | {
|
| 71 | + int ret = 0; |
68 | 72 | struct logic_pio_hwaddr *range;
|
| 73 | + unsigned long vaddr; |
69 | 74 |
|
70 | 75 | range = kzalloc(sizeof(*range), GFP_ATOMIC);
|
71 | 76 | if (!range)
|
72 |
| - return; |
| 77 | + return -ENOMEM; |
73 | 78 |
|
74 |
| - range->fwnode = &of_root->fwnode; |
75 |
| - range->size = MMIO_LOWER_RESERVED; |
76 |
| - range->hw_start = LOONGSON_PCIIO_BASE; |
| 79 | + range->fwnode = fwnode; |
| 80 | + range->size = size; |
| 81 | + range->hw_start = hw_start; |
77 | 82 | range->flags = LOGIC_PIO_CPU_MMIO;
|
78 | 83 |
|
79 |
| - if (logic_pio_register_range(range)) { |
80 |
| - pr_err("Failed to reserve PIO range for legacy ISA\n"); |
81 |
| - goto free_range; |
| 84 | + ret = logic_pio_register_range(range); |
| 85 | + if (ret) { |
| 86 | + kfree(range); |
| 87 | + return ret; |
| 88 | + } |
| 89 | + |
| 90 | + /* Legacy ISA must placed at the start of PCI_IOBASE */ |
| 91 | + if (range->io_start != 0) { |
| 92 | + logic_pio_unregister_range(range); |
| 93 | + kfree(range); |
| 94 | + return -EINVAL; |
82 | 95 | }
|
83 | 96 |
|
84 |
| - if (WARN(range->io_start != 0, |
85 |
| - "Reserved PIO range does not start from 0\n")) |
86 |
| - goto unregister; |
87 |
| - |
88 |
| - /* |
89 |
| - * i8259 would access I/O space, so mapping must be done here. |
90 |
| - * Please remove it when all drivers can be managed by logic_pio. |
91 |
| - */ |
92 |
| - ioremap_page_range(PCI_IOBASE, PCI_IOBASE + MMIO_LOWER_RESERVED, |
93 |
| - LOONGSON_PCIIO_BASE, |
94 |
| - pgprot_device(PAGE_KERNEL)); |
95 |
| - |
96 |
| - return; |
97 |
| -unregister: |
98 |
| - logic_pio_unregister_range(range); |
99 |
| -free_range: |
100 |
| - kfree(range); |
| 97 | + vaddr = PCI_IOBASE + range->io_start; |
| 98 | + |
| 99 | + ioremap_page_range(vaddr, vaddr + size, hw_start, pgprot_device(PAGE_KERNEL)); |
| 100 | + |
| 101 | + return 0; |
| 102 | +} |
| 103 | + |
| 104 | +static __init void reserve_pio_range(void) |
| 105 | +{ |
| 106 | + struct device_node *np; |
| 107 | + |
| 108 | + for_each_node_by_name(np, "isa") { |
| 109 | + struct of_range range; |
| 110 | + struct of_range_parser parser; |
| 111 | + |
| 112 | + pr_info("ISA Bridge: %pOF\n", np); |
| 113 | + |
| 114 | + if (of_range_parser_init(&parser, np)) { |
| 115 | + pr_info("Failed to parse resources.\n"); |
| 116 | + break; |
| 117 | + } |
| 118 | + |
| 119 | + for_each_of_range(&parser, &range) { |
| 120 | + switch (range.flags & IORESOURCE_TYPE_BITS) { |
| 121 | + case IORESOURCE_IO: |
| 122 | + pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n", |
| 123 | + range.cpu_addr, |
| 124 | + range.cpu_addr + range.size - 1, |
| 125 | + range.bus_addr); |
| 126 | + if (add_legacy_isa_io(&np->fwnode, range.cpu_addr, range.size)) |
| 127 | + pr_warn("Failed to reserve legacy IO in Logic PIO\n"); |
| 128 | + break; |
| 129 | + case IORESOURCE_MEM: |
| 130 | + pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx\n", |
| 131 | + range.cpu_addr, |
| 132 | + range.cpu_addr + range.size - 1, |
| 133 | + range.bus_addr); |
| 134 | + break; |
| 135 | + } |
| 136 | + } |
| 137 | + } |
101 | 138 | }
|
102 | 139 |
|
103 | 140 | void __init arch_init_irq(void)
|
|
0 commit comments