@@ -27,7 +27,6 @@ static void cxl_memdev_release(struct device *dev)
2727 struct cxl_memdev * cxlmd = to_cxl_memdev (dev );
2828
2929 ida_free (& cxl_memdev_ida , cxlmd -> id );
30- devm_cxl_memdev_edac_release (cxlmd );
3130 kfree (cxlmd );
3231}
3332
@@ -642,14 +641,24 @@ static void detach_memdev(struct work_struct *work)
642641 struct cxl_memdev * cxlmd ;
643642
644643 cxlmd = container_of (work , typeof (* cxlmd ), detach_work );
645- device_release_driver (& cxlmd -> dev );
644+
645+ /*
646+ * When the creator of @cxlmd sets ->attach it indicates CXL operation
647+ * is required. In that case, @cxlmd detach escalates to parent device
648+ * detach.
649+ */
650+ if (cxlmd -> attach )
651+ device_release_driver (cxlmd -> dev .parent );
652+ else
653+ device_release_driver (& cxlmd -> dev );
646654 put_device (& cxlmd -> dev );
647655}
648656
649657static struct lock_class_key cxl_memdev_key ;
650658
651659static struct cxl_memdev * cxl_memdev_alloc (struct cxl_dev_state * cxlds ,
652- const struct file_operations * fops )
660+ const struct file_operations * fops ,
661+ const struct cxl_memdev_attach * attach )
653662{
654663 struct cxl_memdev * cxlmd ;
655664 struct device * dev ;
@@ -665,6 +674,8 @@ static struct cxl_memdev *cxl_memdev_alloc(struct cxl_dev_state *cxlds,
665674 goto err ;
666675 cxlmd -> id = rc ;
667676 cxlmd -> depth = -1 ;
677+ cxlmd -> attach = attach ;
678+ cxlmd -> endpoint = ERR_PTR (- ENXIO );
668679
669680 dev = & cxlmd -> dev ;
670681 device_initialize (dev );
@@ -1051,50 +1062,84 @@ static const struct file_operations cxl_memdev_fops = {
10511062 .llseek = noop_llseek ,
10521063};
10531064
1054- struct cxl_memdev * devm_cxl_add_memdev (struct device * host ,
1055- struct cxl_dev_state * cxlds )
1065+ /*
1066+ * Activate ioctl operations, no cxl_memdev_rwsem manipulation needed as this is
1067+ * ordered with cdev_add() publishing the device.
1068+ */
1069+ static int cxlmd_add (struct cxl_memdev * cxlmd , struct cxl_dev_state * cxlds )
1070+ {
1071+ int rc ;
1072+
1073+ cxlmd -> cxlds = cxlds ;
1074+ cxlds -> cxlmd = cxlmd ;
1075+
1076+ rc = cdev_device_add (& cxlmd -> cdev , & cxlmd -> dev );
1077+ if (rc ) {
1078+ /*
1079+ * The cdev was briefly live, shutdown any ioctl operations that
1080+ * saw that state.
1081+ */
1082+ cxl_memdev_shutdown (& cxlmd -> dev );
1083+ return rc ;
1084+ }
1085+
1086+ return 0 ;
1087+ }
1088+
1089+ DEFINE_FREE (put_cxlmd , struct cxl_memdev * ,
1090+ if (!IS_ERR_OR_NULL (_T )) put_device (& _T -> dev ))
1091+
1092+ static struct cxl_memdev * cxl_memdev_autoremove (struct cxl_memdev * cxlmd )
1093+ {
1094+ int rc ;
1095+
1096+ /*
1097+ * If @attach is provided fail if the driver is not attached upon
1098+ * return. Note that failure here could be the result of a race to
1099+ * teardown the CXL port topology. I.e. cxl_mem_probe() could have
1100+ * succeeded and then cxl_mem unbound before the lock is acquired.
1101+ */
1102+ guard (device )(& cxlmd -> dev );
1103+ if (cxlmd -> attach && !cxlmd -> dev .driver ) {
1104+ cxl_memdev_unregister (cxlmd );
1105+ return ERR_PTR (- ENXIO );
1106+ }
1107+
1108+ rc = devm_add_action_or_reset (cxlmd -> cxlds -> dev , cxl_memdev_unregister ,
1109+ cxlmd );
1110+ if (rc )
1111+ return ERR_PTR (rc );
1112+
1113+ return cxlmd ;
1114+ }
1115+
1116+ /*
1117+ * Core helper for devm_cxl_add_memdev() that wants to both create a device and
1118+ * assert to the caller that upon return cxl_mem::probe() has been invoked.
1119+ */
1120+ struct cxl_memdev * __devm_cxl_add_memdev (struct cxl_dev_state * cxlds ,
1121+ const struct cxl_memdev_attach * attach )
10561122{
1057- struct cxl_memdev * cxlmd ;
10581123 struct device * dev ;
1059- struct cdev * cdev ;
10601124 int rc ;
10611125
1062- cxlmd = cxl_memdev_alloc (cxlds , & cxl_memdev_fops );
1126+ struct cxl_memdev * cxlmd __free (put_cxlmd ) =
1127+ cxl_memdev_alloc (cxlds , & cxl_memdev_fops , attach );
10631128 if (IS_ERR (cxlmd ))
10641129 return cxlmd ;
10651130
10661131 dev = & cxlmd -> dev ;
10671132 rc = dev_set_name (dev , "mem%d" , cxlmd -> id );
10681133 if (rc )
1069- goto err ;
1070-
1071- /*
1072- * Activate ioctl operations, no cxl_memdev_rwsem manipulation
1073- * needed as this is ordered with cdev_add() publishing the device.
1074- */
1075- cxlmd -> cxlds = cxlds ;
1076- cxlds -> cxlmd = cxlmd ;
1077-
1078- cdev = & cxlmd -> cdev ;
1079- rc = cdev_device_add (cdev , dev );
1080- if (rc )
1081- goto err ;
1134+ return ERR_PTR (rc );
10821135
1083- rc = devm_add_action_or_reset ( host , cxl_memdev_unregister , cxlmd );
1136+ rc = cxlmd_add ( cxlmd , cxlds );
10841137 if (rc )
10851138 return ERR_PTR (rc );
1086- return cxlmd ;
10871139
1088- err :
1089- /*
1090- * The cdev was briefly live, shutdown any ioctl operations that
1091- * saw that state.
1092- */
1093- cxl_memdev_shutdown (dev );
1094- put_device (dev );
1095- return ERR_PTR (rc );
1140+ return cxl_memdev_autoremove (no_free_ptr (cxlmd ));
10961141}
1097- EXPORT_SYMBOL_NS_GPL ( devm_cxl_add_memdev , "CXL " );
1142+ EXPORT_SYMBOL_FOR_MODULES ( __devm_cxl_add_memdev , "cxl_mem " );
10981143
10991144static void sanitize_teardown_notifier (void * data )
11001145{
0 commit comments