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