diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-12 16:52:17 +0900 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-12 16:52:17 +0900 |
commit | 10d0c9705e80bbd3d587c5fad24599aabaca6688 (patch) | |
tree | 9456083a1b04b8d98da08d88e937cfeff80e2a7d /drivers/of | |
parent | 85b656cf1560e27a89354a23f2c10ba229d2f173 (diff) | |
parent | c11eede69b6ad0ac44ebc1e021a8d2699c5f1f8f (diff) | |
download | op-kernel-dev-10d0c9705e80bbd3d587c5fad24599aabaca6688.zip op-kernel-dev-10d0c9705e80bbd3d587c5fad24599aabaca6688.tar.gz |
Merge tag 'devicetree-for-3.13' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux
Pull devicetree updates from Rob Herring:
"DeviceTree updates for 3.13. This is a bit larger pull request than
usual for this cycle with lots of clean-up.
- Cross arch clean-up and consolidation of early DT scanning code.
- Clean-up and removal of arch prom.h headers. Makes arch specific
prom.h optional on all but Sparc.
- Addition of interrupts-extended property for devices connected to
multiple interrupt controllers.
- Refactoring of DT interrupt parsing code in preparation for
deferred probe of interrupts.
- ARM cpu and cpu topology bindings documentation.
- Various DT vendor binding documentation updates"
* tag 'devicetree-for-3.13' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux: (82 commits)
powerpc: add missing explicit OF includes for ppc
dt/irq: add empty of_irq_count for !OF_IRQ
dt: disable self-tests for !OF_IRQ
of: irq: Fix interrupt-map entry matching
MIPS: Netlogic: replace early_init_devtree() call
of: Add Panasonic Corporation vendor prefix
of: Add Chunghwa Picture Tubes Ltd. vendor prefix
of: Add AU Optronics Corporation vendor prefix
of/irq: Fix potential buffer overflow
of/irq: Fix bug in interrupt parsing refactor.
of: set dma_mask to point to coherent_dma_mask
of: add vendor prefix for PHYTEC Messtechnik GmbH
DT: sort vendor-prefixes.txt
of: Add vendor prefix for Cadence
of: Add empty for_each_available_child_of_node() macro definition
arm/versatile: Fix versatile irq specifications.
of/irq: create interrupts-extended property
microblaze/pci: Drop PowerPC-ism from irq parsing
of/irq: Create of_irq_parse_and_map_pci() to consolidate arch code.
of/irq: Use irq_of_parse_and_map()
...
Diffstat (limited to 'drivers/of')
-rw-r--r-- | drivers/of/Kconfig | 1 | ||||
-rw-r--r-- | drivers/of/address.c | 18 | ||||
-rw-r--r-- | drivers/of/base.c | 65 | ||||
-rw-r--r-- | drivers/of/fdt.c | 138 | ||||
-rw-r--r-- | drivers/of/irq.c | 164 | ||||
-rw-r--r-- | drivers/of/of_pci.c | 1 | ||||
-rw-r--r-- | drivers/of/of_pci_irq.c | 41 | ||||
-rw-r--r-- | drivers/of/pdt.c | 1 | ||||
-rw-r--r-- | drivers/of/platform.c | 2 | ||||
-rw-r--r-- | drivers/of/selftest.c | 161 |
10 files changed, 477 insertions, 115 deletions
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 78cc760..de6f899 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -17,6 +17,7 @@ config PROC_DEVICETREE config OF_SELFTEST bool "Device Tree Runtime self tests" + depends on OF_IRQ help This option builds in test cases for the device tree infrastructure that are executed one at boot time, and the results dumped to the diff --git a/drivers/of/address.c b/drivers/of/address.c index b55c218..4b9317b 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -489,7 +489,7 @@ static u64 __of_translate_address(struct device_node *dev, int na, ns, pna, pns; u64 result = OF_BAD_ADDR; - pr_debug("OF: ** translation for device %s **\n", dev->full_name); + pr_debug("OF: ** translation for device %s **\n", of_node_full_name(dev)); /* Increase refcount at current level */ of_node_get(dev); @@ -504,13 +504,13 @@ static u64 __of_translate_address(struct device_node *dev, bus->count_cells(dev, &na, &ns); if (!OF_CHECK_COUNTS(na, ns)) { printk(KERN_ERR "prom_parse: Bad cell count for %s\n", - dev->full_name); + of_node_full_name(dev)); goto bail; } memcpy(addr, in_addr, na * 4); pr_debug("OF: bus is %s (na=%d, ns=%d) on %s\n", - bus->name, na, ns, parent->full_name); + bus->name, na, ns, of_node_full_name(parent)); of_dump_addr("OF: translating address:", addr, na); /* Translate */ @@ -532,12 +532,12 @@ static u64 __of_translate_address(struct device_node *dev, pbus->count_cells(dev, &pna, &pns); if (!OF_CHECK_COUNTS(pna, pns)) { printk(KERN_ERR "prom_parse: Bad cell count for %s\n", - dev->full_name); + of_node_full_name(dev)); break; } pr_debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n", - pbus->name, pna, pns, parent->full_name); + pbus->name, pna, pns, of_node_full_name(parent)); /* Apply bus translation */ if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop)) @@ -626,6 +626,14 @@ const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, } EXPORT_SYMBOL(of_get_address); +unsigned long __weak pci_address_to_pio(phys_addr_t address) +{ + if (address > IO_SPACE_LIMIT) + return (unsigned long)-1; + + return (unsigned long) address; +} + static int __of_address_to_resource(struct device_node *dev, const __be32 *addrp, u64 size, unsigned int flags, const char *name, struct resource *r) diff --git a/drivers/of/base.c b/drivers/of/base.c index aace017..f807d0e 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -74,6 +74,13 @@ int of_n_size_cells(struct device_node *np) } EXPORT_SYMBOL(of_n_size_cells); +#ifdef CONFIG_NUMA +int __weak of_node_to_nid(struct device_node *np) +{ + return numa_node_id(); +} +#endif + #if defined(CONFIG_OF_DYNAMIC) /** * of_node_get - Increment refcount of a node @@ -265,9 +272,9 @@ static bool __of_find_n_match_cpu_property(struct device_node *cpun, ac = of_n_addr_cells(cpun); cell = of_get_property(cpun, prop_name, &prop_len); - if (!cell) + if (!cell || !ac) return false; - prop_len /= sizeof(*cell); + prop_len /= sizeof(*cell) * ac; for (tid = 0; tid < prop_len; tid++) { hwid = of_read_number(cell, ac); if (arch_match_cpu_phys_id(cpu, hwid)) { @@ -280,6 +287,31 @@ static bool __of_find_n_match_cpu_property(struct device_node *cpun, return false; } +/* + * arch_find_n_match_cpu_physical_id - See if the given device node is + * for the cpu corresponding to logical cpu 'cpu'. Return true if so, + * else false. If 'thread' is non-NULL, the local thread number within the + * core is returned in it. + */ +bool __weak arch_find_n_match_cpu_physical_id(struct device_node *cpun, + int cpu, unsigned int *thread) +{ + /* Check for non-standard "ibm,ppc-interrupt-server#s" property + * for thread ids on PowerPC. If it doesn't exist fallback to + * standard "reg" property. + */ + if (IS_ENABLED(CONFIG_PPC) && + __of_find_n_match_cpu_property(cpun, + "ibm,ppc-interrupt-server#s", + cpu, thread)) + return true; + + if (__of_find_n_match_cpu_property(cpun, "reg", cpu, thread)) + return true; + + return false; +} + /** * of_get_cpu_node - Get device node associated with the given logical CPU * @@ -300,24 +332,10 @@ static bool __of_find_n_match_cpu_property(struct device_node *cpun, */ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) { - struct device_node *cpun, *cpus; - - cpus = of_find_node_by_path("/cpus"); - if (!cpus) - return NULL; + struct device_node *cpun; - for_each_child_of_node(cpus, cpun) { - if (of_node_cmp(cpun->type, "cpu")) - continue; - /* Check for non-standard "ibm,ppc-interrupt-server#s" property - * for thread ids on PowerPC. If it doesn't exist fallback to - * standard "reg" property. - */ - if (IS_ENABLED(CONFIG_PPC) && - __of_find_n_match_cpu_property(cpun, - "ibm,ppc-interrupt-server#s", cpu, thread)) - return cpun; - if (__of_find_n_match_cpu_property(cpun, "reg", cpu, thread)) + for_each_node_by_type(cpun, "cpu") { + if (arch_find_n_match_cpu_physical_id(cpun, cpu, thread)) return cpun; } return NULL; @@ -1174,6 +1192,15 @@ int of_property_count_strings(struct device_node *np, const char *propname) } EXPORT_SYMBOL_GPL(of_property_count_strings); +void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) +{ + int i; + printk("%s %s", msg, of_node_full_name(args->np)); + for (i = 0; i < args->args_count; i++) + printk(i ? ",%08x" : ":%08x", args->args[i]); + printk("\n"); +} + static int __of_parse_phandle_with_args(const struct device_node *np, const char *list_name, const char *cells_name, diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index a4fa9ad..2fa024b 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -618,12 +618,72 @@ int __init of_scan_flat_dt_by_path(const char *path, return ret; } +const char * __init of_flat_dt_get_machine_name(void) +{ + const char *name; + unsigned long dt_root = of_get_flat_dt_root(); + + name = of_get_flat_dt_prop(dt_root, "model", NULL); + if (!name) + name = of_get_flat_dt_prop(dt_root, "compatible", NULL); + return name; +} + +/** + * of_flat_dt_match_machine - Iterate match tables to find matching machine. + * + * @default_match: A machine specific ptr to return in case of no match. + * @get_next_compat: callback function to return next compatible match table. + * + * Iterate through machine match tables to find the best match for the machine + * compatible string in the FDT. + */ +const void * __init of_flat_dt_match_machine(const void *default_match, + const void * (*get_next_compat)(const char * const**)) +{ + const void *data = NULL; + const void *best_data = default_match; + const char *const *compat; + unsigned long dt_root; + unsigned int best_score = ~1, score = 0; + + dt_root = of_get_flat_dt_root(); + while ((data = get_next_compat(&compat))) { + score = of_flat_dt_match(dt_root, compat); + if (score > 0 && score < best_score) { + best_data = data; + best_score = score; + } + } + if (!best_data) { + const char *prop; + long size; + + pr_err("\n unrecognized device tree list:\n[ "); + + prop = of_get_flat_dt_prop(dt_root, "compatible", &size); + if (prop) { + while (size > 0) { + printk("'%s' ", prop); + size -= strlen(prop) + 1; + prop += strlen(prop) + 1; + } + } + printk("]\n\n"); + return NULL; + } + + pr_info("Machine model: %s\n", of_flat_dt_get_machine_name()); + + return best_data; +} + #ifdef CONFIG_BLK_DEV_INITRD /** * early_init_dt_check_for_initrd - Decode initrd location from flat tree * @node: reference to node containing initrd location ('chosen') */ -void __init early_init_dt_check_for_initrd(unsigned long node) +static void __init early_init_dt_check_for_initrd(unsigned long node) { u64 start, end; unsigned long len; @@ -641,12 +701,15 @@ void __init early_init_dt_check_for_initrd(unsigned long node) return; end = of_read_number(prop, len/4); - early_init_dt_setup_initrd_arch(start, end); + initrd_start = (unsigned long)__va(start); + initrd_end = (unsigned long)__va(end); + initrd_below_start_ok = 1; + pr_debug("initrd_start=0x%llx initrd_end=0x%llx\n", (unsigned long long)start, (unsigned long long)end); } #else -inline void early_init_dt_check_for_initrd(unsigned long node) +static inline void early_init_dt_check_for_initrd(unsigned long node) { } #endif /* CONFIG_BLK_DEV_INITRD */ @@ -774,6 +837,25 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, } #ifdef CONFIG_HAVE_MEMBLOCK +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 (base + size < phys_offset) { + pr_warning("Ignoring memory block 0x%llx - 0x%llx\n", + base, base + size); + return; + } + if (base < phys_offset) { + pr_warning("Ignoring memory range 0x%llx - 0x%llx\n", + base, phys_offset); + size -= phys_offset - base; + base = phys_offset; + } + memblock_add(base, size); +} + /* * called from unflatten_device_tree() to bootstrap devicetree itself * Architectures can override this definition if memblock isn't used @@ -784,6 +866,32 @@ void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align) } #endif +bool __init early_init_dt_scan(void *params) +{ + if (!params) + return false; + + /* Setup flat device-tree pointer */ + initial_boot_params = params; + + /* check device tree validity */ + if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) { + initial_boot_params = NULL; + return false; + } + + /* Retrieve various information from the /chosen node */ + of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); + + /* Initialize {size,address}-cells info */ + of_scan_flat_dt(early_init_dt_scan_root, NULL); + + /* Setup memory, calling early_init_dt_add_memory_arch */ + of_scan_flat_dt(early_init_dt_scan_memory, NULL); + + return true; +} + /** * unflatten_device_tree - create tree of device_nodes from flat blob * @@ -801,4 +909,28 @@ void __init unflatten_device_tree(void) of_alias_scan(early_init_dt_alloc_memory_arch); } +/** + * unflatten_and_copy_device_tree - copy and create tree of device_nodes from flat blob + * + * Copies and unflattens the device-tree passed by the firmware, creating the + * tree of struct device_node. It also fills the "name" and "type" + * pointers of the nodes so the normal device-tree walking functions + * can be used. This should only be used when the FDT memory has not been + * reserved such is the case when the FDT is built-in to the kernel init + * section. If the FDT memory is reserved already then unflatten_device_tree + * should be used instead. + */ +void __init unflatten_and_copy_device_tree(void) +{ + int size = __be32_to_cpu(initial_boot_params->totalsize); + void *dt = early_init_dt_alloc_memory_arch(size, + __alignof__(struct boot_param_header)); + + if (dt) { + memcpy(dt, initial_boot_params, size); + initial_boot_params = dt; + } + unflatten_device_tree(); +} + #endif /* CONFIG_OF_EARLY_FLATTREE */ diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 1752988..786b0b4 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -31,18 +31,17 @@ * @dev: Device node of the device whose interrupt is to be mapped * @index: Index of the interrupt to map * - * This function is a wrapper that chains of_irq_map_one() and + * This function is a wrapper that chains of_irq_parse_one() and * irq_create_of_mapping() to make things easier to callers */ unsigned int irq_of_parse_and_map(struct device_node *dev, int index) { - struct of_irq oirq; + struct of_phandle_args oirq; - if (of_irq_map_one(dev, index, &oirq)) + if (of_irq_parse_one(dev, index, &oirq)) return 0; - return irq_create_of_mapping(oirq.controller, oirq.specifier, - oirq.size); + return irq_create_of_mapping(&oirq); } EXPORT_SYMBOL_GPL(irq_of_parse_and_map); @@ -79,33 +78,34 @@ struct device_node *of_irq_find_parent(struct device_node *child) } /** - * of_irq_map_raw - Low level interrupt tree parsing + * of_irq_parse_raw - Low level interrupt tree parsing * @parent: the device interrupt parent - * @intspec: interrupt specifier ("interrupts" property of the device) - * @ointsize: size of the passed in interrupt specifier - * @addr: address specifier (start of "reg" property of the device) - * @out_irq: structure of_irq filled by this function + * @addr: address specifier (start of "reg" property of the device) in be32 format + * @out_irq: structure of_irq updated by this function * * Returns 0 on success and a negative number on error * * This function is a low-level interrupt tree walking function. It * can be used to do a partial walk with synthetized reg and interrupts * properties, for example when resolving PCI interrupts when no device - * node exist for the parent. + * node exist for the parent. It takes an interrupt specifier structure as + * input, walks the tree looking for any interrupt-map properties, translates + * the specifier for each map, and then returns the translated map. */ -int of_irq_map_raw(struct device_node *parent, const __be32 *intspec, - u32 ointsize, const __be32 *addr, struct of_irq *out_irq) +int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq) { struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL; - const __be32 *tmp, *imap, *imask; + __be32 initial_match_array[MAX_PHANDLE_ARGS]; + const __be32 *match_array = initial_match_array; + const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = ~0 }; u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0; int imaplen, match, i; - pr_debug("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n", - parent->full_name, be32_to_cpup(intspec), - be32_to_cpup(intspec + 1), ointsize); +#ifdef DEBUG + of_print_phandle_args("of_irq_parse_raw: ", out_irq); +#endif - ipar = of_node_get(parent); + ipar = of_node_get(out_irq->np); /* First get the #interrupt-cells property of the current cursor * that tells us how to interpret the passed-in intspec. If there @@ -126,9 +126,9 @@ int of_irq_map_raw(struct device_node *parent, const __be32 *intspec, goto fail; } - pr_debug("of_irq_map_raw: ipar=%s, size=%d\n", ipar->full_name, intsize); + pr_debug("of_irq_parse_raw: ipar=%s, size=%d\n", of_node_full_name(ipar), intsize); - if (ointsize != intsize) + if (out_irq->args_count != intsize) return -EINVAL; /* Look for this #address-cells. We have to implement the old linux @@ -147,6 +147,16 @@ int of_irq_map_raw(struct device_node *parent, const __be32 *intspec, pr_debug(" -> addrsize=%d\n", addrsize); + /* Range check so that the temporary buffer doesn't overflow */ + if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS)) + goto fail; + + /* Precalculate the match array - this simplifies match loop */ + for (i = 0; i < addrsize; i++) + initial_match_array[i] = addr ? addr[i] : 0; + for (i = 0; i < intsize; i++) + initial_match_array[addrsize + i] = cpu_to_be32(out_irq->args[i]); + /* Now start the actual "proper" walk of the interrupt tree */ while (ipar != NULL) { /* Now check if cursor is an interrupt-controller and if it is @@ -155,15 +165,19 @@ int of_irq_map_raw(struct device_node *parent, const __be32 *intspec, if (of_get_property(ipar, "interrupt-controller", NULL) != NULL) { pr_debug(" -> got it !\n"); - for (i = 0; i < intsize; i++) - out_irq->specifier[i] = - of_read_number(intspec +i, 1); - out_irq->size = intsize; - out_irq->controller = ipar; of_node_put(old); return 0; } + /* + * interrupt-map parsing does not work without a reg + * property when #address-cells != 0 + */ + if (addrsize && !addr) { + pr_debug(" -> no reg passed in when needed !\n"); + goto fail; + } + /* Now look for an interrupt-map */ imap = of_get_property(ipar, "interrupt-map", &imaplen); /* No interrupt map, check for an interrupt parent */ @@ -176,34 +190,16 @@ int of_irq_map_raw(struct device_node *parent, const __be32 *intspec, /* Look for a mask */ imask = of_get_property(ipar, "interrupt-map-mask", NULL); - - /* If we were passed no "reg" property and we attempt to parse - * an interrupt-map, then #address-cells must be 0. - * Fail if it's not. - */ - if (addr == NULL && addrsize != 0) { - pr_debug(" -> no reg passed in when needed !\n"); - goto fail; - } + if (!imask) + imask = dummy_imask; /* Parse interrupt-map */ match = 0; while (imaplen > (addrsize + intsize + 1) && !match) { /* Compare specifiers */ match = 1; - for (i = 0; i < addrsize && match; ++i) { - __be32 mask = imask ? imask[i] - : cpu_to_be32(0xffffffffu); - match = ((addr[i] ^ imap[i]) & mask) == 0; - } - for (; i < (addrsize + intsize) && match; ++i) { - __be32 mask = imask ? imask[i] - : cpu_to_be32(0xffffffffu); - match = - ((intspec[i-addrsize] ^ imap[i]) & mask) == 0; - } - imap += addrsize + intsize; - imaplen -= addrsize + intsize; + for (i = 0; i < (addrsize + intsize); i++, imaplen--) + match &= !((match_array[i] ^ *imap++) & imask[i]); pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen); @@ -237,6 +233,8 @@ int of_irq_map_raw(struct device_node *parent, const __be32 *intspec, newintsize, newaddrsize); /* Check for malformed properties */ + if (WARN_ON(newaddrsize + newintsize > MAX_PHANDLE_ARGS)) + goto fail; if (imaplen < (newaddrsize + newintsize)) goto fail; @@ -248,12 +246,18 @@ int of_irq_map_raw(struct device_node *parent, const __be32 *intspec, if (!match) goto fail; - of_node_put(old); - old = of_node_get(newpar); + /* + * Successfully parsed an interrrupt-map translation; copy new + * interrupt specifier into the out_irq structure + */ + of_node_put(out_irq->np); + out_irq->np = of_node_get(newpar); + + match_array = imap - newaddrsize - newintsize; + for (i = 0; i < newintsize; i++) + out_irq->args[i] = be32_to_cpup(imap - newintsize + i); + out_irq->args_count = intsize = newintsize; addrsize = newaddrsize; - intsize = newintsize; - intspec = imap - intsize; - addr = intspec - addrsize; skiplevel: /* Iterate again with new parent */ @@ -264,46 +268,53 @@ int of_irq_map_raw(struct device_node *parent, const __be32 *intspec, } fail: of_node_put(ipar); - of_node_put(old); + of_node_put(out_irq->np); of_node_put(newpar); return -EINVAL; } -EXPORT_SYMBOL_GPL(of_irq_map_raw); +EXPORT_SYMBOL_GPL(of_irq_parse_raw); /** - * of_irq_map_one - Resolve an interrupt for a device + * of_irq_parse_one - Resolve an interrupt for a device * @device: the device whose interrupt is to be resolved * @index: index of the interrupt to resolve * @out_irq: structure of_irq filled by this function * - * This function resolves an interrupt, walking the tree, for a given - * device-tree node. It's the high level pendant to of_irq_map_raw(). + * This function resolves an interrupt for a node by walking the interrupt tree, + * finding which interrupt controller node it is attached to, and returning the + * interrupt specifier that can be used to retrieve a Linux IRQ number. */ -int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq) +int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq) { struct device_node *p; const __be32 *intspec, *tmp, *addr; u32 intsize, intlen; - int res = -EINVAL; + int i, res = -EINVAL; - pr_debug("of_irq_map_one: dev=%s, index=%d\n", device->full_name, index); + pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index); /* OldWorld mac stuff is "special", handle out of line */ if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC) - return of_irq_map_oldworld(device, index, out_irq); + return of_irq_parse_oldworld(device, index, out_irq); + + /* Get the reg property (if any) */ + addr = of_get_property(device, "reg", NULL); /* Get the interrupts property */ intspec = of_get_property(device, "interrupts", &intlen); - if (intspec == NULL) - return -EINVAL; + if (intspec == NULL) { + /* Try the new-style interrupts-extended */ + res = of_parse_phandle_with_args(device, "interrupts-extended", + "#interrupt-cells", index, out_irq); + if (res) + return -EINVAL; + return of_irq_parse_raw(addr, out_irq); + } intlen /= sizeof(*intspec); pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen); - /* Get the reg property (if any) */ - addr = of_get_property(device, "reg", NULL); - /* Look for the interrupt parent. */ p = of_irq_find_parent(device); if (p == NULL) @@ -321,14 +332,20 @@ int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq if ((index + 1) * intsize > intlen) goto out; - /* Get new specifier and map it */ - res = of_irq_map_raw(p, intspec + index * intsize, intsize, - addr, out_irq); + /* Copy intspec into irq structure */ + intspec += index * intsize; + out_irq->np = p; + out_irq->args_count = intsize; + for (i = 0; i < intsize; i++) + out_irq->args[i] = be32_to_cpup(intspec++); + + /* Check if there are any interrupt-map translations to process */ + res = of_irq_parse_raw(addr, out_irq); out: of_node_put(p); return res; } -EXPORT_SYMBOL_GPL(of_irq_map_one); +EXPORT_SYMBOL_GPL(of_irq_parse_one); /** * of_irq_to_resource - Decode a node's IRQ and return it as a resource @@ -354,8 +371,8 @@ int of_irq_to_resource(struct device_node *dev, int index, struct resource *r) &name); r->start = r->end = irq; - r->flags = IORESOURCE_IRQ; - r->name = name ? name : dev->full_name; + r->flags = IORESOURCE_IRQ | irqd_get_trigger_type(irq_get_irq_data(irq)); + r->name = name ? name : of_node_full_name(dev); } return irq; @@ -368,9 +385,10 @@ EXPORT_SYMBOL_GPL(of_irq_to_resource); */ int of_irq_count(struct device_node *dev) { + struct of_phandle_args irq; int nr = 0; - while (of_irq_to_resource(dev, nr, NULL)) + while (of_irq_parse_one(dev, nr, &irq) == 0) nr++; return nr; diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c index e5ca008..8481996 100644 --- a/drivers/of/of_pci.c +++ b/drivers/of/of_pci.c @@ -2,7 +2,6 @@ #include <linux/export.h> #include <linux/of.h> #include <linux/of_pci.h> -#include <asm/prom.h> static inline int __of_pci_pci_compare(struct device_node *node, unsigned int data) diff --git a/drivers/of/of_pci_irq.c b/drivers/of/of_pci_irq.c index 6770538..8736bc7 100644 --- a/drivers/of/of_pci_irq.c +++ b/drivers/of/of_pci_irq.c @@ -2,10 +2,9 @@ #include <linux/of_pci.h> #include <linux/of_irq.h> #include <linux/export.h> -#include <asm/prom.h> /** - * of_irq_map_pci - Resolve the interrupt for a PCI device + * of_irq_parse_pci - Resolve the interrupt for a PCI device * @pdev: the device whose interrupt is to be resolved * @out_irq: structure of_irq filled by this function * @@ -15,7 +14,7 @@ * PCI tree until an device-node is found, at which point it will finish * resolving using the OF tree walking. */ -int of_irq_map_pci(const struct pci_dev *pdev, struct of_irq *out_irq) +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; @@ -30,7 +29,7 @@ int of_irq_map_pci(const struct pci_dev *pdev, struct of_irq *out_irq) */ dn = pci_device_to_OF_node(pdev); if (dn) { - rc = of_irq_map_one(dn, 0, out_irq); + rc = of_irq_parse_one(dn, 0, out_irq); if (!rc) return rc; } @@ -85,9 +84,37 @@ int of_irq_map_pci(const struct pci_dev *pdev, struct of_irq *out_irq) pdev = ppdev; } + out_irq->np = ppnode; + out_irq->args_count = 1; + out_irq->args[0] = lspec; lspec_be = cpu_to_be32(lspec); laddr[0] = cpu_to_be32((pdev->bus->number << 16) | (pdev->devfn << 8)); - laddr[1] = laddr[2] = cpu_to_be32(0); - return of_irq_map_raw(ppnode, &lspec_be, 1, laddr, out_irq); + laddr[1] = laddr[2] = cpu_to_be32(0); + return of_irq_parse_raw(laddr, out_irq); } -EXPORT_SYMBOL_GPL(of_irq_map_pci); +EXPORT_SYMBOL_GPL(of_irq_parse_pci); + +/** + * of_irq_parse_and_map_pci() - Decode a PCI irq from the device tree and map to a virq + * @dev: The pci device needing an irq + * @slot: PCI slot number; passed when used as map_irq callback. Unused + * @pin: PCI irq pin number; passed when used as map_irq callback. Unused + * + * @slot and @pin are unused, but included in the function so that this + * function can be used directly as the map_irq callback to pci_fixup_irqs(). + */ +int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin) +{ + struct of_phandle_args oirq; + 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); + return 0; /* Proper return code 0 == NO_IRQ */ + } + + return irq_create_of_mapping(&oirq); +} +EXPORT_SYMBOL_GPL(of_irq_parse_and_map_pci); + diff --git a/drivers/of/pdt.c b/drivers/of/pdt.c index 4ec19cb..7b66673 100644 --- a/drivers/of/pdt.c +++ b/drivers/of/pdt.c @@ -22,7 +22,6 @@ #include <linux/slab.h> #include <linux/of.h> #include <linux/of_pdt.h> -#include <asm/prom.h> static struct of_pdt_ops *of_pdt_prom_ops __initdata; diff --git a/drivers/of/platform.c b/drivers/of/platform.c index f6dcde2..fce088e 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -215,6 +215,8 @@ static struct platform_device *of_platform_device_create_pdata( dev->archdata.dma_mask = 0xffffffffUL; #endif dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + if (!dev->dev.dma_mask) + dev->dev.dma_mask = &dev->dev.coherent_dma_mask; dev->dev.bus = &platform_bus_type; dev->dev.platform_data = platform_data; diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c index 0eb5c38..e21012b 100644 --- a/drivers/of/selftest.c +++ b/drivers/of/selftest.c @@ -9,18 +9,24 @@ #include <linux/errno.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_irq.h> #include <linux/list.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/device.h> -static bool selftest_passed = true; +static struct selftest_results { + int passed; + int failed; +} selftest_results; + #define selftest(result, fmt, ...) { \ if (!(result)) { \ - pr_err("FAIL %s:%i " fmt, __FILE__, __LINE__, ##__VA_ARGS__); \ - selftest_passed = false; \ + selftest_results.failed++; \ + pr_err("FAIL %s():%i " fmt, __func__, __LINE__, ##__VA_ARGS__); \ } else { \ - pr_info("pass %s:%i\n", __FILE__, __LINE__); \ + selftest_results.passed++; \ + pr_debug("pass %s():%i\n", __func__, __LINE__); \ } \ } @@ -131,7 +137,6 @@ static void __init of_selftest_property_match_string(void) struct device_node *np; int rc; - pr_info("start\n"); np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a"); if (!np) { pr_err("No testcase data in device tree\n"); @@ -154,6 +159,147 @@ static void __init of_selftest_property_match_string(void) selftest(rc == -EILSEQ, "unterminated string; rc=%i", rc); } +static void __init of_selftest_parse_interrupts(void) +{ + struct device_node *np; + struct of_phandle_args args; + int i, rc; + + np = of_find_node_by_path("/testcase-data/interrupts/interrupts0"); + if (!np) { + pr_err("missing testcase data\n"); + return; + } + + for (i = 0; i < 4; i++) { + bool passed = true; + args.args_count = 0; + rc = of_irq_parse_one(np, i, &args); + + passed &= !rc; + passed &= (args.args_count == 1); + passed &= (args.args[0] == (i + 1)); + + selftest(passed, "index %i - data error on node %s rc=%i\n", + i, args.np->full_name, rc); + } + of_node_put(np); + + np = of_find_node_by_path("/testcase-data/interrupts/interrupts1"); + if (!np) { + pr_err("missing testcase data\n"); + return; + } + + for (i = 0; i < 4; i++) { + bool passed = true; + args.args_count = 0; + rc = of_irq_parse_one(np, i, &args); + + /* Test the values from tests-phandle.dtsi */ + switch (i) { + case 0: + passed &= !rc; + passed &= (args.args_count == 1); + passed &= (args.args[0] == 9); + break; + case 1: + passed &= !rc; + passed &= (args.args_count == 3); + passed &= (args.args[0] == 10); + passed &= (args.args[1] == 11); + passed &= (args.args[2] == 12); + break; + case 2: + passed &= !rc; + passed &= (args.args_count == 2); + passed &= (args.args[0] == 13); + passed &= (args.args[1] == 14); + break; + case 3: + passed &= !rc; + passed &= (args.args_count == 2); + passed &= (args.args[0] == 15); + passed &= (args.args[1] == 16); + break; + default: + passed = false; + } + selftest(passed, "index %i - data error on node %s rc=%i\n", + i, args.np->full_name, rc); + } + of_node_put(np); +} + +static void __init of_selftest_parse_interrupts_extended(void) +{ + struct device_node *np; + struct of_phandle_args args; + int i, rc; + + np = of_find_node_by_path("/testcase-data/interrupts/interrupts-extended0"); + if (!np) { + pr_err("missing testcase data\n"); + return; + } + + for (i = 0; i < 7; i++) { + bool passed = true; + rc = of_irq_parse_one(np, i, &args); + + /* Test the values from tests-phandle.dtsi */ + switch (i) { + case 0: + passed &= !rc; + passed &= (args.args_count == 1); + passed &= (args.args[0] == 1); + break; + case 1: + passed &= !rc; + passed &= (args.args_count == 3); + passed &= (args.args[0] == 2); + passed &= (args.args[1] == 3); + passed &= (args.args[2] == 4); + break; + case 2: + passed &= !rc; + passed &= (args.args_count == 2); + passed &= (args.args[0] == 5); + passed &= (args.args[1] == 6); + break; + case 3: + passed &= !rc; + passed &= (args.args_count == 1); + passed &= (args.args[0] == 9); + break; + case 4: + passed &= !rc; + passed &= (args.args_count == 3); + passed &= (args.args[0] == 10); + passed &= (args.args[1] == 11); + passed &= (args.args[2] == 12); + break; + case 5: + passed &= !rc; + passed &= (args.args_count == 2); + passed &= (args.args[0] == 13); + passed &= (args.args[1] == 14); + break; + case 6: + passed &= !rc; + passed &= (args.args_count == 1); + passed &= (args.args[0] == 15); + break; + default: + passed = false; + } + + selftest(passed, "index %i - data error on node %s rc=%i\n", + i, args.np->full_name, rc); + } + of_node_put(np); +} + static int __init of_selftest(void) { struct device_node *np; @@ -168,7 +314,10 @@ static int __init of_selftest(void) pr_info("start of selftest - you will see error messages\n"); of_selftest_parse_phandle_with_args(); of_selftest_property_match_string(); - pr_info("end of selftest - %s\n", selftest_passed ? "PASS" : "FAIL"); + of_selftest_parse_interrupts(); + of_selftest_parse_interrupts_extended(); + pr_info("end of selftest - %i passed, %i failed\n", + selftest_results.passed, selftest_results.failed); return 0; } late_initcall(of_selftest); |