Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: loongson: Add ACPI init support

Loongson PCH (LS7A chipset) will be used by both MIPS-based and LoongArch-
based Loongson processors. MIPS-based Loongson uses FDT, while LoongArch-
based Loongson uses ACPI.

Add ACPI init support for the driver in pci-loongson.c because it is
currently FDT-only.

LoongArch is a new RISC ISA, mainline support will come soon, and
documentations are here (in translation):

https://github.com/loongson/LoongArch-Documentation

Link: https://lore.kernel.org/r/20220714124216.1489304-4-chenhuacai@loongson.cn
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>

authored by

Huacai Chen and committed by
Bjorn Helgaas
cd89edda dee449aa

+87 -20
+10
drivers/acpi/pci_mcfg.c
··· 172 172 ALTRA_ECAM_QUIRK(1, 14), 173 173 ALTRA_ECAM_QUIRK(1, 15), 174 174 #endif /* ARM64 */ 175 + 176 + #ifdef CONFIG_LOONGARCH 177 + #define LOONGSON_ECAM_MCFG(table_id, seg) \ 178 + { "LOONGS", table_id, 1, seg, MCFG_BUS_ANY, &loongson_pci_ecam_ops } 179 + 180 + LOONGSON_ECAM_MCFG("\0", 0), 181 + LOONGSON_ECAM_MCFG("LOONGSON", 0), 182 + LOONGSON_ECAM_MCFG("\0", 1), 183 + LOONGSON_ECAM_MCFG("LOONGSON", 1), 184 + #endif /* LOONGARCH */ 175 185 }; 176 186 177 187 static char mcfg_oem_id[ACPI_OEM_ID_SIZE];
+1 -1
drivers/pci/controller/Kconfig
··· 293 293 config PCI_LOONGSON 294 294 bool "LOONGSON PCI Controller" 295 295 depends on MACH_LOONGSON64 || COMPILE_TEST 296 - depends on OF 296 + depends on OF || ACPI 297 297 depends on PCI_QUIRKS 298 298 default MACH_LOONGSON64 299 299 help
+75 -19
drivers/pci/controller/pci-loongson.c
··· 9 9 #include <linux/of_pci.h> 10 10 #include <linux/pci.h> 11 11 #include <linux/pci_ids.h> 12 + #include <linux/pci-acpi.h> 13 + #include <linux/pci-ecam.h> 12 14 13 15 #include "../pci.h" 14 16 ··· 99 97 } 100 98 DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, loongson_mrrs_quirk); 101 99 102 - static void __iomem *cfg1_map(struct loongson_pci *priv, int bus, 103 - unsigned int devfn, int where) 100 + static struct loongson_pci *pci_bus_to_loongson_pci(struct pci_bus *bus) 104 101 { 105 - unsigned long addroff = 0x0; 102 + struct pci_config_window *cfg; 106 103 107 - if (bus != 0) 108 - addroff |= BIT(28); /* Type 1 Access */ 109 - addroff |= (where & 0xff) | ((where & 0xf00) << 16); 110 - addroff |= (bus << 16) | (devfn << 8); 111 - return priv->cfg1_base + addroff; 104 + if (acpi_disabled) 105 + return (struct loongson_pci *)(bus->sysdata); 106 + 107 + cfg = bus->sysdata; 108 + return (struct loongson_pci *)(cfg->priv); 112 109 } 113 110 114 - static void __iomem *cfg0_map(struct loongson_pci *priv, int bus, 115 - unsigned int devfn, int where) 111 + static void __iomem *cfg0_map(struct loongson_pci *priv, struct pci_bus *bus, 112 + unsigned int devfn, int where) 116 113 { 117 114 unsigned long addroff = 0x0; 115 + unsigned char busnum = bus->number; 118 116 119 - if (bus != 0) 117 + if (!pci_is_root_bus(bus)) { 120 118 addroff |= BIT(24); /* Type 1 Access */ 121 - addroff |= (bus << 16) | (devfn << 8) | where; 119 + addroff |= (busnum << 16); 120 + } 121 + addroff |= (devfn << 8) | where; 122 122 return priv->cfg0_base + addroff; 123 123 } 124 124 125 - static void __iomem *pci_loongson_map_bus(struct pci_bus *bus, unsigned int devfn, 126 - int where) 125 + static void __iomem *cfg1_map(struct loongson_pci *priv, struct pci_bus *bus, 126 + unsigned int devfn, int where) 127 127 { 128 + unsigned long addroff = 0x0; 128 129 unsigned char busnum = bus->number; 129 - struct pci_host_bridge *bridge = pci_find_host_bridge(bus); 130 - struct loongson_pci *priv = pci_host_bridge_priv(bridge); 130 + 131 + if (!pci_is_root_bus(bus)) { 132 + addroff |= BIT(28); /* Type 1 Access */ 133 + addroff |= (busnum << 16); 134 + } 135 + addroff |= (devfn << 8) | (where & 0xff) | ((where & 0xf00) << 16); 136 + return priv->cfg1_base + addroff; 137 + } 138 + 139 + static void __iomem *pci_loongson_map_bus(struct pci_bus *bus, 140 + unsigned int devfn, int where) 141 + { 142 + struct loongson_pci *priv = pci_bus_to_loongson_pci(bus); 131 143 132 144 /* 133 145 * Do not read more than one device on the bus other than 134 - * the host bus. For our hardware the root bus is always bus 0. 146 + * the host bus. 135 147 */ 136 148 if (priv->data->flags & FLAG_DEV_FIX && 137 149 !pci_is_root_bus(bus) && PCI_SLOT(devfn) > 0) ··· 153 137 154 138 /* CFG0 can only access standard space */ 155 139 if (where < PCI_CFG_SPACE_SIZE && priv->cfg0_base) 156 - return cfg0_map(priv, busnum, devfn, where); 140 + return cfg0_map(priv, bus, devfn, where); 157 141 158 142 /* CFG1 can access extended space */ 159 143 if (where < PCI_CFG_SPACE_EXP_SIZE && priv->cfg1_base) 160 - return cfg1_map(priv, busnum, devfn, where); 144 + return cfg1_map(priv, bus, devfn, where); 161 145 162 146 return NULL; 163 147 } 148 + 149 + #ifdef CONFIG_OF 164 150 165 151 static int loongson_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) 166 152 { ··· 277 259 .probe = loongson_pci_probe, 278 260 }; 279 261 builtin_platform_driver(loongson_pci_driver); 262 + 263 + #endif 264 + 265 + #ifdef CONFIG_ACPI 266 + 267 + static int loongson_pci_ecam_init(struct pci_config_window *cfg) 268 + { 269 + struct device *dev = cfg->parent; 270 + struct loongson_pci *priv; 271 + struct loongson_pci_data *data; 272 + 273 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 274 + if (!priv) 275 + return -ENOMEM; 276 + 277 + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 278 + if (!data) 279 + return -ENOMEM; 280 + 281 + cfg->priv = priv; 282 + data->flags = FLAG_CFG1; 283 + priv->data = data; 284 + priv->cfg1_base = cfg->win - (cfg->busr.start << 16); 285 + 286 + return 0; 287 + } 288 + 289 + const struct pci_ecam_ops loongson_pci_ecam_ops = { 290 + .bus_shift = 16, 291 + .init = loongson_pci_ecam_init, 292 + .pci_ops = { 293 + .map_bus = pci_loongson_map_bus, 294 + .read = pci_generic_config_read, 295 + .write = pci_generic_config_write, 296 + } 297 + }; 298 + 299 + #endif
+1
include/linux/pci-ecam.h
··· 87 87 extern const struct pci_ecam_ops xgene_v2_pcie_ecam_ops; /* APM X-Gene PCIe v2.x */ 88 88 extern const struct pci_ecam_ops al_pcie_ops; /* Amazon Annapurna Labs PCIe */ 89 89 extern const struct pci_ecam_ops tegra194_pcie_ops; /* Tegra194 PCIe */ 90 + extern const struct pci_ecam_ops loongson_pci_ecam_ops; /* Loongson PCIe */ 90 91 #endif 91 92 92 93 #if IS_ENABLED(CONFIG_PCI_HOST_COMMON)