1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 4 */ 5 #include <linux/pci.h> 6 #include <linux/acpi.h> 7 #include <linux/init.h> 8 #include <linux/irq.h> 9 #include <linux/slab.h> 10 #include <linux/pci-acpi.h> 11 #include <linux/pci-ecam.h> 12 13 #include <asm/pci.h> 14 #include <asm/numa.h> 15 #include <asm/loongson.h> 16 17 struct pci_root_info { 18 struct acpi_pci_root_info common; 19 struct pci_config_window *cfg; 20 }; 21 22 void pcibios_add_bus(struct pci_bus *bus) 23 { 24 acpi_pci_add_bus(bus); 25 } 26 27 int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) 28 { 29 struct pci_config_window *cfg = bridge->bus->sysdata; 30 struct acpi_device *adev = to_acpi_device(cfg->parent); 31 struct device *bus_dev = &bridge->bus->dev; 32 33 ACPI_COMPANION_SET(&bridge->dev, adev); 34 set_dev_node(bus_dev, pa_to_nid(cfg->res.start)); 35 36 return 0; 37 } 38 39 int acpi_pci_bus_find_domain_nr(struct pci_bus *bus) 40 { 41 struct pci_config_window *cfg = bus->sysdata; 42 struct acpi_device *adev = to_acpi_device(cfg->parent); 43 struct acpi_pci_root *root = acpi_driver_data(adev); 44 45 return root->segment; 46 } 47 48 static void acpi_release_root_info(struct acpi_pci_root_info *ci) 49 { 50 struct pci_root_info *info; 51 52 info = container_of(ci, struct pci_root_info, common); 53 pci_ecam_free(info->cfg); 54 kfree(ci->ops); 55 kfree(info); 56 } 57 58 static int acpi_prepare_root_resources(struct acpi_pci_root_info *ci) 59 { 60 int status; 61 struct resource_entry *entry, *tmp; 62 struct acpi_device *device = ci->bridge; 63 64 status = acpi_pci_probe_root_resources(ci); 65 if (status > 0) { 66 resource_list_for_each_entry_safe(entry, tmp, &ci->resources) { 67 if (entry->res->flags & IORESOURCE_MEM) { 68 entry->offset = ci->root->mcfg_addr & GENMASK_ULL(63, 40); 69 entry->res->start |= entry->offset; 70 entry->res->end |= entry->offset; 71 } 72 } 73 return status; 74 } 75 76 resource_list_for_each_entry_safe(entry, tmp, &ci->resources) { 77 dev_dbg(&device->dev, 78 "host bridge window %pR (ignored)\n", entry->res); 79 resource_list_destroy_entry(entry); 80 } 81 82 return 0; 83 } 84 85 /* 86 * Lookup the bus range for the domain in MCFG, and set up config space 87 * mapping. 88 */ 89 static struct pci_config_window * 90 pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) 91 { 92 int ret, bus_shift; 93 u16 seg = root->segment; 94 struct device *dev = &root->device->dev; 95 struct resource cfgres; 96 struct resource *bus_res = &root->secondary; 97 struct pci_config_window *cfg; 98 const struct pci_ecam_ops *ecam_ops; 99 100 ret = pci_mcfg_lookup(root, &cfgres, &ecam_ops); 101 if (ret < 0) { 102 dev_err(dev, "%04x:%pR ECAM region not found, use default value\n", seg, bus_res); 103 ecam_ops = &loongson_pci_ecam_ops; 104 root->mcfg_addr = mcfg_addr_init(0); 105 } 106 107 bus_shift = ecam_ops->bus_shift ? : 20; 108 109 cfgres.start = root->mcfg_addr + (bus_res->start << bus_shift); 110 cfgres.end = cfgres.start + (resource_size(bus_res) << bus_shift) - 1; 111 cfgres.flags = IORESOURCE_MEM; 112 113 cfg = pci_ecam_create(dev, &cfgres, bus_res, ecam_ops); 114 if (IS_ERR(cfg)) { 115 dev_err(dev, "%04x:%pR error %ld mapping ECAM\n", seg, bus_res, PTR_ERR(cfg)); 116 return NULL; 117 } 118 119 return cfg; 120 } 121 122 struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) 123 { 124 struct pci_bus *bus; 125 struct pci_root_info *info; 126 struct acpi_pci_root_ops *root_ops; 127 int domain = root->segment; 128 int busnum = root->secondary.start; 129 130 info = kzalloc(sizeof(*info), GFP_KERNEL); 131 if (!info) { 132 pr_warn("pci_bus %04x:%02x: ignored (out of memory)\n", domain, busnum); 133 return NULL; 134 } 135 136 root_ops = kzalloc(sizeof(*root_ops), GFP_KERNEL); 137 if (!root_ops) { 138 kfree(info); 139 return NULL; 140 } 141 142 info->cfg = pci_acpi_setup_ecam_mapping(root); 143 if (!info->cfg) { 144 kfree(info); 145 kfree(root_ops); 146 return NULL; 147 } 148 149 root_ops->release_info = acpi_release_root_info; 150 root_ops->prepare_resources = acpi_prepare_root_resources; 151 root_ops->pci_ops = (struct pci_ops *)&info->cfg->ops->pci_ops; 152 153 bus = pci_find_bus(domain, busnum); 154 if (bus) { 155 memcpy(bus->sysdata, info->cfg, sizeof(struct pci_config_window)); 156 kfree(info); 157 } else { 158 struct pci_bus *child; 159 160 bus = acpi_pci_root_create(root, root_ops, 161 &info->common, info->cfg); 162 if (!bus) { 163 kfree(info); 164 kfree(root_ops); 165 return NULL; 166 } 167 168 pci_bus_size_bridges(bus); 169 pci_bus_assign_resources(bus); 170 list_for_each_entry(child, &bus->children, node) 171 pcie_bus_configure_settings(child); 172 } 173 174 return bus; 175 } 176