1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Support PCI IO workaround 4 * 5 * Copyright (C) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org> 6 * IBM, Corp. 7 * (C) Copyright 2007-2008 TOSHIBA CORPORATION 8 */ 9 #undef DEBUG 10 11 #include <linux/kernel.h> 12 #include <linux/sched/mm.h> /* for init_mm */ 13 #include <linux/pgtable.h> 14 15 #include <asm/io.h> 16 #include <asm/machdep.h> 17 #include <asm/ppc-pci.h> 18 #include <asm/io-workarounds.h> 19 #include <asm/pte-walk.h> 20 21 22 #define IOWA_MAX_BUS 8 23 24 static struct iowa_bus iowa_busses[IOWA_MAX_BUS]; 25 static unsigned int iowa_bus_count; 26 27 static struct iowa_bus *iowa_pci_find(unsigned long vaddr, unsigned long paddr) 28 { 29 int i, j; 30 struct resource *res; 31 unsigned long vstart, vend; 32 33 for (i = 0; i < iowa_bus_count; i++) { 34 struct iowa_bus *bus = &iowa_busses[i]; 35 struct pci_controller *phb = bus->phb; 36 37 if (vaddr) { 38 vstart = (unsigned long)phb->io_base_virt; 39 vend = vstart + phb->pci_io_size - 1; 40 if ((vaddr >= vstart) && (vaddr <= vend)) 41 return bus; 42 } 43 44 if (paddr) 45 for (j = 0; j < 3; j++) { 46 res = &phb->mem_resources[j]; 47 if (paddr >= res->start && paddr <= res->end) 48 return bus; 49 } 50 } 51 52 return NULL; 53 } 54 55 #ifdef CONFIG_PPC_INDIRECT_MMIO 56 struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR addr) 57 { 58 unsigned hugepage_shift; 59 struct iowa_bus *bus; 60 int token; 61 62 token = PCI_GET_ADDR_TOKEN(addr); 63 64 if (token && token <= iowa_bus_count) 65 bus = &iowa_busses[token - 1]; 66 else { 67 unsigned long vaddr, paddr; 68 pte_t *ptep; 69 70 vaddr = (unsigned long)PCI_FIX_ADDR(addr); 71 if (vaddr < PHB_IO_BASE || vaddr >= PHB_IO_END) 72 return NULL; 73 /* 74 * We won't find huge pages here (iomem). Also can't hit 75 * a page table free due to init_mm 76 */ 77 ptep = find_init_mm_pte(vaddr, &hugepage_shift); 78 if (ptep == NULL) 79 paddr = 0; 80 else { 81 WARN_ON(hugepage_shift); 82 paddr = pte_pfn(*ptep) << PAGE_SHIFT; 83 } 84 bus = iowa_pci_find(vaddr, paddr); 85 86 if (bus == NULL) 87 return NULL; 88 } 89 90 return bus; 91 } 92 #else /* CONFIG_PPC_INDIRECT_MMIO */ 93 struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR addr) 94 { 95 return NULL; 96 } 97 #endif /* !CONFIG_PPC_INDIRECT_MMIO */ 98 99 #ifdef CONFIG_PPC_INDIRECT_PIO 100 struct iowa_bus *iowa_pio_find_bus(unsigned long port) 101 { 102 unsigned long vaddr = (unsigned long)pci_io_base + port; 103 return iowa_pci_find(vaddr, 0); 104 } 105 #else 106 struct iowa_bus *iowa_pio_find_bus(unsigned long port) 107 { 108 return NULL; 109 } 110 #endif 111 112 #define DEF_PCI_AC_RET(name, ret, at, al, space, aa) \ 113 static ret iowa_##name at \ 114 { \ 115 struct iowa_bus *bus; \ 116 bus = iowa_##space##_find_bus(aa); \ 117 if (bus && bus->ops && bus->ops->name) \ 118 return bus->ops->name al; \ 119 return __do_##name al; \ 120 } 121 122 #define DEF_PCI_AC_NORET(name, at, al, space, aa) \ 123 static void iowa_##name at \ 124 { \ 125 struct iowa_bus *bus; \ 126 bus = iowa_##space##_find_bus(aa); \ 127 if (bus && bus->ops && bus->ops->name) { \ 128 bus->ops->name al; \ 129 return; \ 130 } \ 131 __do_##name al; \ 132 } 133 134 #include <asm/io-defs.h> 135 136 #undef DEF_PCI_AC_RET 137 #undef DEF_PCI_AC_NORET 138 139 static const struct ppc_pci_io iowa_pci_io = { 140 141 #define DEF_PCI_AC_RET(name, ret, at, al, space, aa) .name = iowa_##name, 142 #define DEF_PCI_AC_NORET(name, at, al, space, aa) .name = iowa_##name, 143 144 #include <asm/io-defs.h> 145 146 #undef DEF_PCI_AC_RET 147 #undef DEF_PCI_AC_NORET 148 149 }; 150 151 #ifdef CONFIG_PPC_INDIRECT_MMIO 152 void __iomem *iowa_ioremap(phys_addr_t addr, unsigned long size, 153 pgprot_t prot, void *caller) 154 { 155 struct iowa_bus *bus; 156 void __iomem *res = __ioremap_caller(addr, size, prot, caller); 157 int busno; 158 159 bus = iowa_pci_find(0, (unsigned long)addr); 160 if (bus != NULL) { 161 busno = bus - iowa_busses; 162 PCI_SET_ADDR_TOKEN(res, busno + 1); 163 } 164 return res; 165 } 166 #endif /* !CONFIG_PPC_INDIRECT_MMIO */ 167 168 bool io_workaround_inited; 169 170 /* Enable IO workaround */ 171 static void io_workaround_init(void) 172 { 173 if (io_workaround_inited) 174 return; 175 ppc_pci_io = iowa_pci_io; 176 io_workaround_inited = true; 177 } 178 179 /* Register new bus to support workaround */ 180 void iowa_register_bus(struct pci_controller *phb, struct ppc_pci_io *ops, 181 int (*initfunc)(struct iowa_bus *, void *), void *data) 182 { 183 struct iowa_bus *bus; 184 struct device_node *np = phb->dn; 185 186 io_workaround_init(); 187 188 if (iowa_bus_count >= IOWA_MAX_BUS) { 189 pr_err("IOWA:Too many pci bridges, " 190 "workarounds disabled for %pOF\n", np); 191 return; 192 } 193 194 bus = &iowa_busses[iowa_bus_count]; 195 bus->phb = phb; 196 bus->ops = ops; 197 bus->private = data; 198 199 if (initfunc) 200 if ((*initfunc)(bus, data)) 201 return; 202 203 iowa_bus_count++; 204 205 pr_debug("IOWA:[%d]Add bus, %pOF.\n", iowa_bus_count-1, np); 206 } 207 208