]> Git Repo - J-linux.git/blobdiff - drivers/fpga/fpga-mgr.c
Merge tag 'ata-5.17-rc1-part2' of git://git.kernel.org/pub/scm/linux/kernel/git/dlemo...
[J-linux.git] / drivers / fpga / fpga-mgr.c
index b85bc47c91a9a127d5da6a162e44ac5cff673141..d49a9ce345688ebc7404c7a9060769daaf00b47e 100644 (file)
@@ -25,8 +25,74 @@ struct fpga_mgr_devres {
        struct fpga_manager *mgr;
 };
 
+static inline void fpga_mgr_fpga_remove(struct fpga_manager *mgr)
+{
+       if (mgr->mops->fpga_remove)
+               mgr->mops->fpga_remove(mgr);
+}
+
+static inline enum fpga_mgr_states fpga_mgr_state(struct fpga_manager *mgr)
+{
+       if (mgr->mops->state)
+               return  mgr->mops->state(mgr);
+       return FPGA_MGR_STATE_UNKNOWN;
+}
+
+static inline u64 fpga_mgr_status(struct fpga_manager *mgr)
+{
+       if (mgr->mops->status)
+               return mgr->mops->status(mgr);
+       return 0;
+}
+
+static inline int fpga_mgr_write(struct fpga_manager *mgr, const char *buf, size_t count)
+{
+       if (mgr->mops->write)
+               return  mgr->mops->write(mgr, buf, count);
+       return -EOPNOTSUPP;
+}
+
+/*
+ * After all the FPGA image has been written, do the device specific steps to
+ * finish and set the FPGA into operating mode.
+ */
+static inline int fpga_mgr_write_complete(struct fpga_manager *mgr,
+                                         struct fpga_image_info *info)
+{
+       int ret = 0;
+
+       mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE;
+       if (mgr->mops->write_complete)
+               ret = mgr->mops->write_complete(mgr, info);
+       if (ret) {
+               dev_err(&mgr->dev, "Error after writing image data to FPGA\n");
+               mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE_ERR;
+               return ret;
+       }
+       mgr->state = FPGA_MGR_STATE_OPERATING;
+
+       return 0;
+}
+
+static inline int fpga_mgr_write_init(struct fpga_manager *mgr,
+                                     struct fpga_image_info *info,
+                                     const char *buf, size_t count)
+{
+       if (mgr->mops->write_init)
+               return  mgr->mops->write_init(mgr, info, buf, count);
+       return 0;
+}
+
+static inline int fpga_mgr_write_sg(struct fpga_manager *mgr,
+                                   struct sg_table *sgt)
+{
+       if (mgr->mops->write_sg)
+               return  mgr->mops->write_sg(mgr, sgt);
+       return -EOPNOTSUPP;
+}
+
 /**
- * fpga_image_info_alloc - Allocate a FPGA image info struct
+ * fpga_image_info_alloc - Allocate an FPGA image info struct
  * @dev: owning device
  *
  * Return: struct fpga_image_info or NULL
@@ -50,7 +116,7 @@ struct fpga_image_info *fpga_image_info_alloc(struct device *dev)
 EXPORT_SYMBOL_GPL(fpga_image_info_alloc);
 
 /**
- * fpga_image_info_free - Free a FPGA image info struct
+ * fpga_image_info_free - Free an FPGA image info struct
  * @info: FPGA image info struct to free
  */
 void fpga_image_info_free(struct fpga_image_info *info)
@@ -83,9 +149,9 @@ static int fpga_mgr_write_init_buf(struct fpga_manager *mgr,
 
        mgr->state = FPGA_MGR_STATE_WRITE_INIT;
        if (!mgr->mops->initial_header_size)
-               ret = mgr->mops->write_init(mgr, info, NULL, 0);
+               ret = fpga_mgr_write_init(mgr, info, NULL, 0);
        else
-               ret = mgr->mops->write_init(
+               ret = fpga_mgr_write_init(
                    mgr, info, buf, min(mgr->mops->initial_header_size, count));
 
        if (ret) {
@@ -137,27 +203,6 @@ static int fpga_mgr_write_init_sg(struct fpga_manager *mgr,
        return ret;
 }
 
-/*
- * After all the FPGA image has been written, do the device specific steps to
- * finish and set the FPGA into operating mode.
- */
-static int fpga_mgr_write_complete(struct fpga_manager *mgr,
-                                  struct fpga_image_info *info)
-{
-       int ret;
-
-       mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE;
-       ret = mgr->mops->write_complete(mgr, info);
-       if (ret) {
-               dev_err(&mgr->dev, "Error after writing image data to FPGA\n");
-               mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE_ERR;
-               return ret;
-       }
-       mgr->state = FPGA_MGR_STATE_OPERATING;
-
-       return 0;
-}
-
 /**
  * fpga_mgr_buf_load_sg - load fpga from image in buffer from a scatter list
  * @mgr:       fpga manager
@@ -188,13 +233,13 @@ static int fpga_mgr_buf_load_sg(struct fpga_manager *mgr,
        /* Write the FPGA image to the FPGA. */
        mgr->state = FPGA_MGR_STATE_WRITE;
        if (mgr->mops->write_sg) {
-               ret = mgr->mops->write_sg(mgr, sgt);
+               ret = fpga_mgr_write_sg(mgr, sgt);
        } else {
                struct sg_mapping_iter miter;
 
                sg_miter_start(&miter, sgt->sgl, sgt->nents, SG_MITER_FROM_SG);
                while (sg_miter_next(&miter)) {
-                       ret = mgr->mops->write(mgr, miter.addr, miter.length);
+                       ret = fpga_mgr_write(mgr, miter.addr, miter.length);
                        if (ret)
                                break;
                }
@@ -224,7 +269,7 @@ static int fpga_mgr_buf_load_mapped(struct fpga_manager *mgr,
         * Write the FPGA image to the FPGA.
         */
        mgr->state = FPGA_MGR_STATE_WRITE;
-       ret = mgr->mops->write(mgr, buf, count);
+       ret = fpga_mgr_write(mgr, buf, count);
        if (ret) {
                dev_err(&mgr->dev, "Error while writing image data to FPGA\n");
                mgr->state = FPGA_MGR_STATE_WRITE_ERR;
@@ -417,10 +462,7 @@ static ssize_t status_show(struct device *dev,
        u64 status;
        int len = 0;
 
-       if (!mgr->mops->status)
-               return -ENOENT;
-
-       status = mgr->mops->status(mgr);
+       status = fpga_mgr_status(mgr);
 
        if (status & FPGA_MGR_STATUS_OPERATION_ERR)
                len += sprintf(buf + len, "reconfig operation error\n");
@@ -470,7 +512,7 @@ static int fpga_mgr_dev_match(struct device *dev, const void *data)
 }
 
 /**
- * fpga_mgr_get - Given a device, get a reference to a fpga mgr.
+ * fpga_mgr_get - Given a device, get a reference to an fpga mgr.
  * @dev:       parent device that fpga mgr was registered with
  *
  * Return: fpga manager struct or IS_ERR() condition containing error code.
@@ -487,7 +529,7 @@ struct fpga_manager *fpga_mgr_get(struct device *dev)
 EXPORT_SYMBOL_GPL(fpga_mgr_get);
 
 /**
- * of_fpga_mgr_get - Given a device node, get a reference to a fpga mgr.
+ * of_fpga_mgr_get - Given a device node, get a reference to an fpga mgr.
  *
  * @node:      device node
  *
@@ -506,7 +548,7 @@ struct fpga_manager *of_fpga_mgr_get(struct device_node *node)
 EXPORT_SYMBOL_GPL(of_fpga_mgr_get);
 
 /**
- * fpga_mgr_put - release a reference to a fpga manager
+ * fpga_mgr_put - release a reference to an fpga manager
  * @mgr:       fpga manager structure
  */
 void fpga_mgr_put(struct fpga_manager *mgr)
@@ -550,61 +592,72 @@ void fpga_mgr_unlock(struct fpga_manager *mgr)
 EXPORT_SYMBOL_GPL(fpga_mgr_unlock);
 
 /**
- * fpga_mgr_create - create and initialize a FPGA manager struct
- * @dev:       fpga manager device from pdev
- * @name:      fpga manager name
- * @mops:      pointer to structure of fpga manager ops
- * @priv:      fpga manager private data
+ * fpga_mgr_register_full - create and register an FPGA Manager device
+ * @parent:    fpga manager device from pdev
+ * @info:      parameters for fpga manager
  *
- * The caller of this function is responsible for freeing the struct with
- * fpga_mgr_free().  Using devm_fpga_mgr_create() instead is recommended.
+ * The caller of this function is responsible for calling fpga_mgr_unregister().
+ * Using devm_fpga_mgr_register_full() instead is recommended.
  *
- * Return: pointer to struct fpga_manager or NULL
+ * Return: pointer to struct fpga_manager pointer or ERR_PTR()
  */
-struct fpga_manager *fpga_mgr_create(struct device *dev, const char *name,
-                                    const struct fpga_manager_ops *mops,
-                                    void *priv)
+struct fpga_manager *
+fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info)
 {
+       const struct fpga_manager_ops *mops = info->mops;
        struct fpga_manager *mgr;
        int id, ret;
 
-       if (!mops || !mops->write_complete || !mops->state ||
-           !mops->write_init || (!mops->write && !mops->write_sg) ||
-           (mops->write && mops->write_sg)) {
-               dev_err(dev, "Attempt to register without fpga_manager_ops\n");
-               return NULL;
+       if (!mops) {
+               dev_err(parent, "Attempt to register without fpga_manager_ops\n");
+               return ERR_PTR(-EINVAL);
        }
 
-       if (!name || !strlen(name)) {
-               dev_err(dev, "Attempt to register with no name!\n");
-               return NULL;
+       if (!info->name || !strlen(info->name)) {
+               dev_err(parent, "Attempt to register with no name!\n");
+               return ERR_PTR(-EINVAL);
        }
 
        mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
        if (!mgr)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        id = ida_simple_get(&fpga_mgr_ida, 0, 0, GFP_KERNEL);
-       if (id < 0)
+       if (id < 0) {
+               ret = id;
                goto error_kfree;
+       }
 
        mutex_init(&mgr->ref_mutex);
 
-       mgr->name = name;
-       mgr->mops = mops;
-       mgr->priv = priv;
+       mgr->name = info->name;
+       mgr->mops = info->mops;
+       mgr->priv = info->priv;
+       mgr->compat_id = info->compat_id;
 
-       device_initialize(&mgr->dev);
        mgr->dev.class = fpga_mgr_class;
        mgr->dev.groups = mops->groups;
-       mgr->dev.parent = dev;
-       mgr->dev.of_node = dev->of_node;
+       mgr->dev.parent = parent;
+       mgr->dev.of_node = parent->of_node;
        mgr->dev.id = id;
 
        ret = dev_set_name(&mgr->dev, "fpga%d", id);
        if (ret)
                goto error_device;
 
+       /*
+        * Initialize framework state by requesting low level driver read state
+        * from device.  FPGA may be in reset mode or may have been programmed
+        * by bootloader or EEPROM.
+        */
+       mgr->state = fpga_mgr_state(mgr);
+
+       ret = device_register(&mgr->dev);
+       if (ret) {
+               put_device(&mgr->dev);
+               return ERR_PTR(ret);
+       }
+
        return mgr;
 
 error_device:
@@ -612,104 +665,44 @@ error_device:
 error_kfree:
        kfree(mgr);
 
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(fpga_mgr_create);
-
-/**
- * fpga_mgr_free - free a FPGA manager created with fpga_mgr_create()
- * @mgr:       fpga manager struct
- */
-void fpga_mgr_free(struct fpga_manager *mgr)
-{
-       ida_simple_remove(&fpga_mgr_ida, mgr->dev.id);
-       kfree(mgr);
-}
-EXPORT_SYMBOL_GPL(fpga_mgr_free);
-
-static void devm_fpga_mgr_release(struct device *dev, void *res)
-{
-       struct fpga_mgr_devres *dr = res;
-
-       fpga_mgr_free(dr->mgr);
+       return ERR_PTR(ret);
 }
+EXPORT_SYMBOL_GPL(fpga_mgr_register_full);
 
 /**
- * devm_fpga_mgr_create - create and initialize a managed FPGA manager struct
- * @dev:       fpga manager device from pdev
+ * 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
  *
- * This function is intended for use in a FPGA manager driver's probe function.
- * After the manager driver creates the manager struct with
- * devm_fpga_mgr_create(), it should register it with fpga_mgr_register().  The
- * manager driver's remove function should call fpga_mgr_unregister().  The
- * manager 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_mgr_register(), the struct will still get cleaned up.
+ * The caller of this function is responsible for calling fpga_mgr_unregister().
+ * Using devm_fpga_mgr_register() instead is recommended. This simple
+ * version of the register function should be sufficient for most users. The
+ * fpga_mgr_register_full() function is available for users that need to pass
+ * additional, optional parameters.
  *
- * Return: pointer to struct fpga_manager or NULL
+ * Return: pointer to struct fpga_manager pointer or ERR_PTR()
  */
-struct fpga_manager *devm_fpga_mgr_create(struct device *dev, const char *name,
-                                         const struct fpga_manager_ops *mops,
-                                         void *priv)
+struct fpga_manager *
+fpga_mgr_register(struct device *parent, const char *name,
+                 const struct fpga_manager_ops *mops, void *priv)
 {
-       struct fpga_mgr_devres *dr;
-
-       dr = devres_alloc(devm_fpga_mgr_release, sizeof(*dr), GFP_KERNEL);
-       if (!dr)
-               return NULL;
-
-       dr->mgr = fpga_mgr_create(dev, name, mops, priv);
-       if (!dr->mgr) {
-               devres_free(dr);
-               return NULL;
-       }
-
-       devres_add(dev, dr);
-
-       return dr->mgr;
-}
-EXPORT_SYMBOL_GPL(devm_fpga_mgr_create);
-
-/**
- * fpga_mgr_register - register a FPGA manager
- * @mgr: fpga manager struct
- *
- * Return: 0 on success, negative error code otherwise.
- */
-int fpga_mgr_register(struct fpga_manager *mgr)
-{
-       int ret;
-
-       /*
-        * Initialize framework state by requesting low level driver read state
-        * from device.  FPGA may be in reset mode or may have been programmed
-        * by bootloader or EEPROM.
-        */
-       mgr->state = mgr->mops->state(mgr);
-
-       ret = device_add(&mgr->dev);
-       if (ret)
-               goto error_device;
-
-       dev_info(&mgr->dev, "%s registered\n", mgr->name);
-
-       return 0;
+       struct fpga_manager_info info = { 0 };
 
-error_device:
-       ida_simple_remove(&fpga_mgr_ida, mgr->dev.id);
+       info.name = name;
+       info.mops = mops;
+       info.priv = priv;
 
-       return ret;
+       return fpga_mgr_register_full(parent, &info);
 }
 EXPORT_SYMBOL_GPL(fpga_mgr_register);
 
 /**
- * fpga_mgr_unregister - unregister a FPGA manager
+ * fpga_mgr_unregister - unregister an FPGA manager
  * @mgr: fpga manager struct
  *
- * This function is intended for use in a FPGA manager driver's remove function.
+ * This function is intended for use in an FPGA manager driver's remove function.
  */
 void fpga_mgr_unregister(struct fpga_manager *mgr)
 {
@@ -719,21 +712,12 @@ void fpga_mgr_unregister(struct fpga_manager *mgr)
         * If the low level driver provides a method for putting fpga into
         * a desired state upon unregister, do it.
         */
-       if (mgr->mops->fpga_remove)
-               mgr->mops->fpga_remove(mgr);
+       fpga_mgr_fpga_remove(mgr);
 
        device_unregister(&mgr->dev);
 }
 EXPORT_SYMBOL_GPL(fpga_mgr_unregister);
 
-static int fpga_mgr_devres_match(struct device *dev, void *res,
-                                void *match_data)
-{
-       struct fpga_mgr_devres *dr = res;
-
-       return match_data == dr->mgr;
-}
-
 static void devm_fpga_mgr_unregister(struct device *dev, void *res)
 {
        struct fpga_mgr_devres *dr = res;
@@ -742,45 +726,67 @@ static void devm_fpga_mgr_unregister(struct device *dev, void *res)
 }
 
 /**
- * devm_fpga_mgr_register - resource managed variant of fpga_mgr_register()
- * @dev: managing device for this FPGA manager
- * @mgr: fpga manager struct
+ * devm_fpga_mgr_register_full - resource managed variant of fpga_mgr_register()
+ * @parent:    fpga manager device from pdev
+ * @info:      parameters for fpga manager
  *
- * This is the devres variant of fpga_mgr_register() for which the unregister
+ * This is the devres variant of fpga_mgr_register_full() for which the unregister
  * function will be called automatically when the managing device is detached.
  */
-int devm_fpga_mgr_register(struct device *dev, struct fpga_manager *mgr)
+struct fpga_manager *
+devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info)
 {
        struct fpga_mgr_devres *dr;
-       int ret;
-
-       /*
-        * Make sure that the struct fpga_manager * that is passed in is
-        * managed itself.
-        */
-       if (WARN_ON(!devres_find(dev, devm_fpga_mgr_release,
-                                fpga_mgr_devres_match, mgr)))
-               return -EINVAL;
+       struct fpga_manager *mgr;
 
        dr = devres_alloc(devm_fpga_mgr_unregister, sizeof(*dr), GFP_KERNEL);
        if (!dr)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
 
-       ret = fpga_mgr_register(mgr);
-       if (ret) {
+       mgr = fpga_mgr_register_full(parent, info);
+       if (IS_ERR(mgr)) {
                devres_free(dr);
-               return ret;
+               return mgr;
        }
 
        dr->mgr = mgr;
-       devres_add(dev, dr);
+       devres_add(parent, dr);
 
-       return 0;
+       return mgr;
+}
+EXPORT_SYMBOL_GPL(devm_fpga_mgr_register_full);
+
+/**
+ * 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
+ *
+ * This is the devres variant of fpga_mgr_register() for which the
+ * unregister function will be called automatically when the managing
+ * device is detached.
+ */
+struct fpga_manager *
+devm_fpga_mgr_register(struct device *parent, const char *name,
+                      const struct fpga_manager_ops *mops, void *priv)
+{
+       struct fpga_manager_info info = { 0 };
+
+       info.name = name;
+       info.mops = mops;
+       info.priv = priv;
+
+       return devm_fpga_mgr_register_full(parent, &info);
 }
 EXPORT_SYMBOL_GPL(devm_fpga_mgr_register);
 
 static void fpga_mgr_dev_release(struct device *dev)
 {
+       struct fpga_manager *mgr = to_fpga_manager(dev);
+
+       ida_simple_remove(&fpga_mgr_ida, mgr->dev.id);
+       kfree(mgr);
 }
 
 static int __init fpga_mgr_class_init(void)
This page took 0.044605 seconds and 4 git commands to generate.