xref: /openbmc/linux/arch/loongarch/pci/acpi.c (revision f5c27da4)
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  * Create a PCI config space window
87  *  - reserve mem region
88  *  - alloc struct pci_config_window with space for all mappings
89  *  - ioremap the config space
90  */
91 static struct pci_config_window *arch_pci_ecam_create(struct device *dev,
92 		struct resource *cfgres, struct resource *busr, const struct pci_ecam_ops *ops)
93 {
94 	int bsz, bus_range, err;
95 	struct resource *conflict;
96 	struct pci_config_window *cfg;
97 
98 	if (busr->start > busr->end)
99 		return ERR_PTR(-EINVAL);
100 
101 	cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
102 	if (!cfg)
103 		return ERR_PTR(-ENOMEM);
104 
105 	cfg->parent = dev;
106 	cfg->ops = ops;
107 	cfg->busr.start = busr->start;
108 	cfg->busr.end = busr->end;
109 	cfg->busr.flags = IORESOURCE_BUS;
110 	bus_range = resource_size(cfgres) >> ops->bus_shift;
111 
112 	bsz = 1 << ops->bus_shift;
113 
114 	cfg->res.start = cfgres->start;
115 	cfg->res.end = cfgres->end;
116 	cfg->res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
117 	cfg->res.name = "PCI ECAM";
118 
119 	conflict = request_resource_conflict(&iomem_resource, &cfg->res);
120 	if (conflict) {
121 		err = -EBUSY;
122 		dev_err(dev, "can't claim ECAM area %pR: address conflict with %s %pR\n",
123 			&cfg->res, conflict->name, conflict);
124 		goto err_exit;
125 	}
126 
127 	cfg->win = pci_remap_cfgspace(cfgres->start, bus_range * bsz);
128 	if (!cfg->win)
129 		goto err_exit_iomap;
130 
131 	if (ops->init) {
132 		err = ops->init(cfg);
133 		if (err)
134 			goto err_exit;
135 	}
136 	dev_info(dev, "ECAM at %pR for %pR\n", &cfg->res, &cfg->busr);
137 
138 	return cfg;
139 
140 err_exit_iomap:
141 	err = -ENOMEM;
142 	dev_err(dev, "ECAM ioremap failed\n");
143 err_exit:
144 	pci_ecam_free(cfg);
145 	return ERR_PTR(err);
146 }
147 
148 /*
149  * Lookup the bus range for the domain in MCFG, and set up config space
150  * mapping.
151  */
152 static struct pci_config_window *
153 pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root)
154 {
155 	int ret, bus_shift;
156 	u16 seg = root->segment;
157 	struct device *dev = &root->device->dev;
158 	struct resource cfgres;
159 	struct resource *bus_res = &root->secondary;
160 	struct pci_config_window *cfg;
161 	const struct pci_ecam_ops *ecam_ops;
162 
163 	ret = pci_mcfg_lookup(root, &cfgres, &ecam_ops);
164 	if (ret < 0) {
165 		dev_err(dev, "%04x:%pR ECAM region not found, use default value\n", seg, bus_res);
166 		ecam_ops = &loongson_pci_ecam_ops;
167 		root->mcfg_addr = mcfg_addr_init(0);
168 	}
169 
170 	bus_shift = ecam_ops->bus_shift ? : 20;
171 
172 	if (bus_shift == 20)
173 		cfg = pci_ecam_create(dev, &cfgres, bus_res, ecam_ops);
174 	else {
175 		cfgres.start = root->mcfg_addr + (bus_res->start << bus_shift);
176 		cfgres.end = cfgres.start + (resource_size(bus_res) << bus_shift) - 1;
177 		cfgres.end |= BIT(28) + (((PCI_CFG_SPACE_EXP_SIZE - 1) & 0xf00) << 16);
178 		cfgres.flags = IORESOURCE_MEM;
179 		cfg = arch_pci_ecam_create(dev, &cfgres, bus_res, ecam_ops);
180 	}
181 
182 	if (IS_ERR(cfg)) {
183 		dev_err(dev, "%04x:%pR error %ld mapping ECAM\n", seg, bus_res, PTR_ERR(cfg));
184 		return NULL;
185 	}
186 
187 	return cfg;
188 }
189 
190 struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
191 {
192 	struct pci_bus *bus;
193 	struct pci_root_info *info;
194 	struct acpi_pci_root_ops *root_ops;
195 	int domain = root->segment;
196 	int busnum = root->secondary.start;
197 
198 	info = kzalloc(sizeof(*info), GFP_KERNEL);
199 	if (!info) {
200 		pr_warn("pci_bus %04x:%02x: ignored (out of memory)\n", domain, busnum);
201 		return NULL;
202 	}
203 
204 	root_ops = kzalloc(sizeof(*root_ops), GFP_KERNEL);
205 	if (!root_ops) {
206 		kfree(info);
207 		return NULL;
208 	}
209 
210 	info->cfg = pci_acpi_setup_ecam_mapping(root);
211 	if (!info->cfg) {
212 		kfree(info);
213 		kfree(root_ops);
214 		return NULL;
215 	}
216 
217 	root_ops->release_info = acpi_release_root_info;
218 	root_ops->prepare_resources = acpi_prepare_root_resources;
219 	root_ops->pci_ops = (struct pci_ops *)&info->cfg->ops->pci_ops;
220 
221 	bus = pci_find_bus(domain, busnum);
222 	if (bus) {
223 		memcpy(bus->sysdata, info->cfg, sizeof(struct pci_config_window));
224 		kfree(info);
225 	} else {
226 		struct pci_bus *child;
227 
228 		bus = acpi_pci_root_create(root, root_ops,
229 					   &info->common, info->cfg);
230 		if (!bus) {
231 			kfree(info);
232 			kfree(root_ops);
233 			return NULL;
234 		}
235 
236 		pci_bus_size_bridges(bus);
237 		pci_bus_assign_resources(bus);
238 		list_for_each_entry(child, &bus->children, node)
239 			pcie_bus_configure_settings(child);
240 	}
241 
242 	return bus;
243 }
244