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 +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 +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 +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 */ + { "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 +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 -- 2.23.0