Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372// SPDX-License-Identifier: GPL-2.0+/* * Procedures for creating, accessing and interpreting the device tree. * * Paul Mackerras August 1996. * Copyright (C) 1996-2005 Paul Mackerras. * * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. * {engebret|bergner}@us.ibm.com * * Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net * * Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell and * Grant Likely. */
#define pr_fmt(fmt) "OF: " fmt
#include <linux/cleanup.h>#include <linux/console.h>#include <linux/ctype.h>#include <linux/cpu.h>#include <linux/module.h>#include <linux/of.h>#include <linux/of_device.h>#include <linux/of_graph.h>#include <linux/spinlock.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/proc_fs.h>
#include "of_private.h"
LIST_HEAD(aliases_lookup);
struct device_node *of_root;EXPORT_SYMBOL(of_root);struct device_node *of_chosen;EXPORT_SYMBOL(of_chosen);struct device_node *of_aliases;struct device_node *of_stdout;static const char *of_stdout_options;
struct kset *of_kset;
/* * Used to protect the of_aliases, to hold off addition of nodes to sysfs. * This mutex must be held whenever modifications are being made to the * device tree. The of_{attach,detach}_node() and * of_{add,remove,update}_property() helpers make sure this happens. */DEFINE_MUTEX(of_mutex);
/* use when traversing tree through the child, sibling, * or parent members of struct device_node. */DEFINE_RAW_SPINLOCK(devtree_lock);
bool of_node_name_eq(const struct device_node *np, const char *name){ const char *node_name; size_t len;
if (!np) return false;
node_name = kbasename(np->full_name); len = strchrnul(node_name, '@') - node_name;
return (strlen(name) == len) && (strncmp(node_name, name, len) == 0);}EXPORT_SYMBOL(of_node_name_eq);
bool of_node_name_prefix(const struct device_node *np, const char *prefix){ if (!np) return false;
return strncmp(kbasename(np->full_name), prefix, strlen(prefix)) == 0;}EXPORT_SYMBOL(of_node_name_prefix);
static bool __of_node_is_type(const struct device_node *np, const char *type){ const char *match; int len;
if (!np || !type) return false;
match = __of_get_property(np, "device_type", &len); if (!match || len <= 0 || strnlen(match, len) >= len) return false;
return !strcmp(match, type);}
#define EXCLUDED_DEFAULT_CELLS_PLATFORMS ( \ IS_ENABLED(CONFIG_SPARC) || \ of_find_compatible_node(NULL, NULL, "coreboot") \)
int of_bus_n_addr_cells(struct device_node *np){ u32 cells;
for (; np; np = np->parent) { if (!of_property_read_u32(np, "#address-cells", &cells)) return cells; /* * Default root value and walking parent nodes for "#address-cells" * is deprecated. Any platforms which hit this warning should * be added to the excluded list. */ WARN_ONCE(!EXCLUDED_DEFAULT_CELLS_PLATFORMS, "Missing '#address-cells' in %pOF\n", np); } return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;}
int of_n_addr_cells(struct device_node *np){ if (np->parent) np = np->parent;
return of_bus_n_addr_cells(np);}EXPORT_SYMBOL(of_n_addr_cells);
int of_bus_n_size_cells(struct device_node *np){ u32 cells;
for (; np; np = np->parent) { if (!of_property_read_u32(np, "#size-cells", &cells)) return cells; /* * Default root value and walking parent nodes for "#size-cells" * is deprecated. Any platforms which hit this warning should * be added to the excluded list. */ WARN_ONCE(!EXCLUDED_DEFAULT_CELLS_PLATFORMS, "Missing '#size-cells' in %pOF\n", np); } return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;}
int of_n_size_cells(struct device_node *np){ if (np->parent) np = np->parent;
return of_bus_n_size_cells(np);}EXPORT_SYMBOL(of_n_size_cells);
#ifdef CONFIG_NUMAint __weak of_node_to_nid(struct device_node *np){ return NUMA_NO_NODE;}#endif
#define OF_PHANDLE_CACHE_BITS 7#define OF_PHANDLE_CACHE_SZ BIT(OF_PHANDLE_CACHE_BITS)
static struct device_node *phandle_cache[OF_PHANDLE_CACHE_SZ];
static u32 of_phandle_cache_hash(phandle handle){ return hash_32(handle, OF_PHANDLE_CACHE_BITS);}
/* * Caller must hold devtree_lock. */void __of_phandle_cache_inv_entry(phandle handle){ u32 handle_hash; struct device_node *np;
if (!handle) return;
handle_hash = of_phandle_cache_hash(handle);
np = phandle_cache[handle_hash]; if (np && handle == np->phandle) phandle_cache[handle_hash] = NULL;}
void __init of_core_init(void){ struct device_node *np;
of_platform_register_reconfig_notifier();
/* Create the kset, and register existing nodes */ mutex_lock(&of_mutex); of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj); if (!of_kset) { mutex_unlock(&of_mutex); pr_err("failed to register existing nodes\n"); return; } for_each_of_allnodes(np) { __of_attach_node_sysfs(np); if (np->phandle && !phandle_cache[of_phandle_cache_hash(np->phandle)]) phandle_cache[of_phandle_cache_hash(np->phandle)] = np; } mutex_unlock(&of_mutex);
/* Symlink in /proc as required by userspace ABI */ if (of_root) proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base");}
static struct property *__of_find_property(const struct device_node *np, const char *name, int *lenp){ struct property *pp;
if (!np) return NULL;
for (pp = np->properties; pp; pp = pp->next) { if (of_prop_cmp(pp->name, name) == 0) { if (lenp) *lenp = pp->length; break; } }
return pp;}
struct property *of_find_property(const struct device_node *np, const char *name, int *lenp){ struct property *pp; unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags); pp = __of_find_property(np, name, lenp); raw_spin_unlock_irqrestore(&devtree_lock, flags);
return pp;}EXPORT_SYMBOL(of_find_property);
struct device_node *__of_find_all_nodes(struct device_node *prev){ struct device_node *np; if (!prev) { np = of_root; } else if (prev->child) { np = prev->child; } else { /* Walk back up looking for a sibling, or the end of the structure */ np = prev; while (np->parent && !np->sibling) np = np->parent; np = np->sibling; /* Might be null at the end of the tree */ } return np;}
/** * of_find_all_nodes - Get next node in global list * @prev: Previous node or NULL to start iteration * of_node_put() will be called on it * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_find_all_nodes(struct device_node *prev){ struct device_node *np; unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags); np = __of_find_all_nodes(prev); of_node_get(np); of_node_put(prev); raw_spin_unlock_irqrestore(&devtree_lock, flags); return np;}EXPORT_SYMBOL(of_find_all_nodes);
/* * Find a property with a given name for a given node * and return the value. */const void *__of_get_property(const struct device_node *np, const char *name, int *lenp){ const struct property *pp = __of_find_property(np, name, lenp);
return pp ? pp->value : NULL;}
/* * Find a property with a given name for a given node * and return the value. */const void *of_get_property(const struct device_node *np, const char *name, int *lenp){ const struct property *pp = of_find_property(np, name, lenp);
return pp ? pp->value : NULL;}EXPORT_SYMBOL(of_get_property);
/** * __of_device_is_compatible() - Check if the node matches given constraints * @device: pointer to node * @compat: required compatible string, NULL or "" for any match * @type: required device_type value, NULL or "" for any match * @name: required node name, NULL or "" for any match * * Checks if the given @compat, @type and @name strings match the * properties of the given @device. A constraints can be skipped by * passing NULL or an empty string as the constraint. * * Returns 0 for no match, and a positive integer on match. The return * value is a relative score with larger values indicating better * matches. The score is weighted for the most specific compatible value * to get the highest score. Matching type is next, followed by matching * name. Practically speaking, this results in the following priority * order for matches: * * 1. specific compatible && type && name * 2. specific compatible && type * 3. specific compatible && name * 4. specific compatible * 5. general compatible && type && name * 6. general compatible && type * 7. general compatible && name * 8. general compatible * 9. type && name * 10. type * 11. name */static int __of_device_is_compatible(const struct device_node *device, const char *compat, const char *type, const char *name){ const struct property *prop; const char *cp; int index = 0, score = 0;
/* Compatible match has highest priority */ if (compat && compat[0]) { prop = __of_find_property(device, "compatible", NULL); for (cp = of_prop_next_string(prop, NULL); cp; cp = of_prop_next_string(prop, cp), index++) { if (of_compat_cmp(cp, compat, strlen(compat)) == 0) { score = INT_MAX/2 - (index << 2); break; } } if (!score) return 0; }
/* Matching type is better than matching name */ if (type && type[0]) { if (!__of_node_is_type(device, type)) return 0; score += 2; }
/* Matching name is a bit better than not */ if (name && name[0]) { if (!of_node_name_eq(device, name)) return 0; score++; }
return score;}
/** Checks if the given "compat" string matches one of the strings in * the device's "compatible" property */int of_device_is_compatible(const struct device_node *device, const char *compat){ unsigned long flags; int res;
raw_spin_lock_irqsave(&devtree_lock, flags); res = __of_device_is_compatible(device, compat, NULL, NULL); raw_spin_unlock_irqrestore(&devtree_lock, flags); return res;}EXPORT_SYMBOL(of_device_is_compatible);
/** Checks if the device is compatible with any of the entries in * a NULL terminated array of strings. Returns the best match * score or 0. */int of_device_compatible_match(const struct device_node *device, const char *const *compat){ unsigned int tmp, score = 0;
if (!compat) return 0;
while (*compat) { tmp = of_device_is_compatible(device, *compat); if (tmp > score) score = tmp; compat++; }
return score;}EXPORT_SYMBOL_GPL(of_device_compatible_match);
/** * of_machine_compatible_match - Test root of device tree against a compatible array * @compats: NULL terminated array of compatible strings to look for in root node's compatible property. * * Returns true if the root node has any of the given compatible values in its * compatible property. */bool of_machine_compatible_match(const char *const *compats){ struct device_node *root; int rc = 0;
root = of_find_node_by_path("/"); if (root) { rc = of_device_compatible_match(root, compats); of_node_put(root); }
return rc != 0;}EXPORT_SYMBOL(of_machine_compatible_match);
/** * of_machine_read_compatible - Get the compatible string of this machine * @compatible: address at which the address of the compatible string will be * stored * @index: index of the compatible entry in the list * * Returns: * 0 on success, negative error number on failure. */int of_machine_read_compatible(const char **compatible, unsigned int index){ return of_property_read_string_index(of_root, "compatible", index, compatible);}EXPORT_SYMBOL_GPL(of_machine_read_compatible);
/** * of_machine_read_model - Get the model string of this machine * @model: address at which the address of the model string will be stored * * Returns: * 0 on success, negative error number on failure. */int of_machine_read_model(const char **model){ return of_property_read_string(of_root, "model", model);}EXPORT_SYMBOL_GPL(of_machine_read_model);
/** * of_machine_get_match - Test root of device tree against an of_device_id array * @matches: NULL terminated array of of_device_id match structures to search in * * Returns matched entry or NULL */const struct of_device_id *of_machine_get_match(const struct of_device_id *matches){ struct device_node *root; const struct of_device_id *match = NULL;
root = of_find_node_by_path("/"); if (root) { match = of_match_node(matches, root); of_node_put(root); }
return match;}EXPORT_SYMBOL(of_machine_get_match);
/** * of_machine_get_match_data - Tell if root of device tree has a matching of_match structure * @matches: NULL terminated array of of_device_id match structures to search in * * Returns data associated with matched entry or NULL */const void *of_machine_get_match_data(const struct of_device_id *matches){ const struct of_device_id *match;
match = of_machine_get_match(matches); if (!match) return NULL;
return match->data;}EXPORT_SYMBOL(of_machine_get_match_data);
static bool __of_device_is_status(const struct device_node *device, const char * const*strings){ const char *status; int statlen;
if (!device) return false;
status = __of_get_property(device, "status", &statlen); if (!status || statlen <= 0) return false; if (strnlen(status, statlen) >= statlen) return false;
while (*strings) { unsigned int len = strlen(*strings);
if ((*strings)[len - 1] == '-') { if (!strncmp(status, *strings, len)) return true; } else { if (!strcmp(status, *strings)) return true; } strings++; }
return false;}
/** * __of_device_is_available - check if a device is available for use * * @device: Node to check for availability, with locks already held * * Return: True if the status property is absent or set to "okay" or "ok", * false otherwise */static bool __of_device_is_available(const struct device_node *device){ static const char * const ok[] = {"okay", "ok", NULL};
if (!device) return false;
return !__of_get_property(device, "status", NULL) || __of_device_is_status(device, ok);}
/** * __of_device_is_reserved - check if a device is reserved * * @device: Node to check for availability, with locks already held * * Return: True if the status property is set to "reserved", false otherwise */static bool __of_device_is_reserved(const struct device_node *device){ static const char * const reserved[] = {"reserved", NULL};
return __of_device_is_status(device, reserved);}
/** * of_device_is_available - check if a device is available for use * * @device: Node to check for availability * * Return: True if the status property is absent or set to "okay" or "ok", * false otherwise */bool of_device_is_available(const struct device_node *device){ unsigned long flags; bool res;
raw_spin_lock_irqsave(&devtree_lock, flags); res = __of_device_is_available(device); raw_spin_unlock_irqrestore(&devtree_lock, flags); return res;
}EXPORT_SYMBOL(of_device_is_available);
/** * __of_device_is_fail - check if a device has status "fail" or "fail-..." * * @device: Node to check status for, with locks already held * * Return: True if the status property is set to "fail" or "fail-..." (for any * error code suffix), false otherwise */static bool __of_device_is_fail(const struct device_node *device){ static const char * const fail[] = {"fail", "fail-", NULL};
return __of_device_is_status(device, fail);}
/** * of_device_is_big_endian - check if a device has BE registers * * @device: Node to check for endianness * * Return: True if the device has a "big-endian" property, or if the kernel * was compiled for BE *and* the device has a "native-endian" property. * Returns false otherwise. * * Callers would nominally use ioread32be/iowrite32be if * of_device_is_big_endian() == true, or readl/writel otherwise. */bool of_device_is_big_endian(const struct device_node *device){ if (of_property_read_bool(device, "big-endian")) return true; if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && of_property_read_bool(device, "native-endian")) return true; return false;}EXPORT_SYMBOL(of_device_is_big_endian);
/** * of_get_parent - Get a node's parent if any * @node: Node to get parent * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_get_parent(const struct device_node *node){ struct device_node *np; unsigned long flags;
if (!node) return NULL;
raw_spin_lock_irqsave(&devtree_lock, flags); np = of_node_get(node->parent); raw_spin_unlock_irqrestore(&devtree_lock, flags); return np;}EXPORT_SYMBOL(of_get_parent);
/** * of_get_next_parent - Iterate to a node's parent * @node: Node to get parent of * * This is like of_get_parent() except that it drops the * refcount on the passed node, making it suitable for iterating * through a node's parents. * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_get_next_parent(struct device_node *node){ struct device_node *parent; unsigned long flags;
if (!node) return NULL;
raw_spin_lock_irqsave(&devtree_lock, flags); parent = of_node_get(node->parent); of_node_put(node); raw_spin_unlock_irqrestore(&devtree_lock, flags); return parent;}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;
if (!node) return NULL;
next = prev ? prev->sibling : node->child; of_node_get(next); 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 * @prev: previous child of the parent node, or NULL to get first * * Return: A node pointer with refcount incremented, use of_node_put() on * it when done. Returns NULL when prev is the last child. Decrements the * refcount of prev. */struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev){ struct device_node *next; unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags); next = __of_get_next_child(node, prev); raw_spin_unlock_irqrestore(&devtree_lock, flags); return next;}EXPORT_SYMBOL(of_get_next_child);
/** * of_get_next_child_with_prefix - Find the next child node with prefix * @node: parent node * @prev: previous child of the parent node, or NULL to get first * @prefix: prefix that the node name should have * * This function is like of_get_next_child(), except that it automatically * skips any nodes whose name doesn't have the given prefix. * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_get_next_child_with_prefix(const struct device_node *node, struct device_node *prev, const char *prefix){ struct device_node *next; unsigned long flags;
if (!node) return NULL;
raw_spin_lock_irqsave(&devtree_lock, flags); next = prev ? prev->sibling : node->child; for (; next; next = next->sibling) { if (!of_node_name_prefix(next, prefix)) continue; if (of_node_get(next)) break; } of_node_put(prev); raw_spin_unlock_irqrestore(&devtree_lock, flags); return next;}EXPORT_SYMBOL(of_get_next_child_with_prefix);
static struct device_node *of_get_next_status_child(const struct device_node *node, struct device_node *prev, bool (*checker)(const struct device_node *)){ struct device_node *next; unsigned long flags;
if (!node) return NULL;
raw_spin_lock_irqsave(&devtree_lock, flags); next = prev ? prev->sibling : node->child; for (; next; next = next->sibling) { if (!checker(next)) continue; if (of_node_get(next)) break; } of_node_put(prev); raw_spin_unlock_irqrestore(&devtree_lock, flags); return next;}
/** * of_get_next_available_child - Find the next available child node * @node: parent node * @prev: previous child of the parent node, or NULL to get first * * This function is like of_get_next_child(), except that it * automatically skips any disabled nodes (i.e. status = "disabled"). */struct device_node *of_get_next_available_child(const struct device_node *node, struct device_node *prev){ return of_get_next_status_child(node, prev, __of_device_is_available);}EXPORT_SYMBOL(of_get_next_available_child);
/** * of_get_next_reserved_child - Find the next reserved child node * @node: parent node * @prev: previous child of the parent node, or NULL to get first * * This function is like of_get_next_child(), except that it * automatically skips any disabled nodes (i.e. status = "disabled"). */struct device_node *of_get_next_reserved_child(const struct device_node *node, struct device_node *prev){ return of_get_next_status_child(node, prev, __of_device_is_reserved);}EXPORT_SYMBOL(of_get_next_reserved_child);
/** * of_get_next_cpu_node - Iterate on cpu nodes * @prev: previous child of the /cpus node, or NULL to get first * * Unusable CPUs (those with the status property set to "fail" or "fail-...") * will be skipped. * * Return: A cpu node pointer with refcount incremented, use of_node_put() * on it when done. Returns NULL when prev is the last child. Decrements * the refcount of prev. */struct device_node *of_get_next_cpu_node(struct device_node *prev){ struct device_node *next = NULL; unsigned long flags; struct device_node *node;
if (!prev) node = of_find_node_by_path("/cpus");
raw_spin_lock_irqsave(&devtree_lock, flags); if (prev) next = prev->sibling; else if (node) { next = node->child; of_node_put(node); } for (; next; next = next->sibling) { if (__of_device_is_fail(next)) continue; if (!(of_node_name_eq(next, "cpu") || __of_node_is_type(next, "cpu"))) continue; if (of_node_get(next)) break; } of_node_put(prev); raw_spin_unlock_irqrestore(&devtree_lock, flags); return next;}EXPORT_SYMBOL(of_get_next_cpu_node);
/** * of_get_compatible_child - Find compatible child node * @parent: parent node * @compatible: compatible string * * Lookup child node whose compatible property contains the given compatible * string. * * Return: a node pointer with refcount incremented, use of_node_put() on it * when done; or NULL if not found. */struct device_node *of_get_compatible_child(const struct device_node *parent, const char *compatible){ struct device_node *child;
for_each_child_of_node(parent, child) { if (of_device_is_compatible(child, compatible)) break; }
return child;}EXPORT_SYMBOL(of_get_compatible_child);
/** * of_get_child_by_name - Find the child node by name for a given parent * @node: parent node * @name: child name to look for. * * This function looks for child node for given matching name * * Return: A node pointer if found, with refcount incremented, use * of_node_put() on it when done. * Returns NULL if node is not found. */struct device_node *of_get_child_by_name(const struct device_node *node, const char *name){ struct device_node *child;
for_each_child_of_node(node, child) if (of_node_name_eq(child, name)) break; return child;}EXPORT_SYMBOL(of_get_child_by_name);
/** * of_get_available_child_by_name - Find the available child node by name for a given parent * @node: parent node * @name: child name to look for. * * This function looks for child node for given matching name and checks the * device's availability for use. * * Return: A node pointer if found, with refcount incremented, use * of_node_put() on it when done. * Returns NULL if node is not found. */struct device_node *of_get_available_child_by_name(const struct device_node *node, const char *name){ struct device_node *child;
child = of_get_child_by_name(node, name); if (child && !of_device_is_available(child)) { of_node_put(child); return NULL; }
return child;}EXPORT_SYMBOL(of_get_available_child_by_name);
struct device_node *__of_find_node_by_path(const struct device_node *parent, const char *path){ struct device_node *child; int len;
len = strcspn(path, "/:"); if (!len) return NULL;
__for_each_child_of_node(parent, child) { const char *name = kbasename(child->full_name); if (strncmp(path, name, len) == 0 && (strlen(name) == len)) return child; } return NULL;}
struct device_node *__of_find_node_by_full_path(struct device_node *node, const char *path){ const char *separator = strchr(path, ':');
while (node && *path == '/') { struct device_node *tmp = node;
path++; /* Increment past '/' delimiter */ node = __of_find_node_by_path(node, path); of_node_put(tmp); path = strchrnul(path, '/'); if (separator && separator < path) break; } return node;}
/** * of_find_node_opts_by_path - Find a node matching a full OF path * @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. * @opts: Address of a pointer into which to store the start of * an options string appended to the end of the path with * a ':' separator. * * Valid paths: * * /foo/bar Full path * * foo Valid alias * * foo/bar Valid alias + relative path * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_find_node_opts_by_path(const char *path, const char **opts){ struct device_node *np = NULL; const struct property *pp; unsigned long flags; const char *separator = strchr(path, ':');
if (opts) *opts = separator ? separator + 1 : NULL;
if (strcmp(path, "/") == 0) return of_node_get(of_root);
/* The path could begin with an alias */ if (*path != '/') { int len; const char *p = strchrnul(path, '/');
if (separator && separator < p) p = separator; 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); if (!np) np = of_node_get(of_root); np = __of_find_node_by_full_path(np, path); raw_spin_unlock_irqrestore(&devtree_lock, flags); return np;}EXPORT_SYMBOL(of_find_node_opts_by_path);
/** * of_find_node_by_name - Find a node by its "name" property * @from: The node to start searching from or NULL; the node * you pass will not be searched, only the next one * will. Typically, you pass what the previous call * returned. of_node_put() will be called on @from. * @name: The name string to match against * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_find_node_by_name(struct device_node *from, const char *name){ struct device_node *np; unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags); for_each_of_allnodes_from(from, np) if (of_node_name_eq(np, name) && of_node_get(np)) break; of_node_put(from); raw_spin_unlock_irqrestore(&devtree_lock, flags); return np;}EXPORT_SYMBOL(of_find_node_by_name);
/** * of_find_node_by_type - Find a node by its "device_type" property * @from: The node to start searching from, or NULL to start searching * the entire device tree. The node you pass will not be * searched, only the next one will; typically, you pass * what the previous call returned. of_node_put() will be * called on from for you. * @type: The type string to match against * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_find_node_by_type(struct device_node *from, const char *type){ struct device_node *np; unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags); for_each_of_allnodes_from(from, np) if (__of_node_is_type(np, type) && of_node_get(np)) break; of_node_put(from); raw_spin_unlock_irqrestore(&devtree_lock, flags); return np;}EXPORT_SYMBOL(of_find_node_by_type);
/** * of_find_compatible_node - Find a node based on type and one of the * tokens in its "compatible" property * @from: The node to start searching from or NULL, the node * you pass will not be searched, only the next one * will; typically, you pass what the previous call * returned. of_node_put() will be called on it * @type: The type string to match "device_type" or NULL to ignore * @compatible: The string to match to one of the tokens in the device * "compatible" list. * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible){ struct device_node *np; unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags); for_each_of_allnodes_from(from, np) if (__of_device_is_compatible(np, compatible, type, NULL) && of_node_get(np)) break; of_node_put(from); raw_spin_unlock_irqrestore(&devtree_lock, flags); return np;}EXPORT_SYMBOL(of_find_compatible_node);
/** * of_find_node_with_property - Find a node which has a property with * the given name. * @from: The node to start searching from or NULL, the node * you pass will not be searched, only the next one * will; typically, you pass what the previous call * returned. of_node_put() will be called on it * @prop_name: The name of the property to look for. * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_find_node_with_property(struct device_node *from, const char *prop_name){ struct device_node *np; unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags); for_each_of_allnodes_from(from, np) { if (__of_find_property(np, prop_name, NULL)) { of_node_get(np); break; } } of_node_put(from); raw_spin_unlock_irqrestore(&devtree_lock, flags); return np;}EXPORT_SYMBOL(of_find_node_with_property);
staticconst struct of_device_id *__of_match_node(const struct of_device_id *matches, const struct device_node *node){ const struct of_device_id *best_match = NULL; int score, best_score = 0;
if (!matches) return NULL;
for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) { score = __of_device_is_compatible(node, matches->compatible, matches->type, matches->name); if (score > best_score) { best_match = matches; best_score = score; } }
return best_match;}
/** * of_match_node - Tell if a device_node has a matching of_match structure * @matches: array of of device match structures to search in * @node: the of device structure to match against * * Low level utility function used by device matching. */const struct of_device_id *of_match_node(const struct of_device_id *matches, const struct device_node *node){ const struct of_device_id *match; unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags); match = __of_match_node(matches, node); raw_spin_unlock_irqrestore(&devtree_lock, flags); return match;}EXPORT_SYMBOL(of_match_node);
/** * of_find_matching_node_and_match - Find a node based on an of_device_id * match table. * @from: The node to start searching from or NULL, the node * you pass will not be searched, only the next one * will; typically, you pass what the previous call * returned. of_node_put() will be called on it * @matches: array of of device match structures to search in * @match: Updated to point at the matches entry which matched * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_find_matching_node_and_match(struct device_node *from, const struct of_device_id *matches, const struct of_device_id **match){ struct device_node *np; const struct of_device_id *m; unsigned long flags;
if (match) *match = NULL;
raw_spin_lock_irqsave(&devtree_lock, flags); for_each_of_allnodes_from(from, np) { m = __of_match_node(matches, np); if (m && of_node_get(np)) { if (match) *match = m; break; } } of_node_put(from); raw_spin_unlock_irqrestore(&devtree_lock, flags); return np;}EXPORT_SYMBOL(of_find_matching_node_and_match);
/** * of_alias_from_compatible - Lookup appropriate alias for a device node * depending on compatible * @node: pointer to a device tree node * @alias: Pointer to buffer that alias value will be copied into * @len: Length of alias value * * Based on the value of the compatible property, this routine will attempt * to choose an appropriate alias value for a particular device tree node. * It does this by stripping the manufacturer prefix (as delimited by a ',') * from the first entry in the compatible list property. * * Note: The matching on just the "product" side of the compatible is a relic * from I2C and SPI. Please do not add any new user. * * Return: This routine returns 0 on success, <0 on failure. */int of_alias_from_compatible(const struct device_node *node, char *alias, int len){ const char *compatible, *p; int ret;
ret = of_property_read_string_index(node, "compatible", 0, &compatible); if (ret) return -ENODEV; p = strchr(compatible, ','); strscpy(alias, p ? p + 1 : compatible, len); return 0;}EXPORT_SYMBOL_GPL(of_alias_from_compatible);
/** * of_find_node_by_phandle - Find a node given a phandle * @handle: phandle of the node to find * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_find_node_by_phandle(phandle handle){ struct device_node *np = NULL; unsigned long flags; u32 handle_hash;
if (!handle) return NULL;
handle_hash = of_phandle_cache_hash(handle);
raw_spin_lock_irqsave(&devtree_lock, flags);
if (phandle_cache[handle_hash] && handle == phandle_cache[handle_hash]->phandle) np = phandle_cache[handle_hash];
if (!np) { for_each_of_allnodes(np) if (np->phandle == handle && !of_node_check_flag(np, OF_DETACHED)) { phandle_cache[handle_hash] = np; break; } }
of_node_get(np); raw_spin_unlock_irqrestore(&devtree_lock, flags); return np;}EXPORT_SYMBOL(of_find_node_by_phandle);
void of_print_phandle_args(const char *msg, const struct of_phandle_args *args){ int i; printk("%s %pOF", msg, args->np); for (i = 0; i < args->args_count; i++) { const char delim = i ? ',' : ':';
pr_cont("%c%08x", delim, args->args[i]); } pr_cont("\n");}
int of_phandle_iterator_init(struct of_phandle_iterator *it, const struct device_node *np, const char *list_name, const char *cells_name, int cell_count){ const __be32 *list; int size;
memset(it, 0, sizeof(*it));
/* * one of cell_count or cells_name must be provided to determine the * argument length. */ if (cell_count < 0 && !cells_name) return -EINVAL;
list = of_get_property(np, list_name, &size); if (!list) return -ENOENT;
it->cells_name = cells_name; it->cell_count = cell_count; it->parent = np; it->list_end = list + size / sizeof(*list); it->phandle_end = list; it->cur = list;
return 0;}EXPORT_SYMBOL_GPL(of_phandle_iterator_init);
int of_phandle_iterator_next(struct of_phandle_iterator *it){ uint32_t count = 0;
if (it->node) { of_node_put(it->node); it->node = NULL; }
if (!it->cur || it->phandle_end >= it->list_end) return -ENOENT;
it->cur = it->phandle_end;
/* If phandle is 0, then it is an empty entry with no arguments. */ it->phandle = be32_to_cpup(it->cur++);
if (it->phandle) {
/* * Find the provider node and parse the #*-cells property to * determine the argument length. */ it->node = of_find_node_by_phandle(it->phandle);
if (it->cells_name) { if (!it->node) { pr_err("%pOF: could not find phandle %d\n", it->parent, it->phandle); goto err; }
if (of_property_read_u32(it->node, it->cells_name, &count)) { /* * If both cell_count and cells_name is given, * fall back to cell_count in absence * of the cells_name property */ if (it->cell_count >= 0) { count = it->cell_count; } else { pr_err("%pOF: could not get %s for %pOF\n", it->parent, it->cells_name, it->node); goto err; } } } else { count = it->cell_count; }
/* * Make sure that the arguments actually fit in the remaining * property data length */ if (it->cur + count > it->list_end) { if (it->cells_name) pr_err("%pOF: %s = %d found %td\n", it->parent, it->cells_name, count, it->list_end - it->cur); else pr_err("%pOF: phandle %s needs %d, found %td\n", it->parent, of_node_full_name(it->node), count, it->list_end - it->cur); goto err; } }
it->phandle_end = it->cur + count; it->cur_count = count;
return 0;
err: if (it->node) { of_node_put(it->node); it->node = NULL; }
return -EINVAL;}EXPORT_SYMBOL_GPL(of_phandle_iterator_next);
int of_phandle_iterator_args(struct of_phandle_iterator *it, uint32_t *args, int size){ int i, count;
count = it->cur_count;
if (WARN_ON(size < count)) count = size;
for (i = 0; i < count; i++) args[i] = be32_to_cpup(it->cur++);
return count;}
int __of_parse_phandle_with_args(const struct device_node *np, const char *list_name, const char *cells_name, int cell_count, int index, struct of_phandle_args *out_args){ struct of_phandle_iterator it; int rc, cur_index = 0;
if (index < 0) return -EINVAL;
/* Loop over the phandles until all the requested entry is found */ of_for_each_phandle(&it, rc, np, list_name, cells_name, cell_count) { /* * All of the error cases bail out of the loop, so at * this point, the parsing is successful. If the requested * index matches, then fill the out_args structure and return, * or return -ENOENT for an empty entry. */ rc = -ENOENT; if (cur_index == index) { if (!it.phandle) goto err;
if (out_args) { int c;
c = of_phandle_iterator_args(&it, out_args->args, MAX_PHANDLE_ARGS); out_args->np = it.node; out_args->args_count = c; } else { of_node_put(it.node); }
/* Found it! return success */ return 0; }
cur_index++; }
/* * Unlock node before returning result; will be one of: * -ENOENT : index is for empty phandle * -EINVAL : parsing error on data */
err: of_node_put(it.node); return rc;}EXPORT_SYMBOL(__of_parse_phandle_with_args);
/** * of_parse_phandle_with_args_map() - Find a node pointed by phandle in a list and remap it * @np: pointer to a device tree node containing a list * @list_name: property name that contains a list * @stem_name: stem of property names that specify phandles' arguments count * @index: index of a phandle to parse out * @out_args: optional pointer to output arguments structure (will be filled) * * This function is useful to parse lists of phandles and their arguments. * Returns 0 on success and fills out_args, on error returns appropriate errno * value. The difference between this function and of_parse_phandle_with_args() * is that this API remaps a phandle if the node the phandle points to has * a <@stem_name>-map property. * * Caller is responsible to call of_node_put() on the returned out_args->np * pointer. * * Example:: * * phandle1: node1 { * #list-cells = <2>; * }; * * phandle2: node2 { * #list-cells = <1>; * }; * * phandle3: node3 { * #list-cells = <1>; * list-map = <0 &phandle2 3>, * <1 &phandle2 2>, * <2 &phandle1 5 1>; * list-map-mask = <0x3>; * }; * * node4 { * list = <&phandle1 1 2 &phandle3 0>; * }; * * To get a device_node of the ``node2`` node you may call this: * of_parse_phandle_with_args(node4, "list", "list", 1, &args); */int of_parse_phandle_with_args_map(const struct device_node *np, const char *list_name, const char *stem_name, int index, struct of_phandle_args *out_args){ char *cells_name __free(kfree) = kasprintf(GFP_KERNEL, "#%s-cells", stem_name); char *map_name __free(kfree) = kasprintf(GFP_KERNEL, "%s-map", stem_name); char *mask_name __free(kfree) = kasprintf(GFP_KERNEL, "%s-map-mask", stem_name); char *pass_name __free(kfree) = kasprintf(GFP_KERNEL, "%s-map-pass-thru", stem_name); struct device_node *cur, *new = NULL; const __be32 *map, *mask, *pass; static const __be32 dummy_mask[] = { [0 ... (MAX_PHANDLE_ARGS - 1)] = cpu_to_be32(~0) }; static const __be32 dummy_pass[] = { [0 ... (MAX_PHANDLE_ARGS - 1)] = cpu_to_be32(0) }; __be32 initial_match_array[MAX_PHANDLE_ARGS]; const __be32 *match_array = initial_match_array; int i, ret, map_len, match; u32 list_size, new_size;
if (index < 0) return -EINVAL;
if (!cells_name || !map_name || !mask_name || !pass_name) return -ENOMEM;
ret = __of_parse_phandle_with_args(np, list_name, cells_name, -1, index, out_args); if (ret) return ret;
/* Get the #<list>-cells property */ cur = out_args->np; ret = of_property_read_u32(cur, cells_name, &list_size); if (ret < 0) goto put;
/* Precalculate the match array - this simplifies match loop */ for (i = 0; i < list_size; i++) initial_match_array[i] = cpu_to_be32(out_args->args[i]);
ret = -EINVAL; while (cur) { /* Get the <list>-map property */ map = of_get_property(cur, map_name, &map_len); if (!map) { return 0; } map_len /= sizeof(u32);
/* Get the <list>-map-mask property (optional) */ mask = of_get_property(cur, mask_name, NULL); if (!mask) mask = dummy_mask; /* Iterate through <list>-map property */ match = 0; while (map_len > (list_size + 1) && !match) { /* Compare specifiers */ match = 1; for (i = 0; i < list_size; i++, map_len--) match &= !((match_array[i] ^ *map++) & mask[i]);
of_node_put(new); new = of_find_node_by_phandle(be32_to_cpup(map)); map++; map_len--;
/* Check if not found */ if (!new) { ret = -EINVAL; goto put; }
if (!of_device_is_available(new)) match = 0;
ret = of_property_read_u32(new, cells_name, &new_size); if (ret) goto put;
/* Check for malformed properties */ if (WARN_ON(new_size > MAX_PHANDLE_ARGS) || map_len < new_size) { ret = -EINVAL; goto put; }
/* Move forward by new node's #<list>-cells amount */ map += new_size; map_len -= new_size; } if (!match) { ret = -ENOENT; goto put; }
/* Get the <list>-map-pass-thru property (optional) */ pass = of_get_property(cur, pass_name, NULL); if (!pass) pass = dummy_pass;
/* * Successfully parsed a <list>-map translation; copy new * specifier into the out_args structure, keeping the * bits specified in <list>-map-pass-thru. */ for (i = 0; i < new_size; i++) { __be32 val = *(map - new_size + i);
if (i < list_size) { val &= ~pass[i]; val |= cpu_to_be32(out_args->args[i]) & pass[i]; }
initial_match_array[i] = val; out_args->args[i] = be32_to_cpu(val); } out_args->args_count = list_size = new_size; /* Iterate again with new provider */ out_args->np = new; of_node_put(cur); cur = new; new = NULL; }put: of_node_put(cur); of_node_put(new); return ret;}EXPORT_SYMBOL(of_parse_phandle_with_args_map);
/** * of_count_phandle_with_args() - Find the number of phandles references in a property * @np: pointer to a device tree node containing a list * @list_name: property name that contains a list * @cells_name: property name that specifies phandles' arguments count * * Return: The number of phandle + argument tuples within a property. It * is a typical pattern to encode a list of phandle and variable * arguments into a single property. The number of arguments is encoded * by a property in the phandle-target node. For example, a gpios * property would contain a list of GPIO specifies consisting of a * phandle and 1 or more arguments. The number of arguments are * determined by the #gpio-cells property in the node pointed to by the * phandle. */int of_count_phandle_with_args(const struct device_node *np, const char *list_name, const char *cells_name){ struct of_phandle_iterator it; int rc, cur_index = 0;
/* * If cells_name is NULL we assume a cell count of 0. This makes * counting the phandles trivial as each 32bit word in the list is a * phandle and no arguments are to consider. So we don't iterate through * the list but just use the length to determine the phandle count. */ if (!cells_name) { const __be32 *list; int size;
list = of_get_property(np, list_name, &size); if (!list) return -ENOENT;
return size / sizeof(*list); }
rc = of_phandle_iterator_init(&it, np, list_name, cells_name, -1); if (rc) return rc;
while ((rc = of_phandle_iterator_next(&it)) == 0) cur_index += 1;
if (rc != -ENOENT) return rc;
return cur_index;}EXPORT_SYMBOL(of_count_phandle_with_args);
static struct property *__of_remove_property_from_list(struct property **list, struct property *prop){ struct property **next;
for (next = list; *next; next = &(*next)->next) { if (*next == prop) { *next = prop->next; prop->next = NULL; return prop; } } return NULL;}
/** * __of_add_property - Add a property to a node without lock operations * @np: Caller's Device Node * @prop: Property to add */int __of_add_property(struct device_node *np, struct property *prop){ int rc = 0; unsigned long flags; struct property **next;
raw_spin_lock_irqsave(&devtree_lock, flags);
__of_remove_property_from_list(&np->deadprops, prop);
prop->next = NULL; next = &np->properties; while (*next) { if (of_prop_cmp(prop->name, (*next)->name) == 0) { /* duplicate ! don't insert it */ rc = -EEXIST; goto out_unlock; } next = &(*next)->next; } *next = prop;
out_unlock: raw_spin_unlock_irqrestore(&devtree_lock, flags); if (rc) return rc;
__of_add_property_sysfs(np, prop); return 0;}
/** * of_add_property - Add a property to a node * @np: Caller's Device Node * @prop: Property to add */int of_add_property(struct device_node *np, struct property *prop){ int rc;
mutex_lock(&of_mutex); rc = __of_add_property(np, prop); mutex_unlock(&of_mutex);
if (!rc) of_property_notify(OF_RECONFIG_ADD_PROPERTY, np, prop, NULL);
return rc;}EXPORT_SYMBOL_GPL(of_add_property);
int __of_remove_property(struct device_node *np, struct property *prop){ unsigned long flags; int rc = -ENODEV;
raw_spin_lock_irqsave(&devtree_lock, flags);
if (__of_remove_property_from_list(&np->properties, prop)) { /* Found the property, add it to deadprops list */ prop->next = np->deadprops; np->deadprops = prop; rc = 0; }
raw_spin_unlock_irqrestore(&devtree_lock, flags); if (rc) return rc;
__of_remove_property_sysfs(np, prop); return 0;}
/** * of_remove_property - Remove a property from a node. * @np: Caller's Device Node * @prop: Property to remove * * Note that we don't actually remove it, since we have given out * who-knows-how-many pointers to the data using get-property. * Instead we just move the property to the "dead properties" * list, so it won't be found any more. */int of_remove_property(struct device_node *np, struct property *prop){ int rc;
if (!prop) return -ENODEV;
mutex_lock(&of_mutex); rc = __of_remove_property(np, prop); mutex_unlock(&of_mutex);
if (!rc) of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop, NULL);
return rc;}EXPORT_SYMBOL_GPL(of_remove_property);
int __of_update_property(struct device_node *np, struct property *newprop, struct property **oldpropp){ struct property **next, *oldprop; unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags);
__of_remove_property_from_list(&np->deadprops, newprop);
for (next = &np->properties; *next; next = &(*next)->next) { if (of_prop_cmp((*next)->name, newprop->name) == 0) break; } *oldpropp = oldprop = *next;
if (oldprop) { /* replace the node */ newprop->next = oldprop->next; *next = newprop; oldprop->next = np->deadprops; np->deadprops = oldprop; } else { /* new node */ newprop->next = NULL; *next = newprop; }
raw_spin_unlock_irqrestore(&devtree_lock, flags);
__of_update_property_sysfs(np, newprop, oldprop);
return 0;}
/* * of_update_property - Update a property in a node, if the property does * not exist, add it. * * Note that we don't actually remove it, since we have given out * who-knows-how-many pointers to the data using get-property. * Instead we just move the property to the "dead properties" list, * and add the new property to the property list */int of_update_property(struct device_node *np, struct property *newprop){ struct property *oldprop; int rc;
if (!newprop->name) return -EINVAL;
mutex_lock(&of_mutex); rc = __of_update_property(np, newprop, &oldprop); mutex_unlock(&of_mutex);
if (!rc) of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop, oldprop);
return rc;}
static void of_alias_add(struct alias_prop *ap, struct device_node *np, int id, const char *stem, int stem_len){ ap->np = np; ap->id = id; strscpy(ap->stem, stem, stem_len + 1); list_add_tail(&ap->link, &aliases_lookup); pr_debug("adding DT alias:%s: stem=%s id=%i node=%pOF\n", ap->alias, ap->stem, ap->id, np);}
/** * of_alias_scan - Scan all properties of the 'aliases' node * @dt_alloc: An allocator that provides a virtual address to memory * for storing the resulting tree * * The function scans all the properties of the 'aliases' node and populates * the global lookup table with the properties. */void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)){ const struct property *pp;
of_aliases = of_find_node_by_path("/aliases"); of_chosen = of_find_node_by_path("/chosen"); if (of_chosen == NULL) of_chosen = of_find_node_by_path("/chosen@0");
if (of_chosen) { /* linux,stdout-path and /aliases/stdout are for legacy compatibility */ const char *name = NULL;
if (of_property_read_string(of_chosen, "stdout-path", &name)) of_property_read_string(of_chosen, "linux,stdout-path", &name); if (IS_ENABLED(CONFIG_PPC) && !name) of_property_read_string(of_aliases, "stdout", &name); if (name) of_stdout = of_find_node_opts_by_path(name, &of_stdout_options); if (of_stdout) fwnode_set_flag(&of_stdout->fwnode, FWNODE_FLAG_BEST_EFFORT); }
if (!of_aliases) return;
for_each_property_of_node(of_aliases, pp) { const char *start = pp->name; const char *end = start + strlen(start); struct device_node *np; struct alias_prop *ap; int id, len;
/* Skip those we do not want to proceed */ if (is_pseudo_property(pp->name)) continue;
np = of_find_node_by_path(pp->value); if (!np) continue;
/* walk the alias backwards to extract the id and work out * the 'stem' string */ while (isdigit(*(end-1)) && end > start) end--; len = end - start;
if (kstrtoint(end, 10, &id) < 0) { of_node_put(np); continue; }
/* Allocate an alias_prop with enough space for the stem */ ap = dt_alloc(sizeof(*ap) + len + 1, __alignof__(*ap)); if (!ap) { of_node_put(np); continue; } memset(ap, 0, sizeof(*ap) + len + 1); ap->alias = start; of_alias_add(ap, np, id, start, len); }}
/** * of_alias_get_id - Get alias id for the given device_node * @np: Pointer to the given device_node * @stem: Alias stem of the given device_node * * The function travels the lookup table to get the alias id for the given * device_node and alias stem. * * Return: The alias id if found. */int of_alias_get_id(const struct device_node *np, const char *stem){ struct alias_prop *app; int id = -ENODEV;
mutex_lock(&of_mutex); list_for_each_entry(app, &aliases_lookup, link) { if (strcmp(app->stem, stem) != 0) continue;
if (np == app->np) { id = app->id; break; } } mutex_unlock(&of_mutex);
return id;}EXPORT_SYMBOL_GPL(of_alias_get_id);
/** * of_alias_get_highest_id - Get highest alias id for the given stem * @stem: Alias stem to be examined * * The function travels the lookup table to get the highest alias id for the * given alias stem. It returns the alias id if found. */int of_alias_get_highest_id(const char *stem){ struct alias_prop *app; int id = -ENODEV;
mutex_lock(&of_mutex); list_for_each_entry(app, &aliases_lookup, link) { if (strcmp(app->stem, stem) != 0) continue;
if (app->id > id) id = app->id; } mutex_unlock(&of_mutex);
return id;}EXPORT_SYMBOL_GPL(of_alias_get_highest_id);
/** * of_console_check() - Test and setup console for DT setup * @dn: Pointer to device node * @name: Name to use for preferred console without index. ex. "ttyS" * @index: Index to use for preferred console. * * Check if the given device node matches the stdout-path property in the * /chosen node. If it does then register it as the preferred console. * * Return: TRUE if console successfully setup. Otherwise return FALSE. */bool of_console_check(const struct device_node *dn, char *name, int index){ if (!dn || dn != of_stdout || console_set_on_cmdline) return false;
/* * XXX: cast `options' to char pointer to suppress complication * warnings: printk, UART and console drivers expect char pointer. */ return !add_preferred_console(name, index, (char *)of_stdout_options);}EXPORT_SYMBOL_GPL(of_console_check);
/** * of_find_next_cache_node - Find a node's subsidiary cache * @np: node of type "cpu" or "cache" * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done. Caller should hold a reference * to np. */struct device_node *of_find_next_cache_node(const struct device_node *np){ struct device_node *child, *cache_node;
cache_node = of_parse_phandle(np, "l2-cache", 0); if (!cache_node) cache_node = of_parse_phandle(np, "next-level-cache", 0);
if (cache_node) return cache_node;
/* OF on pmac has nodes instead of properties named "l2-cache" * beneath CPU nodes. */ if (IS_ENABLED(CONFIG_PPC_PMAC) && of_node_is_type(np, "cpu")) for_each_child_of_node(np, child) if (of_node_is_type(child, "cache")) return child;
return NULL;}
/** * of_find_last_cache_level - Find the level at which the last cache is * present for the given logical cpu * * @cpu: cpu number(logical index) for which the last cache level is needed * * Return: The level at which the last cache is present. It is exactly * same as the total number of cache levels for the given logical cpu. */int of_find_last_cache_level(unsigned int cpu){ u32 cache_level = 0; struct device_node *prev = NULL, *np = of_cpu_device_node_get(cpu);
while (np) { of_node_put(prev); prev = np; np = of_find_next_cache_node(np); }
of_property_read_u32(prev, "cache-level", &cache_level); of_node_put(prev);
return cache_level;}
/* * Some DTs have an iommu-map targeting a 2-cell IOMMU node while * specifying only 1 cell. Fortunately they all consist of value '1' * as the 2nd cell entry with the same target, so check for that pattern. * * Example: * IOMMU node: * #iommu-cells = <2>; * * Device node: * iommu-map = <0x0000 &smmu 0x0000 0x1>, * <0x0100 &smmu 0x0100 0x1>; */static bool of_check_bad_map(const __be32 *map, int len){ __be32 phandle = map[1];
if (len % 4) return false; for (int i = 0; i < len; i += 4) { if (map[i + 1] != phandle || map[i + 3] != cpu_to_be32(1)) return false; } return true;}
/** * of_map_id - Translate an ID through a downstream mapping. * @np: root complex device node. * @id: device ID to map. * @map_name: property name of the map to use. * @cells_name: property name of target specifier cells. * @map_mask_name: optional property name of the mask to use. * @filter_np: pointer to an optional filter node, or NULL to allow bypass. * If non-NULL, the map property must exist (-ENODEV if absent). If * ``*filter_np`` is also non-NULL, only entries targeting that node match. * @arg: pointer to a &struct of_phandle_args for the result. On success, * @arg->args_count will be set to the number of output specifier cells * as defined by @cells_name in the target node, and * @arg->args[0..args_count-1] will contain the translated output * specifier values. If a map entry was matched, @arg->np will be set * to the target node with a reference held that the caller must release * with of_node_put(). * * Given a device ID, look up the appropriate implementation-defined * platform ID and/or the target device which receives transactions on that * ID, as per the "iommu-map" and "msi-map" bindings. * * Return: 0 on success or a standard error code on failure. */int of_map_id(const struct device_node *np, u32 id, const char *map_name, const char *cells_name, const char *map_mask_name, struct device_node * const *filter_np, struct of_phandle_args *arg){ u32 map_mask, masked_id; int map_bytes, map_len, offset = 0; bool bad_map = false; const __be32 *map = NULL;
if (!np || !map_name || !cells_name || !arg) return -EINVAL; /* Ensure bypass/no-match success never returns a stale target node. */ arg->np = NULL;
map = of_get_property(np, map_name, &map_bytes); if (!map) { if (filter_np) return -ENODEV; /* Otherwise, no map implies no translation */ arg->args[0] = id; arg->args_count = 1; return 0; }
if (map_bytes % sizeof(*map)) goto err_map_len; map_len = map_bytes / sizeof(*map);
/* The default is to select all bits. */ map_mask = 0xffffffff;
/* * Can be overridden by "{iommu,msi}-map-mask" property. * If of_property_read_u32() fails, the default is used. */ if (map_mask_name) of_property_read_u32(np, map_mask_name, &map_mask);
masked_id = map_mask & id;
while (offset < map_len) { struct device_node *phandle_node; u32 id_base, phandle, id_len, id_off, cells = 0; const __be32 *out_base;
if (map_len - offset < 2) goto err_map_len;
id_base = be32_to_cpup(map + offset);
if (id_base & ~map_mask) { pr_err("%pOF: Invalid %s translation - %s (0x%x) ignores id-base (0x%x)\n", np, map_name, map_mask_name, map_mask, id_base); return -EFAULT; }
phandle = be32_to_cpup(map + offset + 1); phandle_node = of_find_node_by_phandle(phandle); if (!phandle_node) return -ENODEV;
/* * Assume 1-cell output specifier if the target node lacks the * #cells property, for backward compatibility with controllers * that predate the property (e.g. arm,gic-v2m-frame). */ if (bad_map || of_property_read_u32(phandle_node, cells_name, &cells)) cells = 1;
if (cells > MAX_PHANDLE_ARGS) { pr_err("%pOF: %s cell count %d exceeds maximum\n", phandle_node, cells_name, cells); of_node_put(phandle_node); return -EINVAL; }
if (offset == 0 && cells == 2) { bad_map = of_check_bad_map(map, map_len); if (bad_map) { pr_warn_once("%pOF: %s has 1-cell entries targeting 2-cell %s, treating as 1-cell output\n", np, map_name, cells_name); cells = 1; } }
if (map_len - offset < 3 + cells) { of_node_put(phandle_node); goto err_map_len; }
out_base = map + offset + 2; offset += 3 + cells;
id_len = be32_to_cpup(map + offset - 1); id_off = masked_id - id_base; if (masked_id < id_base || id_off >= id_len) { of_node_put(phandle_node); continue; } if (id_len > 1 && cells > 1) { /* * With 1 output cell we reasonably assume its value * has a linear relationship to the input; with more, * we'd need help from the provider to know what to do. */ pr_err("%pOF: Unsupported %s - cannot handle %d-ID range with %d-cell output specifier\n", np, map_name, id_len, cells); of_node_put(phandle_node); return -EINVAL; }
if (filter_np && *filter_np && *filter_np != phandle_node) { of_node_put(phandle_node); continue; }
arg->np = phandle_node; for (int i = 0; i < cells; i++) arg->args[i] = id_off + be32_to_cpu(out_base[i]); arg->args_count = cells;
pr_debug("%pOF: %s, using mask %08x, id-base: %08x, out-base: %08x, length: %08x, id: %08x -> %08x\n", np, map_name, map_mask, id_base, cells ? be32_to_cpup(out_base) : 0, id_len, id, cells ? id_off + be32_to_cpup(out_base) : id_off); return 0; }
pr_info("%pOF: no %s translation for id 0x%x on %pOF\n", np, map_name, id, filter_np && *filter_np ? *filter_np : NULL);
/* Bypasses translation */ arg->args[0] = id; arg->args_count = 1; return 0;
err_map_len: pr_err("%pOF: Error: Bad %s length: %d\n", np, map_name, map_bytes); return -EINVAL;}EXPORT_SYMBOL_GPL(of_map_id);
/** * of_map_iommu_id - Translate an ID using "iommu-map" bindings. * @np: root complex device node. * @id: Requester ID of the device (e.g. PCI RID/BDF or a platform * stream/device ID) used as the lookup key in the iommu-map table. * @arg: pointer to a &struct of_phandle_args for the result. On success, * @arg->args_count will be set to the number of output specifier cells * and @arg->args[0..args_count-1] will contain the translated output * specifier values. If a map entry was matched, @arg->np holds a * reference to the target node that the caller must release with * of_node_put(). * * Convenience wrapper around of_map_id() using "iommu-map", "#iommu-cells", * and "iommu-map-mask". * * Return: 0 on success or a standard error code on failure. */int of_map_iommu_id(const struct device_node *np, u32 id, struct of_phandle_args *arg){ return of_map_id(np, id, "iommu-map", "#iommu-cells", "iommu-map-mask", NULL, arg);}EXPORT_SYMBOL_GPL(of_map_iommu_id);
/** * of_map_msi_id - Translate an ID using "msi-map" bindings. * @np: root complex device node. * @id: Requester ID of the device (e.g. PCI RID/BDF or a platform * stream/device ID) used as the lookup key in the msi-map table. * @filter_np: pointer to an optional filter node, or NULL to allow bypass. * If non-NULL, the map property must exist (-ENODEV if absent). If * ``*filter_np`` is also non-NULL, only entries targeting that node match. * @arg: pointer to a &struct of_phandle_args for the result. On success, * @arg->args_count will be set to the number of output specifier cells * and @arg->args[0..args_count-1] will contain the translated output * specifier values. If a map entry was matched, @arg->np holds a * reference to the target node that the caller must release with * of_node_put(). * * Convenience wrapper around of_map_id() using "msi-map", "#msi-cells", * and "msi-map-mask". * * Return: 0 on success or a standard error code on failure. */int of_map_msi_id(const struct device_node *np, u32 id, struct device_node * const *filter_np, struct of_phandle_args *arg){ return of_map_id(np, id, "msi-map", "#msi-cells", "msi-map-mask", filter_np, arg);}EXPORT_SYMBOL_GPL(of_map_msi_id);