~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/kernel/io-workarounds.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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         struct iowa_bus *bus;
 59         int token;
 60 
 61         token = PCI_GET_ADDR_TOKEN(addr);
 62 
 63         if (token && token <= iowa_bus_count)
 64                 bus = &iowa_busses[token - 1];
 65         else {
 66                 unsigned long vaddr, paddr;
 67 
 68                 vaddr = (unsigned long)PCI_FIX_ADDR(addr);
 69                 if (vaddr < PHB_IO_BASE || vaddr >= PHB_IO_END)
 70                         return NULL;
 71 
 72                 paddr = ppc_find_vmap_phys(vaddr);
 73 
 74                 bus = iowa_pci_find(vaddr, paddr);
 75 
 76                 if (bus == NULL)
 77                         return NULL;
 78         }
 79 
 80         return bus;
 81 }
 82 #else /* CONFIG_PPC_INDIRECT_MMIO */
 83 struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR addr)
 84 {
 85         return NULL;
 86 }
 87 #endif /* !CONFIG_PPC_INDIRECT_MMIO */
 88 
 89 #ifdef CONFIG_PPC_INDIRECT_PIO
 90 struct iowa_bus *iowa_pio_find_bus(unsigned long port)
 91 {
 92         unsigned long vaddr = (unsigned long)pci_io_base + port;
 93         return iowa_pci_find(vaddr, 0);
 94 }
 95 #else
 96 struct iowa_bus *iowa_pio_find_bus(unsigned long port)
 97 {
 98         return NULL;
 99 }
100 #endif
101 
102 #define DEF_PCI_AC_RET(name, ret, at, al, space, aa)            \
103 static ret iowa_##name at                                       \
104 {                                                               \
105         struct iowa_bus *bus;                                   \
106         bus = iowa_##space##_find_bus(aa);                      \
107         if (bus && bus->ops && bus->ops->name)                  \
108                 return bus->ops->name al;                       \
109         return __do_##name al;                                  \
110 }
111 
112 #define DEF_PCI_AC_NORET(name, at, al, space, aa)               \
113 static void 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                 bus->ops->name al;                              \
119                 return;                                         \
120         }                                                       \
121         __do_##name al;                                         \
122 }
123 
124 #include <asm/io-defs.h>
125 
126 #undef DEF_PCI_AC_RET
127 #undef DEF_PCI_AC_NORET
128 
129 static const struct ppc_pci_io iowa_pci_io = {
130 
131 #define DEF_PCI_AC_RET(name, ret, at, al, space, aa)    .name = iowa_##name,
132 #define DEF_PCI_AC_NORET(name, at, al, space, aa)       .name = iowa_##name,
133 
134 #include <asm/io-defs.h>
135 
136 #undef DEF_PCI_AC_RET
137 #undef DEF_PCI_AC_NORET
138 
139 };
140 
141 #ifdef CONFIG_PPC_INDIRECT_MMIO
142 void __iomem *iowa_ioremap(phys_addr_t addr, unsigned long size,
143                            pgprot_t prot, void *caller)
144 {
145         struct iowa_bus *bus;
146         void __iomem *res = __ioremap_caller(addr, size, prot, caller);
147         int busno;
148 
149         bus = iowa_pci_find(0, (unsigned long)addr);
150         if (bus != NULL) {
151                 busno = bus - iowa_busses;
152                 PCI_SET_ADDR_TOKEN(res, busno + 1);
153         }
154         return res;
155 }
156 #endif /* !CONFIG_PPC_INDIRECT_MMIO */
157 
158 bool io_workaround_inited;
159 
160 /* Enable IO workaround */
161 static void io_workaround_init(void)
162 {
163         if (io_workaround_inited)
164                 return;
165         ppc_pci_io = iowa_pci_io;
166         io_workaround_inited = true;
167 }
168 
169 /* Register new bus to support workaround */
170 void iowa_register_bus(struct pci_controller *phb, struct ppc_pci_io *ops,
171                        int (*initfunc)(struct iowa_bus *, void *), void *data)
172 {
173         struct iowa_bus *bus;
174         struct device_node *np = phb->dn;
175 
176         io_workaround_init();
177 
178         if (iowa_bus_count >= IOWA_MAX_BUS) {
179                 pr_err("IOWA:Too many pci bridges, "
180                        "workarounds disabled for %pOF\n", np);
181                 return;
182         }
183 
184         bus = &iowa_busses[iowa_bus_count];
185         bus->phb = phb;
186         bus->ops = ops;
187         bus->private = data;
188 
189         if (initfunc)
190                 if ((*initfunc)(bus, data))
191                         return;
192 
193         iowa_bus_count++;
194 
195         pr_debug("IOWA:[%d]Add bus, %pOF.\n", iowa_bus_count-1, np);
196 }
197 
198 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php