diff options
Diffstat (limited to 'drivers/fpga/fpga-bridge.c')
| -rw-r--r-- | drivers/fpga/fpga-bridge.c | 267 |
1 files changed, 103 insertions, 164 deletions
diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c index 4bab9028940a..8ef395b49bf8 100644 --- a/drivers/fpga/fpga-bridge.c +++ b/drivers/fpga/fpga-bridge.c @@ -14,10 +14,10 @@ #include <linux/spinlock.h> static DEFINE_IDA(fpga_bridge_ida); -static struct class *fpga_bridge_class; +static const struct class fpga_bridge_class; /* Lock for adding/removing bridges to linked lists*/ -static spinlock_t bridge_list_lock; +static DEFINE_SPINLOCK(bridge_list_lock); /** * fpga_bridge_enable - Enable transactions on the bridge @@ -30,7 +30,7 @@ int fpga_bridge_enable(struct fpga_bridge *bridge) { dev_dbg(&bridge->dev, "enable\n"); - if (bridge->br_ops && bridge->br_ops->enable_set) + if (bridge->br_ops->enable_set) return bridge->br_ops->enable_set(bridge, 1); return 0; @@ -48,62 +48,61 @@ int fpga_bridge_disable(struct fpga_bridge *bridge) { dev_dbg(&bridge->dev, "disable\n"); - if (bridge->br_ops && bridge->br_ops->enable_set) + if (bridge->br_ops->enable_set) return bridge->br_ops->enable_set(bridge, 0); return 0; } EXPORT_SYMBOL_GPL(fpga_bridge_disable); -static struct fpga_bridge *__fpga_bridge_get(struct device *dev, +static struct fpga_bridge *__fpga_bridge_get(struct device *bridge_dev, struct fpga_image_info *info) { struct fpga_bridge *bridge; - int ret = -ENODEV; - bridge = to_fpga_bridge(dev); + bridge = to_fpga_bridge(bridge_dev); bridge->info = info; - if (!mutex_trylock(&bridge->mutex)) { - ret = -EBUSY; - goto err_dev; - } + if (!mutex_trylock(&bridge->mutex)) + return ERR_PTR(-EBUSY); - if (!try_module_get(dev->parent->driver->owner)) - goto err_ll_mod; + if (!try_module_get(bridge->br_ops_owner)) { + mutex_unlock(&bridge->mutex); + return ERR_PTR(-ENODEV); + } dev_dbg(&bridge->dev, "get\n"); return bridge; - -err_ll_mod: - mutex_unlock(&bridge->mutex); -err_dev: - put_device(dev); - return ERR_PTR(ret); } /** - * of_fpga_bridge_get - get an exclusive reference to a fpga bridge + * of_fpga_bridge_get - get an exclusive reference to an fpga bridge * - * @np: node pointer of a FPGA bridge - * @info: fpga image specific information + * @np: node pointer of an FPGA bridge. + * @info: fpga image specific information. * - * Return fpga_bridge struct if successful. - * Return -EBUSY if someone already has a reference to the bridge. - * Return -ENODEV if @np is not a FPGA Bridge. + * Return: + * * fpga_bridge struct pointer if successful. + * * -EBUSY if someone already has a reference to the bridge. + * * -ENODEV if @np is not an FPGA Bridge or can't take parent driver refcount. */ struct fpga_bridge *of_fpga_bridge_get(struct device_node *np, struct fpga_image_info *info) { - struct device *dev; + struct fpga_bridge *bridge; + struct device *bridge_dev; - dev = class_find_device_by_of_node(fpga_bridge_class, np); - if (!dev) + bridge_dev = class_find_device_by_of_node(&fpga_bridge_class, np); + if (!bridge_dev) return ERR_PTR(-ENODEV); - return __fpga_bridge_get(dev, info); + bridge = __fpga_bridge_get(bridge_dev, info); + if (IS_ERR(bridge)) + put_device(bridge_dev); + + return bridge; } EXPORT_SYMBOL_GPL(of_fpga_bridge_get); @@ -113,25 +112,30 @@ static int fpga_bridge_dev_match(struct device *dev, const void *data) } /** - * fpga_bridge_get - get an exclusive reference to a fpga bridge + * fpga_bridge_get - get an exclusive reference to an fpga bridge * @dev: parent device that fpga bridge was registered with - * @info: fpga manager info + * @info: fpga image specific information * - * Given a device, get an exclusive reference to a fpga bridge. + * Given a device, get an exclusive reference to an fpga bridge. * * Return: fpga bridge struct or IS_ERR() condition containing error code. */ struct fpga_bridge *fpga_bridge_get(struct device *dev, struct fpga_image_info *info) { + struct fpga_bridge *bridge; struct device *bridge_dev; - bridge_dev = class_find_device(fpga_bridge_class, NULL, dev, + bridge_dev = class_find_device(&fpga_bridge_class, NULL, dev, fpga_bridge_dev_match); if (!bridge_dev) return ERR_PTR(-ENODEV); - return __fpga_bridge_get(bridge_dev, info); + bridge = __fpga_bridge_get(bridge_dev, info); + if (IS_ERR(bridge)) + put_device(bridge_dev); + + return bridge; } EXPORT_SYMBOL_GPL(fpga_bridge_get); @@ -145,7 +149,7 @@ void fpga_bridge_put(struct fpga_bridge *bridge) dev_dbg(&bridge->dev, "put\n"); bridge->info = NULL; - module_put(bridge->dev.parent->driver->owner); + module_put(bridge->br_ops_owner); mutex_unlock(&bridge->mutex); put_device(&bridge->dev); } @@ -155,9 +159,9 @@ EXPORT_SYMBOL_GPL(fpga_bridge_put); * fpga_bridges_enable - enable bridges in a list * @bridge_list: list of FPGA bridges * - * Enable each bridge in the list. If list is empty, do nothing. + * Enable each bridge in the list. If list is empty, do nothing. * - * Return 0 for success or empty bridge list; return error code otherwise. + * Return: 0 for success or empty bridge list or an error code otherwise. */ int fpga_bridges_enable(struct list_head *bridge_list) { @@ -179,9 +183,9 @@ EXPORT_SYMBOL_GPL(fpga_bridges_enable); * * @bridge_list: list of FPGA bridges * - * Disable each bridge in the list. If list is empty, do nothing. + * Disable each bridge in the list. If list is empty, do nothing. * - * Return 0 for success or empty bridge list; return error code otherwise. + * Return: 0 for success or empty bridge list or an error code otherwise. */ int fpga_bridges_disable(struct list_head *bridge_list) { @@ -224,13 +228,13 @@ EXPORT_SYMBOL_GPL(fpga_bridges_put); /** * of_fpga_bridge_get_to_list - get a bridge, add it to a list * - * @np: node pointer of a FPGA bridge + * @np: node pointer of an FPGA bridge * @info: fpga image specific information * @bridge_list: list of FPGA bridges * - * Get an exclusive reference to the bridge and and it to the list. + * Get an exclusive reference to the bridge and it to the list. * - * Return 0 for success, error code from of_fpga_bridge_get() othewise. + * Return: 0 for success, error code from of_fpga_bridge_get() otherwise. */ int of_fpga_bridge_get_to_list(struct device_node *np, struct fpga_image_info *info, @@ -258,9 +262,9 @@ EXPORT_SYMBOL_GPL(of_fpga_bridge_get_to_list); * @info: fpga image specific information * @bridge_list: list of FPGA bridges * - * Get an exclusive reference to the bridge and and it to the list. + * Get an exclusive reference to the bridge and it to the list. * - * Return 0 for success, error code from fpga_bridge_get() othewise. + * Return: 0 for success, error code from fpga_bridge_get() otherwise. */ int fpga_bridge_get_to_list(struct device *dev, struct fpga_image_info *info, @@ -293,12 +297,15 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct fpga_bridge *bridge = to_fpga_bridge(dev); - int enable = 1; + int state = 1; - if (bridge->br_ops && bridge->br_ops->enable_show) - enable = bridge->br_ops->enable_show(bridge); + if (bridge->br_ops->enable_show) { + state = bridge->br_ops->enable_show(bridge); + if (state < 0) + return state; + } - return sprintf(buf, "%s\n", enable ? "enabled" : "disabled"); + return sysfs_emit(buf, "%s\n", state ? "enabled" : "disabled"); } static DEVICE_ATTR_RO(name); @@ -312,34 +319,38 @@ static struct attribute *fpga_bridge_attrs[] = { ATTRIBUTE_GROUPS(fpga_bridge); /** - * fpga_bridge_create - create and initialize a struct fpga_bridge - * @dev: FPGA bridge device from pdev + * __fpga_bridge_register - create and register an FPGA Bridge device + * @parent: FPGA bridge device from pdev * @name: FPGA bridge name * @br_ops: pointer to structure of fpga bridge ops * @priv: FPGA bridge private data + * @owner: owner module containing the br_ops * - * The caller of this function is responsible for freeing the bridge with - * fpga_bridge_free(). Using devm_fpga_bridge_create() instead is recommended. - * - * Return: struct fpga_bridge or NULL + * Return: struct fpga_bridge pointer or ERR_PTR() */ -struct fpga_bridge *fpga_bridge_create(struct device *dev, const char *name, - const struct fpga_bridge_ops *br_ops, - void *priv) +struct fpga_bridge * +__fpga_bridge_register(struct device *parent, const char *name, + const struct fpga_bridge_ops *br_ops, + void *priv, struct module *owner) { struct fpga_bridge *bridge; - int id, ret = 0; + int id, ret; + + if (!br_ops) { + dev_err(parent, "Attempt to register without fpga_bridge_ops\n"); + return ERR_PTR(-EINVAL); + } if (!name || !strlen(name)) { - dev_err(dev, "Attempt to register with no name!\n"); - return NULL; + dev_err(parent, "Attempt to register with no name!\n"); + return ERR_PTR(-EINVAL); } bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); if (!bridge) - return NULL; + return ERR_PTR(-ENOMEM); - id = ida_simple_get(&fpga_bridge_ida, 0, 0, GFP_KERNEL); + id = ida_alloc(&fpga_bridge_ida, GFP_KERNEL); if (id < 0) { ret = id; goto error_kfree; @@ -350,117 +361,44 @@ struct fpga_bridge *fpga_bridge_create(struct device *dev, const char *name, bridge->name = name; bridge->br_ops = br_ops; + bridge->br_ops_owner = owner; bridge->priv = priv; - device_initialize(&bridge->dev); bridge->dev.groups = br_ops->groups; - bridge->dev.class = fpga_bridge_class; - bridge->dev.parent = dev; - bridge->dev.of_node = dev->of_node; + bridge->dev.class = &fpga_bridge_class; + bridge->dev.parent = parent; + bridge->dev.of_node = parent->of_node; bridge->dev.id = id; ret = dev_set_name(&bridge->dev, "br%d", id); if (ret) goto error_device; + ret = device_register(&bridge->dev); + if (ret) { + put_device(&bridge->dev); + return ERR_PTR(ret); + } + + of_platform_populate(bridge->dev.of_node, NULL, NULL, &bridge->dev); + return bridge; error_device: - ida_simple_remove(&fpga_bridge_ida, id); + ida_free(&fpga_bridge_ida, id); error_kfree: kfree(bridge); - return NULL; -} -EXPORT_SYMBOL_GPL(fpga_bridge_create); - -/** - * fpga_bridge_free - free a fpga bridge created by fpga_bridge_create() - * @bridge: FPGA bridge struct - */ -void fpga_bridge_free(struct fpga_bridge *bridge) -{ - ida_simple_remove(&fpga_bridge_ida, bridge->dev.id); - kfree(bridge); -} -EXPORT_SYMBOL_GPL(fpga_bridge_free); - -static void devm_fpga_bridge_release(struct device *dev, void *res) -{ - struct fpga_bridge *bridge = *(struct fpga_bridge **)res; - - fpga_bridge_free(bridge); -} - -/** - * devm_fpga_bridge_create - create and init a managed struct fpga_bridge - * @dev: FPGA bridge device from pdev - * @name: FPGA bridge name - * @br_ops: pointer to structure of fpga bridge ops - * @priv: FPGA bridge private data - * - * This function is intended for use in a FPGA bridge driver's probe function. - * After the bridge driver creates the struct with devm_fpga_bridge_create(), it - * should register the bridge with fpga_bridge_register(). The bridge driver's - * remove function should call fpga_bridge_unregister(). The bridge struct - * allocated with this function will be freed automatically on driver detach. - * This includes the case of a probe function returning error before calling - * fpga_bridge_register(), the struct will still get cleaned up. - * - * Return: struct fpga_bridge or NULL - */ -struct fpga_bridge -*devm_fpga_bridge_create(struct device *dev, const char *name, - const struct fpga_bridge_ops *br_ops, void *priv) -{ - struct fpga_bridge **ptr, *bridge; - - ptr = devres_alloc(devm_fpga_bridge_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return NULL; - - bridge = fpga_bridge_create(dev, name, br_ops, priv); - if (!bridge) { - devres_free(ptr); - } else { - *ptr = bridge; - devres_add(dev, ptr); - } - - return bridge; -} -EXPORT_SYMBOL_GPL(devm_fpga_bridge_create); - -/** - * fpga_bridge_register - register a FPGA bridge - * - * @bridge: FPGA bridge struct - * - * Return: 0 for success, error code otherwise. - */ -int fpga_bridge_register(struct fpga_bridge *bridge) -{ - struct device *dev = &bridge->dev; - int ret; - - ret = device_add(dev); - if (ret) - return ret; - - of_platform_populate(dev->of_node, NULL, NULL, dev); - - dev_info(dev->parent, "fpga bridge [%s] registered\n", bridge->name); - - return 0; + return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(fpga_bridge_register); +EXPORT_SYMBOL_GPL(__fpga_bridge_register); /** - * fpga_bridge_unregister - unregister a FPGA bridge + * fpga_bridge_unregister - unregister an FPGA bridge * * @bridge: FPGA bridge struct * - * This function is intended for use in a FPGA bridge driver's remove function. + * This function is intended for use in an FPGA bridge driver's remove function. */ void fpga_bridge_unregister(struct fpga_bridge *bridge) { @@ -468,7 +406,7 @@ void fpga_bridge_unregister(struct fpga_bridge *bridge) * If the low level driver provides a method for putting bridge into * a desired state upon unregister, do it. */ - if (bridge->br_ops && bridge->br_ops->fpga_bridge_remove) + if (bridge->br_ops->fpga_bridge_remove) bridge->br_ops->fpga_bridge_remove(bridge); device_unregister(&bridge->dev); @@ -477,25 +415,26 @@ EXPORT_SYMBOL_GPL(fpga_bridge_unregister); static void fpga_bridge_dev_release(struct device *dev) { + struct fpga_bridge *bridge = to_fpga_bridge(dev); + + ida_free(&fpga_bridge_ida, bridge->dev.id); + kfree(bridge); } +static const struct class fpga_bridge_class = { + .name = "fpga_bridge", + .dev_groups = fpga_bridge_groups, + .dev_release = fpga_bridge_dev_release, +}; + static int __init fpga_bridge_dev_init(void) { - spin_lock_init(&bridge_list_lock); - - fpga_bridge_class = class_create(THIS_MODULE, "fpga_bridge"); - if (IS_ERR(fpga_bridge_class)) - return PTR_ERR(fpga_bridge_class); - - fpga_bridge_class->dev_groups = fpga_bridge_groups; - fpga_bridge_class->dev_release = fpga_bridge_dev_release; - - return 0; + return class_register(&fpga_bridge_class); } static void __exit fpga_bridge_dev_exit(void) { - class_destroy(fpga_bridge_class); + class_unregister(&fpga_bridge_class); ida_destroy(&fpga_bridge_ida); } |
