root/drivers/net/wireless/marvell/libertas/firmware.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lbs_fw_loaded
  2. do_load_firmware
  3. main_firmware_cb
  4. helper_firmware_cb
  5. load_next_firmware_from_table
  6. lbs_wait_for_firmware_load
  7. lbs_get_firmware_async
  8. lbs_get_firmware

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Firmware loading and handling functions.
   4  */
   5 
   6 #include <linux/sched.h>
   7 #include <linux/firmware.h>
   8 #include <linux/module.h>
   9 
  10 #include "dev.h"
  11 #include "decl.h"
  12 
  13 static void load_next_firmware_from_table(struct lbs_private *private);
  14 
  15 static void lbs_fw_loaded(struct lbs_private *priv, int ret,
  16         const struct firmware *helper, const struct firmware *mainfw)
  17 {
  18         unsigned long flags;
  19 
  20         lbs_deb_fw("firmware load complete, code %d\n", ret);
  21 
  22         /* User must free helper/mainfw */
  23         priv->fw_callback(priv, ret, helper, mainfw);
  24 
  25         spin_lock_irqsave(&priv->driver_lock, flags);
  26         priv->fw_callback = NULL;
  27         wake_up(&priv->fw_waitq);
  28         spin_unlock_irqrestore(&priv->driver_lock, flags);
  29 }
  30 
  31 static void do_load_firmware(struct lbs_private *priv, const char *name,
  32         void (*cb)(const struct firmware *fw, void *context))
  33 {
  34         int ret;
  35 
  36         lbs_deb_fw("Requesting %s\n", name);
  37         ret = request_firmware_nowait(THIS_MODULE, true, name,
  38                         priv->fw_device, GFP_KERNEL, priv, cb);
  39         if (ret) {
  40                 lbs_deb_fw("request_firmware_nowait error %d\n", ret);
  41                 lbs_fw_loaded(priv, ret, NULL, NULL);
  42         }
  43 }
  44 
  45 static void main_firmware_cb(const struct firmware *firmware, void *context)
  46 {
  47         struct lbs_private *priv = context;
  48 
  49         if (!firmware) {
  50                 /* Failed to find firmware: try next table entry */
  51                 load_next_firmware_from_table(priv);
  52                 return;
  53         }
  54 
  55         /* Firmware found! */
  56         lbs_fw_loaded(priv, 0, priv->helper_fw, firmware);
  57         if (priv->helper_fw) {
  58                 release_firmware (priv->helper_fw);
  59                 priv->helper_fw = NULL;
  60         }
  61         release_firmware (firmware);
  62 }
  63 
  64 static void helper_firmware_cb(const struct firmware *firmware, void *context)
  65 {
  66         struct lbs_private *priv = context;
  67 
  68         if (!firmware) {
  69                 /* Failed to find firmware: try next table entry */
  70                 load_next_firmware_from_table(priv);
  71                 return;
  72         }
  73 
  74         /* Firmware found! */
  75         if (priv->fw_iter->fwname) {
  76                 priv->helper_fw = firmware;
  77                 do_load_firmware(priv, priv->fw_iter->fwname, main_firmware_cb);
  78         } else {
  79                 /* No main firmware needed for this helper --> success! */
  80                 lbs_fw_loaded(priv, 0, firmware, NULL);
  81         }
  82 }
  83 
  84 static void load_next_firmware_from_table(struct lbs_private *priv)
  85 {
  86         const struct lbs_fw_table *iter;
  87 
  88         if (!priv->fw_iter)
  89                 iter = priv->fw_table;
  90         else
  91                 iter = ++priv->fw_iter;
  92 
  93         if (priv->helper_fw) {
  94                 release_firmware(priv->helper_fw);
  95                 priv->helper_fw = NULL;
  96         }
  97 
  98 next:
  99         if (!iter->helper) {
 100                 /* End of table hit. */
 101                 lbs_fw_loaded(priv, -ENOENT, NULL, NULL);
 102                 return;
 103         }
 104 
 105         if (iter->model != priv->fw_model) {
 106                 iter++;
 107                 goto next;
 108         }
 109 
 110         priv->fw_iter = iter;
 111         do_load_firmware(priv, iter->helper, helper_firmware_cb);
 112 }
 113 
 114 void lbs_wait_for_firmware_load(struct lbs_private *priv)
 115 {
 116         wait_event(priv->fw_waitq, priv->fw_callback == NULL);
 117 }
 118 
 119 /**
 120  *  lbs_get_firmware_async - Retrieves firmware asynchronously. Can load
 121  *  either a helper firmware and a main firmware (2-stage), or just the helper.
 122  *
 123  *  @priv:      Pointer to lbs_private instance
 124  *  @dev:       A pointer to &device structure
 125  *  @card_model: Bus-specific card model ID used to filter firmware table
 126  *              elements
 127  *  @fw_table:  Table of firmware file names and device model numbers
 128  *              terminated by an entry with a NULL helper name
 129  *      @callback: User callback to invoke when firmware load succeeds or fails.
 130  */
 131 int lbs_get_firmware_async(struct lbs_private *priv, struct device *device,
 132                             u32 card_model, const struct lbs_fw_table *fw_table,
 133                             lbs_fw_cb callback)
 134 {
 135         unsigned long flags;
 136 
 137         spin_lock_irqsave(&priv->driver_lock, flags);
 138         if (priv->fw_callback) {
 139                 lbs_deb_fw("firmware load already in progress\n");
 140                 spin_unlock_irqrestore(&priv->driver_lock, flags);
 141                 return -EBUSY;
 142         }
 143 
 144         priv->fw_device = device;
 145         priv->fw_callback = callback;
 146         priv->fw_table = fw_table;
 147         priv->fw_iter = NULL;
 148         priv->fw_model = card_model;
 149         spin_unlock_irqrestore(&priv->driver_lock, flags);
 150 
 151         lbs_deb_fw("Starting async firmware load\n");
 152         load_next_firmware_from_table(priv);
 153         return 0;
 154 }
 155 EXPORT_SYMBOL_GPL(lbs_get_firmware_async);
 156 
 157 /**
 158  *  lbs_get_firmware - Retrieves two-stage firmware
 159  *
 160  *  @dev:       A pointer to &device structure
 161  *  @card_model: Bus-specific card model ID used to filter firmware table
 162  *              elements
 163  *  @fw_table:  Table of firmware file names and device model numbers
 164  *              terminated by an entry with a NULL helper name
 165  *  @helper:    On success, the helper firmware; caller must free
 166  *  @mainfw:    On success, the main firmware; caller must free
 167  *
 168  * Deprecated: use lbs_get_firmware_async() instead.
 169  *
 170  *  returns:            0 on success, non-zero on failure
 171  */
 172 int lbs_get_firmware(struct device *dev, u32 card_model,
 173                         const struct lbs_fw_table *fw_table,
 174                         const struct firmware **helper,
 175                         const struct firmware **mainfw)
 176 {
 177         const struct lbs_fw_table *iter;
 178         int ret;
 179 
 180         BUG_ON(helper == NULL);
 181         BUG_ON(mainfw == NULL);
 182 
 183         /* Search for firmware to use from the table. */
 184         iter = fw_table;
 185         while (iter && iter->helper) {
 186                 if (iter->model != card_model)
 187                         goto next;
 188 
 189                 if (*helper == NULL) {
 190                         ret = request_firmware(helper, iter->helper, dev);
 191                         if (ret)
 192                                 goto next;
 193 
 194                         /* If the device has one-stage firmware (ie cf8305) and
 195                          * we've got it then we don't need to bother with the
 196                          * main firmware.
 197                          */
 198                         if (iter->fwname == NULL)
 199                                 return 0;
 200                 }
 201 
 202                 if (*mainfw == NULL) {
 203                         ret = request_firmware(mainfw, iter->fwname, dev);
 204                         if (ret) {
 205                                 /* Clear the helper to ensure we don't have
 206                                  * mismatched firmware pairs.
 207                                  */
 208                                 release_firmware(*helper);
 209                                 *helper = NULL;
 210                         }
 211                 }
 212 
 213                 if (*helper && *mainfw)
 214                         return 0;
 215 
 216   next:
 217                 iter++;
 218         }
 219 
 220         /* Failed */
 221         release_firmware(*helper);
 222         *helper = NULL;
 223         release_firmware(*mainfw);
 224         *mainfw = NULL;
 225 
 226         return -ENOENT;
 227 }
 228 EXPORT_SYMBOL_GPL(lbs_get_firmware);

/* [<][>][^][v][top][bottom][index][help] */