1 /*
2  * Simple, generic PCI host controller driver targetting firmware-initialised
3  * systems and virtual machines (e.g. the PCI emulation provided by kvmtool).
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  * Copyright (C) 2014 ARM Limited
18  *
19  * Author: Will Deacon <will.deacon@arm.com>
20  */
21 
22 #include <linux/kernel.h>
23 #include <linux/module.h>
24 #include <linux/of_address.h>
25 #include <linux/of_pci.h>
26 #include <linux/platform_device.h>
27 
28 struct gen_pci_cfg_bus_ops {
29 	u32 bus_shift;
30 	void __iomem *(*map_bus)(struct pci_bus *, unsigned int, int);
31 };
32 
33 struct gen_pci_cfg_windows {
34 	struct resource				res;
35 	struct resource				*bus_range;
36 	void __iomem				**win;
37 
38 	const struct gen_pci_cfg_bus_ops	*ops;
39 };
40 
41 struct gen_pci {
42 	struct pci_host_bridge			host;
43 	struct gen_pci_cfg_windows		cfg;
44 	struct list_head			resources;
45 };
46 
gen_pci_map_cfg_bus_cam(struct pci_bus * bus,unsigned int devfn,int where)47 static void __iomem *gen_pci_map_cfg_bus_cam(struct pci_bus *bus,
48 					     unsigned int devfn,
49 					     int where)
50 {
51 	struct pci_sys_data *sys = bus->sysdata;
52 	struct gen_pci *pci = sys->private_data;
53 	resource_size_t idx = bus->number - pci->cfg.bus_range->start;
54 
55 	return pci->cfg.win[idx] + ((devfn << 8) | where);
56 }
57 
58 static struct gen_pci_cfg_bus_ops gen_pci_cfg_cam_bus_ops = {
59 	.bus_shift	= 16,
60 	.map_bus	= gen_pci_map_cfg_bus_cam,
61 };
62 
gen_pci_map_cfg_bus_ecam(struct pci_bus * bus,unsigned int devfn,int where)63 static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus,
64 					      unsigned int devfn,
65 					      int where)
66 {
67 	struct pci_sys_data *sys = bus->sysdata;
68 	struct gen_pci *pci = sys->private_data;
69 	resource_size_t idx = bus->number - pci->cfg.bus_range->start;
70 
71 	return pci->cfg.win[idx] + ((devfn << 12) | where);
72 }
73 
74 static struct gen_pci_cfg_bus_ops gen_pci_cfg_ecam_bus_ops = {
75 	.bus_shift	= 20,
76 	.map_bus	= gen_pci_map_cfg_bus_ecam,
77 };
78 
79 static struct pci_ops gen_pci_ops = {
80 	.read	= pci_generic_config_read,
81 	.write	= pci_generic_config_write,
82 };
83 
84 static const struct of_device_id gen_pci_of_match[] = {
85 	{ .compatible = "pci-host-cam-generic",
86 	  .data = &gen_pci_cfg_cam_bus_ops },
87 
88 	{ .compatible = "pci-host-ecam-generic",
89 	  .data = &gen_pci_cfg_ecam_bus_ops },
90 
91 	{ },
92 };
93 MODULE_DEVICE_TABLE(of, gen_pci_of_match);
94 
gen_pci_release_of_pci_ranges(struct gen_pci * pci)95 static void gen_pci_release_of_pci_ranges(struct gen_pci *pci)
96 {
97 	pci_free_resource_list(&pci->resources);
98 }
99 
gen_pci_parse_request_of_pci_ranges(struct gen_pci * pci)100 static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci)
101 {
102 	int err, res_valid = 0;
103 	struct device *dev = pci->host.dev.parent;
104 	struct device_node *np = dev->of_node;
105 	resource_size_t iobase;
106 	struct resource_entry *win;
107 
108 	err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources,
109 					       &iobase);
110 	if (err)
111 		return err;
112 
113 	resource_list_for_each_entry(win, &pci->resources) {
114 		struct resource *parent, *res = win->res;
115 
116 		switch (resource_type(res)) {
117 		case IORESOURCE_IO:
118 			parent = &ioport_resource;
119 			err = pci_remap_iospace(res, iobase);
120 			if (err) {
121 				dev_warn(dev, "error %d: failed to map resource %pR\n",
122 					 err, res);
123 				continue;
124 			}
125 			break;
126 		case IORESOURCE_MEM:
127 			parent = &iomem_resource;
128 			res_valid |= !(res->flags & IORESOURCE_PREFETCH);
129 			break;
130 		case IORESOURCE_BUS:
131 			pci->cfg.bus_range = res;
132 		default:
133 			continue;
134 		}
135 
136 		err = devm_request_resource(dev, parent, res);
137 		if (err)
138 			goto out_release_res;
139 	}
140 
141 	if (!res_valid) {
142 		dev_err(dev, "non-prefetchable memory resource required\n");
143 		err = -EINVAL;
144 		goto out_release_res;
145 	}
146 
147 	return 0;
148 
149 out_release_res:
150 	gen_pci_release_of_pci_ranges(pci);
151 	return err;
152 }
153 
gen_pci_parse_map_cfg_windows(struct gen_pci * pci)154 static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
155 {
156 	int err;
157 	u8 bus_max;
158 	resource_size_t busn;
159 	struct resource *bus_range;
160 	struct device *dev = pci->host.dev.parent;
161 	struct device_node *np = dev->of_node;
162 
163 	err = of_address_to_resource(np, 0, &pci->cfg.res);
164 	if (err) {
165 		dev_err(dev, "missing \"reg\" property\n");
166 		return err;
167 	}
168 
169 	/* Limit the bus-range to fit within reg */
170 	bus_max = pci->cfg.bus_range->start +
171 		  (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1;
172 	pci->cfg.bus_range->end = min_t(resource_size_t,
173 					pci->cfg.bus_range->end, bus_max);
174 
175 	pci->cfg.win = devm_kcalloc(dev, resource_size(pci->cfg.bus_range),
176 				    sizeof(*pci->cfg.win), GFP_KERNEL);
177 	if (!pci->cfg.win)
178 		return -ENOMEM;
179 
180 	/* Map our Configuration Space windows */
181 	if (!devm_request_mem_region(dev, pci->cfg.res.start,
182 				     resource_size(&pci->cfg.res),
183 				     "Configuration Space"))
184 		return -ENOMEM;
185 
186 	bus_range = pci->cfg.bus_range;
187 	for (busn = bus_range->start; busn <= bus_range->end; ++busn) {
188 		u32 idx = busn - bus_range->start;
189 		u32 sz = 1 << pci->cfg.ops->bus_shift;
190 
191 		pci->cfg.win[idx] = devm_ioremap(dev,
192 						 pci->cfg.res.start + busn * sz,
193 						 sz);
194 		if (!pci->cfg.win[idx])
195 			return -ENOMEM;
196 	}
197 
198 	return 0;
199 }
200 
gen_pci_setup(int nr,struct pci_sys_data * sys)201 static int gen_pci_setup(int nr, struct pci_sys_data *sys)
202 {
203 	struct gen_pci *pci = sys->private_data;
204 	list_splice_init(&pci->resources, &sys->resources);
205 	return 1;
206 }
207 
gen_pci_probe(struct platform_device * pdev)208 static int gen_pci_probe(struct platform_device *pdev)
209 {
210 	int err;
211 	const char *type;
212 	const struct of_device_id *of_id;
213 	const int *prop;
214 	struct device *dev = &pdev->dev;
215 	struct device_node *np = dev->of_node;
216 	struct gen_pci *pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
217 	struct hw_pci hw = {
218 		.nr_controllers	= 1,
219 		.private_data	= (void **)&pci,
220 		.setup		= gen_pci_setup,
221 		.map_irq	= of_irq_parse_and_map_pci,
222 		.ops		= &gen_pci_ops,
223 	};
224 
225 	if (!pci)
226 		return -ENOMEM;
227 
228 	type = of_get_property(np, "device_type", NULL);
229 	if (!type || strcmp(type, "pci")) {
230 		dev_err(dev, "invalid \"device_type\" %s\n", type);
231 		return -EINVAL;
232 	}
233 
234 	prop = of_get_property(of_chosen, "linux,pci-probe-only", NULL);
235 	if (prop) {
236 		if (*prop)
237 			pci_add_flags(PCI_PROBE_ONLY);
238 		else
239 			pci_clear_flags(PCI_PROBE_ONLY);
240 	}
241 
242 	of_id = of_match_node(gen_pci_of_match, np);
243 	pci->cfg.ops = of_id->data;
244 	gen_pci_ops.map_bus = pci->cfg.ops->map_bus;
245 	pci->host.dev.parent = dev;
246 	INIT_LIST_HEAD(&pci->host.windows);
247 	INIT_LIST_HEAD(&pci->resources);
248 
249 	/* Parse our PCI ranges and request their resources */
250 	err = gen_pci_parse_request_of_pci_ranges(pci);
251 	if (err)
252 		return err;
253 
254 	/* Parse and map our Configuration Space windows */
255 	err = gen_pci_parse_map_cfg_windows(pci);
256 	if (err) {
257 		gen_pci_release_of_pci_ranges(pci);
258 		return err;
259 	}
260 
261 	pci_common_init_dev(dev, &hw);
262 	return 0;
263 }
264 
265 static struct platform_driver gen_pci_driver = {
266 	.driver = {
267 		.name = "pci-host-generic",
268 		.of_match_table = gen_pci_of_match,
269 	},
270 	.probe = gen_pci_probe,
271 };
272 module_platform_driver(gen_pci_driver);
273 
274 MODULE_DESCRIPTION("Generic PCI host driver");
275 MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
276 MODULE_LICENSE("GPL v2");
277