i3c_bus_maintenance_unlock(&master->bus);
cancel_work_sync(&master->hj_work);
+ cancel_work_sync(&master->reg_work);
}
static void i3c_device_shutdown(struct device *dev)
}
}
+static void i3c_master_reg_work_fn(struct work_struct *work)
+{
+ struct i3c_master_controller *master = container_of(work, typeof(*master), reg_work);
+
+ i3c_bus_normaluse_lock(&master->bus);
+ if (!master->shutting_down)
+ i3c_master_register_new_i3c_devs(master);
+ i3c_bus_normaluse_unlock(&master->bus);
+}
+
/**
* i3c_master_do_daa_ext() - Dynamic Address Assignment (extended version)
* @master: controller
if (ret)
goto out;
- i3c_bus_normaluse_lock(&master->bus);
- i3c_master_register_new_i3c_devs(master);
- i3c_bus_normaluse_unlock(&master->bus);
+ queue_work(master->wq, &master->reg_work);
out:
i3c_master_rpm_put(master);
goto err_put_dev;
}
INIT_WORK(&master->hj_work, i3c_master_hj_work_fn);
+ INIT_WORK(&master->reg_work, i3c_master_reg_work_fn);
ret = i3c_master_bus_init(master);
if (ret)
/*
* We're done initializing the bus and the controller, we can now
- * register I3C devices discovered during the initial DAA.
+ * register I3C devices discovered during the initial DAA. Device
+ * registration is done via reg_work because that keeps a single
+ * registration code path and ensures the worker is the only writer
+ * of desc->dev. Flush the work to preserve synchronous probe-time
+ * behavior.
*/
master->init_done = true;
- i3c_bus_normaluse_lock(&master->bus);
- i3c_master_register_new_i3c_devs(master);
- i3c_bus_normaluse_unlock(&master->bus);
+ queue_work(master->wq, &master->reg_work);
+ flush_work(&master->reg_work);
if (master->ops->set_dev_nack_retry)
device_create_file(&master->dev, &dev_attr_dev_nack_retry_count);
* be done from a sleep-able context
* @hj_work: work item used to run DAA after a Hot-Join event is detected.
* Queued to @wq by i3c_master_queue_hotjoin()
+ * @reg_work: work item used to register newly discovered I3C devices with
+ * the driver model. Queued to @wq by i3c_master_do_daa_ext() so
+ * that device registration is deferred out of the DAA caller's
+ * context (notably the resume path), and is skipped if the
+ * controller is shutting down
* @dev_nack_retry_count: retry count when slave device nack
*
* A &struct i3c_master_controller has to be registered to the I3C subsystem
struct i3c_bus bus;
struct workqueue_struct *wq;
struct work_struct hj_work;
+ struct work_struct reg_work;
unsigned int dev_nack_retry_count;
};