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 | Passed by reference. | 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 | struct clk: | 314 | struct clk: |
| 279 | 315 | ||
| 280 | %pC pll1 | 316 | %pC pll1 |
| @@ -26,7 +26,9 @@ · 25 unmodified lines | |||
| 26 | #size-cells = <0>; | 26 | #size-cells = <0>; |
| 27 | 27 | ||
| 28 | dev@100 { | 28 | dev@100 { |
| 29 | compatible = "test-sub-device"; | 29 | compatible = "test-sub-device", |
| 30 | "test-compat2", | ||
| 31 | "test-compat3"; | ||
| 30 | reg = <0x100>; | 32 | reg = <0x100>; |
| 31 | }; | 33 | }; |
| 32 | }; | 34 | }; |
| @@ -239,6 +239,63 @@ static void __init of_unittest_check_tree_linkage(void) · 238 unmodified lines | |||
| 239 | pr_debug("allnodes list size (%i); sibling lists size (%i)\n", allnode_count, child_count); | 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 | struct node_hash { | 299 | struct node_hash { |
| 243 | struct hlist_node node; | 300 | struct hlist_node node; |
| 244 | struct device_node *np; | 301 | struct device_node *np; |
| @@ -2269,6 +2326,7 @@ static int __init of_unittest(void) · 2024 unmodified lines | |||
| 2269 | of_unittest_find_node_by_name(); | 2326 | of_unittest_find_node_by_name(); |
| 2270 | of_unittest_dynamic(); | 2327 | of_unittest_dynamic(); |
| 2271 | of_unittest_parse_phandle_with_args(); | 2328 | of_unittest_parse_phandle_with_args(); |
| 2329 | of_unittest_printf(); | ||
| 2272 | of_unittest_property_string(); | 2330 | of_unittest_property_string(); |
| 2273 | of_unittest_property_copy(); | 2331 | of_unittest_property_copy(); |
| 2274 | of_unittest_changeset(); | 2332 | of_unittest_changeset(); |
| @@ -31,6 +31,7 @@ · 30 unmodified lines | |||
| 31 | #include <linux/dcache.h> | 31 | #include <linux/dcache.h> |
| 32 | #include <linux/cred.h> | 32 | #include <linux/cred.h> |
| 33 | #include <linux/uuid.h> | 33 | #include <linux/uuid.h> |
| 34 | #include <linux/of.h> | ||
| 34 | #include <net/addrconf.h> | 35 | #include <net/addrconf.h> |
| 35 | #ifdef CONFIG_BLOCK | 36 | #ifdef CONFIG_BLOCK |
| 36 | #include <linux/blkdev.h> | 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 | return format_flags(buf, end, flags, names); | 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 | int kptr_restrict __read_mostly; | 1594 | int kptr_restrict __read_mostly; |
| 1474 | 1595 | ||
| 1475 | /* | 1596 | /* |
| @@ -1566,6 +1687,16 @@ int kptr_restrict __read_mostly; · 90 unmodified lines | |||
| 1566 | * p page flags (see struct page) given as pointer to unsigned long | 1687 | * p page flags (see struct page) given as pointer to unsigned long |
| 1567 | * g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t | 1688 | * g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t |
| 1568 | * v vma flags (VM_*) given as pointer to unsigned long | 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 | * ** Please update also Documentation/printk-formats.txt when making changes ** | 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 | case 'G': | 1853 | case 'G': |
| 1723 | return flags_string(buf, end, ptr, fmt); | 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 | spec.flags |= SMALL; | 1861 | spec.flags |= SMALL; |
| 1726 | if (spec.field_width == -1) { | 1862 | if (spec.field_width == -1) { |
| @@ -5709,7 +5709,7 @@ sub process { · 5708 unmodified lines | |||
| 5709 | for (my $count = $linenr; $count <= $lc; $count++) { | 5709 | for (my $count = $linenr; $count <= $lc; $count++) { |
| 5710 | my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0)); | 5710 | my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0)); |
| 5711 | $fmt =~ s/%%//g; | 5711 | $fmt =~ s/%%//g; |
| 5712 | if ($fmt =~ /(\%[\*\d\.]*p(?![\WFfSsBKRraEhMmIiUDdgVCbGN]).)/) { | 5712 | if ($fmt =~ /(\%[\*\d\.]*p(?![\WFfSsBKRraEhMmIiUDdgVCbGNO]).)/) { |
| 5713 | $bad_extension = $1; | 5713 | $bad_extension = $1; |
| 5714 | last; | 5714 | last; |
| 5715 | } | 5715 | } |