90% of the usage of device node's full_name is printing it out in a kernel message. However, storing the full path for every node is wasteful and redundant. With a custom format specifier, we can generate the full path at run-time and eventually remove the full path from every node. For instance typical use is: pr_info("Frobbing node %s\n", node->full_name); Which can be written now as: pr_info("Frobbing node %pOF\n", node); '%pO' is the base specifier to represent kobjects with '%pOF' representing struct device_node. Currently, struct device_node is the only supported type of kobject. More fine-grained control of formatting includes printing the name, flags, path-spec name and others, explained in the documentation entry. Originally written by Pantelis, but pretty much rewrote the core function using existing string/number functions. The 2 passes were unnecessary and have been removed. Also, updated the checkpatch.pl check. The unittest code was written by Grant Likely.
Unified · Split
| @@ -275,6 +275,42 @@ struct va_format: · 274 unmodified lines | ||
| 275 | 275 | |
| 276 | 276 | Passed by reference. |
| 277 | 277 | |
| 278 | +kobjects: | |
| 279 | + %pO | |
| 280 | + | |
| 281 | + Base specifier for kobject based structs. Must be followed with | |
| 282 | + character for specific type of kobject as listed below: | |
| 283 | + | |
| 284 | + Device tree nodes: | |
| 285 | + | |
| 286 | + %pOF[fnpPcCF] | |
| 287 | + | |
| 288 | + For printing device tree nodes. The optional arguments are: | |
| 289 | + f device node full_name | |
| 290 | + n device node name | |
| 291 | + p device node phandle | |
| 292 | + P device node path spec (name + @unit) | |
| 293 | + F device node flags | |
| 294 | + c major compatible string | |
| 295 | + C full compatible string | |
| 296 | + Without any arguments prints full_name (same as %pOFf) | |
| 297 | + The separator when using multiple arguments is ':' | |
| 298 | + | |
| 299 | + Examples: | |
| 300 | + | |
| 301 | + %pOF /foo/bar@0 - Node full name | |
| 302 | + %pOFf /foo/bar@0 - Same as above | |
| 303 | + %pOFfp /foo/bar@0:10 - Node full name + phandle | |
| 304 | + %pOFfcF /foo/bar@0:foo,device:--P- - Node full name + | |
| 305 | + major compatible string + | |
| 306 | + node flags | |
| 307 | + D - dynamic | |
| 308 | + d - detached | |
| 309 | + P - Populated | |
| 310 | + B - Populated bus | |
| 311 | + | |
| 312 | + Passed by reference. | |
| 313 | + | |
| 278 | 314 | struct clk: |
| 279 | 315 | |
| 280 | 316 | %pC pll1 |
| @@ -26,7 +26,9 @@ · 25 unmodified lines | ||
| 26 | 26 | #size-cells = <0>; |
| 27 | 27 | |
| 28 | 28 | dev@100 { |
| 29 | − compatible = "test-sub-device"; | |
| 29 | + compatible = "test-sub-device", | |
| 30 | + "test-compat2", | |
| 31 | + "test-compat3"; | |
| 30 | 32 | reg = <0x100>; |
| 31 | 33 | }; |
| 32 | 34 | }; |
| @@ -239,6 +239,63 @@ static void __init of_unittest_check_tree_linkage(void) · 238 unmodified lines | ||
| 239 | 239 | pr_debug("allnodes list size (%i); sibling lists size (%i)\n", allnode_count, child_count); |
| 240 | 240 | } |
| 241 | 241 | |
| 242 | +static void __init of_unittest_printf_one(struct device_node *np, const char *fmt, | |
| 243 | + const char *expected) | |
| 244 | +{ | |
| 245 | + unsigned char buf[strlen(expected)+10]; | |
| 246 | + int size, i; | |
| 247 | + | |
| 248 | + /* Baseline; check conversion with a large size limit */ | |
| 249 | + memset(buf, 0xff, sizeof(buf)); | |
| 250 | + size = snprintf(buf, sizeof(buf) - 2, fmt, np); | |
| 251 | + | |
| 252 | + /* use strcmp() instead of strncmp() here to be absolutely sure strings match */ | |
| 253 | + unittest((strcmp(buf, expected) == 0) && (buf[size+1] == 0xff), | |
| 254 | + "sprintf failed; fmt='%s' expected='%s' rslt='%s'\n", | |
| 255 | + fmt, expected, buf); | |
| 256 | + | |
| 257 | + /* Make sure length limits work */ | |
| 258 | + size++; | |
| 259 | + for (i = 0; i < 2; i++, size--) { | |
| 260 | + /* Clear the buffer, and make sure it works correctly still */ | |
| 261 | + memset(buf, 0xff, sizeof(buf)); | |
| 262 | + snprintf(buf, size+1, fmt, np); | |
| 263 | + unittest(strncmp(buf, expected, size) == 0 && (buf[size+1] == 0xff), | |
| 264 | + "snprintf failed; size=%i fmt='%s' expected='%s' rslt='%s'\n", | |
| 265 | + size, fmt, expected, buf); | |
| 266 | + } | |
| 267 | +} | |
| 268 | + | |
| 269 | +static void __init of_unittest_printf(void) | |
| 270 | +{ | |
| 271 | + struct device_node *np; | |
| 272 | + const char *full_name = "/testcase-data/platform-tests/test-device@1/dev@100"; | |
| 273 | + char phandle_str[16] = ""; | |
| 274 | + | |
| 275 | + np = of_find_node_by_path(full_name); | |
| 276 | + if (!np) { | |
| 277 | + unittest(np, "testcase data missing\n"); | |
| 278 | + return; | |
| 279 | + } | |
| 280 | + | |
| 281 | + num_to_str(phandle_str, sizeof(phandle_str), np->phandle); | |
| 282 | + | |
| 283 | + of_unittest_printf_one(np, "%pOF", full_name); | |
| 284 | + of_unittest_printf_one(np, "%pOFf", full_name); | |
| 285 | + of_unittest_printf_one(np, "%pOFp", phandle_str); | |
| 286 | + of_unittest_printf_one(np, "%pOFP", "dev@100"); | |
| 287 | + of_unittest_printf_one(np, "ABC %pOFP ABC", "ABC dev@100 ABC"); | |
| 288 | + of_unittest_printf_one(np, "%10pOFP", " dev@100"); | |
| 289 | + of_unittest_printf_one(np, "%-10pOFP", "dev@100 "); | |
| 290 | + of_unittest_printf_one(of_root, "%pOFP", "/"); | |
| 291 | + of_unittest_printf_one(np, "%pOFF", "----"); | |
| 292 | + of_unittest_printf_one(np, "%pOFPF", "dev@100:----"); | |
| 293 | + of_unittest_printf_one(np, "%pOFPFPc", "dev@100:----:dev@100:test-sub-device"); | |
| 294 | + of_unittest_printf_one(np, "%pOFc", "test-sub-device"); | |
| 295 | + of_unittest_printf_one(np, "%pOFC", | |
| 296 | + "\"test-sub-device\",\"test-compat2\",\"test-compat3\""); | |
| 297 | +} | |
| 298 | + | |
| 242 | 299 | struct node_hash { |
| 243 | 300 | struct hlist_node node; |
| 244 | 301 | struct device_node *np; |
| @@ -2269,6 +2326,7 @@ static int __init of_unittest(void) · 2024 unmodified lines | ||
| 2269 | 2326 | of_unittest_find_node_by_name(); |
| 2270 | 2327 | of_unittest_dynamic(); |
| 2271 | 2328 | of_unittest_parse_phandle_with_args(); |
| 2329 | + of_unittest_printf(); | |
| 2272 | 2330 | of_unittest_property_string(); |
| 2273 | 2331 | of_unittest_property_copy(); |
| 2274 | 2332 | of_unittest_changeset(); |
| @@ -31,6 +31,7 @@ · 30 unmodified lines | ||
| 31 | 31 | #include <linux/dcache.h> |
| 32 | 32 | #include <linux/cred.h> |
| 33 | 33 | #include <linux/uuid.h> |
| 34 | +#include <linux/of.h> | |
| 34 | 35 | #include <net/addrconf.h> |
| 35 | 36 | #ifdef CONFIG_BLOCK |
| 36 | 37 | #include <linux/blkdev.h> |
| @@ -1470,6 +1471,126 @@ char *flags_string(char *buf, char *end, void *flags_ptr, const char *fmt) · 1433 unmodified lines | ||
| 1470 | 1471 | return format_flags(buf, end, flags, names); |
| 1471 | 1472 | } |
| 1472 | 1473 | |
| 1474 | +static const char *device_node_name_for_depth(const struct device_node *np, int depth) | |
| 1475 | +{ | |
| 1476 | + for ( ; np && depth; depth--) | |
| 1477 | + np = np->parent; | |
| 1478 | + | |
| 1479 | + return kbasename(np->full_name); | |
| 1480 | +} | |
| 1481 | + | |
| 1482 | +static noinline_for_stack | |
| 1483 | +char *device_node_gen_full_name(const struct device_node *np, char *buf, char *end) | |
| 1484 | +{ | |
| 1485 | + int depth; | |
| 1486 | + const struct device_node *parent = np->parent; | |
| 1487 | + static const struct printf_spec strspec = { | |
| 1488 | + .field_width = -1, | |
| 1489 | + .precision = -1, | |
| 1490 | + }; | |
| 1491 | + | |
| 1492 | + /* special case for root node */ | |
| 1493 | + if (!parent) | |
| 1494 | + return string(buf, end, "/", strspec); | |
| 1495 | + | |
| 1496 | + for (depth = 0; parent->parent; depth++) | |
| 1497 | + parent = parent->parent; | |
| 1498 | + | |
| 1499 | + for ( ; depth >= 0; depth--) { | |
| 1500 | + buf = string(buf, end, "/", strspec); | |
| 1501 | + buf = string(buf, end, device_node_name_for_depth(np, depth), | |
| 1502 | + strspec); | |
| 1503 | + } | |
| 1504 | + return buf; | |
| 1505 | +} | |
| 1506 | + | |
| 1507 | +static noinline_for_stack | |
| 1508 | +char *device_node_string(char *buf, char *end, struct device_node *dn, | |
| 1509 | + struct printf_spec spec, const char *fmt) | |
| 1510 | +{ | |
| 1511 | + char tbuf[sizeof("xxxx") + 1]; | |
| 1512 | + const char *p; | |
| 1513 | + int ret; | |
| 1514 | + char *buf_start = buf; | |
| 1515 | + struct property *prop; | |
| 1516 | + bool has_mult, pass; | |
| 1517 | + static const struct printf_spec num_spec = { | |
| 1518 | + .flags = SMALL, | |
| 1519 | + .field_width = -1, | |
| 1520 | + .precision = -1, | |
| 1521 | + .base = 10, | |
| 1522 | + }; | |
| 1523 | + | |
| 1524 | + struct printf_spec str_spec = spec; | |
| 1525 | + str_spec.field_width = -1; | |
| 1526 | + | |
| 1527 | + if (!IS_ENABLED(CONFIG_OF)) | |
| 1528 | + return string(buf, end, "(!OF)", spec); | |
| 1529 | + | |
| 1530 | + if ((unsigned long)dn < PAGE_SIZE) | |
| 1531 | + return string(buf, end, "(null)", spec); | |
| 1532 | + | |
| 1533 | + /* simple case without anything any more format specifiers */ | |
| 1534 | + fmt++; | |
| 1535 | + if (fmt[0] == '\0' || strcspn(fmt,"fnpPFcC") > 0) | |
| 1536 | + fmt = "f"; | |
| 1537 | + | |
| 1538 | + for (pass = false; strspn(fmt,"fnpPFcC"); fmt++, pass = true) { | |
| 1539 | + if (pass) { | |
| 1540 | + if (buf < end) | |
| 1541 | + *buf = ':'; | |
| 1542 | + buf++; | |
| 1543 | + } | |
| 1544 | + | |
| 1545 | + switch (*fmt) { | |
| 1546 | + case 'f': /* full_name */ | |
| 1547 | + buf = device_node_gen_full_name(dn, buf, end); | |
| 1548 | + break; | |
| 1549 | + case 'n': /* name */ | |
| 1550 | + buf = string(buf, end, dn->name, str_spec); | |
| 1551 | + break; | |
| 1552 | + case 'p': /* phandle */ | |
| 1553 | + buf = number(buf, end, (unsigned int)dn->phandle, num_spec); | |
| 1554 | + break; | |
| 1555 | + case 'P': /* path-spec */ | |
| 1556 | + p = kbasename(of_node_full_name(dn)); | |
| 1557 | + if (!p[1]) | |
| 1558 | + p = "/"; | |
| 1559 | + buf = string(buf, end, p, str_spec); | |
| 1560 | + break; | |
| 1561 | + case 'F': /* flags */ | |
| 1562 | + tbuf[0] = of_node_check_flag(dn, OF_DYNAMIC) ? 'D' : '-'; | |
| 1563 | + tbuf[1] = of_node_check_flag(dn, OF_DETACHED) ? 'd' : '-'; | |
| 1564 | + tbuf[2] = of_node_check_flag(dn, OF_POPULATED) ? 'P' : '-'; | |
| 1565 | + tbuf[3] = of_node_check_flag(dn, OF_POPULATED_BUS) ? 'B' : '-'; | |
| 1566 | + tbuf[4] = 0; | |
| 1567 | + buf = string(buf, end, tbuf, str_spec); | |
| 1568 | + break; | |
| 1569 | + case 'c': /* major compatible string */ | |
| 1570 | + ret = of_property_read_string(dn, "compatible", &p); | |
| 1571 | + if (!ret) | |
| 1572 | + buf = string(buf, end, p, str_spec); | |
| 1573 | + break; | |
| 1574 | + case 'C': /* full compatible string */ | |
| 1575 | + has_mult = false; | |
| 1576 | + of_property_for_each_string(dn, "compatible", prop, p) { | |
| 1577 | + if (has_mult) | |
| 1578 | + buf = string(buf, end, ",", str_spec); | |
| 1579 | + buf = string(buf, end, "\"", str_spec); | |
| 1580 | + buf = string(buf, end, p, str_spec); | |
| 1581 | + buf = string(buf, end, "\"", str_spec); | |
| 1582 | + | |
| 1583 | + has_mult = true; | |
| 1584 | + } | |
| 1585 | + break; | |
| 1586 | + default: | |
| 1587 | + break; | |
| 1588 | + } | |
| 1589 | + } | |
| 1590 | + | |
| 1591 | + return widen_string(buf, buf - buf_start, end, spec); | |
| 1592 | +} | |
| 1593 | + | |
| 1473 | 1594 | int kptr_restrict __read_mostly; |
| 1474 | 1595 | |
| 1475 | 1596 | /* |
| @@ -1566,6 +1687,16 @@ int kptr_restrict __read_mostly; · 90 unmodified lines | ||
| 1566 | 1687 | * p page flags (see struct page) given as pointer to unsigned long |
| 1567 | 1688 | * g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t |
| 1568 | 1689 | * v vma flags (VM_*) given as pointer to unsigned long |
| 1690 | + * - 'O' For a kobject based struct. Must be one of the following: | |
| 1691 | + * - 'OF[fnpPcCF]' For a device tree object | |
| 1692 | + * Without any optional arguments prints the full_name | |
| 1693 | + * f device node full_name | |
| 1694 | + * n device node name | |
| 1695 | + * p device node phandle | |
| 1696 | + * P device node path spec (name + @unit) | |
| 1697 | + * F device node flags | |
| 1698 | + * c major compatible string | |
| 1699 | + * C full compatible string | |
| 1569 | 1700 | * |
| 1570 | 1701 | * ** Please update also Documentation/printk-formats.txt when making changes ** |
| 1571 | 1702 | * |
| @@ -1721,6 +1852,11 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, · 149 unmodified lines | ||
| 1721 | 1852 | |
| 1722 | 1853 | case 'G': |
| 1723 | 1854 | return flags_string(buf, end, ptr, fmt); |
| 1855 | + case 'O': | |
| 1856 | + switch (fmt[1]) { | |
| 1857 | + case 'F': | |
| 1858 | + return device_node_string(buf, end, ptr, spec, fmt + 1); | |
| 1859 | + } | |
| 1724 | 1860 | } |
| 1725 | 1861 | spec.flags |= SMALL; |
| 1726 | 1862 | if (spec.field_width == -1) { |
| @@ -5709,7 +5709,7 @@ sub process { · 5708 unmodified lines | ||
| 5709 | 5709 | for (my $count = $linenr; $count <= $lc; $count++) { |
| 5710 | 5710 | my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0)); |
| 5711 | 5711 | $fmt =~ s/%%//g; |
| 5712 | − if ($fmt =~ /(\%[\*\d\.]*p(?![\WFfSsBKRraEhMmIiUDdgVCbGN]).)/) { | |
| 5712 | + if ($fmt =~ /(\%[\*\d\.]*p(?![\WFfSsBKRraEhMmIiUDdgVCbGNO]).)/) { | |
| 5713 | 5713 | $bad_extension = $1; |
| 5714 | 5714 | last; |
| 5715 | 5715 | } |