Skip to content

Commit

Permalink
Merge tag 'dt-for-robh' of git://git.secretlab.ca/git/linux into for-…
Browse files Browse the repository at this point in the history
…next

Pull DT changes from Grant Likely:

DT queued up for v3.16

Mostly bug fixes, but also some rework to improve path handling and device naming
  • Loading branch information
Rob Herring committed May 28, 2014
2 parents eafd370 + 08cf78e commit aa10537
Show file tree
Hide file tree
Showing 13 changed files with 222 additions and 84 deletions.
4 changes: 0 additions & 4 deletions arch/powerpc/include/asm/dcr-mmio.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,6 @@ static inline void dcr_write_mmio(dcr_host_mmio_t host,
out_be32(host.token + ((host.base + dcr_n) * host.stride), value);
}

extern u64 of_translate_dcr_address(struct device_node *dev,
unsigned int dcr_n,
unsigned int *stride);

#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_DCR_MMIO_H */

Expand Down
6 changes: 3 additions & 3 deletions arch/powerpc/sysdev/dcr.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,9 @@ EXPORT_SYMBOL_GPL(dcr_resource_len);

#ifdef CONFIG_PPC_DCR_MMIO

u64 of_translate_dcr_address(struct device_node *dev,
unsigned int dcr_n,
unsigned int *out_stride)
static u64 of_translate_dcr_address(struct device_node *dev,
unsigned int dcr_n,
unsigned int *out_stride)
{
struct device_node *dp;
const u32 *p;
Expand Down
7 changes: 5 additions & 2 deletions drivers/base/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,12 @@ EXPORT_SYMBOL_GPL(platform_get_resource_byname);
*/
int platform_get_irq_byname(struct platform_device *dev, const char *name)
{
struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ,
name);
struct resource *r;

if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node)
return of_irq_get_byname(dev->dev.of_node, name);

r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
return r ? r->start : -ENXIO;
}
EXPORT_SYMBOL_GPL(platform_get_irq_byname);
Expand Down
115 changes: 93 additions & 22 deletions drivers/of/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,22 @@ struct device_node *of_get_next_parent(struct device_node *node)
}
EXPORT_SYMBOL(of_get_next_parent);

static struct device_node *__of_get_next_child(const struct device_node *node,
struct device_node *prev)
{
struct device_node *next;

next = prev ? prev->sibling : node->child;
for (; next; next = next->sibling)
if (of_node_get(next))
break;
of_node_put(prev);
return next;
}
#define __for_each_child_of_node(parent, child) \
for (child = __of_get_next_child(parent, NULL); child != NULL; \
child = __of_get_next_child(parent, child))

/**
* of_get_next_child - Iterate a node childs
* @node: parent node
Expand All @@ -710,11 +726,7 @@ struct device_node *of_get_next_child(const struct device_node *node,
unsigned long flags;

raw_spin_lock_irqsave(&devtree_lock, flags);
next = prev ? prev->sibling : node->child;
for (; next; next = next->sibling)
if (of_node_get(next))
break;
of_node_put(prev);
next = __of_get_next_child(node, prev);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return next;
}
Expand Down Expand Up @@ -771,23 +783,78 @@ struct device_node *of_get_child_by_name(const struct device_node *node,
}
EXPORT_SYMBOL(of_get_child_by_name);

static struct device_node *__of_find_node_by_path(struct device_node *parent,
const char *path)
{
struct device_node *child;
int len = strchrnul(path, '/') - path;

if (!len)
return NULL;

__for_each_child_of_node(parent, child) {
const char *name = strrchr(child->full_name, '/');
if (WARN(!name, "malformed device_node %s\n", child->full_name))
continue;
name++;
if (strncmp(path, name, len) == 0 && (strlen(name) == len))
return child;
}
return NULL;
}

/**
* of_find_node_by_path - Find a node matching a full OF path
* @path: The full path to match
* @path: Either the full path to match, or if the path does not
* start with '/', the name of a property of the /aliases
* node (an alias). In the case of an alias, the node
* matching the alias' value will be returned.
*
* Valid paths:
* /foo/bar Full path
* foo Valid alias
* foo/bar Valid alias + relative path
*
* Returns a node pointer with refcount incremented, use
* of_node_put() on it when done.
*/
struct device_node *of_find_node_by_path(const char *path)
{
struct device_node *np = of_allnodes;
struct device_node *np = NULL;
struct property *pp;
unsigned long flags;

if (strcmp(path, "/") == 0)
return of_node_get(of_allnodes);

/* The path could begin with an alias */
if (*path != '/') {
char *p = strchrnul(path, '/');
int len = p - path;

/* of_aliases must not be NULL */
if (!of_aliases)
return NULL;

for_each_property_of_node(of_aliases, pp) {
if (strlen(pp->name) == len && !strncmp(pp->name, path, len)) {
np = of_find_node_by_path(pp->value);
break;
}
}
if (!np)
return NULL;
path = p;
}

/* Step down the tree matching path components */
raw_spin_lock_irqsave(&devtree_lock, flags);
for (; np; np = np->allnext) {
if (np->full_name && (of_node_cmp(np->full_name, path) == 0)
&& of_node_get(np))
break;
if (!np)
np = of_node_get(of_allnodes);
while (np && *path == '/') {
path++; /* Increment past '/' delimiter */
np = __of_find_node_by_path(np, path);
path = strchrnul(path, '/');
}
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
Expand Down Expand Up @@ -1800,7 +1867,7 @@ int of_update_property(struct device_node *np, struct property *newprop)
{
struct property **next, *oldprop;
unsigned long flags;
int rc, found = 0;
int rc;

rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop);
if (rc)
Expand All @@ -1809,30 +1876,34 @@ int of_update_property(struct device_node *np, struct property *newprop)
if (!newprop->name)
return -EINVAL;

oldprop = of_find_property(np, newprop->name, NULL);
if (!oldprop)
return of_add_property(np, newprop);

raw_spin_lock_irqsave(&devtree_lock, flags);
next = &np->properties;
while (*next) {
oldprop = __of_find_property(np, newprop->name, NULL);
if (!oldprop) {
/* add the new node */
rc = __of_add_property(np, newprop);
} else while (*next) {
/* replace the node */
if (*next == oldprop) {
/* found the node */
newprop->next = oldprop->next;
*next = newprop;
oldprop->next = np->deadprops;
np->deadprops = oldprop;
found = 1;
break;
}
next = &(*next)->next;
}
raw_spin_unlock_irqrestore(&devtree_lock, flags);
if (!found)
return -ENODEV;
if (rc)
return rc;

/* At early boot, bail out and defer setup to of_init() */
if (!of_kset)
return 0;

/* Update the sysfs attribute */
sysfs_remove_bin_file(&np->kobj, &oldprop->attr);
if (oldprop)
sysfs_remove_bin_file(&np->kobj, &oldprop->attr);
__of_add_property_sysfs(np, newprop);

return 0;
Expand Down
4 changes: 2 additions & 2 deletions drivers/of/fdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ static void __unflatten_device_tree(void *blob,

/* First pass, scan for size */
start = 0;
size = (unsigned long)unflatten_dt_node(blob, 0, &start, NULL, NULL, 0);
size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, 0);
size = ALIGN(size, 4);

pr_debug(" size is %lx, allocating...\n", size);
Expand Down Expand Up @@ -748,7 +748,7 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
* The longtrail doesn't have a device_type on the
* /memory node, so look for the node called /memory@0.
*/
if (depth != 1 || strcmp(uname, "memory@0") != 0)
if (!IS_ENABLED(CONFIG_PPC32) || depth != 1 || strcmp(uname, "memory@0") != 0)
return 0;
} else if (strcmp(type, "memory") != 0)
return 0;
Expand Down
22 changes: 22 additions & 0 deletions drivers/of/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,28 @@ int of_irq_get(struct device_node *dev, int index)
return irq_create_of_mapping(&oirq);
}

/**
* of_irq_get_byname - Decode a node's IRQ and return it as a Linux irq number
* @dev: pointer to device tree node
* @name: irq name
*
* Returns Linux irq number on success, or -EPROBE_DEFER if the irq domain
* is not yet created, or error code in case of any other failure.
*/
int of_irq_get_byname(struct device_node *dev, const char *name)
{
int index;

if (unlikely(!name))
return -EINVAL;

index = of_property_match_string(dev, "interrupt-names", name);
if (index < 0)
return index;

return of_irq_get(dev, index);
}

/**
* of_irq_count - Count the number of IRQs a node uses
* @dev: pointer to device tree node
Expand Down
8 changes: 2 additions & 6 deletions drivers/of/of_pci_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq
{
struct device_node *dn, *ppnode;
struct pci_dev *ppdev;
u32 lspec;
__be32 lspec_be;
__be32 laddr[3];
u8 pin;
int rc;
Expand All @@ -46,7 +44,6 @@ int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq
return -ENODEV;

/* Now we walk up the PCI tree */
lspec = pin;
for (;;) {
/* Get the pci_dev of our parent */
ppdev = pdev->bus->self;
Expand Down Expand Up @@ -80,14 +77,13 @@ int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq
/* We can only get here if we hit a P2P bridge with no node,
* let's do standard swizzling and try again
*/
lspec = pci_swizzle_interrupt_pin(pdev, lspec);
pin = pci_swizzle_interrupt_pin(pdev, pin);
pdev = ppdev;
}

out_irq->np = ppnode;
out_irq->args_count = 1;
out_irq->args[0] = lspec;
lspec_be = cpu_to_be32(lspec);
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);
Expand Down
62 changes: 18 additions & 44 deletions drivers/of/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,6 @@ struct platform_device *of_find_device_by_node(struct device_node *np)
}
EXPORT_SYMBOL(of_find_device_by_node);

#if defined(CONFIG_PPC_DCR)
#include <asm/dcr.h>
#endif

#ifdef CONFIG_OF_ADDRESS
/*
* The following routines scan a subtree and registers a device for
Expand All @@ -68,57 +64,35 @@ EXPORT_SYMBOL(of_find_device_by_node);
* of_device_make_bus_id - Use the device node data to assign a unique name
* @dev: pointer to device structure that is linked to a device tree node
*
* This routine will first try using either the dcr-reg or the reg property
* value to derive a unique name. As a last resort it will use the node
* name followed by a unique number.
* This routine will first try using the translated bus address to
* derive a unique name. If it cannot, then it will prepend names from
* parent nodes until a unique name can be derived.
*/
void of_device_make_bus_id(struct device *dev)
{
static atomic_t bus_no_reg_magic;
struct device_node *node = dev->of_node;
const __be32 *reg;
u64 addr;
int magic;

#ifdef CONFIG_PPC_DCR
/*
* If it's a DCR based device, use 'd' for native DCRs
* and 'D' for MMIO DCRs.
*/
reg = of_get_property(node, "dcr-reg", NULL);
if (reg) {
#ifdef CONFIG_PPC_DCR_NATIVE
dev_set_name(dev, "d%x.%s", *reg, node->name);
#else /* CONFIG_PPC_DCR_NATIVE */
u64 addr = of_translate_dcr_address(node, *reg, NULL);
if (addr != OF_BAD_ADDR) {
dev_set_name(dev, "D%llx.%s",
(unsigned long long)addr, node->name);
/* Construct the name, using parent nodes if necessary to ensure uniqueness */
while (node->parent) {
/*
* If the address can be translated, then that is as much
* uniqueness as we need. Make it the first component and return
*/
reg = of_get_property(node, "reg", NULL);
if (reg && (addr = of_translate_address(node, reg)) != OF_BAD_ADDR) {
dev_set_name(dev, dev_name(dev) ? "%llx.%s:%s" : "%llx.%s",
(unsigned long long)addr, node->name,
dev_name(dev));
return;
}
#endif /* !CONFIG_PPC_DCR_NATIVE */
}
#endif /* CONFIG_PPC_DCR */

/*
* For MMIO, get the physical address
*/
reg = of_get_property(node, "reg", NULL);
if (reg) {
addr = of_translate_address(node, reg);
if (addr != OF_BAD_ADDR) {
dev_set_name(dev, "%llx.%s",
(unsigned long long)addr, node->name);
return;
}
/* format arguments only used if dev_name() resolves to NULL */
dev_set_name(dev, dev_name(dev) ? "%s:%s" : "%s",
strrchr(node->full_name, '/') + 1, dev_name(dev));
node = node->parent;
}

/*
* No BusID, use the node name and add a globally incremented
* counter (and pray...)
*/
magic = atomic_add_return(1, &bus_no_reg_magic);
dev_set_name(dev, "%s.%d", node->name, magic - 1);
}

/**
Expand Down
Loading

0 comments on commit aa10537

Please sign in to comment.