summaryrefslogtreecommitdiffstats
path: root/kernel/drivers/of
diff options
context:
space:
mode:
authorJosé Pekkarinen <jose.pekkarinen@nokia.com>2016-04-11 10:41:07 +0300
committerJosé Pekkarinen <jose.pekkarinen@nokia.com>2016-04-13 08:17:18 +0300
commite09b41010ba33a20a87472ee821fa407a5b8da36 (patch)
treed10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/drivers/of
parentf93b97fd65072de626c074dbe099a1fff05ce060 (diff)
These changes are the raw update to linux-4.4.6-rt14. Kernel sources
are taken from kernel.org, and rt patch from the rt wiki download page. During the rebasing, the following patch collided: Force tick interrupt and get rid of softirq magic(I70131fb85). Collisions have been removed because its logic was found on the source already. Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769 Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'kernel/drivers/of')
-rw-r--r--kernel/drivers/of/Kconfig29
-rw-r--r--kernel/drivers/of/Makefile3
-rw-r--r--kernel/drivers/of/address.c11
-rw-r--r--kernel/drivers/of/base.c39
-rw-r--r--kernel/drivers/of/device.c23
-rw-r--r--kernel/drivers/of/fdt.c60
-rw-r--r--kernel/drivers/of/irq.c211
-rw-r--r--kernel/drivers/of/of_mdio.c43
-rw-r--r--kernel/drivers/of/of_pci.c36
-rw-r--r--kernel/drivers/of/of_pci_irq.c22
-rw-r--r--kernel/drivers/of/of_reserved_mem.c52
-rw-r--r--kernel/drivers/of/overlay.c11
-rw-r--r--kernel/drivers/of/platform.c19
-rw-r--r--kernel/drivers/of/unittest.c11
14 files changed, 487 insertions, 83 deletions
diff --git a/kernel/drivers/of/Kconfig b/kernel/drivers/of/Kconfig
index 07bb3c8f1..e2a48415d 100644
--- a/kernel/drivers/of/Kconfig
+++ b/kernel/drivers/of/Kconfig
@@ -1,15 +1,20 @@
config DTC
bool
-config OF
- bool
+menuconfig OF
+ bool "Device Tree and Open Firmware support"
+ help
+ This option enables the device tree infrastructure.
+ It is automatically selected by platforms that need it or can
+ be enabled manually for unittests, overlays or
+ compile-coverage.
-menu "Device Tree and Open Firmware support"
- depends on OF
+if OF
config OF_UNITTEST
bool "Device Tree runtime unit tests"
- depends on OF_IRQ && OF_EARLY_FLATTREE
+ depends on OF_IRQ
+ select OF_EARLY_FLATTREE
select OF_RESOLVE
help
This option builds in test cases for the device tree infrastructure
@@ -18,6 +23,16 @@ config OF_UNITTEST
If unsure, say N here, but this option is safe to enable.
+config OF_ALL_DTBS
+ bool "Build all Device Tree Blobs"
+ depends on COMPILE_TEST
+ select DTC
+ help
+ This option builds all possible Device Tree Blobs (DTBs) for the
+ current architecture.
+
+ If unsure, say N here, but this option is safe to enable.
+
config OF_FLATTREE
bool
select DTC
@@ -42,7 +57,7 @@ config OF_DYNAMIC
config OF_ADDRESS
def_bool y
- depends on !SPARC
+ depends on !SPARC && HAS_IOMEM
select OF_ADDRESS_PCI if PCI
config OF_ADDRESS_PCI
@@ -97,4 +112,4 @@ config OF_OVERLAY
While this option is selected automatically when needed, you can
enable it manually to improve device tree unit test coverage.
-endmenu # OF
+endif # OF
diff --git a/kernel/drivers/of/Makefile b/kernel/drivers/of/Makefile
index fcacb186a..156c072b3 100644
--- a/kernel/drivers/of/Makefile
+++ b/kernel/drivers/of/Makefile
@@ -16,6 +16,3 @@ obj-$(CONFIG_OF_RESOLVE) += resolver.o
obj-$(CONFIG_OF_OVERLAY) += overlay.o
obj-$(CONFIG_OF_UNITTEST) += unittest-data/
-
-CFLAGS_fdt.o = -I$(src)/../../scripts/dtc/libfdt
-CFLAGS_fdt_address.o = -I$(src)/../../scripts/dtc/libfdt
diff --git a/kernel/drivers/of/address.c b/kernel/drivers/of/address.c
index 384574c39..9582c5703 100644
--- a/kernel/drivers/of/address.c
+++ b/kernel/drivers/of/address.c
@@ -330,6 +330,12 @@ int of_pci_range_to_resource(struct of_pci_range *range,
}
res->start = port;
} else {
+ if ((sizeof(resource_size_t) < 8) &&
+ upper_32_bits(range->cpu_addr)) {
+ err = -EINVAL;
+ goto invalid_range;
+ }
+
res->start = range->cpu_addr;
}
res->end = res->start + range->size - 1;
@@ -479,9 +485,10 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
int rone;
u64 offset = OF_BAD_ADDR;
- /* Normally, an absence of a "ranges" property means we are
+ /*
+ * Normally, an absence of a "ranges" property means we are
* crossing a non-translatable boundary, and thus the addresses
- * below the current not cannot be converted to CPU physical ones.
+ * below the current cannot be converted to CPU physical ones.
* Unfortunately, while this is very clear in the spec, it's not
* what Apple understood, and they do have things like /uni-n or
* /ht nodes with no "ranges" property and a lot of perfectly
diff --git a/kernel/drivers/of/base.c b/kernel/drivers/of/base.c
index 5ed97246c..017dd94f1 100644
--- a/kernel/drivers/of/base.c
+++ b/kernel/drivers/of/base.c
@@ -375,10 +375,7 @@ bool __weak arch_find_n_match_cpu_physical_id(struct device_node *cpun,
cpu, thread))
return true;
- if (__of_find_n_match_cpu_property(cpun, "reg", cpu, thread))
- return true;
-
- return false;
+ return __of_find_n_match_cpu_property(cpun, "reg", cpu, thread);
}
/**
@@ -2231,6 +2228,40 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
EXPORT_SYMBOL(of_graph_get_next_endpoint);
/**
+ * of_graph_get_endpoint_by_regs() - get endpoint node of specific identifiers
+ * @parent: pointer to the parent device node
+ * @port_reg: identifier (value of reg property) of the parent port node
+ * @reg: identifier (value of reg property) of the endpoint node
+ *
+ * Return: An 'endpoint' node pointer which is identified by reg and at the same
+ * is the child of a port node identified by port_reg. reg and port_reg are
+ * ignored when they are -1.
+ */
+struct device_node *of_graph_get_endpoint_by_regs(
+ const struct device_node *parent, int port_reg, int reg)
+{
+ struct of_endpoint endpoint;
+ struct device_node *node, *prev_node = NULL;
+
+ while (1) {
+ node = of_graph_get_next_endpoint(parent, prev_node);
+ of_node_put(prev_node);
+ if (!node)
+ break;
+
+ of_graph_parse_endpoint(node, &endpoint);
+ if (((port_reg == -1) || (endpoint.port == port_reg)) &&
+ ((reg == -1) || (endpoint.id == reg)))
+ return node;
+
+ prev_node = node;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(of_graph_get_endpoint_by_regs);
+
+/**
* of_graph_get_remote_port_parent() - get remote port's parent node
* @node: pointer to a local endpoint device_node
*
diff --git a/kernel/drivers/of/device.c b/kernel/drivers/of/device.c
index 20c1332a0..e5f47cec7 100644
--- a/kernel/drivers/of/device.c
+++ b/kernel/drivers/of/device.c
@@ -60,11 +60,12 @@ int of_device_add(struct platform_device *ofdev)
ofdev->name = dev_name(&ofdev->dev);
ofdev->id = -1;
- /* device_add will assume that this device is on the same node as
- * the parent. If there is no parent defined, set the node
- * explicitly */
- if (!ofdev->dev.parent)
- set_dev_node(&ofdev->dev, of_node_to_nid(ofdev->dev.of_node));
+ /*
+ * If this device has not binding numa node in devicetree, that is
+ * of_node_to_nid returns NUMA_NO_NODE. device_add will assume that this
+ * device is on the same node as the parent.
+ */
+ set_dev_node(&ofdev->dev, of_node_to_nid(ofdev->dev.of_node));
return device_add(&ofdev->dev);
}
@@ -163,6 +164,18 @@ void of_device_unregister(struct platform_device *ofdev)
}
EXPORT_SYMBOL(of_device_unregister);
+const void *of_device_get_match_data(const struct device *dev)
+{
+ const struct of_device_id *match;
+
+ match = of_match_device(dev->driver->of_match_table, dev);
+ if (!match)
+ return NULL;
+
+ return match->data;
+}
+EXPORT_SYMBOL(of_device_get_match_data);
+
ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len)
{
const char *compat;
diff --git a/kernel/drivers/of/fdt.c b/kernel/drivers/of/fdt.c
index d91f721a0..655f79db7 100644
--- a/kernel/drivers/of/fdt.c
+++ b/kernel/drivers/of/fdt.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/initrd.h>
#include <linux/memblock.h>
+#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_reserved_mem.h>
@@ -164,11 +165,14 @@ static void *unflatten_dt_alloc(void **mem, unsigned long size,
* unflatten_dt_node - Alloc and populate a device_node from the flat tree
* @blob: The parent device tree blob
* @mem: Memory chunk to use for allocating device nodes and properties
- * @p: pointer to node in flat tree
+ * @poffset: pointer to node in flat tree
* @dad: Parent struct device_node
+ * @nodepp: The device_node tree created by the call
* @fpsize: Size of the node path up at the current depth.
+ * @dryrun: If true, do not allocate device nodes but still calculate needed
+ * memory size
*/
-static void * unflatten_dt_node(void *blob,
+static void * unflatten_dt_node(const void *blob,
void *mem,
int *poffset,
struct device_node *dad,
@@ -181,7 +185,7 @@ static void * unflatten_dt_node(void *blob,
struct property *pp, **prev_pp = NULL;
const char *pathp;
unsigned int l, allocl;
- static int depth = 0;
+ static int depth;
int old_depth;
int offset;
int has_name = 0;
@@ -378,7 +382,7 @@ static void * unflatten_dt_node(void *blob,
* @dt_alloc: An allocator that provides a virtual address to memory
* for the resulting tree
*/
-static void __unflatten_device_tree(void *blob,
+static void __unflatten_device_tree(const void *blob,
struct device_node **mynodes,
void * (*dt_alloc)(u64 size, u64 align))
{
@@ -433,6 +437,8 @@ static void *kernel_tree_alloc(u64 size, u64 align)
return kzalloc(size, GFP_KERNEL);
}
+static DEFINE_MUTEX(of_fdt_unflatten_mutex);
+
/**
* of_fdt_unflatten_tree - create tree of device_nodes from flat blob
*
@@ -441,10 +447,12 @@ static void *kernel_tree_alloc(u64 size, u64 align)
* pointers of the nodes so the normal device-tree walking functions
* can be used.
*/
-void of_fdt_unflatten_tree(unsigned long *blob,
+void of_fdt_unflatten_tree(const unsigned long *blob,
struct device_node **mynodes)
{
+ mutex_lock(&of_fdt_unflatten_mutex);
__unflatten_device_tree(blob, mynodes, &kernel_tree_alloc);
+ mutex_unlock(&of_fdt_unflatten_mutex);
}
EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
@@ -580,11 +588,6 @@ void __init early_init_fdt_scan_reserved_mem(void)
if (!initial_boot_params)
return;
- /* Reserve the dtb region */
- early_init_dt_reserve_memory_arch(__pa(initial_boot_params),
- fdt_totalsize(initial_boot_params),
- 0);
-
/* Process header /memreserve/ fields */
for (n = 0; ; n++) {
fdt_get_mem_rsv(initial_boot_params, n, &base, &size);
@@ -598,6 +601,20 @@ void __init early_init_fdt_scan_reserved_mem(void)
}
/**
+ * early_init_fdt_reserve_self() - reserve the memory used by the FDT blob
+ */
+void __init early_init_fdt_reserve_self(void)
+{
+ if (!initial_boot_params)
+ return;
+
+ /* Reserve the dtb region */
+ early_init_dt_reserve_memory_arch(__pa(initial_boot_params),
+ fdt_totalsize(initial_boot_params),
+ 0);
+}
+
+/**
* of_scan_flat_dt - scan flattened tree blob and call callback on each.
* @it: callback function
* @data: context data pointer
@@ -801,20 +818,24 @@ static int __init early_init_dt_scan_chosen_serial(void)
if (!p || !l)
return -ENOENT;
+ /* Remove console options if present */
+ l = strchrnul(p, ':') - p;
+
/* Get the node specified by stdout-path */
- offset = fdt_path_offset(fdt, p);
+ offset = fdt_path_offset_namelen(fdt, p, l);
if (offset < 0)
return -ENODEV;
while (match->compatible[0]) {
- unsigned long addr;
+ u64 addr;
+
if (fdt_node_check_compatible(fdt, offset, match->compatible)) {
match++;
continue;
}
addr = fdt_translate_address(fdt, offset);
- if (!addr)
+ if (addr == OF_BAD_ADDR)
return -ENXIO;
of_setup_earlycon(addr, match->data);
@@ -1017,13 +1038,24 @@ void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align)
return __va(memblock_alloc(size, align));
}
#else
+void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
+{
+ WARN_ON(1);
+}
+
int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
phys_addr_t size, bool nomap)
{
- pr_err("Reserved memory not supported, ignoring range 0x%pa - 0x%pa%s\n",
+ pr_err("Reserved memory not supported, ignoring range %pa - %pa%s\n",
&base, &size, nomap ? " (nomap)" : "");
return -ENOSYS;
}
+
+void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align)
+{
+ WARN_ON(1);
+ return NULL;
+}
#endif
bool __init early_init_dt_verify(void *params)
diff --git a/kernel/drivers/of/irq.c b/kernel/drivers/of/irq.c
index 1a7980692..72a2c1969 100644
--- a/kernel/drivers/of/irq.c
+++ b/kernel/drivers/of/irq.c
@@ -18,6 +18,7 @@
* driver.
*/
+#include <linux/device.h>
#include <linux/errno.h>
#include <linux/list.h>
#include <linux/module.h>
@@ -76,6 +77,7 @@ struct device_node *of_irq_find_parent(struct device_node *child)
return p;
}
+EXPORT_SYMBOL_GPL(of_irq_find_parent);
/**
* of_irq_parse_raw - Low level interrupt tree parsing
@@ -252,8 +254,6 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
* Successfully parsed an interrrupt-map translation; copy new
* interrupt specifier into the out_irq structure
*/
- out_irq->np = newpar;
-
match_array = imap - newaddrsize - newintsize;
for (i = 0; i < newintsize; i++)
out_irq->args[i] = be32_to_cpup(imap - newintsize + i);
@@ -262,6 +262,7 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
skiplevel:
/* Iterate again with new parent */
+ out_irq->np = newpar;
pr_debug(" -> new parent: %s\n", of_node_full_name(newpar));
of_node_put(ipar);
ipar = newpar;
@@ -432,6 +433,7 @@ int of_irq_get_byname(struct device_node *dev, const char *name)
return of_irq_get(dev, index);
}
+EXPORT_SYMBOL_GPL(of_irq_get_byname);
/**
* of_irq_count - Count the number of IRQs a node uses
@@ -469,7 +471,7 @@ int of_irq_to_resource_table(struct device_node *dev, struct resource *res,
}
EXPORT_SYMBOL_GPL(of_irq_to_resource_table);
-struct intc_desc {
+struct of_intc_desc {
struct list_head list;
struct device_node *dev;
struct device_node *interrupt_parent;
@@ -485,7 +487,7 @@ struct intc_desc {
void __init of_irq_init(const struct of_device_id *matches)
{
struct device_node *np, *parent = NULL;
- struct intc_desc *desc, *temp_desc;
+ struct of_intc_desc *desc, *temp_desc;
struct list_head intc_desc_list, intc_parent_list;
INIT_LIST_HEAD(&intc_desc_list);
@@ -496,14 +498,16 @@ void __init of_irq_init(const struct of_device_id *matches)
!of_device_is_available(np))
continue;
/*
- * Here, we allocate and populate an intc_desc with the node
+ * Here, we allocate and populate an of_intc_desc with the node
* pointer, interrupt-parent device_node etc.
*/
desc = kzalloc(sizeof(*desc), GFP_KERNEL);
- if (WARN_ON(!desc))
+ if (WARN_ON(!desc)) {
+ of_node_put(np);
goto err;
+ }
- desc->dev = np;
+ desc->dev = of_node_get(np);
desc->interrupt_parent = of_irq_find_parent(np);
if (desc->interrupt_parent == np)
desc->interrupt_parent = NULL;
@@ -574,6 +578,199 @@ void __init of_irq_init(const struct of_device_id *matches)
err:
list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
list_del(&desc->list);
+ of_node_put(desc->dev);
kfree(desc);
}
}
+
+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;
+ 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;
+}
+
+/**
+ * of_msi_map_rid - Map a MSI requester ID for a device.
+ * @dev: device for which the mapping is to be done.
+ * @msi_np: device node of the expected msi controller.
+ * @rid_in: unmapped MSI requester ID for the device.
+ *
+ * Walk up the device hierarchy looking for devices with a "msi-map"
+ * property. If found, apply the mapping to @rid_in.
+ *
+ * Returns the mapped MSI requester ID.
+ */
+u32 of_msi_map_rid(struct device *dev, struct device_node *msi_np, u32 rid_in)
+{
+ return __of_msi_map_rid(dev, &msi_np, rid_in);
+}
+
+static struct irq_domain *__of_get_msi_domain(struct device_node *np,
+ enum irq_domain_bus_token token)
+{
+ struct irq_domain *d;
+
+ d = irq_find_matching_host(np, token);
+ if (!d)
+ d = irq_find_host(np);
+
+ return d;
+}
+
+/**
+ * of_msi_map_get_device_domain - Use msi-map to find the relevant MSI domain
+ * @dev: device for which the mapping is to be done.
+ * @rid: Requester ID for the device.
+ *
+ * Walk up the device hierarchy looking for devices with a "msi-map"
+ * property.
+ *
+ * Returns: the MSI domain for this device (or NULL on failure)
+ */
+struct irq_domain *of_msi_map_get_device_domain(struct device *dev, u32 rid)
+{
+ struct device_node *np = NULL;
+
+ __of_msi_map_rid(dev, &np, rid);
+ return __of_get_msi_domain(np, DOMAIN_BUS_PCI_MSI);
+}
+
+/**
+ * of_msi_get_domain - Use msi-parent to find the relevant MSI domain
+ * @dev: device for which the domain is requested
+ * @np: device node for @dev
+ * @token: bus type for this domain
+ *
+ * Parse the msi-parent property (both the simple and the complex
+ * versions), and returns the corresponding MSI domain.
+ *
+ * Returns: the MSI domain for this device (or NULL on failure).
+ */
+struct irq_domain *of_msi_get_domain(struct device *dev,
+ struct device_node *np,
+ enum irq_domain_bus_token token)
+{
+ struct device_node *msi_np;
+ struct irq_domain *d;
+
+ /* Check for a single msi-parent property */
+ msi_np = of_parse_phandle(np, "msi-parent", 0);
+ if (msi_np && !of_property_read_bool(msi_np, "#msi-cells")) {
+ d = __of_get_msi_domain(msi_np, token);
+ if (!d)
+ of_node_put(msi_np);
+ return d;
+ }
+
+ if (token == DOMAIN_BUS_PLATFORM_MSI) {
+ /* Check for the complex msi-parent version */
+ struct of_phandle_args args;
+ int index = 0;
+
+ while (!of_parse_phandle_with_args(np, "msi-parent",
+ "#msi-cells",
+ index, &args)) {
+ d = __of_get_msi_domain(args.np, token);
+ if (d)
+ return d;
+
+ of_node_put(args.np);
+ index++;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * of_msi_configure - Set the msi_domain field of a device
+ * @dev: device structure to associate with an MSI irq domain
+ * @np: device node for that device
+ */
+void of_msi_configure(struct device *dev, struct device_node *np)
+{
+ dev_set_msi_domain(dev,
+ of_msi_get_domain(dev, np, DOMAIN_BUS_PLATFORM_MSI));
+}
diff --git a/kernel/drivers/of/of_mdio.c b/kernel/drivers/of/of_mdio.c
index bec8ec2b3..a87a868fe 100644
--- a/kernel/drivers/of/of_mdio.c
+++ b/kernel/drivers/of/of_mdio.c
@@ -16,6 +16,7 @@
#include <linux/phy.h>
#include <linux/phy_fixed.h>
#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/of_mdio.h>
#include <linux/module.h>
@@ -68,6 +69,9 @@ static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *chi
phy->irq = mdio->irq[addr];
}
+ if (of_property_read_bool(child, "broken-turn-around"))
+ mdio->phy_ignore_ta_mask |= 1 << addr;
+
/* Associate the OF node with the device structure so it
* can be looked up later */
of_node_get(child);
@@ -193,7 +197,8 @@ static int of_phy_match(struct device *dev, void *phy_np)
* of_phy_find_device - Give a PHY node, find the phy_device
* @phy_np: Pointer to the phy's device tree node
*
- * Returns a pointer to the phy_device.
+ * If successful, returns a pointer to the phy_device with the embedded
+ * struct device refcount incremented by one, or NULL on failure.
*/
struct phy_device *of_phy_find_device(struct device_node *phy_np)
{
@@ -213,7 +218,9 @@ EXPORT_SYMBOL(of_phy_find_device);
* @hndlr: Link state callback for the network device
* @iface: PHY data interface type
*
- * Returns a pointer to the phy_device if successful. NULL otherwise
+ * If successful, returns a pointer to the phy_device with the embedded
+ * struct device refcount incremented by one, or NULL on failure. The
+ * refcount must be dropped by calling phy_disconnect() or phy_detach().
*/
struct phy_device *of_phy_connect(struct net_device *dev,
struct device_node *phy_np,
@@ -221,13 +228,19 @@ struct phy_device *of_phy_connect(struct net_device *dev,
phy_interface_t iface)
{
struct phy_device *phy = of_phy_find_device(phy_np);
+ int ret;
if (!phy)
return NULL;
phy->dev_flags = flags;
- return phy_connect_direct(dev, phy, hndlr, iface) ? NULL : phy;
+ ret = phy_connect_direct(dev, phy, hndlr, iface);
+
+ /* refcount is held by phy_connect_direct() on success */
+ put_device(&phy->dev);
+
+ return ret ? NULL : phy;
}
EXPORT_SYMBOL(of_phy_connect);
@@ -237,17 +250,27 @@ EXPORT_SYMBOL(of_phy_connect);
* @phy_np: Node pointer for the PHY
* @flags: flags to pass to the PHY
* @iface: PHY data interface type
+ *
+ * If successful, returns a pointer to the phy_device with the embedded
+ * struct device refcount incremented by one, or NULL on failure. The
+ * refcount must be dropped by calling phy_disconnect() or phy_detach().
*/
struct phy_device *of_phy_attach(struct net_device *dev,
struct device_node *phy_np, u32 flags,
phy_interface_t iface)
{
struct phy_device *phy = of_phy_find_device(phy_np);
+ int ret;
if (!phy)
return NULL;
- return phy_attach_direct(dev, phy, flags, iface) ? NULL : phy;
+ ret = phy_attach_direct(dev, phy, flags, iface);
+
+ /* refcount is held by phy_attach_direct() on success */
+ put_device(&phy->dev);
+
+ return ret ? NULL : phy;
}
EXPORT_SYMBOL(of_phy_attach);
@@ -291,6 +314,7 @@ int of_phy_register_fixed_link(struct device_node *np)
struct fixed_phy_status status = {};
struct device_node *fixed_link_node;
const __be32 *fixed_link_prop;
+ int link_gpio;
int len, err;
struct phy_device *phy;
const char *managed;
@@ -299,7 +323,7 @@ int of_phy_register_fixed_link(struct device_node *np)
if (err == 0) {
if (strcmp(managed, "in-band-status") == 0) {
/* status is zeroed, namely its .link member */
- phy = fixed_phy_register(PHY_POLL, &status, np);
+ phy = fixed_phy_register(PHY_POLL, &status, -1, np);
return IS_ERR(phy) ? PTR_ERR(phy) : 0;
}
}
@@ -315,8 +339,13 @@ int of_phy_register_fixed_link(struct device_node *np)
status.pause = of_property_read_bool(fixed_link_node, "pause");
status.asym_pause = of_property_read_bool(fixed_link_node,
"asym-pause");
+ link_gpio = of_get_named_gpio_flags(fixed_link_node,
+ "link-gpios", 0, NULL);
of_node_put(fixed_link_node);
- phy = fixed_phy_register(PHY_POLL, &status, np);
+ if (link_gpio == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ phy = fixed_phy_register(PHY_POLL, &status, link_gpio, np);
return IS_ERR(phy) ? PTR_ERR(phy) : 0;
}
@@ -328,7 +357,7 @@ int of_phy_register_fixed_link(struct device_node *np)
status.speed = be32_to_cpu(fixed_link_prop[2]);
status.pause = be32_to_cpu(fixed_link_prop[3]);
status.asym_pause = be32_to_cpu(fixed_link_prop[4]);
- phy = fixed_phy_register(PHY_POLL, &status, np);
+ phy = fixed_phy_register(PHY_POLL, &status, -1, np);
return IS_ERR(phy) ? PTR_ERR(phy) : 0;
}
diff --git a/kernel/drivers/of/of_pci.c b/kernel/drivers/of/of_pci.c
index 5751dc5b6..b1449f716 100644
--- a/kernel/drivers/of/of_pci.c
+++ b/kernel/drivers/of/of_pci.c
@@ -5,6 +5,7 @@
#include <linux/of_device.h>
#include <linux/of_pci.h>
#include <linux/slab.h>
+#include <asm-generic/pci-bridge.h>
static inline int __of_pci_pci_compare(struct device_node *node,
unsigned int data)
@@ -118,24 +119,29 @@ int of_get_pci_domain_nr(struct device_node *node)
EXPORT_SYMBOL_GPL(of_get_pci_domain_nr);
/**
- * of_pci_dma_configure - Setup DMA configuration
- * @dev: ptr to pci_dev struct of the PCI device
- *
- * Function to update PCI devices's DMA configuration using the same
- * info from the OF node of host bridge's parent (if any).
+ * of_pci_check_probe_only - Setup probe only mode if linux,pci-probe-only
+ * is present and valid
*/
-void of_pci_dma_configure(struct pci_dev *pci_dev)
+void of_pci_check_probe_only(void)
{
- struct device *dev = &pci_dev->dev;
- struct device *bridge = pci_get_host_bridge_device(pci_dev);
+ u32 val;
+ int ret;
- if (!bridge->parent)
+ 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\n");
return;
+ }
+
+ if (val)
+ pci_add_flags(PCI_PROBE_ONLY);
+ else
+ pci_clear_flags(PCI_PROBE_ONLY);
- of_dma_configure(dev, bridge->parent->of_node);
- pci_put_host_bridge_device(bridge);
+ pr_info("PCI: PROBE_ONLY %sabled\n", val ? "en" : "dis");
}
-EXPORT_SYMBOL_GPL(of_pci_dma_configure);
+EXPORT_SYMBOL_GPL(of_pci_check_probe_only);
#if defined(CONFIG_OF_ADDRESS)
/**
@@ -223,8 +229,10 @@ int of_pci_get_host_bridge_resources(struct device_node *dev,
}
err = of_pci_range_to_resource(&range, dev, res);
- if (err)
- goto conversion_failed;
+ if (err) {
+ kfree(res);
+ continue;
+ }
if (resource_type(res) == IORESOURCE_IO) {
if (!io_base) {
diff --git a/kernel/drivers/of/of_pci_irq.c b/kernel/drivers/of/of_pci_irq.c
index 1710d9dc7..2306313c0 100644
--- a/kernel/drivers/of/of_pci_irq.c
+++ b/kernel/drivers/of/of_pci_irq.c
@@ -38,8 +38,8 @@ int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq
*/
rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin);
if (rc != 0)
- return rc;
- /* No pin, exit */
+ goto err;
+ /* No pin, exit with no error message. */
if (pin == 0)
return -ENODEV;
@@ -53,8 +53,10 @@ int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq
ppnode = pci_bus_to_OF_node(pdev->bus);
/* No node for host bridge ? give up */
- if (ppnode == NULL)
- return -EINVAL;
+ 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);
@@ -86,7 +88,13 @@ int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq
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);
- return of_irq_parse_raw(laddr, out_irq);
+ rc = of_irq_parse_raw(laddr, out_irq);
+ if (rc)
+ goto err;
+ return 0;
+err:
+ dev_err(&pdev->dev, "of_irq_parse_pci() failed with rc=%d\n", rc);
+ return rc;
}
EXPORT_SYMBOL_GPL(of_irq_parse_pci);
@@ -105,10 +113,8 @@ int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin)
int ret;
ret = of_irq_parse_pci(dev, &oirq);
- if (ret) {
- dev_err(&dev->dev, "of_irq_parse_pci() failed with rc=%d\n", ret);
+ if (ret)
return 0; /* Proper return code 0 == NO_IRQ */
- }
return irq_create_of_mapping(&oirq);
}
diff --git a/kernel/drivers/of/of_reserved_mem.c b/kernel/drivers/of/of_reserved_mem.c
index 726ebe792..1a3556a9e 100644
--- a/kernel/drivers/of/of_reserved_mem.c
+++ b/kernel/drivers/of/of_reserved_mem.c
@@ -1,7 +1,7 @@
/*
* Device tree based initialization code for reserved memory.
*
- * Copyright (c) 2013, The Linux Foundation. All Rights Reserved.
+ * Copyright (c) 2013, 2015 The Linux Foundation. All Rights Reserved.
* Copyright (c) 2013,2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com
* Author: Marek Szyprowski <m.szyprowski@samsung.com>
@@ -20,6 +20,7 @@
#include <linux/mm.h>
#include <linux/sizes.h>
#include <linux/of_reserved_mem.h>
+#include <linux/sort.h>
#define MAX_RESERVED_REGIONS 16
static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
@@ -123,6 +124,10 @@ static int __init __reserved_mem_alloc_size(unsigned long node,
align = dt_mem_next_cell(dt_root_addr_cells, &prop);
}
+ /* Need adjust the alignment to satisfy the CMA requirement */
+ if (IS_ENABLED(CONFIG_CMA) && of_flat_dt_is_compatible(node, "shared-dma-pool"))
+ align = max(align, (phys_addr_t)PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order));
+
prop = of_get_flat_dt_prop(node, "alloc-ranges", &len);
if (prop) {
@@ -197,12 +202,57 @@ static int __init __reserved_mem_init_node(struct reserved_mem *rmem)
return -ENOENT;
}
+static int __init __rmem_cmp(const void *a, const void *b)
+{
+ const struct reserved_mem *ra = a, *rb = b;
+
+ if (ra->base < rb->base)
+ return -1;
+
+ if (ra->base > rb->base)
+ return 1;
+
+ return 0;
+}
+
+static void __init __rmem_check_for_overlap(void)
+{
+ int i;
+
+ if (reserved_mem_count < 2)
+ return;
+
+ sort(reserved_mem, reserved_mem_count, sizeof(reserved_mem[0]),
+ __rmem_cmp, NULL);
+ for (i = 0; i < reserved_mem_count - 1; i++) {
+ struct reserved_mem *this, *next;
+
+ this = &reserved_mem[i];
+ next = &reserved_mem[i + 1];
+ if (!(this->base && next->base))
+ continue;
+ if (this->base + this->size > next->base) {
+ phys_addr_t this_end, next_end;
+
+ this_end = this->base + this->size;
+ next_end = next->base + next->size;
+ pr_err("Reserved memory: OVERLAP DETECTED!\n%s (%pa--%pa) overlaps with %s (%pa--%pa)\n",
+ this->name, &this->base, &this_end,
+ next->name, &next->base, &next_end);
+ }
+ }
+}
+
/**
* fdt_init_reserved_mem - allocate and init all saved reserved memory regions
*/
void __init fdt_init_reserved_mem(void)
{
int i;
+
+ /* check for overlapping reserved regions */
+ __rmem_check_for_overlap();
+
for (i = 0; i < reserved_mem_count; i++) {
struct reserved_mem *rmem = &reserved_mem[i];
unsigned long node = rmem->fdt_node;
diff --git a/kernel/drivers/of/overlay.c b/kernel/drivers/of/overlay.c
index dee9270ba..54e5af9d7 100644
--- a/kernel/drivers/of/overlay.c
+++ b/kernel/drivers/of/overlay.c
@@ -149,6 +149,7 @@ static int of_overlay_apply_one(struct of_overlay *ov,
pr_err("%s: Failed to apply single node @%s/%s\n",
__func__, target->full_name,
child->name);
+ of_node_put(child);
return ret;
}
}
@@ -333,7 +334,7 @@ static DEFINE_IDR(ov_idr);
* of the overlay in a list. This list can be used to prevent
* illegal overlay removals.
*
- * Returns the id of the created overlay, or an negative error number
+ * Returns the id of the created overlay, or a negative error number
*/
int of_overlay_create(struct device_node *tree)
{
@@ -417,8 +418,10 @@ static int overlay_subtree_check(struct device_node *tree,
return 1;
for_each_child_of_node(tree, child) {
- if (overlay_subtree_check(child, dn))
+ if (overlay_subtree_check(child, dn)) {
+ of_node_put(child);
return 1;
+ }
}
return 0;
@@ -481,7 +484,7 @@ static int overlay_removal_is_ok(struct of_overlay *ov)
*
* Removes an overlay if it is permissible.
*
- * Returns 0 on success, or an negative error number
+ * Returns 0 on success, or a negative error number
*/
int of_overlay_destroy(int id)
{
@@ -528,7 +531,7 @@ EXPORT_SYMBOL_GPL(of_overlay_destroy);
*
* Removes all overlays from the system in the correct order.
*
- * Returns 0 on success, or an negative error number
+ * Returns 0 on success, or a negative error number
*/
int of_overlay_destroy_all(void)
{
diff --git a/kernel/drivers/of/platform.c b/kernel/drivers/of/platform.c
index a01f57c9e..af9834361 100644
--- a/kernel/drivers/of/platform.c
+++ b/kernel/drivers/of/platform.c
@@ -25,6 +25,7 @@
const struct of_device_id of_default_bus_match_table[] = {
{ .compatible = "simple-bus", },
+ { .compatible = "simple-mfd", },
#ifdef CONFIG_ARM_AMBA
{ .compatible = "arm,amba-bus", },
#endif /* CONFIG_ARM_AMBA */
@@ -183,6 +184,7 @@ static struct platform_device *of_platform_device_create_pdata(
dev->dev.bus = &platform_bus_type;
dev->dev.platform_data = platform_data;
of_dma_configure(&dev->dev, dev->dev.of_node);
+ of_msi_configure(&dev->dev, dev->dev.of_node);
if (of_device_add(dev) != 0) {
of_dma_deconfigure(&dev->dev);
@@ -403,8 +405,10 @@ int of_platform_bus_probe(struct device_node *root,
if (!of_match_node(matches, child))
continue;
rc = of_platform_bus_create(child, matches, NULL, parent, false);
- if (rc)
+ if (rc) {
+ of_node_put(child);
break;
+ }
}
of_node_put(root);
@@ -445,8 +449,10 @@ int of_platform_populate(struct device_node *root,
for_each_child_of_node(root, child) {
rc = of_platform_bus_create(child, matches, lookup, parent, true);
- if (rc)
+ if (rc) {
+ of_node_put(child);
break;
+ }
}
of_node_set_flag(root, OF_POPULATED_BUS);
@@ -455,6 +461,15 @@ int of_platform_populate(struct device_node *root,
}
EXPORT_SYMBOL_GPL(of_platform_populate);
+int of_platform_default_populate(struct device_node *root,
+ const struct of_dev_auxdata *lookup,
+ struct device *parent)
+{
+ return of_platform_populate(root, of_default_bus_match_table, lookup,
+ parent);
+}
+EXPORT_SYMBOL_GPL(of_platform_default_populate);
+
static int of_platform_device_destroy(struct device *dev, void *data)
{
/* Do not touch devices not populated from the device tree */
diff --git a/kernel/drivers/of/unittest.c b/kernel/drivers/of/unittest.c
index 18016341d..e16ea5717 100644
--- a/kernel/drivers/of/unittest.c
+++ b/kernel/drivers/of/unittest.c
@@ -205,16 +205,20 @@ static int __init of_unittest_check_node_linkage(struct device_node *np)
if (child->parent != np) {
pr_err("Child node %s links to wrong parent %s\n",
child->name, np->name);
- return -EINVAL;
+ rc = -EINVAL;
+ goto put_child;
}
rc = of_unittest_check_node_linkage(child);
if (rc < 0)
- return rc;
+ goto put_child;
count += rc;
}
return count + 1;
+put_child:
+ of_node_put(child);
+ return rc;
}
static void __init of_unittest_check_tree_linkage(void)
@@ -979,7 +983,6 @@ static struct platform_driver unittest_driver = {
.remove = unittest_remove,
.driver = {
.name = "unittest",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(unittest_match),
},
};
@@ -1666,7 +1669,6 @@ static const struct i2c_device_id unittest_i2c_dev_id[] = {
static struct i2c_driver unittest_i2c_dev_driver = {
.driver = {
.name = "unittest-i2c-dev",
- .owner = THIS_MODULE,
},
.probe = unittest_i2c_dev_probe,
.remove = unittest_i2c_dev_remove,
@@ -1761,7 +1763,6 @@ static const struct i2c_device_id unittest_i2c_mux_id[] = {
static struct i2c_driver unittest_i2c_mux_driver = {
.driver = {
.name = "unittest-i2c-mux",
- .owner = THIS_MODULE,
},
.probe = unittest_i2c_mux_probe,
.remove = unittest_i2c_mux_remove,