Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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)