fpga: manager: add owner module and take its refcount
[linux-block.git] / drivers / fpga / fpga-mgr.c
index 06651389c59262c46b2fc576dd22aaa152c1b464..0f4035b089a2ea18ac66d88ac850307e0cf9b0a6 100644 (file)
@@ -664,20 +664,16 @@ static struct attribute *fpga_mgr_attrs[] = {
 };
 ATTRIBUTE_GROUPS(fpga_mgr);
 
-static struct fpga_manager *__fpga_mgr_get(struct device *dev)
+static struct fpga_manager *__fpga_mgr_get(struct device *mgr_dev)
 {
        struct fpga_manager *mgr;
 
-       mgr = to_fpga_manager(dev);
+       mgr = to_fpga_manager(mgr_dev);
 
-       if (!try_module_get(dev->parent->driver->owner))
-               goto err_dev;
+       if (!try_module_get(mgr->mops_owner))
+               mgr = ERR_PTR(-ENODEV);
 
        return mgr;
-
-err_dev:
-       put_device(dev);
-       return ERR_PTR(-ENODEV);
 }
 
 static int fpga_mgr_dev_match(struct device *dev, const void *data)
@@ -693,12 +689,18 @@ static int fpga_mgr_dev_match(struct device *dev, const void *data)
  */
 struct fpga_manager *fpga_mgr_get(struct device *dev)
 {
-       struct device *mgr_dev = class_find_device(&fpga_mgr_class, NULL, dev,
-                                                  fpga_mgr_dev_match);
+       struct fpga_manager *mgr;
+       struct device *mgr_dev;
+
+       mgr_dev = class_find_device(&fpga_mgr_class, NULL, dev, fpga_mgr_dev_match);
        if (!mgr_dev)
                return ERR_PTR(-ENODEV);
 
-       return __fpga_mgr_get(mgr_dev);
+       mgr = __fpga_mgr_get(mgr_dev);
+       if (IS_ERR(mgr))
+               put_device(mgr_dev);
+
+       return mgr;
 }
 EXPORT_SYMBOL_GPL(fpga_mgr_get);
 
@@ -711,13 +713,18 @@ EXPORT_SYMBOL_GPL(fpga_mgr_get);
  */
 struct fpga_manager *of_fpga_mgr_get(struct device_node *node)
 {
-       struct device *dev;
+       struct fpga_manager *mgr;
+       struct device *mgr_dev;
 
-       dev = class_find_device_by_of_node(&fpga_mgr_class, node);
-       if (!dev)
+       mgr_dev = class_find_device_by_of_node(&fpga_mgr_class, node);
+       if (!mgr_dev)
                return ERR_PTR(-ENODEV);
 
-       return __fpga_mgr_get(dev);
+       mgr = __fpga_mgr_get(mgr_dev);
+       if (IS_ERR(mgr))
+               put_device(mgr_dev);
+
+       return mgr;
 }
 EXPORT_SYMBOL_GPL(of_fpga_mgr_get);
 
@@ -727,7 +734,7 @@ EXPORT_SYMBOL_GPL(of_fpga_mgr_get);
  */
 void fpga_mgr_put(struct fpga_manager *mgr)
 {
-       module_put(mgr->dev.parent->driver->owner);
+       module_put(mgr->mops_owner);
        put_device(&mgr->dev);
 }
 EXPORT_SYMBOL_GPL(fpga_mgr_put);
@@ -766,9 +773,10 @@ void fpga_mgr_unlock(struct fpga_manager *mgr)
 EXPORT_SYMBOL_GPL(fpga_mgr_unlock);
 
 /**
- * fpga_mgr_register_full - create and register an FPGA Manager device
+ * __fpga_mgr_register_full - create and register an FPGA Manager device
  * @parent:    fpga manager device from pdev
  * @info:      parameters for fpga manager
+ * @owner:     owner module containing the ops
  *
  * The caller of this function is responsible for calling fpga_mgr_unregister().
  * Using devm_fpga_mgr_register_full() instead is recommended.
@@ -776,7 +784,8 @@ EXPORT_SYMBOL_GPL(fpga_mgr_unlock);
  * Return: pointer to struct fpga_manager pointer or ERR_PTR()
  */
 struct fpga_manager *
-fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info)
+__fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info,
+                        struct module *owner)
 {
        const struct fpga_manager_ops *mops = info->mops;
        struct fpga_manager *mgr;
@@ -804,6 +813,8 @@ fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *in
 
        mutex_init(&mgr->ref_mutex);
 
+       mgr->mops_owner = owner;
+
        mgr->name = info->name;
        mgr->mops = info->mops;
        mgr->priv = info->priv;
@@ -841,14 +852,15 @@ error_kfree:
 
        return ERR_PTR(ret);
 }
-EXPORT_SYMBOL_GPL(fpga_mgr_register_full);
+EXPORT_SYMBOL_GPL(__fpga_mgr_register_full);
 
 /**
- * fpga_mgr_register - create and register an FPGA Manager device
+ * __fpga_mgr_register - create and register an FPGA Manager device
  * @parent:    fpga manager device from pdev
  * @name:      fpga manager name
  * @mops:      pointer to structure of fpga manager ops
  * @priv:      fpga manager private data
+ * @owner:     owner module containing the ops
  *
  * The caller of this function is responsible for calling fpga_mgr_unregister().
  * Using devm_fpga_mgr_register() instead is recommended. This simple
@@ -859,8 +871,8 @@ EXPORT_SYMBOL_GPL(fpga_mgr_register_full);
  * Return: pointer to struct fpga_manager pointer or ERR_PTR()
  */
 struct fpga_manager *
-fpga_mgr_register(struct device *parent, const char *name,
-                 const struct fpga_manager_ops *mops, void *priv)
+__fpga_mgr_register(struct device *parent, const char *name,
+                   const struct fpga_manager_ops *mops, void *priv, struct module *owner)
 {
        struct fpga_manager_info info = { 0 };
 
@@ -868,9 +880,9 @@ fpga_mgr_register(struct device *parent, const char *name,
        info.mops = mops;
        info.priv = priv;
 
-       return fpga_mgr_register_full(parent, &info);
+       return __fpga_mgr_register_full(parent, &info, owner);
 }
-EXPORT_SYMBOL_GPL(fpga_mgr_register);
+EXPORT_SYMBOL_GPL(__fpga_mgr_register);
 
 /**
  * fpga_mgr_unregister - unregister an FPGA manager
@@ -900,9 +912,10 @@ static void devm_fpga_mgr_unregister(struct device *dev, void *res)
 }
 
 /**
- * devm_fpga_mgr_register_full - resource managed variant of fpga_mgr_register()
+ * __devm_fpga_mgr_register_full - resource managed variant of fpga_mgr_register()
  * @parent:    fpga manager device from pdev
  * @info:      parameters for fpga manager
+ * @owner:     owner module containing the ops
  *
  * Return:  fpga manager pointer on success, negative error code otherwise.
  *
@@ -910,7 +923,8 @@ static void devm_fpga_mgr_unregister(struct device *dev, void *res)
  * function will be called automatically when the managing device is detached.
  */
 struct fpga_manager *
-devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info)
+__devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info,
+                             struct module *owner)
 {
        struct fpga_mgr_devres *dr;
        struct fpga_manager *mgr;
@@ -919,7 +933,7 @@ devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_inf
        if (!dr)
                return ERR_PTR(-ENOMEM);
 
-       mgr = fpga_mgr_register_full(parent, info);
+       mgr = __fpga_mgr_register_full(parent, info, owner);
        if (IS_ERR(mgr)) {
                devres_free(dr);
                return mgr;
@@ -930,14 +944,15 @@ devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_inf
 
        return mgr;
 }
-EXPORT_SYMBOL_GPL(devm_fpga_mgr_register_full);
+EXPORT_SYMBOL_GPL(__devm_fpga_mgr_register_full);
 
 /**
- * devm_fpga_mgr_register - resource managed variant of fpga_mgr_register()
+ * __devm_fpga_mgr_register - resource managed variant of fpga_mgr_register()
  * @parent:    fpga manager device from pdev
  * @name:      fpga manager name
  * @mops:      pointer to structure of fpga manager ops
  * @priv:      fpga manager private data
+ * @owner:     owner module containing the ops
  *
  * Return:  fpga manager pointer on success, negative error code otherwise.
  *
@@ -946,8 +961,9 @@ EXPORT_SYMBOL_GPL(devm_fpga_mgr_register_full);
  * device is detached.
  */
 struct fpga_manager *
-devm_fpga_mgr_register(struct device *parent, const char *name,
-                      const struct fpga_manager_ops *mops, void *priv)
+__devm_fpga_mgr_register(struct device *parent, const char *name,
+                        const struct fpga_manager_ops *mops, void *priv,
+                        struct module *owner)
 {
        struct fpga_manager_info info = { 0 };
 
@@ -955,9 +971,9 @@ devm_fpga_mgr_register(struct device *parent, const char *name,
        info.mops = mops;
        info.priv = priv;
 
-       return devm_fpga_mgr_register_full(parent, &info);
+       return __devm_fpga_mgr_register_full(parent, &info, owner);
 }
-EXPORT_SYMBOL_GPL(devm_fpga_mgr_register);
+EXPORT_SYMBOL_GPL(__devm_fpga_mgr_register);
 
 static void fpga_mgr_dev_release(struct device *dev)
 {