Blame view

drivers/pci/of.c 15.9 KB
736759ef5   Bjorn Helgaas   PCI: Add SPDX GPL...
1
  // SPDX-License-Identifier: GPL-2.0+
98d9f30c8   Benjamin Herrenschmidt   pci/of: Match PCI...
2
3
4
5
  /*
   * PCI <-> OF mapping helpers
   *
   * Copyright 2011 IBM Corp.
98d9f30c8   Benjamin Herrenschmidt   pci/of: Match PCI...
6
   */
4670d610d   Rob Herring   PCI: Move OF-rela...
7
  #define pr_fmt(fmt)	"PCI: OF: " fmt
98d9f30c8   Benjamin Herrenschmidt   pci/of: Match PCI...
8

b165e2b60   Marc Zyngier   PCI/MSI: Add supp...
9
  #include <linux/irqdomain.h>
98d9f30c8   Benjamin Herrenschmidt   pci/of: Match PCI...
10
11
12
  #include <linux/kernel.h>
  #include <linux/pci.h>
  #include <linux/of.h>
c8d175883   Marc Zyngier   PCI/MSI: Use of_m...
13
  #include <linux/of_irq.h>
4670d610d   Rob Herring   PCI: Move OF-rela...
14
  #include <linux/of_address.h>
98d9f30c8   Benjamin Herrenschmidt   pci/of: Match PCI...
15
16
  #include <linux/of_pci.h>
  #include "pci.h"
40e5d614a   Kishon Vijay Abraham I   PCI: OF: Allow of...
17
  #ifdef CONFIG_PCI
98d9f30c8   Benjamin Herrenschmidt   pci/of: Match PCI...
18
19
20
21
22
23
  void pci_set_of_node(struct pci_dev *dev)
  {
  	if (!dev->bus->dev.of_node)
  		return;
  	dev->dev.of_node = of_pci_find_child_device(dev->bus->dev.of_node,
  						    dev->devfn);
59b099a6c   Jean-Philippe Brucker   PCI: OF: Initiali...
24
25
  	if (dev->dev.of_node)
  		dev->dev.fwnode = &dev->dev.of_node->fwnode;
98d9f30c8   Benjamin Herrenschmidt   pci/of: Match PCI...
26
27
28
29
30
31
  }
  
  void pci_release_of_node(struct pci_dev *dev)
  {
  	of_node_put(dev->dev.of_node);
  	dev->dev.of_node = NULL;
59b099a6c   Jean-Philippe Brucker   PCI: OF: Initiali...
32
  	dev->dev.fwnode = NULL;
98d9f30c8   Benjamin Herrenschmidt   pci/of: Match PCI...
33
34
35
36
  }
  
  void pci_set_bus_of_node(struct pci_bus *bus)
  {
9cb30a71a   Jean-Philippe Brucker   PCI: OF: Support ...
37
38
39
40
41
42
43
  	struct device_node *node;
  
  	if (bus->self == NULL) {
  		node = pcibios_get_phb_of_node(bus);
  	} else {
  		node = of_node_get(bus->self->dev.of_node);
  		if (node && of_property_read_bool(node, "external-facing"))
99b50be9d   Rajat Jain   PCI: Treat "exter...
44
  			bus->self->external_facing = true;
9cb30a71a   Jean-Philippe Brucker   PCI: OF: Support ...
45
  	}
59b099a6c   Jean-Philippe Brucker   PCI: OF: Initiali...
46

9cb30a71a   Jean-Philippe Brucker   PCI: OF: Support ...
47
  	bus->dev.of_node = node;
59b099a6c   Jean-Philippe Brucker   PCI: OF: Initiali...
48
49
50
  
  	if (bus->dev.of_node)
  		bus->dev.fwnode = &bus->dev.of_node->fwnode;
98d9f30c8   Benjamin Herrenschmidt   pci/of: Match PCI...
51
52
53
54
55
56
  }
  
  void pci_release_bus_of_node(struct pci_bus *bus)
  {
  	of_node_put(bus->dev.of_node);
  	bus->dev.of_node = NULL;
59b099a6c   Jean-Philippe Brucker   PCI: OF: Initiali...
57
  	bus->dev.fwnode = NULL;
98d9f30c8   Benjamin Herrenschmidt   pci/of: Match PCI...
58
59
60
61
62
63
64
  }
  
  struct device_node * __weak pcibios_get_phb_of_node(struct pci_bus *bus)
  {
  	/* This should only be called for PHBs */
  	if (WARN_ON(bus->self || bus->parent))
  		return NULL;
4670d610d   Rob Herring   PCI: Move OF-rela...
65
66
67
  	/*
  	 * Look for a node pointer in either the intermediary device we
  	 * create above the root bus or its own parent. Normally only
98d9f30c8   Benjamin Herrenschmidt   pci/of: Match PCI...
68
69
70
71
  	 * the later is populated.
  	 */
  	if (bus->bridge->of_node)
  		return of_node_get(bus->bridge->of_node);
69566dd8b   David Daney   PCI: OF: Don't cr...
72
  	if (bus->bridge->parent && bus->bridge->parent->of_node)
98d9f30c8   Benjamin Herrenschmidt   pci/of: Match PCI...
73
74
75
  		return of_node_get(bus->bridge->parent->of_node);
  	return NULL;
  }
b165e2b60   Marc Zyngier   PCI/MSI: Add supp...
76
77
78
79
  
  struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus)
  {
  #ifdef CONFIG_IRQ_DOMAIN
b165e2b60   Marc Zyngier   PCI/MSI: Add supp...
80
81
82
83
84
85
  	struct irq_domain *d;
  
  	if (!bus->dev.of_node)
  		return NULL;
  
  	/* Start looking for a phandle to an MSI controller. */
c8d175883   Marc Zyngier   PCI/MSI: Use of_m...
86
87
88
  	d = of_msi_get_domain(&bus->dev, bus->dev.of_node, DOMAIN_BUS_PCI_MSI);
  	if (d)
  		return d;
471c931cb   Marc Zyngier   PCI/MSI: Allow ms...
89
90
91
92
93
  
  	/*
  	 * If we don't have an msi-parent property, look for a domain
  	 * directly attached to the host bridge.
  	 */
c8d175883   Marc Zyngier   PCI/MSI: Use of_m...
94
  	d = irq_find_matching_host(bus->dev.of_node, DOMAIN_BUS_PCI_MSI);
b165e2b60   Marc Zyngier   PCI/MSI: Add supp...
95
96
  	if (d)
  		return d;
c8d175883   Marc Zyngier   PCI/MSI: Use of_m...
97
  	return irq_find_host(bus->dev.of_node);
b165e2b60   Marc Zyngier   PCI/MSI: Add supp...
98
99
100
101
  #else
  	return NULL;
  #endif
  }
4670d610d   Rob Herring   PCI: Move OF-rela...
102

4670d610d   Rob Herring   PCI: Move OF-rela...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
  static inline int __of_pci_pci_compare(struct device_node *node,
  				       unsigned int data)
  {
  	int devfn;
  
  	devfn = of_pci_get_devfn(node);
  	if (devfn < 0)
  		return 0;
  
  	return devfn == data;
  }
  
  struct device_node *of_pci_find_child_device(struct device_node *parent,
  					     unsigned int devfn)
  {
  	struct device_node *node, *node2;
  
  	for_each_child_of_node(parent, node) {
  		if (__of_pci_pci_compare(node, devfn))
  			return node;
  		/*
  		 * Some OFs create a parent node "multifunc-device" as
  		 * a fake root for all functions of a multi-function
  		 * device we go down them as well.
  		 */
83a50d3a2   Rob Herring   PCI: Use of_node_...
128
  		if (of_node_name_eq(node, "multifunc-device")) {
4670d610d   Rob Herring   PCI: Move OF-rela...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
  			for_each_child_of_node(node, node2) {
  				if (__of_pci_pci_compare(node2, devfn)) {
  					of_node_put(node);
  					return node2;
  				}
  			}
  		}
  	}
  	return NULL;
  }
  EXPORT_SYMBOL_GPL(of_pci_find_child_device);
  
  /**
   * of_pci_get_devfn() - Get device and function numbers for a device node
   * @np: device node
   *
   * Parses a standard 5-cell PCI resource and returns an 8-bit value that can
   * be passed to the PCI_SLOT() and PCI_FUNC() macros to extract the device
   * and function numbers respectively. On error a negative error code is
   * returned.
   */
  int of_pci_get_devfn(struct device_node *np)
  {
  	u32 reg[5];
  	int error;
  
  	error = of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg));
  	if (error)
  		return error;
  
  	return (reg[0] >> 8) & 0xff;
  }
  EXPORT_SYMBOL_GPL(of_pci_get_devfn);
  
  /**
   * of_pci_parse_bus_range() - parse the bus-range property of a PCI device
   * @node: device node
   * @res: address to a struct resource to return the bus-range
   *
   * Returns 0 on success or a negative error-code on failure.
   */
  int of_pci_parse_bus_range(struct device_node *node, struct resource *res)
  {
  	u32 bus_range[2];
  	int error;
  
  	error = of_property_read_u32_array(node, "bus-range", bus_range,
  					   ARRAY_SIZE(bus_range));
  	if (error)
  		return error;
  
  	res->name = node->name;
  	res->start = bus_range[0];
  	res->end = bus_range[1];
  	res->flags = IORESOURCE_BUS;
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(of_pci_parse_bus_range);
  
  /**
   * This function will try to obtain the host bridge domain number by
   * finding a property called "linux,pci-domain" of the given device node.
   *
   * @node: device tree node with the domain information
   *
   * Returns the associated domain number from DT in the range [0-0xffff], or
   * a negative value if the required property is not found.
   */
  int of_get_pci_domain_nr(struct device_node *node)
  {
  	u32 domain;
  	int error;
  
  	error = of_property_read_u32(node, "linux,pci-domain", &domain);
  	if (error)
  		return error;
  
  	return (u16)domain;
  }
  EXPORT_SYMBOL_GPL(of_get_pci_domain_nr);
  
  /**
4670d610d   Rob Herring   PCI: Move OF-rela...
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
   * of_pci_check_probe_only - Setup probe only mode if linux,pci-probe-only
   *                           is present and valid
   */
  void of_pci_check_probe_only(void)
  {
  	u32 val;
  	int ret;
  
  	ret = of_property_read_u32(of_chosen, "linux,pci-probe-only", &val);
  	if (ret) {
  		if (ret == -ENODATA || ret == -EOVERFLOW)
  			pr_warn("linux,pci-probe-only without valid value, ignoring
  ");
  		return;
  	}
  
  	if (val)
  		pci_add_flags(PCI_PROBE_ONLY);
  	else
  		pci_clear_flags(PCI_PROBE_ONLY);
  
  	pr_info("PROBE_ONLY %sabled
  ", val ? "en" : "dis");
  }
  EXPORT_SYMBOL_GPL(of_pci_check_probe_only);
4670d610d   Rob Herring   PCI: Move OF-rela...
237
  /**
5bd51b35c   Jan Kiszka   PCI: Rework of_pc...
238
239
   * devm_of_pci_get_host_bridge_resources() - Resource-managed parsing of PCI
   *                                           host bridge resources from DT
055f87a2a   Jan Kiszka   PCI: Pass struct ...
240
   * @dev: host bridge device
4670d610d   Rob Herring   PCI: Move OF-rela...
241
242
243
   * @busno: bus number associated with the bridge root bus
   * @bus_max: maximum number of buses for this bridge
   * @resources: list where the range of resources will be added after DT parsing
9b41d19af   Krzysztof Kozlowski   PCI: Fix kerneldo...
244
245
   * @ib_resources: list where the range of inbound resources (with addresses
   *                from 'dma-ranges') will be added after DT parsing
4670d610d   Rob Herring   PCI: Move OF-rela...
246
247
248
249
   * @io_base: pointer to a variable that will contain on return the physical
   * address for the start of the I/O range. Can be NULL if the caller doesn't
   * expect I/O ranges to be present in the device tree.
   *
4670d610d   Rob Herring   PCI: Move OF-rela...
250
251
252
253
254
255
256
   * This function will parse the "ranges" property of a PCI host bridge device
   * node and setup the resource mapping based on its content. It is expected
   * that the property conforms with the Power ePAPR document.
   *
   * It returns zero if the range parsing has been successful or a standard error
   * value if it failed.
   */
3b55809cf   Rob Herring   PCI: Make devm_of...
257
  static int devm_of_pci_get_host_bridge_resources(struct device *dev,
4670d610d   Rob Herring   PCI: Move OF-rela...
258
  			unsigned char busno, unsigned char bus_max,
331f63457   Rob Herring   PCI: of: Add inbo...
259
260
261
  			struct list_head *resources,
  			struct list_head *ib_resources,
  			resource_size_t *io_base)
4670d610d   Rob Herring   PCI: Move OF-rela...
262
  {
055f87a2a   Jan Kiszka   PCI: Pass struct ...
263
  	struct device_node *dev_node = dev->of_node;
93c9a7f87   Jan Kiszka   PCI: Clean up res...
264
  	struct resource *res, tmp_res;
4670d610d   Rob Herring   PCI: Move OF-rela...
265
266
267
  	struct resource *bus_range;
  	struct of_pci_range range;
  	struct of_pci_range_parser parser;
331f63457   Rob Herring   PCI: of: Add inbo...
268
  	const char *range_type;
4670d610d   Rob Herring   PCI: Move OF-rela...
269
270
271
272
  	int err;
  
  	if (io_base)
  		*io_base = (resource_size_t)OF_BAD_ADDR;
5bd51b35c   Jan Kiszka   PCI: Rework of_pc...
273
  	bus_range = devm_kzalloc(dev, sizeof(*bus_range), GFP_KERNEL);
4670d610d   Rob Herring   PCI: Move OF-rela...
274
275
  	if (!bus_range)
  		return -ENOMEM;
d9c5d5ac2   Jan Kiszka   PCI: Use dev_prin...
276
277
  	dev_info(dev, "host bridge %pOF ranges:
  ", dev_node);
4670d610d   Rob Herring   PCI: Move OF-rela...
278

126b7de6b   Jan Kiszka   PCI: Rename of_pc...
279
  	err = of_pci_parse_bus_range(dev_node, bus_range);
4670d610d   Rob Herring   PCI: Move OF-rela...
280
281
282
283
  	if (err) {
  		bus_range->start = busno;
  		bus_range->end = bus_max;
  		bus_range->flags = IORESOURCE_BUS;
d9c5d5ac2   Jan Kiszka   PCI: Use dev_prin...
284
285
286
  		dev_info(dev, "  No bus range found for %pOF, using %pR
  ",
  			 dev_node, bus_range);
4670d610d   Rob Herring   PCI: Move OF-rela...
287
288
289
290
291
292
293
  	} else {
  		if (bus_range->end > bus_range->start + bus_max)
  			bus_range->end = bus_range->start + bus_max;
  	}
  	pci_add_resource(resources, bus_range);
  
  	/* Check for ranges property */
126b7de6b   Jan Kiszka   PCI: Rename of_pc...
294
  	err = of_pci_range_parser_init(&parser, dev_node);
4670d610d   Rob Herring   PCI: Move OF-rela...
295
  	if (err)
5bd51b35c   Jan Kiszka   PCI: Rework of_pc...
296
  		goto failed;
4670d610d   Rob Herring   PCI: Move OF-rela...
297

d9c5d5ac2   Jan Kiszka   PCI: Use dev_prin...
298
299
  	dev_dbg(dev, "Parsing ranges property...
  ");
4670d610d   Rob Herring   PCI: Move OF-rela...
300
301
302
  	for_each_of_pci_range(&parser, &range) {
  		/* Read next ranges element */
  		if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO)
331f63457   Rob Herring   PCI: of: Add inbo...
303
  			range_type = "IO";
4670d610d   Rob Herring   PCI: Move OF-rela...
304
  		else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM)
331f63457   Rob Herring   PCI: of: Add inbo...
305
  			range_type = "MEM";
4670d610d   Rob Herring   PCI: Move OF-rela...
306
  		else
331f63457   Rob Herring   PCI: of: Add inbo...
307
308
309
  			range_type = "err";
  		dev_info(dev, "  %6s %#012llx..%#012llx -> %#012llx
  ",
d9c5d5ac2   Jan Kiszka   PCI: Use dev_prin...
310
311
  			 range_type, range.cpu_addr,
  			 range.cpu_addr + range.size - 1, range.pci_addr);
4670d610d   Rob Herring   PCI: Move OF-rela...
312
313
314
315
316
317
318
  
  		/*
  		 * If we failed translation or got a zero-sized region
  		 * then skip this range
  		 */
  		if (range.cpu_addr == OF_BAD_ADDR || range.size == 0)
  			continue;
93c9a7f87   Jan Kiszka   PCI: Clean up res...
319
320
321
322
323
  		err = of_pci_range_to_resource(&range, dev_node, &tmp_res);
  		if (err)
  			continue;
  
  		res = devm_kmemdup(dev, &tmp_res, sizeof(tmp_res), GFP_KERNEL);
4670d610d   Rob Herring   PCI: Move OF-rela...
324
325
  		if (!res) {
  			err = -ENOMEM;
5bd51b35c   Jan Kiszka   PCI: Rework of_pc...
326
  			goto failed;
4670d610d   Rob Herring   PCI: Move OF-rela...
327
  		}
4670d610d   Rob Herring   PCI: Move OF-rela...
328
329
  		if (resource_type(res) == IORESOURCE_IO) {
  			if (!io_base) {
d9c5d5ac2   Jan Kiszka   PCI: Use dev_prin...
330
331
  				dev_err(dev, "I/O range found for %pOF. Please provide an io_base pointer to save CPU base address
  ",
126b7de6b   Jan Kiszka   PCI: Rename of_pc...
332
  					dev_node);
4670d610d   Rob Herring   PCI: Move OF-rela...
333
  				err = -EINVAL;
5bd51b35c   Jan Kiszka   PCI: Rework of_pc...
334
  				goto failed;
4670d610d   Rob Herring   PCI: Move OF-rela...
335
336
  			}
  			if (*io_base != (resource_size_t)OF_BAD_ADDR)
d9c5d5ac2   Jan Kiszka   PCI: Use dev_prin...
337
338
339
  				dev_warn(dev, "More than one I/O resource converted for %pOF. CPU base address for old range lost!
  ",
  					 dev_node);
4670d610d   Rob Herring   PCI: Move OF-rela...
340
341
342
343
344
  			*io_base = range.cpu_addr;
  		}
  
  		pci_add_resource_offset(resources, res,	res->start - range.pci_addr);
  	}
331f63457   Rob Herring   PCI: of: Add inbo...
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
  	/* Check for dma-ranges property */
  	if (!ib_resources)
  		return 0;
  	err = of_pci_dma_range_parser_init(&parser, dev_node);
  	if (err)
  		return 0;
  
  	dev_dbg(dev, "Parsing dma-ranges property...
  ");
  	for_each_of_pci_range(&parser, &range) {
  		struct resource_entry *entry;
  		/*
  		 * If we failed translation or got a zero-sized region
  		 * then skip this range
  		 */
  		if (((range.flags & IORESOURCE_TYPE_BITS) != IORESOURCE_MEM) ||
  		    range.cpu_addr == OF_BAD_ADDR || range.size == 0)
  			continue;
  
  		dev_info(dev, "  %6s %#012llx..%#012llx -> %#012llx
  ",
  			 "IB MEM", range.cpu_addr,
  			 range.cpu_addr + range.size - 1, range.pci_addr);
  
  
  		err = of_pci_range_to_resource(&range, dev_node, &tmp_res);
  		if (err)
  			continue;
  
  		res = devm_kmemdup(dev, &tmp_res, sizeof(tmp_res), GFP_KERNEL);
  		if (!res) {
  			err = -ENOMEM;
  			goto failed;
  		}
  
  		/* Keep the resource list sorted */
  		resource_list_for_each_entry(entry, ib_resources)
  			if (entry->res->start > res->start)
  				break;
  
  		pci_add_resource_offset(&entry->node, res,
  					res->start - range.pci_addr);
  	}
4670d610d   Rob Herring   PCI: Move OF-rela...
388
  	return 0;
5bd51b35c   Jan Kiszka   PCI: Rework of_pc...
389
  failed:
4670d610d   Rob Herring   PCI: Move OF-rela...
390
391
392
  	pci_free_resource_list(resources);
  	return err;
  }
4670d610d   Rob Herring   PCI: Move OF-rela...
393

4670d610d   Rob Herring   PCI: Move OF-rela...
394
395
396
397
  #if IS_ENABLED(CONFIG_OF_IRQ)
  /**
   * of_irq_parse_pci - Resolve the interrupt for a PCI device
   * @pdev:       the device whose interrupt is to be resolved
b071c1fd7   Lubomir Rintel   PCI: OF: Correct ...
398
   * @out_irq:    structure of_phandle_args filled by this function
4670d610d   Rob Herring   PCI: Move OF-rela...
399
400
401
402
403
404
405
   *
   * This function resolves the PCI interrupt for a given PCI device. If a
   * device-node exists for a given pci_dev, it will use normal OF tree
   * walking. If not, it will implement standard swizzling and walk up the
   * PCI tree until an device-node is found, at which point it will finish
   * resolving using the OF tree walking.
   */
7e2978430   Rob Herring   PCI: Make of_irq_...
406
  static int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq)
4670d610d   Rob Herring   PCI: Move OF-rela...
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
  {
  	struct device_node *dn, *ppnode;
  	struct pci_dev *ppdev;
  	__be32 laddr[3];
  	u8 pin;
  	int rc;
  
  	/*
  	 * Check if we have a device node, if yes, fallback to standard
  	 * device tree parsing
  	 */
  	dn = pci_device_to_OF_node(pdev);
  	if (dn) {
  		rc = of_irq_parse_one(dn, 0, out_irq);
  		if (!rc)
  			return rc;
  	}
  
  	/*
  	 * Ok, we don't, time to have fun. Let's start by building up an
  	 * interrupt spec.  we assume #interrupt-cells is 1, which is standard
  	 * for PCI. If you do different, then don't use that routine.
  	 */
  	rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin);
  	if (rc != 0)
  		goto err;
  	/* No pin, exit with no error message. */
  	if (pin == 0)
  		return -ENODEV;
  
  	/* Now we walk up the PCI tree */
  	for (;;) {
  		/* Get the pci_dev of our parent */
  		ppdev = pdev->bus->self;
  
  		/* Ouch, it's a host bridge... */
  		if (ppdev == NULL) {
  			ppnode = pci_bus_to_OF_node(pdev->bus);
  
  			/* No node for host bridge ? give up */
  			if (ppnode == NULL) {
  				rc = -EINVAL;
  				goto err;
  			}
  		} else {
  			/* We found a P2P bridge, check if it has a node */
  			ppnode = pci_device_to_OF_node(ppdev);
  		}
  
  		/*
  		 * Ok, we have found a parent with a device-node, hand over to
  		 * the OF parsing code.
  		 * We build a unit address from the linux device to be used for
  		 * resolution. Note that we use the linux bus number which may
  		 * not match your firmware bus numbering.
  		 * Fortunately, in most cases, interrupt-map-mask doesn't
  		 * include the bus number as part of the matching.
  		 * You should still be careful about that though if you intend
  		 * to rely on this function (you ship a firmware that doesn't
  		 * create device nodes for all PCI devices).
  		 */
  		if (ppnode)
  			break;
  
  		/*
  		 * We can only get here if we hit a P2P bridge with no node;
  		 * let's do standard swizzling and try again
  		 */
  		pin = pci_swizzle_interrupt_pin(pdev, pin);
  		pdev = ppdev;
  	}
  
  	out_irq->np = ppnode;
  	out_irq->args_count = 1;
  	out_irq->args[0] = pin;
  	laddr[0] = cpu_to_be32((pdev->bus->number << 16) | (pdev->devfn << 8));
  	laddr[1] = laddr[2] = cpu_to_be32(0);
  	rc = of_irq_parse_raw(laddr, out_irq);
  	if (rc)
  		goto err;
  	return 0;
  err:
  	if (rc == -ENOENT) {
  		dev_warn(&pdev->dev,
  			"%s: no interrupt-map found, INTx interrupts not available
  ",
  			__func__);
  		pr_warn_once("%s: possibly some PCI slots don't have level triggered interrupts capability
  ",
  			__func__);
  	} else {
  		dev_err(&pdev->dev, "%s: failed with rc=%d
  ", __func__, rc);
  	}
  	return rc;
  }
4670d610d   Rob Herring   PCI: Move OF-rela...
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
  
  /**
   * of_irq_parse_and_map_pci() - Decode a PCI IRQ from the device tree and map to a VIRQ
   * @dev: The PCI device needing an IRQ
   * @slot: PCI slot number; passed when used as map_irq callback. Unused
   * @pin: PCI IRQ pin number; passed when used as map_irq callback. Unused
   *
   * @slot and @pin are unused, but included in the function so that this
   * function can be used directly as the map_irq callback to
   * pci_assign_irq() and struct pci_host_bridge.map_irq pointer
   */
  int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin)
  {
  	struct of_phandle_args oirq;
  	int ret;
  
  	ret = of_irq_parse_pci(dev, &oirq);
  	if (ret)
  		return 0; /* Proper return code 0 == NO_IRQ */
  
  	return irq_create_of_mapping(&oirq);
  }
  EXPORT_SYMBOL_GPL(of_irq_parse_and_map_pci);
  #endif	/* CONFIG_OF_IRQ */
c7f75aecb   Bjorn Helgaas   Merge remote-trac...
527

669cbc708   Rob Herring   PCI: Move DT reso...
528
529
  static int pci_parse_request_of_pci_ranges(struct device *dev,
  					   struct pci_host_bridge *bridge)
3a8f77e48   Cyrille Pitchen   PCI: OF: Add gene...
530
531
  {
  	int err, res_valid = 0;
3a8f77e48   Cyrille Pitchen   PCI: OF: Add gene...
532
533
  	resource_size_t iobase;
  	struct resource_entry *win, *tmp;
669cbc708   Rob Herring   PCI: Move DT reso...
534
535
536
537
538
  	INIT_LIST_HEAD(&bridge->windows);
  	INIT_LIST_HEAD(&bridge->dma_ranges);
  
  	err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &bridge->windows,
  						    &bridge->dma_ranges, &iobase);
3a8f77e48   Cyrille Pitchen   PCI: OF: Add gene...
539
540
  	if (err)
  		return err;
669cbc708   Rob Herring   PCI: Move DT reso...
541
  	err = devm_request_pci_bus_resources(dev, &bridge->windows);
3a8f77e48   Cyrille Pitchen   PCI: OF: Add gene...
542
  	if (err)
669cbc708   Rob Herring   PCI: Move DT reso...
543
  		return err;
3a8f77e48   Cyrille Pitchen   PCI: OF: Add gene...
544

669cbc708   Rob Herring   PCI: Move DT reso...
545
  	resource_list_for_each_entry_safe(win, tmp, &bridge->windows) {
3a8f77e48   Cyrille Pitchen   PCI: OF: Add gene...
546
547
548
549
  		struct resource *res = win->res;
  
  		switch (resource_type(res)) {
  		case IORESOURCE_IO:
a5fb9fb02   Sergei Shtylyov   PCI: OF: Fix I/O ...
550
  			err = devm_pci_remap_iospace(dev, res, iobase);
3a8f77e48   Cyrille Pitchen   PCI: OF: Add gene...
551
552
553
554
555
556
557
558
559
560
  			if (err) {
  				dev_warn(dev, "error %d: failed to map resource %pR
  ",
  					 err, res);
  				resource_list_destroy_entry(win);
  			}
  			break;
  		case IORESOURCE_MEM:
  			res_valid |= !(res->flags & IORESOURCE_PREFETCH);
  			break;
3a8f77e48   Cyrille Pitchen   PCI: OF: Add gene...
561
562
  		}
  	}
4cb18d13b   Rob Herring   PCI: of: Reduce m...
563
564
565
  	if (!res_valid)
  		dev_warn(dev, "non-prefetchable memory resource required
  ");
3a8f77e48   Cyrille Pitchen   PCI: OF: Add gene...
566

4cb18d13b   Rob Herring   PCI: of: Reduce m...
567
  	return 0;
669cbc708   Rob Herring   PCI: Move DT reso...
568
  }
3a8f77e48   Cyrille Pitchen   PCI: OF: Add gene...
569

669cbc708   Rob Herring   PCI: Move DT reso...
570
571
572
  int devm_of_pci_bridge_init(struct device *dev, struct pci_host_bridge *bridge)
  {
  	if (!dev->of_node)
3a8f77e48   Cyrille Pitchen   PCI: OF: Add gene...
573
  		return 0;
b64aa11eb   Rob Herring   PCI: Set bridge m...
574
575
  	bridge->swizzle_irq = pci_common_swizzle;
  	bridge->map_irq = of_irq_parse_and_map_pci;
3a8f77e48   Cyrille Pitchen   PCI: OF: Add gene...
576

669cbc708   Rob Herring   PCI: Move DT reso...
577
  	return pci_parse_request_of_pci_ranges(dev, bridge);
3a8f77e48   Cyrille Pitchen   PCI: OF: Add gene...
578
  }
c7f75aecb   Bjorn Helgaas   Merge remote-trac...
579

40e5d614a   Kishon Vijay Abraham I   PCI: OF: Allow of...
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
  #endif /* CONFIG_PCI */
  
  /**
   * This function will try to find the limitation of link speed by finding
   * a property called "max-link-speed" of the given device node.
   *
   * @node: device tree node with the max link speed information
   *
   * Returns the associated max link speed from DT, or a negative value if the
   * required property is not found or is invalid.
   */
  int of_pci_get_max_link_speed(struct device_node *node)
  {
  	u32 max_link_speed;
  
  	if (of_property_read_u32(node, "max-link-speed", &max_link_speed) ||
2dd9072e8   Pali Rohár   PCI: of: Zero max...
596
  	    max_link_speed == 0 || max_link_speed > 4)
40e5d614a   Kishon Vijay Abraham I   PCI: OF: Allow of...
597
598
599
600
601
  		return -EINVAL;
  
  	return max_link_speed;
  }
  EXPORT_SYMBOL_GPL(of_pci_get_max_link_speed);