driver core: Add fw_devlink kernel commandline option

fwnode_operations.add_links allows creating device links from
information provided by firmware.

fwnode_operations.add_links is currently implemented only by
OF/devicetree code and a specific case of efi. However, there's nothing
preventing ACPI or other firmware types from implementing it.

The OF implementation is currently controlled by a kernel commandline
parameter called of_devlink.

Since this feature is generic isn't limited to OF, add a generic
fw_devlink kernel commandline parameter to control this feature across
firmware types.

Signed-off-by: Saravana Kannan <saravanak@google.com>
Link: https://lore.kernel.org/r/20200222014038.180923-3-saravanak@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Saravana Kannan 2020-02-21 17:40:35 -08:00 committed by Greg Kroah-Hartman
parent 1745d299af
commit 8375e74f2b
3 changed files with 46 additions and 1 deletions

View File

@ -1350,6 +1350,24 @@
can be changed at run time by the max_graph_depth file
in the tracefs tracing directory. default: 0 (no limit)
fw_devlink= [KNL] Create device links between consumer and supplier
devices by scanning the firmware to infer the
consumer/supplier relationships. This feature is
especially useful when drivers are loaded as modules as
it ensures proper ordering of tasks like device probing
(suppliers first, then consumers), supplier boot state
clean up (only after all consumers have probed),
suspend/resume & runtime PM (consumers first, then
suppliers).
Format: { off | permissive | on | rpm }
off -- Don't create device links from firmware info.
permissive -- Create device links from firmware info
but use it only for ordering boot state clean
up (sync_state() calls).
on -- Create device links from firmware info and use it
to enforce probe and suspend/resume ordering.
rpm -- Like "on", but also use to order runtime PM.
gamecon.map[2|3]=
[HW,JOY] Multisystem joystick and NES/SNES/PSX pad
support via parallel port (up to 5 devices per port)

View File

@ -2332,6 +2332,31 @@ static int device_private_init(struct device *dev)
return 0;
}
u32 fw_devlink_flags;
static int __init fw_devlink_setup(char *arg)
{
if (!arg)
return -EINVAL;
if (strcmp(arg, "off") == 0) {
fw_devlink_flags = 0;
} else if (strcmp(arg, "permissive") == 0) {
fw_devlink_flags = DL_FLAG_SYNC_STATE_ONLY;
} else if (strcmp(arg, "on") == 0) {
fw_devlink_flags = DL_FLAG_AUTOPROBE_CONSUMER;
} else if (strcmp(arg, "rpm") == 0) {
fw_devlink_flags = DL_FLAG_AUTOPROBE_CONSUMER |
DL_FLAG_PM_RUNTIME;
}
return 0;
}
early_param("fw_devlink", fw_devlink_setup);
u32 fw_devlink_get_flags(void)
{
return fw_devlink_flags;
}
/**
* device_add - add device to device hierarchy.
* @dev: device.
@ -2480,7 +2505,7 @@ int device_add(struct device *dev)
*/
device_link_add_missing_supplier_links();
if (fwnode_has_op(dev->fwnode, add_links)) {
if (fw_devlink_flags && fwnode_has_op(dev->fwnode, add_links)) {
fw_ret = fwnode_call_int_op(dev->fwnode, add_links, dev);
if (fw_ret == -ENODEV)
device_link_wait_for_mandatory_supplier(dev);

View File

@ -170,4 +170,6 @@ struct fwnode_operations {
} while (false)
#define get_dev_from_fwnode(fwnode) get_device((fwnode)->dev)
extern u32 fw_devlink_get_flags(void);
#endif