diff options
Diffstat (limited to 'drivers/of')
-rw-r--r-- | drivers/of/Kconfig | 4 | ||||
-rw-r--r-- | drivers/of/base.c | 173 | ||||
-rw-r--r-- | drivers/of/fdt.c | 11 | ||||
-rw-r--r-- | drivers/of/irq.c | 78 | ||||
-rw-r--r-- | drivers/of/of_numa.c | 66 | ||||
-rw-r--r-- | drivers/of/of_pci.c | 102 | ||||
-rw-r--r-- | drivers/of/platform.c | 2 |
7 files changed, 255 insertions, 181 deletions
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index bc07ad30c9bf..ba7b034b2b91 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -90,10 +90,6 @@ config OF_PCI_IRQ help OpenFirmware PCI IRQ routing helpers -config OF_MTD - depends on MTD - def_bool y - config OF_RESERVED_MEM depends on OF_EARLY_FLATTREE bool diff --git a/drivers/of/base.c b/drivers/of/base.c index 3ce69536a7b3..d687e6de24a0 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1146,16 +1146,18 @@ EXPORT_SYMBOL_GPL(of_property_count_elems_of_size); * * @np: device node from which the property value is to be read. * @propname: name of the property to be searched. - * @len: requested length of property value + * @min: minimum allowed length of property value + * @max: maximum allowed length of property value (0 means unlimited) + * @len: if !=NULL, actual length is written to here * * Search for a property in a device node and valid the requested size. * Returns the property value on success, -EINVAL if the property does not * exist, -ENODATA if property does not have a value, and -EOVERFLOW if the - * property data isn't large enough. + * property data is too small or too large. * */ static void *of_find_property_value_of_size(const struct device_node *np, - const char *propname, u32 len) + const char *propname, u32 min, u32 max, size_t *len) { struct property *prop = of_find_property(np, propname, NULL); @@ -1163,9 +1165,14 @@ static void *of_find_property_value_of_size(const struct device_node *np, return ERR_PTR(-EINVAL); if (!prop->value) return ERR_PTR(-ENODATA); - if (len > prop->length) + if (prop->length < min) + return ERR_PTR(-EOVERFLOW); + if (max && prop->length > max) return ERR_PTR(-EOVERFLOW); + if (len) + *len = prop->length; + return prop->value; } @@ -1189,7 +1196,9 @@ int of_property_read_u32_index(const struct device_node *np, u32 index, u32 *out_value) { const u32 *val = of_find_property_value_of_size(np, propname, - ((index + 1) * sizeof(*out_value))); + ((index + 1) * sizeof(*out_value)), + 0, + NULL); if (IS_ERR(val)) return PTR_ERR(val); @@ -1200,102 +1209,145 @@ int of_property_read_u32_index(const struct device_node *np, EXPORT_SYMBOL_GPL(of_property_read_u32_index); /** - * of_property_read_u8_array - Find and read an array of u8 from a property. + * of_property_read_variable_u8_array - Find and read an array of u8 from a + * property, with bounds on the minimum and maximum array size. * * @np: device node from which the property value is to be read. * @propname: name of the property to be searched. * @out_values: pointer to return value, modified only if return value is 0. - * @sz: number of array elements to read + * @sz_min: minimum number of array elements to read + * @sz_max: maximum number of array elements to read, if zero there is no + * upper limit on the number of elements in the dts entry but only + * sz_min will be read. * * Search for a property in a device node and read 8-bit value(s) from - * it. Returns 0 on success, -EINVAL if the property does not exist, - * -ENODATA if property does not have a value, and -EOVERFLOW if the - * property data isn't large enough. + * it. Returns number of elements read on success, -EINVAL if the property + * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW + * if the property data is smaller than sz_min or longer than sz_max. * * dts entry of array should be like: * property = /bits/ 8 <0x50 0x60 0x70>; * * The out_values is modified only if a valid u8 value can be decoded. */ -int of_property_read_u8_array(const struct device_node *np, - const char *propname, u8 *out_values, size_t sz) +int of_property_read_variable_u8_array(const struct device_node *np, + const char *propname, u8 *out_values, + size_t sz_min, size_t sz_max) { + size_t sz, count; const u8 *val = of_find_property_value_of_size(np, propname, - (sz * sizeof(*out_values))); + (sz_min * sizeof(*out_values)), + (sz_max * sizeof(*out_values)), + &sz); if (IS_ERR(val)) return PTR_ERR(val); - while (sz--) + if (!sz_max) + sz = sz_min; + else + sz /= sizeof(*out_values); + + count = sz; + while (count--) *out_values++ = *val++; - return 0; + + return sz; } -EXPORT_SYMBOL_GPL(of_property_read_u8_array); +EXPORT_SYMBOL_GPL(of_property_read_variable_u8_array); /** - * of_property_read_u16_array - Find and read an array of u16 from a property. + * of_property_read_variable_u16_array - Find and read an array of u16 from a + * property, with bounds on the minimum and maximum array size. * * @np: device node from which the property value is to be read. * @propname: name of the property to be searched. * @out_values: pointer to return value, modified only if return value is 0. - * @sz: number of array elements to read + * @sz_min: minimum number of array elements to read + * @sz_max: maximum number of array elements to read, if zero there is no + * upper limit on the number of elements in the dts entry but only + * sz_min will be read. * * Search for a property in a device node and read 16-bit value(s) from - * it. Returns 0 on success, -EINVAL if the property does not exist, - * -ENODATA if property does not have a value, and -EOVERFLOW if the - * property data isn't large enough. + * it. Returns number of elements read on success, -EINVAL if the property + * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW + * if the property data is smaller than sz_min or longer than sz_max. * * dts entry of array should be like: * property = /bits/ 16 <0x5000 0x6000 0x7000>; * * The out_values is modified only if a valid u16 value can be decoded. */ -int of_property_read_u16_array(const struct device_node *np, - const char *propname, u16 *out_values, size_t sz) +int of_property_read_variable_u16_array(const struct device_node *np, + const char *propname, u16 *out_values, + size_t sz_min, size_t sz_max) { + size_t sz, count; const __be16 *val = of_find_property_value_of_size(np, propname, - (sz * sizeof(*out_values))); + (sz_min * sizeof(*out_values)), + (sz_max * sizeof(*out_values)), + &sz); if (IS_ERR(val)) return PTR_ERR(val); - while (sz--) + if (!sz_max) + sz = sz_min; + else + sz /= sizeof(*out_values); + + count = sz; + while (count--) *out_values++ = be16_to_cpup(val++); - return 0; + + return sz; } -EXPORT_SYMBOL_GPL(of_property_read_u16_array); +EXPORT_SYMBOL_GPL(of_property_read_variable_u16_array); /** - * of_property_read_u32_array - Find and read an array of 32 bit integers - * from a property. + * of_property_read_variable_u32_array - Find and read an array of 32 bit + * integers from a property, with bounds on the minimum and maximum array size. * * @np: device node from which the property value is to be read. * @propname: name of the property to be searched. * @out_values: pointer to return value, modified only if return value is 0. - * @sz: number of array elements to read + * @sz_min: minimum number of array elements to read + * @sz_max: maximum number of array elements to read, if zero there is no + * upper limit on the number of elements in the dts entry but only + * sz_min will be read. * * Search for a property in a device node and read 32-bit value(s) from - * it. Returns 0 on success, -EINVAL if the property does not exist, - * -ENODATA if property does not have a value, and -EOVERFLOW if the - * property data isn't large enough. + * it. Returns number of elements read on success, -EINVAL if the property + * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW + * if the property data is smaller than sz_min or longer than sz_max. * * The out_values is modified only if a valid u32 value can be decoded. */ -int of_property_read_u32_array(const struct device_node *np, +int of_property_read_variable_u32_array(const struct device_node *np, const char *propname, u32 *out_values, - size_t sz) + size_t sz_min, size_t sz_max) { + size_t sz, count; const __be32 *val = of_find_property_value_of_size(np, propname, - (sz * sizeof(*out_values))); + (sz_min * sizeof(*out_values)), + (sz_max * sizeof(*out_values)), + &sz); if (IS_ERR(val)) return PTR_ERR(val); - while (sz--) + if (!sz_max) + sz = sz_min; + else + sz /= sizeof(*out_values); + + count = sz; + while (count--) *out_values++ = be32_to_cpup(val++); - return 0; + + return sz; } -EXPORT_SYMBOL_GPL(of_property_read_u32_array); +EXPORT_SYMBOL_GPL(of_property_read_variable_u32_array); /** * of_property_read_u64 - Find and read a 64 bit integer from a property @@ -1314,7 +1366,9 @@ int of_property_read_u64(const struct device_node *np, const char *propname, u64 *out_value) { const __be32 *val = of_find_property_value_of_size(np, propname, - sizeof(*out_value)); + sizeof(*out_value), + 0, + NULL); if (IS_ERR(val)) return PTR_ERR(val); @@ -1325,38 +1379,51 @@ int of_property_read_u64(const struct device_node *np, const char *propname, EXPORT_SYMBOL_GPL(of_property_read_u64); /** - * of_property_read_u64_array - Find and read an array of 64 bit integers - * from a property. + * of_property_read_variable_u64_array - Find and read an array of 64 bit + * integers from a property, with bounds on the minimum and maximum array size. * * @np: device node from which the property value is to be read. * @propname: name of the property to be searched. * @out_values: pointer to return value, modified only if return value is 0. - * @sz: number of array elements to read + * @sz_min: minimum number of array elements to read + * @sz_max: maximum number of array elements to read, if zero there is no + * upper limit on the number of elements in the dts entry but only + * sz_min will be read. * * Search for a property in a device node and read 64-bit value(s) from - * it. Returns 0 on success, -EINVAL if the property does not exist, - * -ENODATA if property does not have a value, and -EOVERFLOW if the - * property data isn't large enough. + * it. Returns number of elements read on success, -EINVAL if the property + * does not exist, -ENODATA if property does not have a value, and -EOVERFLOW + * if the property data is smaller than sz_min or longer than sz_max. * * The out_values is modified only if a valid u64 value can be decoded. */ -int of_property_read_u64_array(const struct device_node *np, +int of_property_read_variable_u64_array(const struct device_node *np, const char *propname, u64 *out_values, - size_t sz) + size_t sz_min, size_t sz_max) { + size_t sz, count; const __be32 *val = of_find_property_value_of_size(np, propname, - (sz * sizeof(*out_values))); + (sz_min * sizeof(*out_values)), + (sz_max * sizeof(*out_values)), + &sz); if (IS_ERR(val)) return PTR_ERR(val); - while (sz--) { + if (!sz_max) + sz = sz_min; + else + sz /= sizeof(*out_values); + + count = sz; + while (count--) { *out_values++ = of_read_number(val, 2); val += 2; } - return 0; + + return sz; } -EXPORT_SYMBOL_GPL(of_property_read_u64_array); +EXPORT_SYMBOL_GPL(of_property_read_variable_u64_array); /** * of_property_read_string - Find and read a string from a property @@ -2010,6 +2077,8 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)) name = of_get_property(of_aliases, "stdout", NULL); if (name) of_stdout = of_find_node_opts_by_path(name, &of_stdout_options); + if (of_stdout) + console_set_by_of(); } if (!of_aliases) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 085c6389afd1..c89d5d231a0e 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -924,7 +924,7 @@ static inline void early_init_dt_check_for_initrd(unsigned long node) #ifdef CONFIG_SERIAL_EARLYCON -static int __init early_init_dt_scan_chosen_serial(void) +int __init early_init_dt_scan_chosen_stdout(void) { int offset; const char *p, *q, *options = NULL; @@ -968,15 +968,6 @@ static int __init early_init_dt_scan_chosen_serial(void) } return -ENODEV; } - -static int __init setup_of_earlycon(char *buf) -{ - if (buf) - return 0; - - return early_init_dt_scan_chosen_serial(); -} -early_param("earlycon", setup_of_earlycon); #endif /** diff --git a/drivers/of/irq.c b/drivers/of/irq.c index a2e68f740eda..393fea85eb4e 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -26,6 +26,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_irq.h> +#include <linux/of_pci.h> #include <linux/string.h> #include <linux/slab.h> @@ -592,87 +593,16 @@ static u32 __of_msi_map_rid(struct device *dev, struct device_node **np, u32 rid_in) { struct device *parent_dev; - struct device_node *msi_controller_node; - struct device_node *msi_np = *np; - u32 map_mask, masked_rid, rid_base, msi_base, rid_len, phandle; - int msi_map_len; - bool matched; u32 rid_out = rid_in; - const __be32 *msi_map = NULL; /* * Walk up the device parent links looking for one with a * "msi-map" property. */ - for (parent_dev = dev; parent_dev; parent_dev = parent_dev->parent) { - if (!parent_dev->of_node) - continue; - - msi_map = of_get_property(parent_dev->of_node, - "msi-map", &msi_map_len); - if (!msi_map) - continue; - - if (msi_map_len % (4 * sizeof(__be32))) { - dev_err(parent_dev, "Error: Bad msi-map length: %d\n", - msi_map_len); - return rid_out; - } - /* We have a good parent_dev and msi_map, let's use them. */ - break; - } - if (!msi_map) - return rid_out; - - /* The default is to select all bits. */ - map_mask = 0xffffffff; - - /* - * Can be overridden by "msi-map-mask" property. If - * of_property_read_u32() fails, the default is used. - */ - of_property_read_u32(parent_dev->of_node, "msi-map-mask", &map_mask); - - masked_rid = map_mask & rid_in; - matched = false; - while (!matched && msi_map_len >= 4 * sizeof(__be32)) { - rid_base = be32_to_cpup(msi_map + 0); - phandle = be32_to_cpup(msi_map + 1); - msi_base = be32_to_cpup(msi_map + 2); - rid_len = be32_to_cpup(msi_map + 3); - - if (rid_base & ~map_mask) { - dev_err(parent_dev, - "Invalid msi-map translation - msi-map-mask (0x%x) ignores rid-base (0x%x)\n", - map_mask, rid_base); - return rid_out; - } - - msi_controller_node = of_find_node_by_phandle(phandle); - - matched = (masked_rid >= rid_base && - masked_rid < rid_base + rid_len); - if (msi_np) - matched &= msi_np == msi_controller_node; - - if (matched && !msi_np) { - *np = msi_np = msi_controller_node; + for (parent_dev = dev; parent_dev; parent_dev = parent_dev->parent) + if (!of_pci_map_rid(parent_dev->of_node, rid_in, "msi-map", + "msi-map-mask", np, &rid_out)) break; - } - - of_node_put(msi_controller_node); - msi_map_len -= 4 * sizeof(__be32); - msi_map += 4; - } - if (!matched) - return rid_out; - - rid_out = masked_rid - rid_base + msi_base; - dev_dbg(dev, - "msi-map at: %s, using mask %08x, rid-base: %08x, msi-base: %08x, length: %08x, rid: %08x -> %08x\n", - dev_name(parent_dev), map_mask, rid_base, msi_base, - rid_len, rid_in, rid_out); - return rid_out; } diff --git a/drivers/of/of_numa.c b/drivers/of/of_numa.c index ed5a097f0801..f63d4b0deff0 100644 --- a/drivers/of/of_numa.c +++ b/drivers/of/of_numa.c @@ -16,6 +16,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#define pr_fmt(fmt) "OF: NUMA: " fmt + #include <linux/of.h> #include <linux/of_address.h> #include <linux/nodemask.h> @@ -49,10 +51,9 @@ static void __init of_numa_parse_cpu_nodes(void) if (r) continue; - pr_debug("NUMA: CPU on %u\n", nid); + pr_debug("CPU on %u\n", nid); if (nid >= MAX_NUMNODES) - pr_warn("NUMA: Node id %u exceeds maximum value\n", - nid); + pr_warn("Node id %u exceeds maximum value\n", nid); else node_set(nid, numa_nodes_parsed); } @@ -63,13 +64,9 @@ static int __init of_numa_parse_memory_nodes(void) struct device_node *np = NULL; struct resource rsrc; u32 nid; - int r = 0; - - for (;;) { - np = of_find_node_by_type(np, "memory"); - if (!np) - break; + int i, r; + for_each_node_by_type(np, "memory") { r = of_property_read_u32(np, "numa-node-id", &nid); if (r == -EINVAL) /* @@ -78,27 +75,23 @@ static int __init of_numa_parse_memory_nodes(void) * "numa-node-id" property */ continue; - else if (r) - /* some other error */ - break; - r = of_address_to_resource(np, 0, &rsrc); - if (r) { - pr_err("NUMA: bad reg property in memory node\n"); - break; + if (nid >= MAX_NUMNODES) { + pr_warn("Node id %u exceeds maximum value\n", nid); + r = -EINVAL; } - pr_debug("NUMA: base = %llx len = %llx, node = %u\n", - rsrc.start, rsrc.end - rsrc.start + 1, nid); - + for (i = 0; !r && !of_address_to_resource(np, i, &rsrc); i++) + r = numa_add_memblk(nid, rsrc.start, rsrc.end + 1); - r = numa_add_memblk(nid, rsrc.start, rsrc.end + 1); - if (r) - break; + if (!i || r) { + of_node_put(np); + pr_err("bad property in memory node\n"); + return r ? : -EINVAL; + } } - of_node_put(np); - return r; + return 0; } static int __init of_numa_parse_distance_map_v1(struct device_node *map) @@ -107,17 +100,17 @@ static int __init of_numa_parse_distance_map_v1(struct device_node *map) int entry_count; int i; - pr_info("NUMA: parsing numa-distance-map-v1\n"); + pr_info("parsing numa-distance-map-v1\n"); matrix = of_get_property(map, "distance-matrix", NULL); if (!matrix) { - pr_err("NUMA: No distance-matrix property in distance-map\n"); + pr_err("No distance-matrix property in distance-map\n"); return -EINVAL; } entry_count = of_property_count_u32_elems(map, "distance-matrix"); if (entry_count <= 0) { - pr_err("NUMA: Invalid distance-matrix\n"); + pr_err("Invalid distance-matrix\n"); return -EINVAL; } @@ -132,7 +125,7 @@ static int __init of_numa_parse_distance_map_v1(struct device_node *map) matrix++; numa_set_distance(nodea, nodeb, distance); - pr_debug("NUMA: distance[node%d -> node%d] = %d\n", + pr_debug("distance[node%d -> node%d] = %d\n", nodea, nodeb, distance); /* Set default distance of node B->A same as A->B */ @@ -166,8 +159,6 @@ int of_node_to_nid(struct device_node *device) np = of_node_get(device); while (np) { - struct device_node *parent; - r = of_property_read_u32(np, "numa-node-id", &nid); /* * -EINVAL indicates the property was not found, and @@ -178,22 +169,15 @@ int of_node_to_nid(struct device_node *device) if (r != -EINVAL) break; - parent = of_get_parent(np); - of_node_put(np); - np = parent; + np = of_get_next_parent(np); } if (np && r) - pr_warn("NUMA: Invalid \"numa-node-id\" property in node %s\n", + pr_warn("Invalid \"numa-node-id\" property in node %s\n", np->name); of_node_put(np); - if (!r) { - if (nid >= MAX_NUMNODES) - pr_warn("NUMA: Node id %u exceeds maximum value\n", - nid); - else - return nid; - } + if (!r) + return nid; return NUMA_NO_NODE; } diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c index 589b30c68e14..b58be12ab277 100644 --- a/drivers/of/of_pci.c +++ b/drivers/of/of_pci.c @@ -308,3 +308,105 @@ struct msi_controller *of_pci_find_msi_chip_by_node(struct device_node *of_node) EXPORT_SYMBOL_GPL(of_pci_find_msi_chip_by_node); #endif /* CONFIG_PCI_MSI */ + +/** + * of_pci_map_rid - Translate a requester ID through a downstream mapping. + * @np: root complex device node. + * @rid: PCI requester ID to map. + * @map_name: property name of the map to use. + * @map_mask_name: optional property name of the mask to use. + * @target: optional pointer to a target device node. + * @id_out: optional pointer to receive the translated ID. + * + * Given a PCI requester ID, look up the appropriate implementation-defined + * platform ID and/or the target device which receives transactions on that + * ID, as per the "iommu-map" and "msi-map" bindings. Either of @target or + * @id_out may be NULL if only the other is required. If @target points to + * a non-NULL device node pointer, only entries targeting that node will be + * matched; if it points to a NULL value, it will receive the device node of + * the first matching target phandle, with a reference held. + * + * Return: 0 on success or a standard error code on failure. + */ +int of_pci_map_rid(struct device_node *np, u32 rid, + const char *map_name, const char *map_mask_name, + struct device_node **target, u32 *id_out) +{ + u32 map_mask, masked_rid; + int map_len; + const __be32 *map = NULL; + + if (!np || !map_name || (!target && !id_out)) + return -EINVAL; + + map = of_get_property(np, map_name, &map_len); + if (!map) { + if (target) + return -ENODEV; + /* Otherwise, no map implies no translation */ + *id_out = rid; + return 0; + } + + if (!map_len || map_len % (4 * sizeof(*map))) { + pr_err("%s: Error: Bad %s length: %d\n", np->full_name, + map_name, map_len); + return -EINVAL; + } + + /* The default is to select all bits. */ + map_mask = 0xffffffff; + + /* + * Can be overridden by "{iommu,msi}-map-mask" property. + * If of_property_read_u32() fails, the default is used. + */ + if (map_mask_name) + of_property_read_u32(np, map_mask_name, &map_mask); + + masked_rid = map_mask & rid; + for ( ; map_len > 0; map_len -= 4 * sizeof(*map), map += 4) { + struct device_node *phandle_node; + u32 rid_base = be32_to_cpup(map + 0); + u32 phandle = be32_to_cpup(map + 1); + u32 out_base = be32_to_cpup(map + 2); + u32 rid_len = be32_to_cpup(map + 3); + + if (rid_base & ~map_mask) { + pr_err("%s: Invalid %s translation - %s-mask (0x%x) ignores rid-base (0x%x)\n", + np->full_name, map_name, map_name, + map_mask, rid_base); + return -EFAULT; + } + + if (masked_rid < rid_base || masked_rid >= rid_base + rid_len) + continue; + + phandle_node = of_find_node_by_phandle(phandle); + if (!phandle_node) + return -ENODEV; + + if (target) { + if (*target) + of_node_put(phandle_node); + else + *target = phandle_node; + + if (*target != phandle_node) + continue; + } + + if (id_out) + *id_out = masked_rid - rid_base + out_base; + + pr_debug("%s: %s, using mask %08x, rid-base: %08x, out-base: %08x, length: %08x, rid: %08x -> %08x\n", + np->full_name, map_name, map_mask, rid_base, out_base, + rid_len, rid, *id_out); + return 0; + } + + pr_err("%s: Invalid %s translation - no match for rid 0x%x on %s\n", + np->full_name, map_name, rid, + target && *target ? (*target)->full_name : "any target"); + return -EFAULT; +} diff --git a/drivers/of/platform.c b/drivers/of/platform.c index d85e4318b099..e4bf07d20f9b 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -143,6 +143,7 @@ struct platform_device *of_device_alloc(struct device_node *np, } dev->dev.of_node = of_node_get(np); + dev->dev.fwnode = &np->fwnode; dev->dev.parent = parent ? : &platform_bus; if (bus_id) @@ -242,6 +243,7 @@ static struct amba_device *of_amba_device_create(struct device_node *node, /* setup generic device info */ dev->dev.of_node = of_node_get(node); + dev->dev.fwnode = &node->fwnode; dev->dev.parent = parent ? : &platform_bus; dev->dev.platform_data = platform_data; if (bus_id) |