linux-stable/arch/powerpc/kernel/io-workarounds.c

198 lines
4.2 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0-only
/*
* Support PCI IO workaround
*
* Copyright (C) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>
* IBM, Corp.
* (C) Copyright 2007-2008 TOSHIBA CORPORATION
*/
#undef DEBUG
#include <linux/kernel.h>
#include <linux/sched/mm.h> /* for init_mm */
mm: reorder includes after introduction of linux/pgtable.h The replacement of <asm/pgrable.h> with <linux/pgtable.h> made the include of the latter in the middle of asm includes. Fix this up with the aid of the below script and manual adjustments here and there. import sys import re if len(sys.argv) is not 3: print "USAGE: %s <file> <header>" % (sys.argv[0]) sys.exit(1) hdr_to_move="#include <linux/%s>" % sys.argv[2] moved = False in_hdrs = False with open(sys.argv[1], "r") as f: lines = f.readlines() for _line in lines: line = _line.rstrip(' ') if line == hdr_to_move: continue if line.startswith("#include <linux/"): in_hdrs = True elif not moved and in_hdrs: moved = True print hdr_to_move print line Signed-off-by: Mike Rapoport <rppt@linux.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Borislav Petkov <bp@alien8.de> Cc: Brian Cain <bcain@codeaurora.org> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Chris Zankel <chris@zankel.net> Cc: "David S. Miller" <davem@davemloft.net> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Cc: Greentime Hu <green.hu@gmail.com> Cc: Greg Ungerer <gerg@linux-m68k.org> Cc: Guan Xuetao <gxt@pku.edu.cn> Cc: Guo Ren <guoren@kernel.org> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: Helge Deller <deller@gmx.de> Cc: Ingo Molnar <mingo@redhat.com> Cc: Ley Foon Tan <ley.foon.tan@intel.com> Cc: Mark Salter <msalter@redhat.com> Cc: Matthew Wilcox <willy@infradead.org> Cc: Matt Turner <mattst88@gmail.com> Cc: Max Filippov <jcmvbkbc@gmail.com> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Michal Simek <monstr@monstr.eu> Cc: Nick Hu <nickhu@andestech.com> Cc: Paul Walmsley <paul.walmsley@sifive.com> Cc: Richard Weinberger <richard@nod.at> Cc: Rich Felker <dalias@libc.org> Cc: Russell King <linux@armlinux.org.uk> Cc: Stafford Horne <shorne@gmail.com> Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Tony Luck <tony.luck@intel.com> Cc: Vincent Chen <deanbo422@gmail.com> Cc: Vineet Gupta <vgupta@synopsys.com> Cc: Will Deacon <will@kernel.org> Cc: Yoshinori Sato <ysato@users.sourceforge.jp> Link: http://lkml.kernel.org/r/20200514170327.31389-4-rppt@kernel.org Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-06-09 04:32:42 +00:00
#include <linux/pgtable.h>
#include <asm/io.h>
#include <asm/machdep.h>
#include <asm/ppc-pci.h>
#include <asm/io-workarounds.h>
#include <asm/pte-walk.h>
#define IOWA_MAX_BUS 8
static struct iowa_bus iowa_busses[IOWA_MAX_BUS];
static unsigned int iowa_bus_count;
static struct iowa_bus *iowa_pci_find(unsigned long vaddr, unsigned long paddr)
{
int i, j;
struct resource *res;
unsigned long vstart, vend;
for (i = 0; i < iowa_bus_count; i++) {
struct iowa_bus *bus = &iowa_busses[i];
struct pci_controller *phb = bus->phb;
if (vaddr) {
vstart = (unsigned long)phb->io_base_virt;
vend = vstart + phb->pci_io_size - 1;
if ((vaddr >= vstart) && (vaddr <= vend))
return bus;
}
if (paddr)
for (j = 0; j < 3; j++) {
res = &phb->mem_resources[j];
if (paddr >= res->start && paddr <= res->end)
return bus;
}
}
return NULL;
}
#ifdef CONFIG_PPC_INDIRECT_MMIO
struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR addr)
{
struct iowa_bus *bus;
int token;
token = PCI_GET_ADDR_TOKEN(addr);
if (token && token <= iowa_bus_count)
bus = &iowa_busses[token - 1];
else {
unsigned long vaddr, paddr;
vaddr = (unsigned long)PCI_FIX_ADDR(addr);
if (vaddr < PHB_IO_BASE || vaddr >= PHB_IO_END)
return NULL;
paddr = ppc_find_vmap_phys(vaddr);
bus = iowa_pci_find(vaddr, paddr);
if (bus == NULL)
return NULL;
}
return bus;
}
#else /* CONFIG_PPC_INDIRECT_MMIO */
struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR addr)
{
return NULL;
}
#endif /* !CONFIG_PPC_INDIRECT_MMIO */
#ifdef CONFIG_PPC_INDIRECT_PIO
struct iowa_bus *iowa_pio_find_bus(unsigned long port)
{
unsigned long vaddr = (unsigned long)pci_io_base + port;
return iowa_pci_find(vaddr, 0);
}
#else
struct iowa_bus *iowa_pio_find_bus(unsigned long port)
{
return NULL;
}
#endif
#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) \
static ret iowa_##name at \
{ \
struct iowa_bus *bus; \
bus = iowa_##space##_find_bus(aa); \
if (bus && bus->ops && bus->ops->name) \
return bus->ops->name al; \
return __do_##name al; \
}
#define DEF_PCI_AC_NORET(name, at, al, space, aa) \
static void iowa_##name at \
{ \
struct iowa_bus *bus; \
bus = iowa_##space##_find_bus(aa); \
if (bus && bus->ops && bus->ops->name) { \
bus->ops->name al; \
return; \
} \
__do_##name al; \
}
#include <asm/io-defs.h>
#undef DEF_PCI_AC_RET
#undef DEF_PCI_AC_NORET
static const struct ppc_pci_io iowa_pci_io = {
#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) .name = iowa_##name,
#define DEF_PCI_AC_NORET(name, at, al, space, aa) .name = iowa_##name,
#include <asm/io-defs.h>
#undef DEF_PCI_AC_RET
#undef DEF_PCI_AC_NORET
};
#ifdef CONFIG_PPC_INDIRECT_MMIO
void __iomem *iowa_ioremap(phys_addr_t addr, unsigned long size,
pgprot_t prot, void *caller)
{
struct iowa_bus *bus;
void __iomem *res = __ioremap_caller(addr, size, prot, caller);
int busno;
bus = iowa_pci_find(0, (unsigned long)addr);
if (bus != NULL) {
busno = bus - iowa_busses;
PCI_SET_ADDR_TOKEN(res, busno + 1);
}
return res;
}
#endif /* !CONFIG_PPC_INDIRECT_MMIO */
bool io_workaround_inited;
/* Enable IO workaround */
static void io_workaround_init(void)
{
if (io_workaround_inited)
return;
ppc_pci_io = iowa_pci_io;
io_workaround_inited = true;
}
/* Register new bus to support workaround */
void iowa_register_bus(struct pci_controller *phb, struct ppc_pci_io *ops,
int (*initfunc)(struct iowa_bus *, void *), void *data)
{
struct iowa_bus *bus;
struct device_node *np = phb->dn;
io_workaround_init();
if (iowa_bus_count >= IOWA_MAX_BUS) {
pr_err("IOWA:Too many pci bridges, "
"workarounds disabled for %pOF\n", np);
return;
}
bus = &iowa_busses[iowa_bus_count];
bus->phb = phb;
bus->ops = ops;
bus->private = data;
if (initfunc)
if ((*initfunc)(bus, data))
return;
iowa_bus_count++;
pr_debug("IOWA:[%d]Add bus, %pOF.\n", iowa_bus_count-1, np);
}