aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2014-10-23 11:23:07 -0400
committerBjorn Helgaas <bhelgaas@google.com>2014-11-05 18:57:41 -0500
commitdbf9826d57974c2b4e68928528a4a6c354ceddb3 (patch)
treed2540876d4c313d7dd8ae09b89425c3b5d12f6a0
parenta5525b240368cf496e669703a5fe169febbc72ef (diff)
PCI: generic: Convert to DT resource parsing API
In order to consolidate DT configuration for PCI host controllers in the kernel, a new API, of_pci_get_host_bridge_resources(), was developed to allow parsing and assigning IO/BUS/MEM resources from DT, removing duplicated code present in the majority of PCI host driver implementations. Convert the existing PCI generic host controller driver to the new API. Most of the code parsing ranges and creating resources is now delegated to the of_pci_get_host_bridge_resources() API. The PCI host controller code filters the resulting resource list and maps IO space by using the newly introduced pci_ioremap_iospace() API. New code supports only one IO resource per generic host controller, which should cater for all existing host controller configurations. [bhelgaas: changelog] Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Acked-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--drivers/pci/host/pci-host-generic.c120
1 files changed, 27 insertions, 93 deletions
diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c
index 1e1a80fc6faa..18959075d164 100644
--- a/drivers/pci/host/pci-host-generic.c
+++ b/drivers/pci/host/pci-host-generic.c
@@ -32,7 +32,7 @@ struct gen_pci_cfg_bus_ops {
32 32
33struct gen_pci_cfg_windows { 33struct gen_pci_cfg_windows {
34 struct resource res; 34 struct resource res;
35 struct resource bus_range; 35 struct resource *bus_range;
36 void __iomem **win; 36 void __iomem **win;
37 37
38 const struct gen_pci_cfg_bus_ops *ops; 38 const struct gen_pci_cfg_bus_ops *ops;
@@ -50,7 +50,7 @@ static void __iomem *gen_pci_map_cfg_bus_cam(struct pci_bus *bus,
50{ 50{
51 struct pci_sys_data *sys = bus->sysdata; 51 struct pci_sys_data *sys = bus->sysdata;
52 struct gen_pci *pci = sys->private_data; 52 struct gen_pci *pci = sys->private_data;
53 resource_size_t idx = bus->number - pci->cfg.bus_range.start; 53 resource_size_t idx = bus->number - pci->cfg.bus_range->start;
54 54
55 return pci->cfg.win[idx] + ((devfn << 8) | where); 55 return pci->cfg.win[idx] + ((devfn << 8) | where);
56} 56}
@@ -66,7 +66,7 @@ static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus,
66{ 66{
67 struct pci_sys_data *sys = bus->sysdata; 67 struct pci_sys_data *sys = bus->sysdata;
68 struct gen_pci *pci = sys->private_data; 68 struct gen_pci *pci = sys->private_data;
69 resource_size_t idx = bus->number - pci->cfg.bus_range.start; 69 resource_size_t idx = bus->number - pci->cfg.bus_range->start;
70 70
71 return pci->cfg.win[idx] + ((devfn << 12) | where); 71 return pci->cfg.win[idx] + ((devfn << 12) | where);
72} 72}
@@ -138,106 +138,50 @@ static const struct of_device_id gen_pci_of_match[] = {
138}; 138};
139MODULE_DEVICE_TABLE(of, gen_pci_of_match); 139MODULE_DEVICE_TABLE(of, gen_pci_of_match);
140 140
141static int gen_pci_calc_io_offset(struct device *dev,
142 struct of_pci_range *range,
143 struct resource *res,
144 resource_size_t *offset)
145{
146 static atomic_t wins = ATOMIC_INIT(0);
147 int err, idx, max_win;
148 unsigned int window;
149
150 if (!PAGE_ALIGNED(range->cpu_addr))
151 return -EINVAL;
152
153 max_win = (IO_SPACE_LIMIT + 1) / SZ_64K;
154 idx = atomic_inc_return(&wins);
155 if (idx > max_win)
156 return -ENOSPC;
157
158 window = (idx - 1) * SZ_64K;
159 err = pci_ioremap_io(window, range->cpu_addr);
160 if (err)
161 return err;
162
163 of_pci_range_to_resource(range, dev->of_node, res);
164 res->start = window;
165 res->end = res->start + range->size - 1;
166 *offset = window - range->pci_addr;
167 return 0;
168}
169
170static int gen_pci_calc_mem_offset(struct device *dev,
171 struct of_pci_range *range,
172 struct resource *res,
173 resource_size_t *offset)
174{
175 of_pci_range_to_resource(range, dev->of_node, res);
176 *offset = range->cpu_addr - range->pci_addr;
177 return 0;
178}
179
180static void gen_pci_release_of_pci_ranges(struct gen_pci *pci) 141static void gen_pci_release_of_pci_ranges(struct gen_pci *pci)
181{ 142{
182 struct pci_host_bridge_window *win;
183
184 list_for_each_entry(win, &pci->resources, list)
185 release_resource(win->res);
186
187 pci_free_resource_list(&pci->resources); 143 pci_free_resource_list(&pci->resources);
188} 144}
189 145
190static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci) 146static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci)
191{ 147{
192 struct of_pci_range range;
193 struct of_pci_range_parser parser;
194 int err, res_valid = 0; 148 int err, res_valid = 0;
195 struct device *dev = pci->host.dev.parent; 149 struct device *dev = pci->host.dev.parent;
196 struct device_node *np = dev->of_node; 150 struct device_node *np = dev->of_node;
151 resource_size_t iobase;
152 struct pci_host_bridge_window *win;
197 153
198 if (of_pci_range_parser_init(&parser, np)) { 154 err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources,
199 dev_err(dev, "missing \"ranges\" property\n"); 155 &iobase);
200 return -EINVAL; 156 if (err)
201 } 157 return err;
202 158
203 for_each_of_pci_range(&parser, &range) { 159 list_for_each_entry(win, &pci->resources, list) {
204 struct resource *parent, *res; 160 struct resource *parent, *res = win->res;
205 resource_size_t offset;
206 u32 restype = range.flags & IORESOURCE_TYPE_BITS;
207 161
208 res = devm_kmalloc(dev, sizeof(*res), GFP_KERNEL); 162 switch (resource_type(res)) {
209 if (!res) {
210 err = -ENOMEM;
211 goto out_release_res;
212 }
213
214 switch (restype) {
215 case IORESOURCE_IO: 163 case IORESOURCE_IO:
216 parent = &ioport_resource; 164 parent = &ioport_resource;
217 err = gen_pci_calc_io_offset(dev, &range, res, &offset); 165 err = pci_remap_iospace(res, iobase);
166 if (err) {
167 dev_warn(dev, "error %d: failed to map resource %pR\n",
168 err, res);
169 continue;
170 }
218 break; 171 break;
219 case IORESOURCE_MEM: 172 case IORESOURCE_MEM:
220 parent = &iomem_resource; 173 parent = &iomem_resource;
221 err = gen_pci_calc_mem_offset(dev, &range, res, &offset); 174 res_valid |= !(res->flags & IORESOURCE_PREFETCH);
222 res_valid |= !(res->flags & IORESOURCE_PREFETCH || err);
223 break; 175 break;
176 case IORESOURCE_BUS:
177 pci->cfg.bus_range = res;
224 default: 178 default:
225 err = -EINVAL;
226 continue; 179 continue;
227 } 180 }
228 181
229 if (err) { 182 err = devm_request_resource(dev, parent, res);
230 dev_warn(dev,
231 "error %d: failed to add resource [type 0x%x, %lld bytes]\n",
232 err, restype, range.size);
233 continue;
234 }
235
236 err = request_resource(parent, res);
237 if (err) 183 if (err)
238 goto out_release_res; 184 goto out_release_res;
239
240 pci_add_resource_offset(&pci->resources, res, offset);
241 } 185 }
242 186
243 if (!res_valid) { 187 if (!res_valid) {
@@ -262,14 +206,6 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
262 struct device *dev = pci->host.dev.parent; 206 struct device *dev = pci->host.dev.parent;
263 struct device_node *np = dev->of_node; 207 struct device_node *np = dev->of_node;
264 208
265 if (of_pci_parse_bus_range(np, &pci->cfg.bus_range))
266 pci->cfg.bus_range = (struct resource) {
267 .name = np->name,
268 .start = 0,
269 .end = 0xff,
270 .flags = IORESOURCE_BUS,
271 };
272
273 err = of_address_to_resource(np, 0, &pci->cfg.res); 209 err = of_address_to_resource(np, 0, &pci->cfg.res);
274 if (err) { 210 if (err) {
275 dev_err(dev, "missing \"reg\" property\n"); 211 dev_err(dev, "missing \"reg\" property\n");
@@ -277,12 +213,12 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
277 } 213 }
278 214
279 /* Limit the bus-range to fit within reg */ 215 /* Limit the bus-range to fit within reg */
280 bus_max = pci->cfg.bus_range.start + 216 bus_max = pci->cfg.bus_range->start +
281 (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1; 217 (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1;
282 pci->cfg.bus_range.end = min_t(resource_size_t, pci->cfg.bus_range.end, 218 pci->cfg.bus_range->end = min_t(resource_size_t,
283 bus_max); 219 pci->cfg.bus_range->end, bus_max);
284 220
285 pci->cfg.win = devm_kcalloc(dev, resource_size(&pci->cfg.bus_range), 221 pci->cfg.win = devm_kcalloc(dev, resource_size(pci->cfg.bus_range),
286 sizeof(*pci->cfg.win), GFP_KERNEL); 222 sizeof(*pci->cfg.win), GFP_KERNEL);
287 if (!pci->cfg.win) 223 if (!pci->cfg.win)
288 return -ENOMEM; 224 return -ENOMEM;
@@ -293,7 +229,7 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
293 "Configuration Space")) 229 "Configuration Space"))
294 return -ENOMEM; 230 return -ENOMEM;
295 231
296 bus_range = &pci->cfg.bus_range; 232 bus_range = pci->cfg.bus_range;
297 for (busn = bus_range->start; busn <= bus_range->end; ++busn) { 233 for (busn = bus_range->start; busn <= bus_range->end; ++busn) {
298 u32 idx = busn - bus_range->start; 234 u32 idx = busn - bus_range->start;
299 u32 sz = 1 << pci->cfg.ops->bus_shift; 235 u32 sz = 1 << pci->cfg.ops->bus_shift;
@@ -305,8 +241,6 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
305 return -ENOMEM; 241 return -ENOMEM;
306 } 242 }
307 243
308 /* Register bus resource */
309 pci_add_resource(&pci->resources, bus_range);
310 return 0; 244 return 0;
311} 245}
312 246