1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2020 Loongson Technology Corporation Limited 4 * 5 */ 6#include <linux/pci.h> 7#include <linux/acpi.h> 8#include <linux/init.h> 9#include <linux/irq.h> 10#include <linux/slab.h> 11#include <linux/pci-acpi.h> 12#include <linux/pci-ecam.h> 13 14#include <asm/numa.h> 15#include <asm/pci.h> 16#include <loongson.h> 17 18struct pci_root_info { 19 struct acpi_pci_root_info common; 20 struct pci_config_window *cfg; 21}; 22 23void pcibios_add_bus(struct pci_bus *bus) 24{ 25 acpi_pci_add_bus(bus); 26} 27 28int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) 29{ 30 struct pci_config_window *cfg = bridge->bus->sysdata; 31 struct acpi_device *adev = to_acpi_device(cfg->parent); 32 struct device *bus_dev = &bridge->bus->dev; 33 34 ACPI_COMPANION_SET(&bridge->dev, adev); 35 set_dev_node(bus_dev, pa_to_nid(cfg->res.start)); 36 37 return 0; 38} 39 40int acpi_pci_bus_find_domain_nr(struct pci_bus *bus) 41{ 42 struct pci_config_window *cfg = bus->sysdata; 43 struct acpi_device *adev = to_acpi_device(cfg->parent); 44 struct acpi_pci_root *root = acpi_driver_data(adev); 45 46 return root->segment; 47} 48 49static void acpi_release_root_info(struct acpi_pci_root_info *ci) 50{ 51 struct pci_root_info *info; 52 53 info = container_of(ci, struct pci_root_info, common); 54 pci_ecam_free(info->cfg); 55 kfree(ci->ops); 56 kfree(info); 57} 58 59static int acpi_prepare_root_resources(struct acpi_pci_root_info *ci) 60{ 61 struct acpi_device *device = ci->bridge; 62 struct resource_entry *entry, *tmp; 63 int status; 64 65 status = acpi_pci_probe_root_resources(ci); 66 if (status > 0) { 67 resource_list_for_each_entry_safe(entry, tmp, &ci->resources) { 68 if (entry->res->flags & IORESOURCE_MEM) { 69 entry->offset = ci->root->mcfg_addr & GENMASK_ULL(63, 40); 70 entry->res->start |= entry->offset; 71 entry->res->end |= entry->offset; 72 } 73 } 74 return status; 75 } 76 77 resource_list_for_each_entry_safe(entry, tmp, &ci->resources) { 78 dev_printk(KERN_DEBUG, &device->dev, 79 "host bridge window %pR (ignored)\n", entry->res); 80 resource_list_destroy_entry(entry); 81 } 82 83 return 0; 84} 85 86/* 87 * Create a PCI config space window 88 * - reserve mem region 89 * - alloc struct pci_config_window with space for all mappings 90 * - ioremap the config space 91 */ 92static struct pci_config_window *arch_pci_ecam_create(struct device *dev, 93 struct resource *cfgres, struct resource *busr, const struct pci_ecam_ops *ops) 94{ 95 int err; 96 unsigned int bus_range, bsz; 97 struct resource *conflict; 98 struct pci_config_window *cfg; 99 100 if (busr->start > busr->end) 101 return ERR_PTR(-EINVAL); 102 103 cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); 104 if (!cfg) 105 return ERR_PTR(-ENOMEM); 106 107 cfg->parent = dev; 108 cfg->ops = ops; 109 cfg->busr.start = busr->start; 110 cfg->busr.end = busr->end; 111 cfg->busr.flags = IORESOURCE_BUS; 112 bus_range = resource_size(cfgres) >> ops->bus_shift; 113 114 bsz = 1 << ops->bus_shift; 115 116 cfg->res.start = cfgres->start; 117 cfg->res.end = cfgres->end; 118 cfg->res.flags = IORESOURCE_MEM | IORESOURCE_BUSY; 119 cfg->res.name = "PCI ECAM"; 120 121 conflict = request_resource_conflict(&iomem_resource, &cfg->res); 122 if (conflict) { 123 err = -EBUSY; 124 dev_err(dev, "can't claim ECAM area %pR: address conflict with %s %pR\n", 125 &cfg->res, conflict->name, conflict); 126 goto err_exit; 127 } 128 129 cfg->win = pci_remap_cfgspace(cfgres->start, bus_range * bsz); 130 if (!cfg->win) 131 goto err_exit_iomap; 132 133 if (ops->init) { 134 err = ops->init(cfg); 135 if (err) 136 goto err_exit; 137 } 138 dev_info(dev, "ECAM at %pR for %pR\n", &cfg->res, &cfg->busr); 139 return cfg; 140 141err_exit_iomap: 142 err = -ENOMEM; 143 dev_err(dev, "ECAM ioremap failed\n"); 144err_exit: 145 pci_ecam_free(cfg); 146 return ERR_PTR(err); 147} 148 149/* 150 * Lookup the bus range for the domain in MCFG, and set up config space 151 * mapping. 152 */ 153static struct pci_config_window * 154pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) 155{ 156 int ret, bus_shift; 157 u16 seg = root->segment; 158 struct device *dev = &root->device->dev; 159 struct resource cfgres; 160 struct resource *bus_res = &root->secondary; 161 struct pci_config_window *cfg; 162 const struct pci_ecam_ops *ecam_ops; 163 164 ret = pci_mcfg_lookup(root, &cfgres, &ecam_ops); 165 if (ret < 0) { 166 dev_err(dev, "%04x:%pR ECAM region not found, use default value\n", seg, bus_res); 167 ecam_ops = &loongson_pci_ecam_ops; 168 root->mcfg_addr = mcfg_addr_init(0); 169 } 170 171 bus_shift = ecam_ops->bus_shift ? : 20; 172 173 if (bus_shift == 20) 174 cfg = pci_ecam_create(dev, &cfgres, bus_res, ecam_ops); 175 else { 176 cfgres.start = root->mcfg_addr + (bus_res->start << bus_shift); 177 cfgres.end = cfgres.start + (resource_size(bus_res) << bus_shift) - 1; 178 cfgres.end |= BIT(28) + (((PCI_CFG_SPACE_EXP_SIZE - 1) & 0xf00) << 16); 179 cfgres.flags = IORESOURCE_MEM; 180 cfg = arch_pci_ecam_create(dev, &cfgres, bus_res, ecam_ops); 181 } 182 183 if (IS_ERR(cfg)) { 184 dev_err(dev, "%04x:%pR error %ld mapping ECAM\n", seg, bus_res, PTR_ERR(cfg)); 185 return NULL; 186 } 187 188 return cfg; 189} 190 191struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) 192{ 193 struct pci_bus *bus; 194 struct pci_root_info *info; 195 struct acpi_pci_root_ops *root_ops; 196 int domain = root->segment; 197 int busnum = root->secondary.start; 198 199 info = kzalloc(sizeof(*info), GFP_KERNEL); 200 if (!info) { 201 printk(KERN_WARNING "pci_bus %04x:%02x: " 202 "ignored (out of memory)\n", domain, busnum); 203 return NULL; 204 } 205 206 root_ops = kzalloc(sizeof(*root_ops), GFP_KERNEL); 207 if (!root_ops) { 208 kfree(info); 209 return NULL; 210 } 211 212 info->cfg = pci_acpi_setup_ecam_mapping(root); 213 if (!info->cfg) { 214 kfree(info); 215 kfree(root_ops); 216 return NULL; 217 } 218 219 root_ops->release_info = acpi_release_root_info; 220 root_ops->prepare_resources = acpi_prepare_root_resources; 221 root_ops->pci_ops = (struct pci_ops *)&info->cfg->ops->pci_ops; 222 223 bus = pci_find_bus(domain, busnum); 224 if (bus) { 225 memcpy(bus->sysdata, info->cfg, sizeof(struct pci_config_window)); 226 kfree(info); 227 } else { 228 struct pci_bus *child; 229 230 bus = acpi_pci_root_create(root, root_ops, 231 &info->common, info->cfg); 232 if (!bus) { 233 kfree(info); 234 kfree(root_ops); 235 return NULL; 236 } 237 238 pci_bus_size_bridges(bus); 239 pci_bus_assign_resources(bus); 240 list_for_each_entry(child, &bus->children, node) 241 pcie_bus_configure_settings(child); 242 } 243 244 return bus; 245} 246