aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-11-27 11:06:20 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2019-11-27 11:06:20 -0800
commit9a3d7fd275be4559277667228902824165153c80 (patch)
tree09e74ef51c6388ac42b6123ad789ebc5b6ad8ed6 /include
parentMerge tag 'staging-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging (diff)
parenttracing: Remove unnecessary DEBUG_FS dependency (diff)
downloadlinux-dev-9a3d7fd275be4559277667228902824165153c80.tar.xz
linux-dev-9a3d7fd275be4559277667228902824165153c80.zip
Merge tag 'driver-core-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core
Pull driver core updates from Greg KH: "Here is the "big" set of driver core patches for 5.5-rc1 There's a few minor cleanups and fixes in here, but the majority of the patches in here fall into two buckets: - debugfs api cleanups and fixes - driver core device link support for boot dependancy issues The debugfs api cleanups are working to slowly refactor the debugfs apis so that it is even harder to use incorrectly. That work has been happening for the past few kernel releases and will continue over time, it's a long-term project/goal The driver core device link support missed 5.4 by just a bit, so it's been sitting and baking for many months now. It's from Saravana Kannan to help resolve the problems that DT-based systems have at boot time with dependancy graphs and kernel modules. Turns out that no one has actually tried to build a generic arm64 kernel with loads of modules and have it "just work" for a variety of platforms (like a distro kernel). The big problem turned out to be a lack of dependency information between different areas of DT entries, and the work here resolves that problem and now allows devices to boot properly, and quicker than a monolith kernel. All of these patches have been in linux-next for a long time with no reported issues" * tag 'driver-core-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (68 commits) tracing: Remove unnecessary DEBUG_FS dependency of: property: Add device link support for interrupt-parent, dmas and -gpio(s) debugfs: Fix !DEBUG_FS debugfs_create_automount of: property: Add device link support for "iommu-map" of: property: Fix the semantics of of_is_ancestor_of() i2c: of: Populate fwnode in of_i2c_get_board_info() drivers: base: Fix Kconfig indentation firmware_loader: Fix labels with comma for builtin firmware driver core: Allow device link operations inside sync_state() driver core: platform: Declare ret variable only once cpu-topology: declare parse_acpi_topology in <linux/arch_topology.h> crypto: hisilicon: no need to check return value of debugfs_create functions driver core: platform: use the correct callback type for bus_find_device firmware_class: make firmware caching configurable driver core: Clarify documentation for fwnode_operations.add_links() mailbox: tegra: Fix superfluous IRQ error message net: caif: Fix debugfs on 64-bit platforms mac80211: Use debugfs_create_xul() helper media: c8sectpfe: no need to check return value of debugfs_create functions of: property: Add device link support for iommus, mboxes and io-channels ...
Diffstat (limited to 'include')
-rw-r--r--include/linux/arch_topology.h1
-rw-r--r--include/linux/debugfs.h136
-rw-r--r--include/linux/device.h33
-rw-r--r--include/linux/fwnode.h42
-rw-r--r--include/linux/platform_device.h70
-rw-r--r--include/linux/sys_soc.h1
6 files changed, 158 insertions, 125 deletions
diff --git a/include/linux/arch_topology.h b/include/linux/arch_topology.h
index 42f2b5126094..3015ecbb90b1 100644
--- a/include/linux/arch_topology.h
+++ b/include/linux/arch_topology.h
@@ -57,6 +57,7 @@ const struct cpumask *cpu_coregroup_mask(int cpu);
void update_siblings_masks(unsigned int cpu);
void remove_cpu_topology(unsigned int cpuid);
void reset_cpu_topology(void);
+int parse_acpi_topology(void);
#endif
#endif /* _LINUX_ARCH_TOPOLOGY_H_ */
diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h
index 58424eb3b329..bf9b6cafa4c2 100644
--- a/include/linux/debugfs.h
+++ b/include/linux/debugfs.h
@@ -54,6 +54,8 @@ static const struct file_operations __fops = { \
.llseek = no_llseek, \
}
+typedef struct vfsmount *(*debugfs_automount_t)(struct dentry *, void *);
+
#if defined(CONFIG_DEBUG_FS)
struct dentry *debugfs_lookup(const char *name, struct dentry *parent);
@@ -75,7 +77,6 @@ struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
const char *dest);
-typedef struct vfsmount *(*debugfs_automount_t)(struct dentry *, void *);
struct dentry *debugfs_create_automount(const char *name,
struct dentry *parent,
debugfs_automount_t f,
@@ -97,28 +98,28 @@ ssize_t debugfs_attr_write(struct file *file, const char __user *buf,
struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
struct dentry *new_dir, const char *new_name);
-struct dentry *debugfs_create_u8(const char *name, umode_t mode,
- struct dentry *parent, u8 *value);
-struct dentry *debugfs_create_u16(const char *name, umode_t mode,
- struct dentry *parent, u16 *value);
+void debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent,
+ u8 *value);
+void debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent,
+ u16 *value);
struct dentry *debugfs_create_u32(const char *name, umode_t mode,
struct dentry *parent, u32 *value);
-struct dentry *debugfs_create_u64(const char *name, umode_t mode,
- struct dentry *parent, u64 *value);
+void debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent,
+ u64 *value);
struct dentry *debugfs_create_ulong(const char *name, umode_t mode,
struct dentry *parent, unsigned long *value);
-struct dentry *debugfs_create_x8(const char *name, umode_t mode,
- struct dentry *parent, u8 *value);
-struct dentry *debugfs_create_x16(const char *name, umode_t mode,
- struct dentry *parent, u16 *value);
-struct dentry *debugfs_create_x32(const char *name, umode_t mode,
- struct dentry *parent, u32 *value);
-struct dentry *debugfs_create_x64(const char *name, umode_t mode,
- struct dentry *parent, u64 *value);
-struct dentry *debugfs_create_size_t(const char *name, umode_t mode,
- struct dentry *parent, size_t *value);
-struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode,
- struct dentry *parent, atomic_t *value);
+void debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent,
+ u8 *value);
+void debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent,
+ u16 *value);
+void debugfs_create_x32(const char *name, umode_t mode, struct dentry *parent,
+ u32 *value);
+void debugfs_create_x64(const char *name, umode_t mode, struct dentry *parent,
+ u64 *value);
+void debugfs_create_size_t(const char *name, umode_t mode,
+ struct dentry *parent, size_t *value);
+void debugfs_create_atomic_t(const char *name, umode_t mode,
+ struct dentry *parent, atomic_t *value);
struct dentry *debugfs_create_bool(const char *name, umode_t mode,
struct dentry *parent, bool *value);
@@ -203,7 +204,7 @@ static inline struct dentry *debugfs_create_symlink(const char *name,
static inline struct dentry *debugfs_create_automount(const char *name,
struct dentry *parent,
- struct vfsmount *(*f)(void *),
+ debugfs_automount_t f,
void *data)
{
return ERR_PTR(-ENODEV);
@@ -244,19 +245,11 @@ static inline struct dentry *debugfs_rename(struct dentry *old_dir, struct dentr
return ERR_PTR(-ENODEV);
}
-static inline struct dentry *debugfs_create_u8(const char *name, umode_t mode,
- struct dentry *parent,
- u8 *value)
-{
- return ERR_PTR(-ENODEV);
-}
+static inline void debugfs_create_u8(const char *name, umode_t mode,
+ struct dentry *parent, u8 *value) { }
-static inline struct dentry *debugfs_create_u16(const char *name, umode_t mode,
- struct dentry *parent,
- u16 *value)
-{
- return ERR_PTR(-ENODEV);
-}
+static inline void debugfs_create_u16(const char *name, umode_t mode,
+ struct dentry *parent, u16 *value) { }
static inline struct dentry *debugfs_create_u32(const char *name, umode_t mode,
struct dentry *parent,
@@ -265,12 +258,8 @@ static inline struct dentry *debugfs_create_u32(const char *name, umode_t mode,
return ERR_PTR(-ENODEV);
}
-static inline struct dentry *debugfs_create_u64(const char *name, umode_t mode,
- struct dentry *parent,
- u64 *value)
-{
- return ERR_PTR(-ENODEV);
-}
+static inline void debugfs_create_u64(const char *name, umode_t mode,
+ struct dentry *parent, u64 *value) { }
static inline struct dentry *debugfs_create_ulong(const char *name,
umode_t mode,
@@ -280,46 +269,26 @@ static inline struct dentry *debugfs_create_ulong(const char *name,
return ERR_PTR(-ENODEV);
}
-static inline struct dentry *debugfs_create_x8(const char *name, umode_t mode,
- struct dentry *parent,
- u8 *value)
-{
- return ERR_PTR(-ENODEV);
-}
+static inline void debugfs_create_x8(const char *name, umode_t mode,
+ struct dentry *parent, u8 *value) { }
-static inline struct dentry *debugfs_create_x16(const char *name, umode_t mode,
- struct dentry *parent,
- u16 *value)
-{
- return ERR_PTR(-ENODEV);
-}
+static inline void debugfs_create_x16(const char *name, umode_t mode,
+ struct dentry *parent, u16 *value) { }
-static inline struct dentry *debugfs_create_x32(const char *name, umode_t mode,
- struct dentry *parent,
- u32 *value)
-{
- return ERR_PTR(-ENODEV);
-}
+static inline void debugfs_create_x32(const char *name, umode_t mode,
+ struct dentry *parent, u32 *value) { }
-static inline struct dentry *debugfs_create_x64(const char *name, umode_t mode,
- struct dentry *parent,
- u64 *value)
-{
- return ERR_PTR(-ENODEV);
-}
+static inline void debugfs_create_x64(const char *name, umode_t mode,
+ struct dentry *parent, u64 *value) { }
-static inline struct dentry *debugfs_create_size_t(const char *name, umode_t mode,
- struct dentry *parent,
- size_t *value)
-{
- return ERR_PTR(-ENODEV);
-}
+static inline void debugfs_create_size_t(const char *name, umode_t mode,
+ struct dentry *parent, size_t *value)
+{ }
-static inline struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode,
- struct dentry *parent, atomic_t *value)
-{
- return ERR_PTR(-ENODEV);
-}
+static inline void debugfs_create_atomic_t(const char *name, umode_t mode,
+ struct dentry *parent,
+ atomic_t *value)
+{ }
static inline struct dentry *debugfs_create_bool(const char *name, umode_t mode,
struct dentry *parent,
@@ -383,4 +352,25 @@ static inline ssize_t debugfs_write_file_bool(struct file *file,
#endif
+/**
+ * debugfs_create_xul - create a debugfs file that is used to read and write an
+ * unsigned long value, formatted in hexadecimal
+ * @name: a pointer to a string containing the name of the file to create.
+ * @mode: the permission that the file should have
+ * @parent: a pointer to the parent dentry for this file. This should be a
+ * directory dentry if set. If this parameter is %NULL, then the
+ * file will be created in the root of the debugfs filesystem.
+ * @value: a pointer to the variable that the file should read to and write
+ * from.
+ */
+static inline void debugfs_create_xul(const char *name, umode_t mode,
+ struct dentry *parent,
+ unsigned long *value)
+{
+ if (sizeof(*value) == sizeof(u32))
+ debugfs_create_x32(name, mode, parent, (u32 *)value);
+ else
+ debugfs_create_x64(name, mode, parent, (u64 *)value);
+}
+
#endif
diff --git a/include/linux/device.h b/include/linux/device.h
index 297239a08bb7..f05c5b92e61f 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -80,6 +80,13 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
* that generate uevents to add the environment variables.
* @probe: Called when a new device or driver add to this bus, and callback
* the specific driver's probe to initial the matched device.
+ * @sync_state: Called to sync device state to software state after all the
+ * state tracking consumers linked to this device (present at
+ * the time of late_initcall) have successfully bound to a
+ * driver. If the device has no consumers, this function will
+ * be called at late_initcall_sync level. If the device has
+ * consumers that are never bound to a driver, this function
+ * will never get called until they do.
* @remove: Called when a device removed from this bus.
* @shutdown: Called at shut-down time to quiesce the device.
*
@@ -123,6 +130,7 @@ struct bus_type {
int (*match)(struct device *dev, struct device_driver *drv);
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
int (*probe)(struct device *dev);
+ void (*sync_state)(struct device *dev);
int (*remove)(struct device *dev);
void (*shutdown)(struct device *dev);
@@ -340,6 +348,13 @@ enum probe_type {
* @probe: Called to query the existence of a specific device,
* whether this driver can work with it, and bind the driver
* to a specific device.
+ * @sync_state: Called to sync device state to software state after all the
+ * state tracking consumers linked to this device (present at
+ * the time of late_initcall) have successfully bound to a
+ * driver. If the device has no consumers, this function will
+ * be called at late_initcall_sync level. If the device has
+ * consumers that are never bound to a driver, this function
+ * will never get called until they do.
* @remove: Called when the device is removed from the system to
* unbind a device from this driver.
* @shutdown: Called at shut-down time to quiesce the device.
@@ -379,6 +394,7 @@ struct device_driver {
const struct acpi_device_id *acpi_match_table;
int (*probe) (struct device *dev);
+ void (*sync_state)(struct device *dev);
int (*remove) (struct device *dev);
void (*shutdown) (struct device *dev);
int (*suspend) (struct device *dev, pm_message_t state);
@@ -946,6 +962,8 @@ extern void devm_free_pages(struct device *dev, unsigned long addr);
void __iomem *devm_ioremap_resource(struct device *dev,
const struct resource *res);
+void __iomem *devm_ioremap_resource_wc(struct device *dev,
+ const struct resource *res);
void __iomem *devm_of_iomap(struct device *dev,
struct device_node *node, int index,
@@ -1080,6 +1098,7 @@ enum device_link_state {
* AUTOREMOVE_SUPPLIER: Remove the link automatically on supplier driver unbind.
* AUTOPROBE_CONSUMER: Probe consumer driver automatically after supplier binds.
* MANAGED: The core tracks presence of supplier/consumer drivers (internal).
+ * SYNC_STATE_ONLY: Link only affects sync_state() behavior.
*/
#define DL_FLAG_STATELESS BIT(0)
#define DL_FLAG_AUTOREMOVE_CONSUMER BIT(1)
@@ -1088,6 +1107,7 @@ enum device_link_state {
#define DL_FLAG_AUTOREMOVE_SUPPLIER BIT(4)
#define DL_FLAG_AUTOPROBE_CONSUMER BIT(5)
#define DL_FLAG_MANAGED BIT(6)
+#define DL_FLAG_SYNC_STATE_ONLY BIT(7)
/**
* struct device_link - Device link representation.
@@ -1135,11 +1155,18 @@ enum dl_dev_state {
* struct dev_links_info - Device data related to device links.
* @suppliers: List of links to supplier devices.
* @consumers: List of links to consumer devices.
+ * @needs_suppliers: Hook to global list of devices waiting for suppliers.
+ * @defer_sync: Hook to global list of devices that have deferred sync_state.
+ * @need_for_probe: If needs_suppliers is on a list, this indicates if the
+ * suppliers are needed for probe or not.
* @status: Driver status information.
*/
struct dev_links_info {
struct list_head suppliers;
struct list_head consumers;
+ struct list_head needs_suppliers;
+ struct list_head defer_sync;
+ bool need_for_probe;
enum dl_dev_state status;
};
@@ -1215,6 +1242,9 @@ struct dev_links_info {
* @offline: Set after successful invocation of bus type's .offline().
* @of_node_reused: Set if the device-tree node is shared with an ancestor
* device.
+ * @state_synced: The hardware state of this device has been synced to match
+ * the software state of this device by calling the driver/bus
+ * sync_state() callback.
* @dma_coherent: this particular device is dma coherent, even if the
* architecture supports non-coherent devices.
*
@@ -1311,6 +1341,7 @@ struct device {
bool offline_disabled:1;
bool offline:1;
bool of_node_reused:1;
+ bool state_synced:1;
#if defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE) || \
defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU) || \
defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL)
@@ -1653,6 +1684,8 @@ struct device_link *device_link_add(struct device *consumer,
struct device *supplier, u32 flags);
void device_link_del(struct device_link *link);
void device_link_remove(void *consumer, struct device *supplier);
+void device_links_supplier_sync_state_pause(void);
+void device_links_supplier_sync_state_resume(void);
#ifndef dev_fmt
#define dev_fmt(fmt) fmt
diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h
index 9d9dc444d787..8feeb94b8acc 100644
--- a/include/linux/fwnode.h
+++ b/include/linux/fwnode.h
@@ -17,6 +17,7 @@ struct device;
struct fwnode_handle {
struct fwnode_handle *secondary;
const struct fwnode_operations *ops;
+ struct device *dev;
};
/**
@@ -67,6 +68,44 @@ struct fwnode_reference_args {
* endpoint node.
* @graph_get_port_parent: Return the parent node of a port node.
* @graph_parse_endpoint: Parse endpoint for port and endpoint id.
+ * @add_links: Called after the device corresponding to the fwnode is added
+ * using device_add(). The function is expected to create device
+ * links to all the suppliers of the device that are available at
+ * the time this function is called. The function must NOT stop
+ * at the first failed device link if other unlinked supplier
+ * devices are present in the system. This is necessary for the
+ * driver/bus sync_state() callbacks to work correctly.
+ *
+ * For example, say Device-C depends on suppliers Device-S1 and
+ * Device-S2 and the dependency is listed in that order in the
+ * firmware. Say, S1 gets populated from the firmware after
+ * late_initcall_sync(). Say S2 is populated and probed way
+ * before that in device_initcall(). When C is populated, if this
+ * add_links() function doesn't continue past a "failed linking to
+ * S1" and continue linking C to S2, then S2 will get a
+ * sync_state() callback before C is probed. This is because from
+ * the perspective of S2, C was never a consumer when its
+ * sync_state() evaluation is done. To avoid this, the add_links()
+ * function has to go through all available suppliers of the
+ * device (that corresponds to this fwnode) and link to them
+ * before returning.
+ *
+ * If some suppliers are not yet available (indicated by an error
+ * return value), this function will be called again when other
+ * devices are added to allow creating device links to any newly
+ * available suppliers.
+ *
+ * Return 0 if device links have been successfully created to all
+ * the known suppliers of this device or if the supplier
+ * information is not known.
+ *
+ * Return -ENODEV if the suppliers needed for probing this device
+ * have not been registered yet (because device links can only be
+ * created to devices registered with the driver core).
+ *
+ * Return -EAGAIN if some of the suppliers of this device have not
+ * been registered yet, but none of those suppliers are necessary
+ * for probing the device.
*/
struct fwnode_operations {
struct fwnode_handle *(*get)(struct fwnode_handle *fwnode);
@@ -106,6 +145,8 @@ struct fwnode_operations {
(*graph_get_port_parent)(struct fwnode_handle *fwnode);
int (*graph_parse_endpoint)(const struct fwnode_handle *fwnode,
struct fwnode_endpoint *endpoint);
+ int (*add_links)(const struct fwnode_handle *fwnode,
+ struct device *dev);
};
#define fwnode_has_op(fwnode, op) \
@@ -127,5 +168,6 @@ struct fwnode_operations {
if (fwnode_has_op(fwnode, op)) \
(fwnode)->ops->op(fwnode, ## __VA_ARGS__); \
} while (false)
+#define get_dev_from_fwnode(fwnode) get_device((fwnode)->dev)
#endif
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index f2688404d1cd..276a03c24691 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -57,6 +57,12 @@ platform_find_device_by_driver(struct device *start,
extern void __iomem *
devm_platform_ioremap_resource(struct platform_device *pdev,
unsigned int index);
+extern void __iomem *
+devm_platform_ioremap_resource_wc(struct platform_device *pdev,
+ unsigned int index);
+extern void __iomem *
+devm_platform_ioremap_resource_byname(struct platform_device *pdev,
+ const char *name);
extern int platform_get_irq(struct platform_device *, unsigned int);
extern int platform_get_irq_optional(struct platform_device *, unsigned int);
extern int platform_irq_count(struct platform_device *);
@@ -294,58 +300,6 @@ void platform_unregister_drivers(struct platform_driver * const *drivers,
#define platform_register_drivers(drivers, count) \
__platform_register_drivers(drivers, count, THIS_MODULE)
-/* early platform driver interface */
-struct early_platform_driver {
- const char *class_str;
- struct platform_driver *pdrv;
- struct list_head list;
- int requested_id;
- char *buffer;
- int bufsize;
-};
-
-#define EARLY_PLATFORM_ID_UNSET -2
-#define EARLY_PLATFORM_ID_ERROR -3
-
-extern int early_platform_driver_register(struct early_platform_driver *epdrv,
- char *buf);
-extern void early_platform_add_devices(struct platform_device **devs, int num);
-
-static inline int is_early_platform_device(struct platform_device *pdev)
-{
- return !pdev->dev.driver;
-}
-
-extern void early_platform_driver_register_all(char *class_str);
-extern int early_platform_driver_probe(char *class_str,
- int nr_probe, int user_only);
-extern void early_platform_cleanup(void);
-
-#define early_platform_init(class_string, platdrv) \
- early_platform_init_buffer(class_string, platdrv, NULL, 0)
-
-#ifndef MODULE
-#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
-static __initdata struct early_platform_driver early_driver = { \
- .class_str = class_string, \
- .buffer = buf, \
- .bufsize = bufsiz, \
- .pdrv = platdrv, \
- .requested_id = EARLY_PLATFORM_ID_UNSET, \
-}; \
-static int __init early_platform_driver_setup_func(char *buffer) \
-{ \
- return early_platform_driver_register(&early_driver, buffer); \
-} \
-early_param(class_string, early_platform_driver_setup_func)
-#else /* MODULE */
-#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
-static inline char *early_platform_driver_setup_func(void) \
-{ \
- return bufsiz ? buf : NULL; \
-}
-#endif /* MODULE */
-
#ifdef CONFIG_SUSPEND
extern int platform_pm_suspend(struct device *dev);
extern int platform_pm_resume(struct device *dev);
@@ -380,4 +334,16 @@ extern int platform_dma_configure(struct device *dev);
#define USE_PLATFORM_PM_SLEEP_OPS
#endif
+#ifndef CONFIG_SUPERH
+/*
+ * REVISIT: This stub is needed for all non-SuperH users of early platform
+ * drivers. It should go away once we introduce the new platform_device-based
+ * early driver framework.
+ */
+static inline int is_sh_early_platform_device(struct platform_device *pdev)
+{
+ return 0;
+}
+#endif /* CONFIG_SUPERH */
+
#endif /* _PLATFORM_DEVICE_H_ */
diff --git a/include/linux/sys_soc.h b/include/linux/sys_soc.h
index 48ceea867dd6..d9b3cf0f410c 100644
--- a/include/linux/sys_soc.h
+++ b/include/linux/sys_soc.h
@@ -15,6 +15,7 @@ struct soc_device_attribute {
const char *serial_number;
const char *soc_id;
const void *data;
+ const struct attribute_group *custom_attr_group;
};
/**