Commit ae36e95c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'devicetree-for-linus' of git://git.secretlab.ca/git/linux

Pull device tree updates from Grant Likely:
 "The branch contains the following device tree changes the v3.17 merge
  window:

  Group changes to the device tree.  In preparation for adding device
  tree overlay support, OF_DYNAMIC is reworked so that a set of device
  tree changes can be prepared and applied to the tree all at once.
  OF_RECONFIG notifiers see the most significant change here so that
  users always get a consistent view of the tree.  Notifiers generation
  is moved from before a change to after it, and notifiers for a group
  of changes are emitted after the entire block of changes have been
  applied

  Automatic console selection from DT.  Console drivers can now use
  of_console_check() to see if the device node is specified as a console
  device.  If so then it gets added as a preferred console.  UART
  devices get this support automatically when uart_add_one_port() is
  called.

  DT unit tests no longer depend on pre-loaded data in the device tree.
  Data is loaded dynamically at the start of unit tests, and then
  unloaded again when the tests have completed.

  Also contains a few bugfixes for reserved regions and early memory
  setup"

* tag 'devicetree-for-linus' of git://git.secretlab.ca/git/linux: (21 commits)
  of: Fixing OF Selftest build error
  drivers: of: add automated assignment of reserved regions to client devices
  of: Use proper types for checking memory overflow
  of: typo fix in __of_prop_dup()
  Adding selftest testdata dynamically into live tree
  of: Add todo tasklist for Devicetree
  of: Transactional DT support.
  of: Reorder device tree changes and notifiers
  of: Move dynamic node fixups out of powerpc and into common code
  of: Make sure attached nodes don't carry along extra children
  of: Make devicetree sysfs update functions consistent.
  of: Create unlocked versions of node and property add/remove functions
  OF: Utility helper functions for dynamic nodes
  of: Move CONFIG_OF_DYNAMIC code into a separate file
  of: rename of_aliases_mutex to just of_mutex
  of/platform: Fix of_platform_device_destroy iteration of devices
  of: Migrate of_find_node_by_name() users to for_each_node_by_name()
  tty: Update hypervisor tty drivers to use core stdout parsing code.
  arm/versatile: Add the uart as the stdout device.
  of: Enable console on serial ports specified by /chosen/stdout-path
  ...
parents cc8a44c6 663d3f7c
A DT changeset is a method which allows one to apply changes
in the live tree in such a way that either the full set of changes
will be applied, or none of them will be. If an error occurs partway
through applying the changeset, then the tree will be rolled back to the
previous state. A changeset can also be removed after it has been
applied.
When a changeset is applied, all of the changes get applied to the tree
at once before emitting OF_RECONFIG notifiers. This is so that the
receiver sees a complete and consistent state of the tree when it
receives the notifier.
The sequence of a changeset is as follows.
1. of_changeset_init() - initializes a changeset
2. A number of DT tree change calls, of_changeset_attach_node(),
of_changeset_detach_node(), of_changeset_add_property(),
of_changeset_remove_property, of_changeset_update_property() to prepare
a set of changes. No changes to the active tree are made at this point.
All the change operations are recorded in the of_changeset 'entries'
list.
3. mutex_lock(of_mutex) - starts a changeset; The global of_mutex
ensures there can only be one editor at a time.
4. of_changeset_apply() - Apply the changes to the tree. Either the
entire changeset will get applied, or if there is an error the tree will
be restored to the previous state
5. mutex_unlock(of_mutex) - All operations complete, release the mutex
If a successfully applied changeset needs to be removed, it can be done
with the following sequence.
1. mutex_lock(of_mutex)
2. of_changeset_revert()
3. mutex_unlock(of_mutex)
Todo list for devicetree:
=== General structure ===
- Switch from custom lists to (h)list_head for nodes and properties structure
- Remove of_allnodes list and iterate using list of child nodes alone
=== CONFIG_OF_DYNAMIC ===
- Switch to RCU for tree updates and get rid of global spinlock
- Document node lifecycle for CONFIG_OF_DYNAMIC
- Always set ->full_name at of_attach_node() time
- pseries: Get rid of open-coded tree modification from arch/powerpc/platforms/pseries/dlpar.c
......@@ -15,6 +15,10 @@ aliases {
i2c0 = &i2c0;
};
chosen {
stdout-path = &uart0;
};
memory {
reg = <0x0 0x08000000>;
};
......
......@@ -56,5 +56,3 @@ mmc@b000 {
};
};
};
#include <testcases.dtsi>
......@@ -818,76 +818,6 @@ int cpu_to_chip_id(int cpu)
}
EXPORT_SYMBOL(cpu_to_chip_id);
#ifdef CONFIG_PPC_PSERIES
/*
* Fix up the uninitialized fields in a new device node:
* name, type and pci-specific fields
*/
static int of_finish_dynamic_node(struct device_node *node)
{
struct device_node *parent = of_get_parent(node);
int err = 0;
const phandle *ibm_phandle;
node->name = of_get_property(node, "name", NULL);
node->type = of_get_property(node, "device_type", NULL);
if (!node->name)
node->name = "<NULL>";
if (!node->type)
node->type = "<NULL>";
if (!parent) {
err = -ENODEV;
goto out;
}
/* We don't support that function on PowerMac, at least
* not yet
*/
if (machine_is(powermac))
return -ENODEV;
/* fix up new node's phandle field */
if ((ibm_phandle = of_get_property(node, "ibm,phandle", NULL)))
node->phandle = *ibm_phandle;
out:
of_node_put(parent);
return err;
}
static int prom_reconfig_notifier(struct notifier_block *nb,
unsigned long action, void *node)
{
int err;
switch (action) {
case OF_RECONFIG_ATTACH_NODE:
err = of_finish_dynamic_node(node);
if (err < 0)
printk(KERN_ERR "finish_node returned %d\n", err);
break;
default:
err = 0;
break;
}
return notifier_from_errno(err);
}
static struct notifier_block prom_reconfig_nb = {
.notifier_call = prom_reconfig_notifier,
.priority = 10, /* This one needs to run first */
};
static int __init prom_reconfig_setup(void)
{
return of_reconfig_notifier_register(&prom_reconfig_nb);
}
__initcall(prom_reconfig_setup);
#endif
bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
{
return (int)phys_id == get_hard_smp_processor_id(cpu);
......
......@@ -2805,25 +2805,20 @@ set_initial_features(void)
/* Enable GMAC for now for PCI probing. It will be disabled
* later on after PCI probe
*/
np = of_find_node_by_name(NULL, "ethernet");
while(np) {
for_each_node_by_name(np, "ethernet")
if (of_device_is_compatible(np, "K2-GMAC"))
g5_gmac_enable(np, 0, 1);
np = of_find_node_by_name(np, "ethernet");
}
/* Enable FW before PCI probe. Will be disabled later on
* Note: We should have a batter way to check that we are
* dealing with uninorth internal cell and not a PCI cell
* on the external PCI. The code below works though.
*/
np = of_find_node_by_name(NULL, "firewire");
while(np) {
for_each_node_by_name(np, "firewire") {
if (of_device_is_compatible(np, "pci106b,5811")) {
macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
g5_fw_enable(np, 0, 1);
}
np = of_find_node_by_name(np, "firewire");
}
}
#else /* CONFIG_PPC64 */
......@@ -2834,13 +2829,11 @@ set_initial_features(void)
/* Enable GMAC for now for PCI probing. It will be disabled
* later on after PCI probe
*/
np = of_find_node_by_name(NULL, "ethernet");
while(np) {
for_each_node_by_name(np, "ethernet") {
if (np->parent
&& of_device_is_compatible(np->parent, "uni-north")
&& of_device_is_compatible(np, "gmac"))
core99_gmac_enable(np, 0, 1);
np = of_find_node_by_name(np, "ethernet");
}
/* Enable FW before PCI probe. Will be disabled later on
......@@ -2848,8 +2841,7 @@ set_initial_features(void)
* dealing with uninorth internal cell and not a PCI cell
* on the external PCI. The code below works though.
*/
np = of_find_node_by_name(NULL, "firewire");
while(np) {
for_each_node_by_name(np, "firewire") {
if (np->parent
&& of_device_is_compatible(np->parent, "uni-north")
&& (of_device_is_compatible(np, "pci106b,18") ||
......@@ -2858,18 +2850,16 @@ set_initial_features(void)
macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
core99_firewire_enable(np, 0, 1);
}
np = of_find_node_by_name(np, "firewire");
}
/* Enable ATA-100 before PCI probe. */
np = of_find_node_by_name(NULL, "ata-6");
while(np) {
for_each_node_by_name(np, "ata-6") {
if (np->parent
&& of_device_is_compatible(np->parent, "uni-north")
&& of_device_is_compatible(np, "kauai-ata")) {
core99_ata100_enable(np, 1);
}
np = of_find_node_by_name(np, "ata-6");
}
/* Switch airport off */
......
......@@ -698,7 +698,7 @@ static void __init fixup_nec_usb2(void)
{
struct device_node *nec;
for (nec = NULL; (nec = of_find_node_by_name(nec, "usb")) != NULL;) {
for_each_node_by_name(nec, "usb") {
struct pci_controller *hose;
u32 data;
const u32 *prop;
......
......@@ -577,7 +577,7 @@ static void __init smp_core99_setup_i2c_hwsync(int ncpus)
int ok;
/* Look for the clock chip */
while ((cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL) {
for_each_node_by_name(cc, "i2c-hwclock") {
p = of_get_parent(cc);
ok = p && of_device_is_compatible(p, "uni-n-i2c");
of_node_put(p);
......
......@@ -191,7 +191,7 @@ int __init udbg_adb_init(int force_btext)
* of type "adb". If not, we return a failure, but we keep the
* bext output set for now
*/
for (np = NULL; (np = of_find_node_by_name(np, "keyboard")) != NULL;) {
for_each_node_by_name(np, "keyboard") {
struct device_node *parent = of_get_parent(np);
int found = (parent && strcmp(parent->type, "adb") == 0);
of_node_put(parent);
......
......@@ -194,7 +194,7 @@ static int pseries_update_drconf_memory(struct of_prop_reconfig *pr)
if (!memblock_size)
return -EINVAL;
p = (u32 *)of_get_property(pr->dn, "ibm,dynamic-memory", NULL);
p = (u32 *) pr->old_prop->value;
if (!p)
return -EINVAL;
......
......@@ -232,8 +232,7 @@ static void __init pseries_discover_pic(void)
struct device_node *np;
const char *typep;
for (np = NULL; (np = of_find_node_by_name(np,
"interrupt-controller"));) {
for_each_node_by_name(np, "interrupt-controller") {
typep = of_get_property(np, "compatible", NULL);
if (strstr(typep, "open-pic")) {
pSeries_mpic_node = of_node_get(np);
......
......@@ -499,8 +499,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpunode)
}
/* Lookup the i2c hwclock */
for (hwclock = NULL;
(hwclock = of_find_node_by_name(hwclock, "i2c-hwclock")) != NULL;){
for_each_node_by_name(hwclock, "i2c-hwclock") {
const char *loc = of_get_property(hwclock,
"hwctrl-location", NULL);
if (loc == NULL)
......
......@@ -936,28 +936,14 @@ static int nx842_OF_upd(struct property *new_prop)
goto error_out;
}
/* Set ptr to new property if provided */
if (new_prop) {
/* Single property */
if (!strncmp(new_prop->name, "status", new_prop->length)) {
status = new_prop;
} else if (!strncmp(new_prop->name, "ibm,max-sg-len",
new_prop->length)) {
maxsglen = new_prop;
} else if (!strncmp(new_prop->name, "ibm,max-sync-cop",
new_prop->length)) {
maxsyncop = new_prop;
} else {
/*
* Skip the update, the property being updated
* has no impact.
* If this is a property update, there are only certain properties that
* we care about. Bail if it isn't in the below list
*/
if (new_prop && (strncmp(new_prop->name, "status", new_prop->length) ||
strncmp(new_prop->name, "ibm,max-sg-len", new_prop->length) ||
strncmp(new_prop->name, "ibm,max-sync-cop", new_prop->length)))
goto out;
}
}
/* Perform property updates */
ret = nx842_OF_upd_status(new_devdata, status);
......
......@@ -134,8 +134,7 @@ static void cell_edac_init_csrows(struct mem_ctl_info *mci)
int j;
u32 nr_pages;
for (np = NULL;
(np = of_find_node_by_name(np, "memory")) != NULL;) {
for_each_node_by_name(np, "memory") {
struct resource r;
/* We "know" that the Cell firmware only creates one entry
......
......@@ -9,7 +9,8 @@ menu "Device Tree and Open Firmware support"
config OF_SELFTEST
bool "Device Tree Runtime self tests"
depends on OF_IRQ
depends on OF_IRQ && OF_EARLY_FLATTREE
select OF_DYNAMIC
help
This option builds in test cases for the device tree infrastructure
that are executed once at boot time, and the results dumped to the
......
obj-y = base.o device.o platform.o
obj-$(CONFIG_OF_DYNAMIC) += dynamic.o
obj-$(CONFIG_OF_FLATTREE) += fdt.o
obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
obj-$(CONFIG_OF_PROMTREE) += pdt.o
obj-$(CONFIG_OF_ADDRESS) += address.o
obj-$(CONFIG_OF_IRQ) += irq.o
obj-$(CONFIG_OF_NET) += of_net.o
obj-$(CONFIG_OF_SELFTEST) += selftest.o
obj-$(CONFIG_OF_SELFTEST) += of_selftest.o
of_selftest-objs := selftest.o testcase-data/testcases.dtb.o
obj-$(CONFIG_OF_MDIO) += of_mdio.o
obj-$(CONFIG_OF_PCI) += of_pci.o
obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
......
This diff is collapsed.
......@@ -160,7 +160,7 @@ void of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen);
seen = 0;
mutex_lock(&of_aliases_mutex);
mutex_lock(&of_mutex);
list_for_each_entry(app, &aliases_lookup, link) {
if (dev->of_node == app->np) {
add_uevent_var(env, "OF_ALIAS_%d=%s", seen,
......@@ -168,7 +168,7 @@ void of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
seen++;
}
}
mutex_unlock(&of_aliases_mutex);
mutex_unlock(&of_mutex);
}
int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
......
This diff is collapsed.
......@@ -923,24 +923,24 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
}
#ifdef CONFIG_HAVE_MEMBLOCK
#define MAX_PHYS_ADDR ((phys_addr_t)~0)
void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
{
const u64 phys_offset = __pa(PAGE_OFFSET);
base &= PAGE_MASK;
size &= PAGE_MASK;
if (sizeof(phys_addr_t) < sizeof(u64)) {
if (base > ULONG_MAX) {
if (base > MAX_PHYS_ADDR) {
pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
base, base + size);
return;
}
if (base + size > ULONG_MAX) {
if (base + size > MAX_PHYS_ADDR) {
pr_warning("Ignoring memory range 0x%lx - 0x%llx\n",
ULONG_MAX, base + size);
size = ULONG_MAX - base;
}
size = MAX_PHYS_ADDR - base;
}
if (base + size < phys_offset) {
......
......@@ -31,6 +31,63 @@ struct alias_prop {
char stem[0];
};
extern struct mutex of_aliases_mutex;
extern struct mutex of_mutex;
extern struct list_head aliases_lookup;
extern struct kset *of_kset;
static inline struct device_node *kobj_to_device_node(struct kobject *kobj)
{
return container_of(kobj, struct device_node, kobj);
}
#if defined(CONFIG_OF_DYNAMIC)
extern int of_property_notify(int action, struct device_node *np,
struct property *prop, struct property *old_prop);
extern void of_node_release(struct kobject *kobj);
#else /* CONFIG_OF_DYNAMIC */
static inline int of_property_notify(int action, struct device_node *np,
struct property *prop, struct property *old_prop)
{
return 0;
}
#endif /* CONFIG_OF_DYNAMIC */
/**
* General utilities for working with live trees.
*
* All functions with two leading underscores operate
* without taking node references, so you either have to
* own the devtree lock or work on detached trees only.
*/
struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags);
struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags);
extern const void *__of_get_property(const struct device_node *np,
const char *name, int *lenp);
extern int __of_add_property(struct device_node *np, struct property *prop);
extern int __of_add_property_sysfs(struct device_node *np,
struct property *prop);
extern int __of_remove_property(struct device_node *np, struct property *prop);
extern void __of_remove_property_sysfs(struct device_node *np,
struct property *prop);
extern int __of_update_property(struct device_node *np,
struct property *newprop, struct property **oldprop);
extern void __of_update_property_sysfs(struct device_node *np,
struct property *newprop, struct property *oldprop);
extern void __of_attach_node(struct device_node *np);
extern int __of_attach_node_sysfs(struct device_node *np);
extern void __of_detach_node(struct device_node *np);
extern void __of_detach_node_sysfs(struct device_node *np);
/* iterators for transactions, used for overlays */
/* forward iterator */
#define for_each_transaction_entry(_oft, _te) \
list_for_each_entry(_te, &(_oft)->te_list, node)
/* reverse iterator */
#define for_each_transaction_entry_reverse(_oft, _te) \
list_for_each_entry_reverse(_te, &(_oft)->te_list, node)
#endif /* _LINUX_OF_PRIVATE_H */
......@@ -206,8 +206,16 @@ void __init fdt_init_reserved_mem(void)
for (i = 0; i < reserved_mem_count; i++) {
struct reserved_mem *rmem = &reserved_mem[i];
unsigned long node = rmem->fdt_node;
int len;
const __be32 *prop;
int err = 0;
prop = of_get_flat_dt_prop(node, "phandle", &len);
if (!prop)
prop = of_get_flat_dt_prop(node, "linux,phandle", &len);
if (prop)
rmem->phandle = of_read_number(prop, len/4);
if (rmem->size == 0)
err = __reserved_mem_alloc_size(node, rmem->name,
&rmem->base, &rmem->size);
......@@ -215,3 +223,65 @@ void __init fdt_init_reserved_mem(void)
__reserved_mem_init_node(rmem);
}
}
static inline struct reserved_mem *__find_rmem(struct device_node *node)
{
unsigned int i;
if (!node->phandle)
return NULL;
for (i = 0; i < reserved_mem_count; i++)
if (reserved_mem[i].phandle == node->phandle)
return &reserved_mem[i];
return NULL;
}
/**
* of_reserved_mem_device_init() - assign reserved memory region to given device
*
* This function assign memory region pointed by "memory-region" device tree
* property to the given device.
*/
void of_reserved_mem_device_init(struct device *dev)
{
struct reserved_mem *rmem;
struct device_node *np;
np = of_parse_phandle(dev->of_node, "memory-region", 0);
if (!np)
return;
rmem = __find_rmem(np);
of_node_put(np);
if (!rmem || !rmem->ops || !rmem->ops->device_init)
return;
rmem->ops->device_init(rmem, dev);
dev_info(dev, "assigned reserved memory node %s\n", rmem->name);
}
/**
* of_reserved_mem_device_release() - release reserved memory device structures
*
* This function releases structures allocated for memory region handling for
* the given device.
*/
void of_reserved_mem_device_release(struct device *dev)
{
struct reserved_mem *rmem;
struct device_node *np;
np = of_parse_phandle(dev->of_node, "memory-region", 0);
if (!np)
return;
rmem = __find_rmem(np);
of_node_put(np);
if (!rmem || !rmem->ops || !rmem->ops->device_release)
return;
rmem->ops->device_release(rmem, dev);
}
......@@ -422,6 +422,7 @@ static int of_platform_bus_create(struct device_node *bus,
break;
}
}
of_node_set_flag(bus, OF_POPULATED_BUS);
return rc;
}
......@@ -508,19 +509,13 @@ EXPORT_SYMBOL_GPL(of_platform_populate);
static int of_platform_device_destroy(struct device *dev, void *data)
{
bool *children_left = data;
/* Do not touch devices not populated from the device tree */
if (!dev->of_node || !of_node_check_flag(dev->of_node, OF_POPULATED)) {
*children_left = true;
if (!dev->of_node || !of_node_check_flag(dev->of_node, OF_POPULATED))
return 0;
}
/* Recurse, but don't touch this device if it has any children left */
if (of_platform_depopulate(dev) != 0) {
*children_left = true;
return 0;
}
/* Recurse for any nodes that were treated as busses */
if (of_node_check_flag(dev->of_node, OF_POPULATED_BUS))
device_for_each_child(dev, NULL, of_platform_device_destroy);
if (dev->bus == &platform_bus_type)
platform_device_unregister(to_platform_device(dev));
......@@ -528,19 +523,15 @@ static int of_platform_device_destroy(struct device *dev, void *data)
else if (dev->bus == &amba_bustype)
amba_device_unregister(to_amba_device(dev));
#endif
else {
*children_left = true;
return 0;
}
of_node_clear_flag(dev->of_node, OF_POPULATED);
of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
return 0;
}
/**
* of_platform_depopulate() - Remove devices populated from device tree
* @parent: device which childred will be removed
* @parent: device which children will be removed
*
* Complementary to of_platform_populate(), this function removes children
* of the given device (and, recurrently, their children) that have been
......@@ -550,14 +541,9 @@ static int of_platform_device_destroy(struct device *dev, void *data)
* Returns 0 when all children devices have been removed or
* -EBUSY when some children remained.
*/
int of_platform_depopulate(struct device *parent)
void of_platform_depopulate(struct device *parent)
{
bool children_left = false;
device_for_each_child(parent, &children_left,
of_platform_device_destroy);
return children_left ? -EBUSY : 0;
device_for_each_child(parent, NULL, of_platform_device_destroy);
}
EXPORT_SYMBOL_GPL(of_platform_depopulate);
......
......@@ -9,6 +9,7 @@
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/list.h>
......@@ -16,11 +17,17 @@
#include <linux/slab.h>
#include <linux/device.h>
#include "of_private.h"
static struct selftest_results {
int passed;
int failed;
} selftest_results;
#define NO_OF_NODES 2
static struct device_node *nodes[NO_OF_NODES];
static int last_node_index;
#define selftest(result, fmt, ...) { \
if (!(result)) { \
selftest_results.failed++; \
......@@ -266,6 +273,81 @@ static void __init of_selftest_property_match_string(void)
selftest(rc == -EILSEQ, "unterminated string; rc=%i", rc);
}
#define propcmp(p1, p2) (((p1)->length == (p2)->length) && \
(p1)->value && (p2)->value && \
!memcmp((p1)->value, (p2)->value, (p1)->length) && \
!strcmp((p1)->name, (p2)->name))
static void __init of_selftest_property_copy(void)
{
#ifdef CONFIG_OF_DYNAMIC
struct property p1 = { .name = "p1", .length = 0, .value = "" };
struct property p2 = { .name = "p2", .length = 5, .value = "abcd" };
struct property *new;
new = __of_prop_dup(&p1, GFP_KERNEL);
selftest(new && propcmp(&p1, new), "empty property didn't copy correctly\n");
kfree(new->value);
kfree(new->name);
kfree(new);
new = __of_prop_dup(&p2, GFP_KERNEL);
selftest(new && propcmp(&p2, new), "non-empty property didn't copy correctly\n");
kfree(new->value);
kfree(new->name);
kfree(new);
#endif
}
static void __init of_selftest_changeset(void)
{
#ifdef CONFIG_OF_DYNAMIC
struct property *ppadd, padd = { .name = "prop-add", .length = 0, .value = "" };
struct property *ppupdate, pupdate = { .name = "prop-update", .length = 5, .value = "abcd" };
struct property *ppremove;
struct device_node *n1, *n2, *n21, *nremove, *parent;
struct of_changeset chgset;
of_changeset_init(&chgset);
n1 = __of_node_alloc("/testcase-data/changeset/n1", GFP_KERNEL);
selftest(n1, "testcase setup failure\n");
n2 = __of_node_alloc("/testcase-data/changeset/n2", GFP_KERNEL);
selftest(n2, "testcase setup failure\n");
n21 = __of_node_alloc("/testcase-data/changeset/n2/n21", GFP_KERNEL);
selftest(n21, "testcase setup failure %p\n", n21);
nremove = of_find_node_by_path("/testcase-data/changeset/node-remove");
selftest(nremove, "testcase setup failure\n");
ppadd = __of_prop_dup(&padd, GFP_KERNEL);
selftest(ppadd, "testcase setup failure\n");
ppupdate = __of_prop_dup(&pupdate, GFP_KERNEL);
selftest(ppupdate, "testcase setup failure\n");
parent = nremove->parent;
n1->parent = parent;
n2->parent = parent;
n21->parent = n2;
n2->child = n21;
ppremove = of_find_property(parent, "prop-remove", NULL);
selftest(ppremove, "failed to find removal prop");
of_changeset_init(&chgset);
selftest(!of_changeset_attach_node(&chgset, n1), "fail attach n1\n");
selftest(!of_changeset_attach_node(&chgset, n2), "fail attach n2\n");
selftest(!of_changeset_detach_node(&chgset, nremove), "fail remove node\n");
selftest(!of_changeset_attach_node(&chgset, n21), "fail attach n21\n");
selftest(!of_changeset_add_property(&chgset, parent, ppadd), "fail add prop\n");
selftest(!of_changeset_update_property(&chgset, parent, ppupdate), "fail update prop\n");
selftest(!of_changeset_remove_property(&chgset, parent, ppremove), "fail remove prop\n");
mutex_lock(&of_mutex);
selftest(!of_changeset_apply(&chgset), "apply failed\n");
mutex_unlock(&of_mutex);
mutex_lock(&of_mutex);
selftest(!of_changeset_revert(&chgset), "revert failed\n");
mutex_unlock(&of_mutex);
of_changeset_destroy(&chgset);
#endif
}
static void __init of_selftest_parse_interrupts(void)
{
struct device_node *np;
......@@ -517,9 +599,156 @@ static void __init of_selftest_platform_populate(void)
}
}
/**
* update_node_properties - adds the properties
* of np into dup node (present in live tree) and
* updates parent of children of np to dup.
*
* @np: node already present in live tree
* @dup: node present in live tree to be updated
*/
static void update_node_properties(struct device_node *np,
struct device_node *dup)
{
struct property *prop;
struct device_node *child;
for_each_property_of_node(np, prop)
of_add_property(dup, prop);
for_each_child_of_node(np, child)
child->parent = dup;
}
/**
* attach_node_and_children - attaches nodes
* and its children to live tree
*
* @np: Node to attach to live tree
*/
static int attach_node_and_children(struct device_node *np)
{
struct device_node *next, *root = np, *dup;
if (!np) {
pr_warn("%s: No tree to attach; not running tests\n",
__func__);
return -ENODATA;
}
/* skip root node */
np = np->child;
/* storing a copy in temporary node */
dup = np;
while (dup) {
nodes[last_node_index++] = dup;
dup = dup->sibling;
}
dup = NULL;
while (np) {
next = np->allnext;
dup = of_find_node_by_path(np->full_name);
if (dup)
update_node_properties(np, dup);
else {
np->child = NULL;
if (np->parent == root)
np->parent = of_allnodes;
of_attach_node(np);
}
np = next;
}
return 0;
}
/**
* selftest_data_add - Reads, copies data from
* linked tree and attaches it to the live tree
*/
static int __init selftest_data_add(void)
{
void *selftest_data;
struct device_node *selftest_data_node;
extern uint8_t __dtb_testcases_begin[];
extern uint8_t __dtb_testcases_end[];
const int size = __dtb_testcases_end - __dtb_testcases_begin;
if (!size || !of_allnodes) {
pr_warn("%s: No testcase data to attach; not running tests\n",
__func__);
return -ENODATA;
}
/* creating copy */
selftest_data = kmemdup(__dtb_testcases_begin, size, GFP_KERNEL);
if (!selftest_data) {
pr_warn("%s: Failed to allocate memory for selftest_data; "
"not running tests\n", __func__);
return -ENOMEM;
}
of_fdt_unflatten_tree(selftest_data, &selftest_data_node);
/* attach the sub-tree to live tree */
return attach_node_and_children(selftest_data_node);
}
/**
* detach_node_and_children - detaches node
* and its children from live tree
*
* @np: Node to detach from live tree
*/
static void detach_node_and_children(struct device_node *np)
{
while (np->child)
detach_node_and_children(np->child);
while (np->sibling)
detach_node_and_children(np->sibling);
of_detach_node(np);
}
/**
* selftest_data_remove - removes the selftest data
* nodes from the live tree
*/
static void selftest_data_remove(void)
{
struct device_node *np;
struct property *prop;
while (last_node_index >= 0) {
if (nodes[last_node_index]) {
np = of_find_node_by_path(nodes[last_node_index]->full_name);
if (strcmp(np->full_name, "/aliases") != 0) {
detach_node_and_children(np->child);
of_detach_node(np);
} else {
for_each_property_of_node(np, prop) {
if (strcmp(prop->name, "testcase-alias") == 0)
of_remove_property(np, prop);
}
}
}
last_node_index--;
}
}
static int __init of_selftest(void)
{
struct device_node *np;
int res;
/* adding data for selftest */
res = selftest_data_add();
if (res)
return res;
np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
if (!np) {
......@@ -533,12 +762,18 @@ static int __init of_selftest(void)
of_selftest_dynamic();
of_selftest_parse_phandle_with_args();
of_selftest_property_match_string();
of_selftest_property_copy();
of_selftest_changeset();
of_selftest_parse_interrupts();
of_selftest_parse_interrupts_extended();
of_selftest_match_node();
of_selftest_platform_populate();
pr_info("end of selftest - %i passed, %i failed\n",
selftest_results.passed, selftest_results.failed);
/* removing selftest data from live tree */
selftest_data_remove();
return 0;
}
late_initcall(of_selftest);
/dts-v1/;
/ {
testcase-data {
changeset {
prop-update = "hello";
prop-remove = "world";
node-remove {
};
};
};
};
#include "tests-phandle.dtsi"
#include "tests-interrupts.dtsi"
#include "tests-match.dtsi"
......
......@@ -375,11 +375,11 @@ static void __exit cleanup_slots(void)
static int __init rpaphp_init(void)
{
struct device_node *dn = NULL;
struct device_node *dn;
info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
while ((dn = of_find_node_by_name(dn, "pci")))
for_each_node_by_name(dn, "pci")
rpaphp_add_slot(dn);
return 0;
......
......@@ -108,55 +108,23 @@ static void disable_tx_interrupt(struct ehv_bc_data *bc)
*
* The byte channel to be used for the console is specified via a "stdout"
* property in the /chosen node.
*
* For compatible with legacy device trees, we also look for a "stdout" alias.
*/
static int find_console_handle(void)
{
struct device_node *np, *np2;
struct device_node *np = of_stdout;
const char *sprop = NULL;
const uint32_t *iprop;
np = of_find_node_by_path("/chosen");
if (np)
sprop = of_get_property(np, "stdout-path", NULL);
if (!np || !sprop) {
of_node_put(np);
np = of_find_node_by_name(NULL, "aliases");
if (np)
sprop = of_get_property(np, "stdout", NULL);
}
if (!sprop) {
of_node_put(np);
return 0;
}
/* We don't care what the aliased node is actually called. We only
* care if it's compatible with "epapr,hv-byte-channel", because that
* indicates that it's a byte channel node. We use a temporary
* variable, 'np2', because we can't release 'np' until we're done with
* 'sprop'.
*/
np2 = of_find_node_by_path(sprop);
of_node_put(np);
np = np2;
if (!np) {
pr_warning("ehv-bc: stdout node '%s' does not exist\n", sprop);
return 0;
}
/* Is it a byte channel? */
if (!of_device_is_compatible(np, "epapr,hv-byte-channel")) {
of_node_put(np);
* indicates that it's a byte channel node.
*/
if (!np || !of_device_is_compatible(np, "epapr,hv-byte-channel"))
return 0;
}
stdout_irq = irq_of_parse_and_map(np, 0);
if (stdout_irq == NO_IRQ) {
pr_err("ehv-bc: no 'interrupts' property in %s node\n", sprop);
of_node_put(np);
pr_err("ehv-bc: no 'interrupts' property in %s node\n", np->full_name);
return 0;
}
......@@ -167,12 +135,9 @@ static int find_console_handle(void)
if (!iprop) {
pr_err("ehv-bc: no 'hv-handle' property in %s node\n",
np->name);
of_node_put(np);
return 0;
}
stdout_bc = be32_to_cpu(*iprop);
of_node_put(np);
return 1;
}
......
......@@ -342,22 +342,13 @@ static void udbg_init_opal_common(void)
void __init hvc_opal_init_early(void)
{
struct device_node *stdout_node = NULL;
struct device_node *stdout_node = of_node_get(of_stdout);
const __be32 *termno;
const char *name = NULL;
const struct hv_ops *ops;
u32 index;
/* find the boot console from /chosen/stdout */
if (of_chosen)
name = of_get_property(of_chosen, "linux,stdout-path", NULL);
if (name) {
stdout_node = of_find_node_by_path(name);
/* If the console wasn't in /chosen, try /ibm,opal */
if (!stdout_node) {
pr_err("hvc_opal: Failed to locate default console!\n");
return;
}
} else {
struct device_node *opal, *np;
/* Current OPAL takeover doesn't provide the stdout
......
......@@ -404,42 +404,35 @@ module_exit(hvc_vio_exit);
void __init hvc_vio_init_early(void)
{
struct device_node *stdout_node;
const __be32 *termno;
const char *name;
const struct hv_ops *ops;
/* find the boot console from /chosen/stdout */
if (!of_chosen)
if (!of_stdout)
return;
name = of_get_property(of_chosen, "linux,stdout-path", NULL);
if (name == NULL)
return;
stdout_node = of_find_node_by_path(name);
if (!stdout_node)
return;
name = of_get_property(stdout_node, "name", NULL);
name = of_get_property(of_stdout, "name", NULL);
if (!name) {
printk(KERN_WARNING "stdout node missing 'name' property!\n");
goto out;
return;
}
/* Check if it's a virtual terminal */
if (strncmp(name, "vty", 3) != 0)
goto out;
termno = of_get_property(stdout_node, "reg", NULL);
return;
termno = of_get_property(of_stdout, "reg", NULL);
if (termno == NULL)
goto out;
return;
hvterm_priv0.termno = of_read_number(termno, 1);
spin_lock_init(&hvterm_priv0.buf_lock);
hvterm_privs[0] = &hvterm_priv0;
/* Check the protocol */
if (of_device_is_compatible(stdout_node, "hvterm1")) {
if (of_device_is_compatible(of_stdout, "hvterm1")) {
hvterm_priv0.proto = HV_PROTOCOL_RAW;
ops = &hvterm_raw_ops;
}
else if (of_device_is_compatible(stdout_node, "hvterm-protocol")) {
else if (of_device_is_compatible(of_stdout, "hvterm-protocol")) {
hvterm_priv0.proto = HV_PROTOCOL_HVSI;
ops = &hvterm_hvsi_ops;
hvsilib_init(&hvterm_priv0.hvsi, hvc_get_chars, hvc_put_chars,
......@@ -447,7 +440,7 @@ void __init hvc_vio_init_early(void)
/* HVSI, perform the handshake now */
hvsilib_establish(&hvterm_priv0.hvsi);
} else
goto out;
return;
udbg_putc = udbg_hvc_putc;
udbg_getc = udbg_hvc_getc;
udbg_getc_poll = udbg_hvc_getc_poll;
......@@ -456,14 +449,12 @@ void __init hvc_vio_init_early(void)
* backend for HVSI, only do udbg
*/
if (hvterm_priv0.proto == HV_PROTOCOL_HVSI)
goto out;
return;
#endif
/* Check whether the user has requested a different console. */
if (!strstr(cmd_line, "console="))
add_preferred_console("hvc", 0, NULL);
hvc_instantiate(0, 0, ops);
out:
of_node_put(stdout_node);
}
/* call this from early_init() for a working debug console on
......
......@@ -1653,8 +1653,7 @@ static int __init pmz_probe(void)
/*
* Find all escc chips in the system
*/
node_p = of_find_node_by_name(NULL, "escc");
while (node_p) {
for_each_node_by_name(node_p, "escc") {
/*
* First get channel A/B node pointers
*
......@@ -1672,7 +1671,7 @@ static int __init pmz_probe(void)
of_node_put(node_b);
printk(KERN_ERR "pmac_zilog: missing node %c for escc %s\n",
(!node_a) ? 'a' : 'b', node_p->full_name);
goto next;
continue;
}
/*
......@@ -1699,11 +1698,9 @@ static int __init pmz_probe(void)
of_node_put(node_b);
memset(&pmz_ports[count], 0, sizeof(struct uart_pmac_port));
memset(&pmz_ports[count+1], 0, sizeof(struct uart_pmac_port));
goto next;
continue;
}
count += 2;
next:
node_p = of_find_node_by_name(node_p, "escc");
}
pmz_ports_count = count;
......
......@@ -26,6 +26,7 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/of.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/device.h>
......@@ -2611,6 +2612,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
spin_lock_init(&uport->lock);
lockdep_set_class(&uport->lock, &port_lock_key);
}
if (uport->cons && uport->dev)
of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
uart_configure_port(drv, state, uport);
......
......@@ -74,8 +74,6 @@ struct of_phandle_args {
uint32_t args[MAX_PHANDLE_ARGS];
};
extern int of_node_add(struct device_node *node);
/* initialize a node */
extern struct kobj_type of_node_ktype;
static inline void of_node_init(struct device_node *node)
......@@ -113,6 +111,7 @@ static inline void of_node_put(struct device_node *node) { }
extern struct device_node *of_allnodes;
extern struct device_node *of_chosen;
extern struct device_node *of_aliases;
extern struct device_node *of_stdout;
extern raw_spinlock_t devtree_lock;
static inline bool of_have_populated_dt(void)
......@@ -204,6 +203,7 @@ static inline unsigned long of_read_ulong(const __be32 *cell, int size)
#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */
#define OF_DETACHED 2 /* node has been detached from the device tree */
#define OF_POPULATED 3 /* device already created for the node */
#define OF_POPULATED_BUS 4 /* of_platform_populate recursed to children of this node */
#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
......@@ -322,6 +322,7 @@ extern int of_update_property(struct device_node *np, struct property *newprop);
struct of_prop_reconfig {
struct device_node *dn;
struct property *prop;
struct property *old_prop;
};
extern int of_reconfig_notifier_register(struct notifier_block *);
......@@ -352,7 +353,7 @@ const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
*/
const char *of_prop_next_string(struct property *prop, const char *cur);
int of_device_is_stdout_path(struct device_node *dn);
bool of_console_check(struct device_node *dn, char *name, int index);
#else /* CONFIG_OF */
......@@ -564,9 +565,9 @@ static inline int of_machine_is_compatible(const char *compat)
return 0;
}
static inline int of_device_is_stdout_path(struct device_node *dn)
static inline bool of_console_check(const struct device_node *dn, const char *name, int index)
{
return 0;
return false;
}
static inline const __be32 *of_prop_next_u32(struct property *prop,
......@@ -786,4 +787,80 @@ typedef void (*of_init_fn_1)(struct device_node *);
#define OF_DECLARE_2(table, name, compat, fn) \
_OF_DECLARE(table, name, compat, fn, of_init_fn_2)
/**
* struct of_changeset_entry - Holds a changeset entry
*
* @node: list_head for the log list
* @action: notifier action
* @np: pointer to the device node affected
* @prop: pointer to the property affected
* @old_prop: hold a pointer to the original property
*
* Every modification of the device tree during a changeset
* is held in a list of of_changeset_entry structures.
* That way we can recover from a partial application, or we can
* revert the changeset
*/
struct of_changeset_entry {
struct list_head node;
unsigned long action;
struct device_node *np;
struct property *prop;
struct property *old_prop;
};
/**
* struct of_changeset - changeset tracker structure
*
* @entries: list_head for the changeset entries
*
* changesets are a convenient way to apply bulk changes to the
* live tree. In case of an error, changes are rolled-back.
* changesets live on after initial application, and if not
* destroyed after use, they can be reverted in one single call.
*/
struct of_changeset {
struct list_head entries;
};
#ifdef CONFIG_OF_DYNAMIC
extern void of_changeset_init(struct of_changeset *ocs);
extern void of_changeset_destroy(struct of_changeset *ocs);
extern int of_changeset_apply(struct of_changeset *ocs);
extern int of_changeset_revert(struct of_changeset *ocs);
extern int of_changeset_action(struct of_changeset *ocs,
unsigned long action, struct device_node *np,
struct property *prop);
static inline int of_changeset_attach_node(struct of_changeset *ocs,
struct device_node *np)
{
return of_changeset_action(ocs, OF_RECONFIG_ATTACH_NODE, np, NULL);
}
static inline int of_changeset_detach_node(struct of_changeset *ocs,
struct device_node *np)
{
return of_changeset_action(ocs, OF_RECONFIG_DETACH_NODE, np, NULL);
}
static inline int of_changeset_add_property(struct of_changeset *ocs,
struct device_node *np, struct property *prop)
{
return of_changeset_action(ocs, OF_RECONFIG_ADD_PROPERTY, np, prop);
}
static inline int of_changeset_remove_property(struct of_changeset *ocs,
struct device_node *np, struct property *prop)
{
return of_changeset_action(ocs, OF_RECONFIG_REMOVE_PROPERTY, np, prop);
}
static inline int of_changeset_update_property(struct of_changeset *ocs,
struct device_node *np, struct property *prop)
{
return of_changeset_action(ocs, OF_RECONFIG_UPDATE_PROPERTY, np, prop);
}
#endif
#endif /* _LINUX_OF_H */
......@@ -72,7 +72,7 @@ extern int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent);
extern int of_platform_depopulate(struct device *parent);
extern void of_platform_depopulate(struct device *parent);
#else
static inline int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
......@@ -81,10 +81,7 @@ static inline int of_platform_populate(struct device_node *root,
{
return -ENODEV;
}
static inline int of_platform_depopulate(struct device *parent)
{
return -ENODEV;
}
static inline void of_platform_depopulate(struct device *parent) { }
#endif
#endif /* _LINUX_OF_PLATFORM_H */
......@@ -8,6 +8,7 @@ struct reserved_mem_ops;
struct reserved_mem {
const char *name;
unsigned long fdt_node;
unsigned long phandle;
const struct reserved_mem_ops *ops;
phys_addr_t base;
phys_addr_t size;
......@@ -27,10 +28,16 @@ typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem);
_OF_DECLARE(reservedmem, name, compat, init, reservedmem_of_init_fn)
#ifdef CONFIG_OF_RESERVED_MEM
void of_reserved_mem_device_init(struct device *dev);
void of_reserved_mem_device_release(struct device *dev);
void fdt_init_reserved_mem(void);
void fdt_reserved_mem_save_node(unsigned long node, const char *uname,
phys_addr_t base, phys_addr_t size);
#else
static inline void of_reserved_mem_device_init(struct device *dev) { }
static inline void of_reserved_mem_device_release(struct device *pdev) { }
static inline void fdt_init_reserved_mem(void) { }
static inline void fdt_reserved_mem_save_node(unsigned long node,
const char *uname, phys_addr_t base, phys_addr_t size) { }
......
......@@ -992,9 +992,9 @@ static int snd_pmac_detect(struct snd_pmac *chip)
return -ENODEV;
if (!sound) {
sound = of_find_node_by_name(NULL, "sound");
while (sound && sound->parent != chip->node)
sound = of_find_node_by_name(sound, "sound");
for_each_node_by_name(sound, "sound")
if (sound->parent == chip->node)
break;
}
if (! sound) {
of_node_put(chip->node);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment