diff options
Diffstat (limited to 'drivers/fpga/fpga-region.c')
| -rw-r--r-- | drivers/fpga/fpga-region.c | 119 | 
1 files changed, 44 insertions, 75 deletions
| diff --git a/drivers/fpga/fpga-region.c b/drivers/fpga/fpga-region.c index a4838715221f..b0ac18de4885 100644 --- a/drivers/fpga/fpga-region.c +++ b/drivers/fpga/fpga-region.c @@ -180,39 +180,42 @@ static struct attribute *fpga_region_attrs[] = {  ATTRIBUTE_GROUPS(fpga_region);  /** - * fpga_region_create - alloc and init a struct fpga_region + * fpga_region_register_full - create and register an FPGA Region device   * @parent: device parent - * @mgr: manager that programs this region - * @get_bridges: optional function to get bridges to a list - * - * The caller of this function is responsible for freeing the resulting region - * struct with fpga_region_free().  Using devm_fpga_region_create() instead is - * recommended. + * @info: parameters for FPGA Region   * - * Return: struct fpga_region or NULL + * Return: struct fpga_region or ERR_PTR()   */ -struct fpga_region -*fpga_region_create(struct device *parent, -		    struct fpga_manager *mgr, -		    int (*get_bridges)(struct fpga_region *)) +struct fpga_region * +fpga_region_register_full(struct device *parent, const struct fpga_region_info *info)  {  	struct fpga_region *region;  	int id, ret = 0; +	if (!info) { +		dev_err(parent, +			"Attempt to register without required info structure\n"); +		return ERR_PTR(-EINVAL); +	} +  	region = kzalloc(sizeof(*region), GFP_KERNEL);  	if (!region) -		return NULL; +		return ERR_PTR(-ENOMEM);  	id = ida_simple_get(&fpga_region_ida, 0, 0, GFP_KERNEL); -	if (id < 0) +	if (id < 0) { +		ret = id;  		goto err_free; +	} + +	region->mgr = info->mgr; +	region->compat_id = info->compat_id; +	region->priv = info->priv; +	region->get_bridges = info->get_bridges; -	region->mgr = mgr; -	region->get_bridges = get_bridges;  	mutex_init(®ion->mutex);  	INIT_LIST_HEAD(®ion->bridge_list); -	device_initialize(®ion->dev);  	region->dev.class = fpga_region_class;  	region->dev.parent = parent;  	region->dev.of_node = parent->of_node; @@ -222,6 +225,12 @@ struct fpga_region  	if (ret)  		goto err_remove; +	ret = device_register(®ion->dev); +	if (ret) { +		put_device(®ion->dev); +		return ERR_PTR(ret); +	} +  	return region;  err_remove: @@ -229,76 +238,32 @@ err_remove:  err_free:  	kfree(region); -	return NULL; -} -EXPORT_SYMBOL_GPL(fpga_region_create); - -/** - * fpga_region_free - free an FPGA region created by fpga_region_create() - * @region: FPGA region - */ -void fpga_region_free(struct fpga_region *region) -{ -	ida_simple_remove(&fpga_region_ida, region->dev.id); -	kfree(region); -} -EXPORT_SYMBOL_GPL(fpga_region_free); - -static void devm_fpga_region_release(struct device *dev, void *res) -{ -	struct fpga_region *region = *(struct fpga_region **)res; - -	fpga_region_free(region); +	return ERR_PTR(ret);  } +EXPORT_SYMBOL_GPL(fpga_region_register_full);  /** - * devm_fpga_region_create - create and initialize a managed FPGA region struct + * fpga_region_register - create and register an FPGA Region device   * @parent: device parent   * @mgr: manager that programs this region   * @get_bridges: optional function to get bridges to a list   * - * This function is intended for use in an FPGA region driver's probe function. - * After the region driver creates the region struct with - * devm_fpga_region_create(), it should register it with fpga_region_register(). - * The region driver's remove function should call fpga_region_unregister(). - * The region 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_region_register(), the struct will still get cleaned up. + * This simple version of the register function should be sufficient for most users. + * The fpga_region_register_full() function is available for users that need to + * pass additional, optional parameters.   * - * Return: struct fpga_region or NULL + * Return: struct fpga_region or ERR_PTR()   */ -struct fpga_region -*devm_fpga_region_create(struct device *parent, -			 struct fpga_manager *mgr, -			 int (*get_bridges)(struct fpga_region *)) +struct fpga_region * +fpga_region_register(struct device *parent, struct fpga_manager *mgr, +		     int (*get_bridges)(struct fpga_region *))  { -	struct fpga_region **ptr, *region; - -	ptr = devres_alloc(devm_fpga_region_release, sizeof(*ptr), GFP_KERNEL); -	if (!ptr) -		return NULL; +	struct fpga_region_info info = { 0 }; -	region = fpga_region_create(parent, mgr, get_bridges); -	if (!region) { -		devres_free(ptr); -	} else { -		*ptr = region; -		devres_add(parent, ptr); -	} +	info.mgr = mgr; +	info.get_bridges = get_bridges; -	return region; -} -EXPORT_SYMBOL_GPL(devm_fpga_region_create); - -/** - * fpga_region_register - register an FPGA region - * @region: FPGA region - * - * Return: 0 or -errno - */ -int fpga_region_register(struct fpga_region *region) -{ -	return device_add(®ion->dev); +	return fpga_region_register_full(parent, &info);  }  EXPORT_SYMBOL_GPL(fpga_region_register); @@ -316,6 +281,10 @@ EXPORT_SYMBOL_GPL(fpga_region_unregister);  static void fpga_region_dev_release(struct device *dev)  { +	struct fpga_region *region = to_fpga_region(dev); + +	ida_simple_remove(&fpga_region_ida, region->dev.id); +	kfree(region);  }  /** | 
