From: Thomas Bogendoerfer <tbogendoerfer@suse.de>
Subject: kabi protect fwnode_handle
Patch-Mainline: never, kABI
References: bsc#1098633
Commit 3708184afc77 ("device property: Move FW type specific functionality to FW specific files")
added field ops to struct fwnode_handle, which breaks kabi. Simply
hiding the new field from kabi checker isn't enough, because fwnode_handle
is embedded in the middle of struct device_node. This kabi workaround
uses thetype field in struct fwnode_handle to map to the appropriate
fwnode_operations.
Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
---
drivers/acpi/property.c | 1 -
drivers/acpi/scan.c | 1 -
drivers/base/property.c | 15 ++++++++++++++-
include/linux/acpi.h | 1 -
include/linux/fwnode.h | 21 +++++++++++++++------
include/linux/of.h | 1 -
6 files changed, 29 insertions(+), 11 deletions(-)
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -57,7 +57,6 @@ static bool acpi_nondev_subnode_extract(
dn->name = link->package.elements[0].string.pointer;
dn->fwnode.type = FWNODE_ACPI_DATA;
- dn->fwnode.ops = &acpi_fwnode_ops;
dn->parent = parent;
INIT_LIST_HEAD(&dn->data.subnodes);
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1474,7 +1474,6 @@ void acpi_init_device_object(struct acpi
device->handle = handle;
device->parent = acpi_bus_get_parent(handle);
device->fwnode.type = FWNODE_ACPI;
- device->fwnode.ops = &acpi_fwnode_ops;
acpi_set_device_status(device, sta);
acpi_device_get_busid(device);
acpi_set_pnp_ids(handle, &device->pnp, type);
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -906,7 +906,6 @@ int device_add_properties(struct device
return PTR_ERR(p);
p->fwnode.type = FWNODE_PDATA;
- p->fwnode.ops = &pset_fwnode_ops;
set_secondary_fwnode(dev, &p->fwnode);
p->dev = dev;
return 0;
@@ -1315,3 +1314,17 @@ int fwnode_graph_parse_endpoint(struct f
return fwnode_call_int_op(fwnode, graph_parse_endpoint, endpoint);
}
EXPORT_SYMBOL(fwnode_graph_parse_endpoint);
+
+const struct fwnode_operations *fwnode_ops[FWNODE_MAX] =
+{
+#ifdef CONFIG_OF
+ [FWNODE_OF] = &of_fwnode_ops,
+#endif
+#ifdef CONFIG_ACPI
+ [FWNODE_ACPI] = &acpi_fwnode_ops,
+ [FWNODE_ACPI_DATA] = &acpi_fwnode_ops,
+ [FWNODE_ACPI_STATIC] = &acpi_fwnode_ops,
+#endif
+ [FWNODE_PDATA] = &pset_fwnode_ops
+};
+EXPORT_SYMBOL(fwnode_ops);
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -71,7 +71,6 @@ static inline struct fwnode_handle *acpi
return NULL;
fwnode->type = FWNODE_ACPI_STATIC;
- fwnode->ops = &acpi_fwnode_ops;
return fwnode;
}
--- a/include/linux/fwnode.h
+++ b/include/linux/fwnode.h
@@ -22,6 +22,10 @@ enum fwnode_type {
FWNODE_ACPI_STATIC,
FWNODE_PDATA,
FWNODE_IRQCHIP
+#ifndef __GENKSYMS__
+ ,
+ FWNODE_MAX
+#endif
};
struct fwnode_operations;
@@ -29,7 +33,6 @@ struct fwnode_operations;
struct fwnode_handle {
enum fwnode_type type;
struct fwnode_handle *secondary;
- const struct fwnode_operations *ops;
};
/**
@@ -93,23 +96,29 @@ struct fwnode_operations {
struct fwnode_endpoint *endpoint);
};
+extern const struct fwnode_operations *fwnode_ops[FWNODE_MAX];
+
+#define fwops(fwnode) \
+ (((fwnode)->type >= FWNODE_INVALID && (fwnode)->type < FWNODE_MAX) ? \
+ fwnode_ops[fwnode->type] : NULL)
+
#define fwnode_has_op(fwnode, op) \
- ((fwnode) && (fwnode)->ops && (fwnode)->ops->op)
+ ((fwnode) && (fwops(fwnode)) && (fwops(fwnode))->op)
#define fwnode_call_int_op(fwnode, op, ...) \
(fwnode ? (fwnode_has_op(fwnode, op) ? \
- (fwnode)->ops->op(fwnode, ## __VA_ARGS__) : -ENXIO) : \
+ (fwops(fwnode))->op(fwnode, ## __VA_ARGS__) : -ENXIO) : \
-EINVAL)
#define fwnode_call_bool_op(fwnode, op, ...) \
(fwnode ? (fwnode_has_op(fwnode, op) ? \
- (fwnode)->ops->op(fwnode, ## __VA_ARGS__) : false) : \
+ (fwops(fwnode))->op(fwnode, ## __VA_ARGS__) : false) : \
false)
#define fwnode_call_ptr_op(fwnode, op, ...) \
(fwnode_has_op(fwnode, op) ? \
- (fwnode)->ops->op(fwnode, ## __VA_ARGS__) : NULL)
+ (fwops(fwnode))->op(fwnode, ## __VA_ARGS__) : NULL)
#define fwnode_call_void_op(fwnode, op, ...) \
do { \
if (fwnode_has_op(fwnode, op)) \
- (fwnode)->ops->op(fwnode, ## __VA_ARGS__); \
+ (fwops(fwnode))->op(fwnode, ## __VA_ARGS__); \
} while (false)
#endif
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -105,7 +105,6 @@ static inline void of_node_init(struct d
{
kobject_init(&node->kobj, &of_node_ktype);
node->fwnode.type = FWNODE_OF;
- node->fwnode.ops = &of_fwnode_ops;
}
/* true when node is initialized */