Re: [RFC PATCH 2/2] software node: Add documentation

From: Randy Dunlap
Date: Thu Oct 03 2019 - 22:57:06 EST


Hi,
Below are a few doc edits for you.


On 10/2/19 5:33 AM, Heikki Krogerus wrote:
> API documentation for the software nodes.
>
> Signed-off-by: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx>
> ---
> Documentation/driver-api/software_node.rst | 197 +++++++++++++++++++++
> 1 file changed, 197 insertions(+)
> create mode 100644 Documentation/driver-api/software_node.rst
>
> diff --git a/Documentation/driver-api/software_node.rst b/Documentation/driver-api/software_node.rst
> new file mode 100644
> index 000000000000..cf8a05c34e9e
> --- /dev/null
> +++ b/Documentation/driver-api/software_node.rst
> @@ -0,0 +1,197 @@
> +
> +.. _software_node:
> +
> +==============
> +Software nodes
> +==============
> +
> +Introduction
> +============
> +
> +Software node is a :c:type:`struct fwnode_handle <fwnode_handle>` type,
> +analogous to the ACPI and DT firmware nodes except that the software nodes are
> +created in kernel code (hence the name "software" node). The software nodes can
> +be used to complement fwnodes representing real firmware nodes when they are
> +incomplete, for example missing device properties, and to supply the primary
> +fwnode when the firmware lacks hardware description for a device completely.
> +
> +NOTE! The primary hardware description should always come from either ACPI
> +tables or DT. Describing an entire system with software nodes, though possible,
> +is not acceptable! The software nodes should only complement the primary
> +hardware description.
> +
> +Hierarchy
> +=========
> +
> +The software nodes support hierarchy (i.e. the software nodes can have child

I would s/child/children/

> +software nodes and a parent software node) just like ACPI and DT firmware nodes,
> +but there is no dedicated root software node object. It means that a software
> +node at the root level does not have a parent.
> +
> +Note! Only other software nodes can be children and the parent for a software
> +node.
> +
> +Device properties
> +=================
> +
> +The software node device properties are described with :c:type:`struct
> +property_entry <property_entry>`. When a software node is created that has
> +device properties, it is supplied with a zero terminated array of property
> +entries. Normally the properties are described with helper macros::
> +
> + static const u8 u8_array[] = { 0, 1, 2, 3 };
> + static const u16 u16_array[] = { 0, 1, 2, 3 };
> + static const u32 u32_array[] = { 0, 1, 2, 3 };
> + static const u64 u64_array[] = { 0, 1, 2, 3 };
> +
> + static const struct property_entry my_props[] = {
> + PROPERTY_ENTRY_U8_ARRAY("u8_array_example", u8_array),
> + PROPERTY_ENTRY_U16_ARRAY("u16_array_example", u16_array),
> + PROPERTY_ENTRY_U32_ARRAY("u32_array_example", u32_array),
> + PROPERTY_ENTRY_U64_ARRAY("u64_array_example", u64_array),
> + PROPERTY_ENTRY_U8("u8_example", 0xff),
> + PROPERTY_ENTRY_U16("u16_example", 0xffff),
> + PROPERTY_ENTRY_U32("u32_example", 0xffffffff),
> + PROPERTY_ENTRY_U64("u64_example", 0xffffffffffffffff),
> + PROPERTY_ENTRY_STRING("string_example", "string"),
> + { }
> + };
> +
> +Note! If "build-in" device properties are supplied to already existing device

"built-in"

> +entries by using :c:func:`device_add_properties`, a software node is actually
> +created for that device. That software node is just assigned to the device
> +automatically in the function.
> +
> +Usage
> +=====
> +
> +Node creation
> +-------------
> +
> +Static nodes
> +~~~~~~~~~~~~
> +
> +In a normal case the software nodes are described statically with
> +:c:type:`struct software_node <software_node>`, and then registered with
> +:c:func:`software_node_register`. Usually there is more then one software node

than

> +that needs to be registered. A helper :c:func:`software_node_register_nodes`
> +registers a zero terminated array of software nodes::
> +
> + static const struct property_entry props[] = {
> + PROPERTY_ENTRY_STRING("foo", "bar"),
> + { }
> + };
> +
> + static const struct software_node my_nodes[] = {
> + { "grandparent" }, /* no parent nor properties */
> + { "parent", &my_nodes[0] }, /* parent, but no propreties */

properties

> + { "child", &my_nodes[1], props }, /* parent and properties */
> + { }
> + };
> +
> + static int my_init(void)
> + {
> + return software_node_register_nodes(my_nodes);
> + }
> +
> +Note! The above example names the nodes "grandparent", "parent" and "child", but
> +the software nodes don't actually have to be named. If no name is supplied for a
> +software node when it's being registered, the API names the node "node<n>" where
> +<n> is index number.
> +
> +Dynamic nodes
> +~~~~~~~~~~~~~
> +
> +The Quick (and dirty) method. A software node can be created on the fly with
> +:c:func:`fwnode_create_software_node`. The nodes create "on-the-fly" don't

created

> +differ from statically described software nodes in any way, but for now the API
> +does not support naming of these nodes::
> +
> + static const struct property_entry my_props[] = {
> + PROPERTY_ENTRY_STRING("foo", "bar"),
> + { }
> + };
> +
> + static int my_init(void)
> + {
> + struct fwnode_handle *fwnode;
> +
> + /* Software node without a parent. */
> + fwnode = fwnode_create_software_node(my_props, NULL);
> + if (IS_ERR(fwnode))
> + return PTR_ERR(fwnode);
> +
> + return -1;
> + }
> +
> +Linking software nodes with the device (struct device) entries
> +--------------------------------------------------------------
> +
> +Ideally the software node should be assigned to the device entry before the
> +device is registered (just like any other fwnode).
> +
> +When the software node is the primary fwnode for the device, the fwnode of the
> +device needs to simply point to the software node fwnode. Using a helper
> +:c:func:`software_node_fwnode` in the following example::
> +
> + static const struct software_node my_node = {
> + .name = "thenode",
> + };
> +
> + static int my_init(void)
> + {
> + struct device my_device = { };
> + int ret;
> +
> + ret = software_node_register(my_node);
> + if (ret)
> + return ret;
> +
> + device_initialize(&my_device);
> + dev_set_name(&my_device, "thedevice")
> +
> + my_device.fwnode = software_node_fwnode(swnode);
> +
> + return device_add(&my_device);
> + }
> +
> +When the software node is the secondary fwnode for a device, i.e. the device has
> +either ACPI or DT (or something else) firmware node as the primary fwnode, the
> +node should be assigned with :c:func:`set_secondary_fwnode`. If the
> +``secondary`` member of the primary fwnode needs to be manually made to point
> +to the software node, the code needs to make sure that the ``secondary`` member
> +of the software node fwnode points to a specific value of ``ERR_PTR(-ENODEV)``::
> +
> + struct fwnode_handle *fwnode = software_node_fwnode(swnode);
> +
> + fwnode->secondary = ERR_PTR(-ENODEV);
> + dev->fwnode->secondary = fwnode;
> +
> +Note! There is no requirement to bind a software node with a device entry, i.e.
> +having "sub-nodes" that represent for example certain resources the parent
> +software node has is not a problem.
> +
> +Node References
> +---------------
> +
> +TODO
> +
> +Device graph
> +------------
> +
> +TODO
> +
> +API
> +===
> +
> +.. kernel-doc:: include/linux/property.h
> + :internal: software_node
> +
> +.. kernel-doc:: include/linux/fwnode.h
> + :internal: fwnode_handle
> +
> +.. kernel-doc:: drivers/base/core.c
> + :functions: set_secondary_fwnode
> +
> +.. kernel-doc:: drivers/base/swnode.c
> + :functions: is_software_node is_software_node software_node_fwnode software_node_find_by_name software_node_register_nodes software_node_unregister_nodes software_node_register software_node_register fwnode_create_software_node fwnode_remove_software_node
>

Thanks for the doc.
--
~Randy