0001
0002
0003
0004
0005
0006
0007
0008
0009 #undef DEBUG
0010
0011 #include <linux/kernel.h>
0012 #include <linux/sched/mm.h> /* for init_mm */
0013 #include <linux/pgtable.h>
0014
0015 #include <asm/io.h>
0016 #include <asm/machdep.h>
0017 #include <asm/ppc-pci.h>
0018 #include <asm/io-workarounds.h>
0019 #include <asm/pte-walk.h>
0020
0021
0022 #define IOWA_MAX_BUS 8
0023
0024 static struct iowa_bus iowa_busses[IOWA_MAX_BUS];
0025 static unsigned int iowa_bus_count;
0026
0027 static struct iowa_bus *iowa_pci_find(unsigned long vaddr, unsigned long paddr)
0028 {
0029 int i, j;
0030 struct resource *res;
0031 unsigned long vstart, vend;
0032
0033 for (i = 0; i < iowa_bus_count; i++) {
0034 struct iowa_bus *bus = &iowa_busses[i];
0035 struct pci_controller *phb = bus->phb;
0036
0037 if (vaddr) {
0038 vstart = (unsigned long)phb->io_base_virt;
0039 vend = vstart + phb->pci_io_size - 1;
0040 if ((vaddr >= vstart) && (vaddr <= vend))
0041 return bus;
0042 }
0043
0044 if (paddr)
0045 for (j = 0; j < 3; j++) {
0046 res = &phb->mem_resources[j];
0047 if (paddr >= res->start && paddr <= res->end)
0048 return bus;
0049 }
0050 }
0051
0052 return NULL;
0053 }
0054
0055 #ifdef CONFIG_PPC_INDIRECT_MMIO
0056 struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR addr)
0057 {
0058 struct iowa_bus *bus;
0059 int token;
0060
0061 token = PCI_GET_ADDR_TOKEN(addr);
0062
0063 if (token && token <= iowa_bus_count)
0064 bus = &iowa_busses[token - 1];
0065 else {
0066 unsigned long vaddr, paddr;
0067
0068 vaddr = (unsigned long)PCI_FIX_ADDR(addr);
0069 if (vaddr < PHB_IO_BASE || vaddr >= PHB_IO_END)
0070 return NULL;
0071
0072 paddr = ppc_find_vmap_phys(vaddr);
0073
0074 bus = iowa_pci_find(vaddr, paddr);
0075
0076 if (bus == NULL)
0077 return NULL;
0078 }
0079
0080 return bus;
0081 }
0082 #else
0083 struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR addr)
0084 {
0085 return NULL;
0086 }
0087 #endif
0088
0089 #ifdef CONFIG_PPC_INDIRECT_PIO
0090 struct iowa_bus *iowa_pio_find_bus(unsigned long port)
0091 {
0092 unsigned long vaddr = (unsigned long)pci_io_base + port;
0093 return iowa_pci_find(vaddr, 0);
0094 }
0095 #else
0096 struct iowa_bus *iowa_pio_find_bus(unsigned long port)
0097 {
0098 return NULL;
0099 }
0100 #endif
0101
0102 #define DEF_PCI_AC_RET(name, ret, at, al, space, aa) \
0103 static ret iowa_##name at \
0104 { \
0105 struct iowa_bus *bus; \
0106 bus = iowa_##space##_find_bus(aa); \
0107 if (bus && bus->ops && bus->ops->name) \
0108 return bus->ops->name al; \
0109 return __do_##name al; \
0110 }
0111
0112 #define DEF_PCI_AC_NORET(name, at, al, space, aa) \
0113 static void iowa_##name at \
0114 { \
0115 struct iowa_bus *bus; \
0116 bus = iowa_##space##_find_bus(aa); \
0117 if (bus && bus->ops && bus->ops->name) { \
0118 bus->ops->name al; \
0119 return; \
0120 } \
0121 __do_##name al; \
0122 }
0123
0124 #include <asm/io-defs.h>
0125
0126 #undef DEF_PCI_AC_RET
0127 #undef DEF_PCI_AC_NORET
0128
0129 static const struct ppc_pci_io iowa_pci_io = {
0130
0131 #define DEF_PCI_AC_RET(name, ret, at, al, space, aa) .name = iowa_##name,
0132 #define DEF_PCI_AC_NORET(name, at, al, space, aa) .name = iowa_##name,
0133
0134 #include <asm/io-defs.h>
0135
0136 #undef DEF_PCI_AC_RET
0137 #undef DEF_PCI_AC_NORET
0138
0139 };
0140
0141 #ifdef CONFIG_PPC_INDIRECT_MMIO
0142 void __iomem *iowa_ioremap(phys_addr_t addr, unsigned long size,
0143 pgprot_t prot, void *caller)
0144 {
0145 struct iowa_bus *bus;
0146 void __iomem *res = __ioremap_caller(addr, size, prot, caller);
0147 int busno;
0148
0149 bus = iowa_pci_find(0, (unsigned long)addr);
0150 if (bus != NULL) {
0151 busno = bus - iowa_busses;
0152 PCI_SET_ADDR_TOKEN(res, busno + 1);
0153 }
0154 return res;
0155 }
0156 #endif
0157
0158 bool io_workaround_inited;
0159
0160
0161 static void io_workaround_init(void)
0162 {
0163 if (io_workaround_inited)
0164 return;
0165 ppc_pci_io = iowa_pci_io;
0166 io_workaround_inited = true;
0167 }
0168
0169
0170 void iowa_register_bus(struct pci_controller *phb, struct ppc_pci_io *ops,
0171 int (*initfunc)(struct iowa_bus *, void *), void *data)
0172 {
0173 struct iowa_bus *bus;
0174 struct device_node *np = phb->dn;
0175
0176 io_workaround_init();
0177
0178 if (iowa_bus_count >= IOWA_MAX_BUS) {
0179 pr_err("IOWA:Too many pci bridges, "
0180 "workarounds disabled for %pOF\n", np);
0181 return;
0182 }
0183
0184 bus = &iowa_busses[iowa_bus_count];
0185 bus->phb = phb;
0186 bus->ops = ops;
0187 bus->private = data;
0188
0189 if (initfunc)
0190 if ((*initfunc)(bus, data))
0191 return;
0192
0193 iowa_bus_count++;
0194
0195 pr_debug("IOWA:[%d]Add bus, %pOF.\n", iowa_bus_count-1, np);
0196 }
0197