Blame view

drivers/of/of_pci.c 3.17 KB
04bea68b2   Sebastian Andrzej Siewior   of/pci: move of_i...
1
  #include <linux/kernel.h>
9775913fa   Paul Gortmaker   of: of_pci.c need...
2
  #include <linux/export.h>
a64228501   Grant Likely   of: fix missing i...
3
  #include <linux/of.h>
04bea68b2   Sebastian Andrzej Siewior   of/pci: move of_i...
4
  #include <linux/of_pci.h>
04bea68b2   Sebastian Andrzej Siewior   of/pci: move of_i...
5

98d9f30c8   Benjamin Herrenschmidt   pci/of: Match PCI...
6
  static inline int __of_pci_pci_compare(struct device_node *node,
45ab9702f   Thierry Reding   of/pci: Add of_pc...
7
  				       unsigned int data)
04bea68b2   Sebastian Andrzej Siewior   of/pci: move of_i...
8
  {
45ab9702f   Thierry Reding   of/pci: Add of_pc...
9
  	int devfn;
04bea68b2   Sebastian Andrzej Siewior   of/pci: move of_i...
10

45ab9702f   Thierry Reding   of/pci: Add of_pc...
11
12
  	devfn = of_pci_get_devfn(node);
  	if (devfn < 0)
98d9f30c8   Benjamin Herrenschmidt   pci/of: Match PCI...
13
  		return 0;
45ab9702f   Thierry Reding   of/pci: Add of_pc...
14
15
  
  	return devfn == data;
98d9f30c8   Benjamin Herrenschmidt   pci/of: Match PCI...
16
  }
04bea68b2   Sebastian Andrzej Siewior   of/pci: move of_i...
17

98d9f30c8   Benjamin Herrenschmidt   pci/of: Match PCI...
18
19
20
21
22
23
24
25
26
27
28
29
  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.
04bea68b2   Sebastian Andrzej Siewior   of/pci: move of_i...
30
  		 */
98d9f30c8   Benjamin Herrenschmidt   pci/of: Match PCI...
31
32
33
34
35
36
37
38
  		if (!strcmp(node->name, "multifunc-device")) {
  			for_each_child_of_node(node, node2) {
  				if (__of_pci_pci_compare(node2, devfn)) {
  					of_node_put(node);
  					return node2;
  				}
  			}
  		}
04bea68b2   Sebastian Andrzej Siewior   of/pci: move of_i...
39
  	}
98d9f30c8   Benjamin Herrenschmidt   pci/of: Match PCI...
40
  	return NULL;
04bea68b2   Sebastian Andrzej Siewior   of/pci: move of_i...
41
  }
98d9f30c8   Benjamin Herrenschmidt   pci/of: Match PCI...
42
  EXPORT_SYMBOL_GPL(of_pci_find_child_device);
45ab9702f   Thierry Reding   of/pci: Add of_pc...
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
  
  /**
   * 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)
  {
  	unsigned int size;
  	const __be32 *reg;
  
  	reg = of_get_property(np, "reg", &size);
  
  	if (!reg || size < 5 * sizeof(__be32))
  		return -EINVAL;
  
  	return (be32_to_cpup(reg) >> 8) & 0xff;
  }
  EXPORT_SYMBOL_GPL(of_pci_get_devfn);
4e23d3f50   Thierry Reding   of/pci: Add of_pc...
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  
  /**
   * 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)
  {
  	const __be32 *values;
  	int len;
  
  	values = of_get_property(node, "bus-range", &len);
  	if (!values || len < sizeof(*values) * 2)
  		return -EINVAL;
  
  	res->name = node->name;
  	res->start = be32_to_cpup(values++);
  	res->end = be32_to_cpup(values);
  	res->flags = IORESOURCE_BUS;
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(of_pci_parse_bus_range);
0d5a6db3a   Thomas Petazzoni   of: pci: add regi...
91
92
93
94
95
96
97
98
99
100
101
102
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
128
129
130
131
132
133
134
135
  
  #ifdef CONFIG_PCI_MSI
  
  static LIST_HEAD(of_pci_msi_chip_list);
  static DEFINE_MUTEX(of_pci_msi_chip_mutex);
  
  int of_pci_msi_chip_add(struct msi_chip *chip)
  {
  	if (!of_property_read_bool(chip->of_node, "msi-controller"))
  		return -EINVAL;
  
  	mutex_lock(&of_pci_msi_chip_mutex);
  	list_add(&chip->list, &of_pci_msi_chip_list);
  	mutex_unlock(&of_pci_msi_chip_mutex);
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(of_pci_msi_chip_add);
  
  void of_pci_msi_chip_remove(struct msi_chip *chip)
  {
  	mutex_lock(&of_pci_msi_chip_mutex);
  	list_del(&chip->list);
  	mutex_unlock(&of_pci_msi_chip_mutex);
  }
  EXPORT_SYMBOL_GPL(of_pci_msi_chip_remove);
  
  struct msi_chip *of_pci_find_msi_chip_by_node(struct device_node *of_node)
  {
  	struct msi_chip *c;
  
  	mutex_lock(&of_pci_msi_chip_mutex);
  	list_for_each_entry(c, &of_pci_msi_chip_list, list) {
  		if (c->of_node == of_node) {
  			mutex_unlock(&of_pci_msi_chip_mutex);
  			return c;
  		}
  	}
  	mutex_unlock(&of_pci_msi_chip_mutex);
  
  	return NULL;
  }
  EXPORT_SYMBOL_GPL(of_pci_find_msi_chip_by_node);
  
  #endif /* CONFIG_PCI_MSI */