@@ -47,6 +47,22 @@ static bool fw_devlink_drv_reg_done;
static bool fw_devlink_best_effort;
static struct workqueue_struct *device_link_wq;
+/**
+ * system_is_shutting_down - Check if system state is not active.
+ *
+ * When system state is not active and in shutdown state, new devices
+ * should not be allowed to be added.
+ *
+ * If system_state is SYSTEM_HALT || SYSTEM_POWER_OFF || SYSTEM_RESTART
+ * this function will return true.
+ */
+static inline bool system_is_shutting_down(void)
+{
+ return system_state == SYSTEM_HALT ||
+ system_state == SYSTEM_POWER_OFF ||
+ system_state == SYSTEM_RESTART;
+}
+
/**
* __fwnode_link_add - Create a link between two fwnode_handles.
* @con: Consumer end of the link.
@@ -3614,6 +3630,9 @@ static int device_private_init(struct device *dev)
return 0;
}
+
+DEFINE_STATIC_SRCU(device_add_srcu);
+
/**
* device_add - add device to device hierarchy.
* @dev: device.
@@ -3647,13 +3666,20 @@ int device_add(struct device *dev)
struct device *parent;
struct kobject *kobj;
struct class_interface *class_intf;
- int error = -EINVAL;
+ int idx, error = -EINVAL;
struct kobject *glue_dir = NULL;
+ idx = srcu_read_lock(&device_add_srcu);
+
dev = get_device(dev);
if (!dev)
goto done;
+ if (unlikely(system_is_shutting_down())) {
+ error = -ESHUTDOWN;
+ goto done;
+ }
+
if (!dev->p) {
error = device_private_init(dev);
if (error)
@@ -3803,6 +3829,7 @@ int device_add(struct device *dev)
}
done:
put_device(dev);
+ srcu_read_unlock(&device_add_srcu, idx);
return error;
SysEntryError:
if (MAJOR(dev->devt))
@@ -4877,6 +4904,7 @@ void device_shutdown(void)
wait_for_device_probe();
device_block_probing();
+ synchronize_srcu(&device_add_srcu);
cpufreq_suspend();