1

fpga: manager: add owner module and take its refcount

The current implementation of the fpga manager assumes that the low-level
module registers a driver for the parent device and uses its owner pointer
to take the module's refcount. This approach is problematic since it can
lead to a null pointer dereference while attempting to get the manager if
the parent device does not have a driver.

To address this problem, add a module owner pointer to the fpga_manager
struct and use it to take the module's refcount. Modify the functions for
registering the manager to take an additional owner module parameter and
rename them to avoid conflicts. Use the old function names for helper
macros that automatically set the module that registers the manager as the
owner. This ensures compatibility with existing low-level control modules
and reduces the chances of registering a manager without setting the owner.

Also, update the documentation to keep it consistent with the new interface
for registering an fpga manager.

Other changes: opportunistically move put_device() from __fpga_mgr_get() to
fpga_mgr_get() and of_fpga_mgr_get() to improve code clarity since the
manager device is taken in these functions.

Fixes: 654ba4cc0f ("fpga manager: ensure lifetime with of_fpga_mgr_get")
Suggested-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Suggested-by: Xu Yilun <yilun.xu@intel.com>
Signed-off-by: Marco Pagani <marpagan@redhat.com>
Acked-by: Xu Yilun <yilun.xu@intel.com>
Link: https://lore.kernel.org/r/20240305192926.84886-1-marpagan@redhat.com
Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
This commit is contained in:
Marco Pagani 2024-03-05 20:29:26 +01:00 committed by Xu Yilun
parent 4cece76496
commit 4d4d2d4346
No known key found for this signature in database
GPG Key ID: FCB70381A4A08CDA
3 changed files with 89 additions and 53 deletions

View File

@ -24,7 +24,8 @@ How to support a new FPGA device
-------------------------------- --------------------------------
To add another FPGA manager, write a driver that implements a set of ops. The To add another FPGA manager, write a driver that implements a set of ops. The
probe function calls fpga_mgr_register() or fpga_mgr_register_full(), such as:: probe function calls ``fpga_mgr_register()`` or ``fpga_mgr_register_full()``,
such as::
static const struct fpga_manager_ops socfpga_fpga_ops = { static const struct fpga_manager_ops socfpga_fpga_ops = {
.write_init = socfpga_fpga_ops_configure_init, .write_init = socfpga_fpga_ops_configure_init,
@ -69,10 +70,11 @@ probe function calls fpga_mgr_register() or fpga_mgr_register_full(), such as::
} }
Alternatively, the probe function could call one of the resource managed Alternatively, the probe function could call one of the resource managed
register functions, devm_fpga_mgr_register() or devm_fpga_mgr_register_full(). register functions, ``devm_fpga_mgr_register()`` or
When these functions are used, the parameter syntax is the same, but the call ``devm_fpga_mgr_register_full()``. When these functions are used, the
to fpga_mgr_unregister() should be removed. In the above example, the parameter syntax is the same, but the call to ``fpga_mgr_unregister()`` should be
socfpga_fpga_remove() function would not be required. removed. In the above example, the ``socfpga_fpga_remove()`` function would not be
required.
The ops will implement whatever device specific register writes are needed to The ops will implement whatever device specific register writes are needed to
do the programming sequence for this particular FPGA. These ops return 0 for do the programming sequence for this particular FPGA. These ops return 0 for
@ -125,15 +127,19 @@ API for implementing a new FPGA Manager driver
* struct fpga_manager - the FPGA manager struct * struct fpga_manager - the FPGA manager struct
* struct fpga_manager_ops - Low level FPGA manager driver ops * struct fpga_manager_ops - Low level FPGA manager driver ops
* struct fpga_manager_info - Parameter structure for fpga_mgr_register_full() * struct fpga_manager_info - Parameter structure for fpga_mgr_register_full()
* fpga_mgr_register_full() - Create and register an FPGA manager using the * __fpga_mgr_register_full() - Create and register an FPGA manager using the
fpga_mgr_info structure to provide the full flexibility of options fpga_mgr_info structure to provide the full flexibility of options
* fpga_mgr_register() - Create and register an FPGA manager using standard * __fpga_mgr_register() - Create and register an FPGA manager using standard
arguments arguments
* devm_fpga_mgr_register_full() - Resource managed version of * __devm_fpga_mgr_register_full() - Resource managed version of
fpga_mgr_register_full() __fpga_mgr_register_full()
* devm_fpga_mgr_register() - Resource managed version of fpga_mgr_register() * __devm_fpga_mgr_register() - Resource managed version of __fpga_mgr_register()
* fpga_mgr_unregister() - Unregister an FPGA manager * fpga_mgr_unregister() - Unregister an FPGA manager
Helper macros ``fpga_mgr_register_full()``, ``fpga_mgr_register()``,
``devm_fpga_mgr_register_full()``, and ``devm_fpga_mgr_register()`` are available
to ease the registration.
.. kernel-doc:: include/linux/fpga/fpga-mgr.h .. kernel-doc:: include/linux/fpga/fpga-mgr.h
:functions: fpga_mgr_states :functions: fpga_mgr_states
@ -147,16 +153,16 @@ API for implementing a new FPGA Manager driver
:functions: fpga_manager_info :functions: fpga_manager_info
.. kernel-doc:: drivers/fpga/fpga-mgr.c .. kernel-doc:: drivers/fpga/fpga-mgr.c
:functions: fpga_mgr_register_full :functions: __fpga_mgr_register_full
.. kernel-doc:: drivers/fpga/fpga-mgr.c .. kernel-doc:: drivers/fpga/fpga-mgr.c
:functions: fpga_mgr_register :functions: __fpga_mgr_register
.. kernel-doc:: drivers/fpga/fpga-mgr.c .. kernel-doc:: drivers/fpga/fpga-mgr.c
:functions: devm_fpga_mgr_register_full :functions: __devm_fpga_mgr_register_full
.. kernel-doc:: drivers/fpga/fpga-mgr.c .. kernel-doc:: drivers/fpga/fpga-mgr.c
:functions: devm_fpga_mgr_register :functions: __devm_fpga_mgr_register
.. kernel-doc:: drivers/fpga/fpga-mgr.c .. kernel-doc:: drivers/fpga/fpga-mgr.c
:functions: fpga_mgr_unregister :functions: fpga_mgr_unregister

View File

@ -664,20 +664,16 @@ static struct attribute *fpga_mgr_attrs[] = {
}; };
ATTRIBUTE_GROUPS(fpga_mgr); 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; struct fpga_manager *mgr;
mgr = to_fpga_manager(dev); mgr = to_fpga_manager(mgr_dev);
if (!try_module_get(dev->parent->driver->owner)) if (!try_module_get(mgr->mops_owner))
goto err_dev; mgr = ERR_PTR(-ENODEV);
return mgr; return mgr;
err_dev:
put_device(dev);
return ERR_PTR(-ENODEV);
} }
static int fpga_mgr_dev_match(struct device *dev, const void *data) 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 fpga_manager *fpga_mgr_get(struct device *dev)
{ {
struct device *mgr_dev = class_find_device(&fpga_mgr_class, NULL, dev, struct fpga_manager *mgr;
fpga_mgr_dev_match); struct device *mgr_dev;
mgr_dev = class_find_device(&fpga_mgr_class, NULL, dev, fpga_mgr_dev_match);
if (!mgr_dev) if (!mgr_dev)
return ERR_PTR(-ENODEV); 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); 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 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); mgr_dev = class_find_device_by_of_node(&fpga_mgr_class, node);
if (!dev) if (!mgr_dev)
return ERR_PTR(-ENODEV); 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); 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) void fpga_mgr_put(struct fpga_manager *mgr)
{ {
module_put(mgr->dev.parent->driver->owner); module_put(mgr->mops_owner);
put_device(&mgr->dev); put_device(&mgr->dev);
} }
EXPORT_SYMBOL_GPL(fpga_mgr_put); EXPORT_SYMBOL_GPL(fpga_mgr_put);
@ -766,9 +773,10 @@ void fpga_mgr_unlock(struct fpga_manager *mgr)
EXPORT_SYMBOL_GPL(fpga_mgr_unlock); 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 * @parent: fpga manager device from pdev
* @info: parameters for fpga manager * @info: parameters for fpga manager
* @owner: owner module containing the ops
* *
* The caller of this function is responsible for calling fpga_mgr_unregister(). * The caller of this function is responsible for calling fpga_mgr_unregister().
* Using devm_fpga_mgr_register_full() instead is recommended. * 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() * Return: pointer to struct fpga_manager pointer or ERR_PTR()
*/ */
struct fpga_manager * 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; const struct fpga_manager_ops *mops = info->mops;
struct fpga_manager *mgr; 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); mutex_init(&mgr->ref_mutex);
mgr->mops_owner = owner;
mgr->name = info->name; mgr->name = info->name;
mgr->mops = info->mops; mgr->mops = info->mops;
mgr->priv = info->priv; mgr->priv = info->priv;
@ -841,14 +852,15 @@ error_kfree:
return ERR_PTR(ret); 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 * @parent: fpga manager device from pdev
* @name: fpga manager name * @name: fpga manager name
* @mops: pointer to structure of fpga manager ops * @mops: pointer to structure of fpga manager ops
* @priv: fpga manager private data * @priv: fpga manager private data
* @owner: owner module containing the ops
* *
* The caller of this function is responsible for calling fpga_mgr_unregister(). * The caller of this function is responsible for calling fpga_mgr_unregister().
* Using devm_fpga_mgr_register() instead is recommended. This simple * 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() * Return: pointer to struct fpga_manager pointer or ERR_PTR()
*/ */
struct fpga_manager * struct fpga_manager *
fpga_mgr_register(struct device *parent, const char *name, __fpga_mgr_register(struct device *parent, const char *name,
const struct fpga_manager_ops *mops, void *priv) const struct fpga_manager_ops *mops, void *priv, struct module *owner)
{ {
struct fpga_manager_info info = { 0 }; struct fpga_manager_info info = { 0 };
@ -868,9 +880,9 @@ fpga_mgr_register(struct device *parent, const char *name,
info.mops = mops; info.mops = mops;
info.priv = priv; 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 * 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 * @parent: fpga manager device from pdev
* @info: parameters for fpga manager * @info: parameters for fpga manager
* @owner: owner module containing the ops
* *
* Return: fpga manager pointer on success, negative error code otherwise. * 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. * function will be called automatically when the managing device is detached.
*/ */
struct fpga_manager * 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_mgr_devres *dr;
struct fpga_manager *mgr; struct fpga_manager *mgr;
@ -919,7 +933,7 @@ devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_inf
if (!dr) if (!dr)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
mgr = fpga_mgr_register_full(parent, info); mgr = __fpga_mgr_register_full(parent, info, owner);
if (IS_ERR(mgr)) { if (IS_ERR(mgr)) {
devres_free(dr); devres_free(dr);
return mgr; return mgr;
@ -930,14 +944,15 @@ devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_inf
return mgr; 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 * @parent: fpga manager device from pdev
* @name: fpga manager name * @name: fpga manager name
* @mops: pointer to structure of fpga manager ops * @mops: pointer to structure of fpga manager ops
* @priv: fpga manager private data * @priv: fpga manager private data
* @owner: owner module containing the ops
* *
* Return: fpga manager pointer on success, negative error code otherwise. * 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. * device is detached.
*/ */
struct fpga_manager * struct fpga_manager *
devm_fpga_mgr_register(struct device *parent, const char *name, __devm_fpga_mgr_register(struct device *parent, const char *name,
const struct fpga_manager_ops *mops, void *priv) const struct fpga_manager_ops *mops, void *priv,
struct module *owner)
{ {
struct fpga_manager_info info = { 0 }; struct fpga_manager_info info = { 0 };
@ -955,9 +971,9 @@ devm_fpga_mgr_register(struct device *parent, const char *name,
info.mops = mops; info.mops = mops;
info.priv = priv; 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) static void fpga_mgr_dev_release(struct device *dev)
{ {

View File

@ -201,6 +201,7 @@ struct fpga_manager_ops {
* @state: state of fpga manager * @state: state of fpga manager
* @compat_id: FPGA manager id for compatibility check. * @compat_id: FPGA manager id for compatibility check.
* @mops: pointer to struct of fpga manager ops * @mops: pointer to struct of fpga manager ops
* @mops_owner: module containing the mops
* @priv: low level driver private date * @priv: low level driver private date
*/ */
struct fpga_manager { struct fpga_manager {
@ -210,6 +211,7 @@ struct fpga_manager {
enum fpga_mgr_states state; enum fpga_mgr_states state;
struct fpga_compat_id *compat_id; struct fpga_compat_id *compat_id;
const struct fpga_manager_ops *mops; const struct fpga_manager_ops *mops;
struct module *mops_owner;
void *priv; void *priv;
}; };
@ -230,18 +232,30 @@ struct fpga_manager *fpga_mgr_get(struct device *dev);
void fpga_mgr_put(struct fpga_manager *mgr); void fpga_mgr_put(struct fpga_manager *mgr);
#define fpga_mgr_register_full(parent, info) \
__fpga_mgr_register_full(parent, info, THIS_MODULE)
struct fpga_manager * 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);
#define fpga_mgr_register(parent, name, mops, priv) \
__fpga_mgr_register(parent, name, mops, priv, THIS_MODULE)
struct fpga_manager * struct fpga_manager *
fpga_mgr_register(struct device *parent, const char *name, __fpga_mgr_register(struct device *parent, const char *name,
const struct fpga_manager_ops *mops, void *priv); const struct fpga_manager_ops *mops, void *priv, struct module *owner);
void fpga_mgr_unregister(struct fpga_manager *mgr); void fpga_mgr_unregister(struct fpga_manager *mgr);
#define devm_fpga_mgr_register_full(parent, info) \
__devm_fpga_mgr_register_full(parent, info, THIS_MODULE)
struct fpga_manager * 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);
#define devm_fpga_mgr_register(parent, name, mops, priv) \
__devm_fpga_mgr_register(parent, name, mops, priv, THIS_MODULE)
struct fpga_manager * struct fpga_manager *
devm_fpga_mgr_register(struct device *parent, const char *name, __devm_fpga_mgr_register(struct device *parent, const char *name,
const struct fpga_manager_ops *mops, void *priv); const struct fpga_manager_ops *mops, void *priv,
struct module *owner);
#endif /*_LINUX_FPGA_MGR_H */ #endif /*_LINUX_FPGA_MGR_H */