diff options
author | Stephen Warren <swarren@nvidia.com> | 2012-07-25 19:34:37 -0400 |
---|---|---|
committer | Rob Herring <rob.herring@calxeda.com> | 2012-08-03 09:01:46 -0400 |
commit | 5d61b165c892853f2daf6220d2ec6577487e273a (patch) | |
tree | 3bcff9b185383c768b702461c1194cb8eb9d0002 /drivers | |
parent | 0d7614f09c1ebdbaa1599a5aba7593f147bf96ee (diff) |
of: Allow busses with #size-cells=0
It's quite legitimate for a DT node to specify #size-cells=0. One example
is a node that's used to collect a number of non-memory-mapped devices.
In that scenario, there may be multiple child nodes with the same name
(type) thus necessitating the use of unit addresses in node names, and
reg properties:
/ {
regulators {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <0>;
regulator@0 {
compatible = "regulator-fixed";
reg = <0>;
...
};
regulator@1 {
compatible = "regulator-fixed";
reg = <1>;
...
};
...
};
};
However, #size-cells=0 prevents translation of reg property values into
the parent node's address space. In turn, this triggers the kernel to
emit error messages during boot, such as:
prom_parse: Bad cell count for /regulators/regulator@0
To prevent printing these error messages for legitimate DT content, a
number of changes are made:
1) of_get_address()/of_get_pci_address() are modified only to validate
the value of #address-cells, and not #size-cells.
2) of_can_translate_address() is added to indicate whether address
translation is possible.
3) of_device_make_bus_id() is modified to name devices based on the
translated address only where possible, and otherwise fall back to
using the (first cell of the) raw untranslated address.
4) of_device_alloc() is modified to create memory resources for a device
only if the address can be translated into the CPU's address space.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/of/address.c | 27 | ||||
-rw-r--r-- | drivers/of/platform.c | 16 |
2 files changed, 36 insertions, 7 deletions
diff --git a/drivers/of/address.c b/drivers/of/address.c index 7e262a6124c5..7a07751428de 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c | |||
@@ -9,8 +9,8 @@ | |||
9 | 9 | ||
10 | /* Max address size we deal with */ | 10 | /* Max address size we deal with */ |
11 | #define OF_MAX_ADDR_CELLS 4 | 11 | #define OF_MAX_ADDR_CELLS 4 |
12 | #define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ | 12 | #define OF_CHECK_ADDR_COUNT(na) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS) |
13 | (ns) > 0) | 13 | #define OF_CHECK_COUNTS(na, ns) (OF_CHECK_ADDR_COUNT(na) && (ns) > 0) |
14 | 14 | ||
15 | static struct of_bus *of_match_bus(struct device_node *np); | 15 | static struct of_bus *of_match_bus(struct device_node *np); |
16 | static int __of_address_to_resource(struct device_node *dev, | 16 | static int __of_address_to_resource(struct device_node *dev, |
@@ -182,7 +182,7 @@ const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, | |||
182 | } | 182 | } |
183 | bus->count_cells(dev, &na, &ns); | 183 | bus->count_cells(dev, &na, &ns); |
184 | of_node_put(parent); | 184 | of_node_put(parent); |
185 | if (!OF_CHECK_COUNTS(na, ns)) | 185 | if (!OF_CHECK_ADDR_COUNT(na)) |
186 | return NULL; | 186 | return NULL; |
187 | 187 | ||
188 | /* Get "reg" or "assigned-addresses" property */ | 188 | /* Get "reg" or "assigned-addresses" property */ |
@@ -490,6 +490,25 @@ u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr) | |||
490 | } | 490 | } |
491 | EXPORT_SYMBOL(of_translate_dma_address); | 491 | EXPORT_SYMBOL(of_translate_dma_address); |
492 | 492 | ||
493 | bool of_can_translate_address(struct device_node *dev) | ||
494 | { | ||
495 | struct device_node *parent; | ||
496 | struct of_bus *bus; | ||
497 | int na, ns; | ||
498 | |||
499 | parent = of_get_parent(dev); | ||
500 | if (parent == NULL) | ||
501 | return false; | ||
502 | |||
503 | bus = of_match_bus(parent); | ||
504 | bus->count_cells(dev, &na, &ns); | ||
505 | |||
506 | of_node_put(parent); | ||
507 | |||
508 | return OF_CHECK_COUNTS(na, ns); | ||
509 | } | ||
510 | EXPORT_SYMBOL(of_can_translate_address); | ||
511 | |||
493 | const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, | 512 | const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, |
494 | unsigned int *flags) | 513 | unsigned int *flags) |
495 | { | 514 | { |
@@ -506,7 +525,7 @@ const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, | |||
506 | bus = of_match_bus(parent); | 525 | bus = of_match_bus(parent); |
507 | bus->count_cells(dev, &na, &ns); | 526 | bus->count_cells(dev, &na, &ns); |
508 | of_node_put(parent); | 527 | of_node_put(parent); |
509 | if (!OF_CHECK_COUNTS(na, ns)) | 528 | if (!OF_CHECK_ADDR_COUNT(na)) |
510 | return NULL; | 529 | return NULL; |
511 | 530 | ||
512 | /* Get "reg" or "assigned-addresses" property */ | 531 | /* Get "reg" or "assigned-addresses" property */ |
diff --git a/drivers/of/platform.c b/drivers/of/platform.c index e44f8c2d239d..9bdeaf30b17d 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c | |||
@@ -78,6 +78,7 @@ void of_device_make_bus_id(struct device *dev) | |||
78 | struct device_node *node = dev->of_node; | 78 | struct device_node *node = dev->of_node; |
79 | const u32 *reg; | 79 | const u32 *reg; |
80 | u64 addr; | 80 | u64 addr; |
81 | const __be32 *addrp; | ||
81 | int magic; | 82 | int magic; |
82 | 83 | ||
83 | #ifdef CONFIG_PPC_DCR | 84 | #ifdef CONFIG_PPC_DCR |
@@ -105,7 +106,15 @@ void of_device_make_bus_id(struct device *dev) | |||
105 | */ | 106 | */ |
106 | reg = of_get_property(node, "reg", NULL); | 107 | reg = of_get_property(node, "reg", NULL); |
107 | if (reg) { | 108 | if (reg) { |
108 | addr = of_translate_address(node, reg); | 109 | if (of_can_translate_address(node)) { |
110 | addr = of_translate_address(node, reg); | ||
111 | } else { | ||
112 | addrp = of_get_address(node, 0, NULL, NULL); | ||
113 | if (addrp) | ||
114 | addr = of_read_number(addrp, 1); | ||
115 | else | ||
116 | addr = OF_BAD_ADDR; | ||
117 | } | ||
109 | if (addr != OF_BAD_ADDR) { | 118 | if (addr != OF_BAD_ADDR) { |
110 | dev_set_name(dev, "%llx.%s", | 119 | dev_set_name(dev, "%llx.%s", |
111 | (unsigned long long)addr, node->name); | 120 | (unsigned long long)addr, node->name); |
@@ -140,8 +149,9 @@ struct platform_device *of_device_alloc(struct device_node *np, | |||
140 | return NULL; | 149 | return NULL; |
141 | 150 | ||
142 | /* count the io and irq resources */ | 151 | /* count the io and irq resources */ |
143 | while (of_address_to_resource(np, num_reg, &temp_res) == 0) | 152 | if (of_can_translate_address(np)) |
144 | num_reg++; | 153 | while (of_address_to_resource(np, num_reg, &temp_res) == 0) |
154 | num_reg++; | ||
145 | num_irq = of_irq_count(np); | 155 | num_irq = of_irq_count(np); |
146 | 156 | ||
147 | /* Populate the resource table */ | 157 | /* Populate the resource table */ |