libertas: Firmware loading simplifications
authorDaniel Drake <dsd@laptop.org>
Mon, 16 Apr 2012 22:52:42 +0000 (23:52 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 17 Apr 2012 18:57:13 +0000 (14:57 -0400)
Remove the ability to pass module parameters with firmware filenames
for USB and SDIO interfaces.

Remove the ability to pass custom "user" filenames to lbs_get_firmware().

Remove the ability to reprogram internal device memory with a different
firmware from the USB driver (we don't know of any users), and simplify
the OLPC firmware loading quirk to simply placing the OLPC firmware
at the top of the list (we don't know of any users other than OLPC).

Move lbs_get_firmware() into its own file.

These simplifications should have no real-life effect but make the
upcoming transition to asynchronous firmware loading considerably less
painful.

Signed-off-by: Daniel Drake <dsd@laptop.org>
Acked-by: Dan Williams <dcbw@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/libertas/Makefile
drivers/net/wireless/libertas/decl.h
drivers/net/wireless/libertas/firmware.c [new file with mode: 0644]
drivers/net/wireless/libertas/if_cs.c
drivers/net/wireless/libertas/if_sdio.c
drivers/net/wireless/libertas/if_spi.c
drivers/net/wireless/libertas/if_usb.c
drivers/net/wireless/libertas/main.c

index f7d01bfa2e4a1ccd8046607457b32639037cb7cc..eac72f7bd341f7463f1f3d9e7cc28f201c76f714 100644 (file)
@@ -6,6 +6,7 @@ libertas-y += ethtool.o
 libertas-y += main.o
 libertas-y += rx.o
 libertas-y += tx.o
+libertas-y += firmware.o
 libertas-$(CONFIG_LIBERTAS_MESH) += mesh.o
 
 usb8xxx-objs += if_usb.o
index bc951ab4b6818954c756d6da0c0455915757a31d..2fb2e31733eeb7c3c51569cfb8a273f3e87b3242 100644 (file)
@@ -66,8 +66,7 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
 u32 lbs_fw_index_to_data_rate(u8 index);
 u8 lbs_data_rate_to_fw_index(u32 rate);
 
-int lbs_get_firmware(struct device *dev, const char *user_helper,
-                       const char *user_mainfw, u32 card_model,
+int lbs_get_firmware(struct device *dev, u32 card_model,
                        const struct lbs_fw_table *fw_table,
                        const struct firmware **helper,
                        const struct firmware **mainfw);
diff --git a/drivers/net/wireless/libertas/firmware.c b/drivers/net/wireless/libertas/firmware.c
new file mode 100644 (file)
index 0000000..0c8c845
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Firmware loading and handling functions.
+ */
+
+#include <linux/firmware.h>
+#include <linux/module.h>
+
+#include "decl.h"
+
+/**
+ *  lbs_get_firmware - Retrieves two-stage firmware
+ *
+ *  @dev:      A pointer to &device structure
+ *  @card_model: Bus-specific card model ID used to filter firmware table
+ *             elements
+ *  @fw_table: Table of firmware file names and device model numbers
+ *             terminated by an entry with a NULL helper name
+ *  @helper:   On success, the helper firmware; caller must free
+ *  @mainfw:   On success, the main firmware; caller must free
+ *
+ *  returns:           0 on success, non-zero on failure
+ */
+int lbs_get_firmware(struct device *dev, u32 card_model,
+                       const struct lbs_fw_table *fw_table,
+                       const struct firmware **helper,
+                       const struct firmware **mainfw)
+{
+       const struct lbs_fw_table *iter;
+       int ret;
+
+       BUG_ON(helper == NULL);
+       BUG_ON(mainfw == NULL);
+
+       /* Search for firmware to use from the table. */
+       iter = fw_table;
+       while (iter && iter->helper) {
+               if (iter->model != card_model)
+                       goto next;
+
+               if (*helper == NULL) {
+                       ret = request_firmware(helper, iter->helper, dev);
+                       if (ret)
+                               goto next;
+
+                       /* If the device has one-stage firmware (ie cf8305) and
+                        * we've got it then we don't need to bother with the
+                        * main firmware.
+                        */
+                       if (iter->fwname == NULL)
+                               return 0;
+               }
+
+               if (*mainfw == NULL) {
+                       ret = request_firmware(mainfw, iter->fwname, dev);
+                       if (ret) {
+                               /* Clear the helper to ensure we don't have
+                                * mismatched firmware pairs.
+                                */
+                               release_firmware(*helper);
+                               *helper = NULL;
+                       }
+               }
+
+               if (*helper && *mainfw)
+                       return 0;
+
+  next:
+               iter++;
+       }
+
+       /* Failed */
+       release_firmware(*helper);
+       *helper = NULL;
+       release_firmware(*mainfw);
+       *mainfw = NULL;
+
+       return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(lbs_get_firmware);
index 171a06b8879d9e842b4d84adb32d9520166c4b47..cee50528522b863e7c19b8bdf3be6673519f3c74 100644 (file)
@@ -890,8 +890,8 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
                goto out2;
        }
 
-       ret = lbs_get_firmware(&p_dev->dev, NULL, NULL, card->model,
-                               &fw_table[0], &helper, &mainfw);
+       ret = lbs_get_firmware(&p_dev->dev, card->model, &fw_table[0],
+                               &helper, &mainfw);
        if (ret) {
                pr_err("failed to find firmware (%d)\n", ret);
                goto out2;
index 15bfe2f589f7c5ac0177b7218cf6db067d6f6e98..6590febb366be96b5e29ec04414915eae1c40405 100644 (file)
@@ -65,12 +65,6 @@ static void if_sdio_interrupt(struct sdio_func *func);
  */
 static u8 user_rmmod;
 
-static char *lbs_helper_name = NULL;
-module_param_named(helper_name, lbs_helper_name, charp, 0644);
-
-static char *lbs_fw_name = NULL;
-module_param_named(fw_name, lbs_fw_name, charp, 0644);
-
 static const struct sdio_device_id if_sdio_ids[] = {
        { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL,
                        SDIO_DEVICE_ID_MARVELL_LIBERTAS) },
@@ -124,11 +118,6 @@ struct if_sdio_card {
        unsigned long           ioport;
        unsigned int            scratch_reg;
 
-       const char              *helper;
-       const char              *firmware;
-       bool                    helper_allocated;
-       bool                    firmware_allocated;
-
        u8                      buffer[65536] __attribute__((aligned(4)));
 
        spinlock_t              lock;
@@ -725,8 +714,8 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
                goto success;
        }
 
-       ret = lbs_get_firmware(&card->func->dev, lbs_helper_name, lbs_fw_name,
-                               card->model, &fw_table[0], &helper, &mainfw);
+       ret = lbs_get_firmware(&card->func->dev, card->model, &fw_table[0],
+                               &helper, &mainfw);
        if (ret) {
                pr_err("failed to find firmware (%d)\n", ret);
                goto out;
@@ -1242,10 +1231,6 @@ free:
                kfree(packet);
        }
 
-       if (card->helper_allocated)
-               kfree(card->helper);
-       if (card->firmware_allocated)
-               kfree(card->firmware);
        kfree(card);
 
        goto out;
@@ -1293,12 +1278,6 @@ static void if_sdio_remove(struct sdio_func *func)
                kfree(packet);
        }
 
-       if (card->helper_allocated)
-               kfree(card->helper);
-       if (card->firmware_allocated)
-               kfree(card->firmware);
-       kfree(card);
-
        lbs_deb_leave(LBS_DEB_SDIO);
 }
 
index 7a5df4f4cb7c4580046c299f79a80d45f41e88e5..9604a1c4a74d9ac158d6ea6f4928ed75765fada1 100644 (file)
@@ -1064,9 +1064,8 @@ static int if_spi_init_card(struct if_spi_card *card)
                        goto out;
                }
 
-               err = lbs_get_firmware(&card->spi->dev, NULL, NULL,
-                                       card->card_id, &fw_table[0], &helper,
-                                       &mainfw);
+               err = lbs_get_firmware(&card->spi->dev, card->card_id,
+                                       &fw_table[0], &helper, &mainfw);
                if (err) {
                        netdev_err(priv->dev, "failed to find firmware (%d)\n",
                                   err);
index ce4938dec2ca45a35d9db362ab369c8a719f99e1..f29471b80603325d12b2774fb7e293dbfb2bcd48 100644 (file)
@@ -29,9 +29,6 @@
 
 #define MESSAGE_HEADER_LEN     4
 
-static char *lbs_fw_name = NULL;
-module_param_named(fw_name, lbs_fw_name, charp, 0644);
-
 MODULE_FIRMWARE("libertas/usb8388_v9.bin");
 MODULE_FIRMWARE("libertas/usb8388_v5.bin");
 MODULE_FIRMWARE("libertas/usb8388.bin");
@@ -55,10 +52,7 @@ MODULE_DEVICE_TABLE(usb, if_usb_table);
 
 static void if_usb_receive(struct urb *urb);
 static void if_usb_receive_fwload(struct urb *urb);
-static int __if_usb_prog_firmware(struct if_usb_card *cardp,
-                                       const char *fwname, int cmd);
-static int if_usb_prog_firmware(struct if_usb_card *cardp,
-                                       const char *fwname, int cmd);
+static int if_usb_prog_firmware(struct if_usb_card *cardp);
 static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
                               uint8_t *payload, uint16_t nb);
 static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
@@ -67,69 +61,6 @@ static void if_usb_free(struct if_usb_card *cardp);
 static int if_usb_submit_rx_urb(struct if_usb_card *cardp);
 static int if_usb_reset_device(struct if_usb_card *cardp);
 
-/* sysfs hooks */
-
-/*
- *  Set function to write firmware to device's persistent memory
- */
-static ssize_t if_usb_firmware_set(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-       struct if_usb_card *cardp = priv->card;
-       int ret;
-
-       BUG_ON(buf == NULL);
-
-       ret = if_usb_prog_firmware(cardp, buf, BOOT_CMD_UPDATE_FW);
-       if (ret == 0)
-               return count;
-
-       return ret;
-}
-
-/*
- * lbs_flash_fw attribute to be exported per ethX interface through sysfs
- * (/sys/class/net/ethX/lbs_flash_fw).  Use this like so to write firmware to
- * the device's persistent memory:
- * echo usb8388-5.126.0.p5.bin > /sys/class/net/ethX/lbs_flash_fw
- */
-static DEVICE_ATTR(lbs_flash_fw, 0200, NULL, if_usb_firmware_set);
-
-/**
- * if_usb_boot2_set - write firmware to device's persistent memory
- *
- * @dev: target device
- * @attr: device attributes
- * @buf: firmware buffer to write
- * @count: number of bytes to write
- *
- * returns: number of bytes written or negative error code
- */
-static ssize_t if_usb_boot2_set(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
-       struct if_usb_card *cardp = priv->card;
-       int ret;
-
-       BUG_ON(buf == NULL);
-
-       ret = if_usb_prog_firmware(cardp, buf, BOOT_CMD_UPDATE_BOOT2);
-       if (ret == 0)
-               return count;
-
-       return ret;
-}
-
-/*
- * lbs_flash_boot2 attribute to be exported per ethX interface through sysfs
- * (/sys/class/net/ethX/lbs_flash_boot2).  Use this like so to write firmware
- * to the device's persistent memory:
- * echo usb8388-5.126.0.p5.bin > /sys/class/net/ethX/lbs_flash_boot2
- */
-static DEVICE_ATTR(lbs_flash_boot2, 0200, NULL, if_usb_boot2_set);
-
 /**
  * if_usb_write_bulk_callback - callback function to handle the status
  * of the URB
@@ -314,13 +245,10 @@ static int if_usb_probe(struct usb_interface *intf,
        }
 
        /* Upload firmware */
-       kparam_block_sysfs_write(fw_name);
-       if (__if_usb_prog_firmware(cardp, lbs_fw_name, BOOT_CMD_FW_BY_USB)) {
-               kparam_unblock_sysfs_write(fw_name);
+       if (if_usb_prog_firmware(cardp)) {
                lbs_deb_usbd(&udev->dev, "FW upload failed\n");
                goto err_prog_firmware;
        }
-       kparam_unblock_sysfs_write(fw_name);
 
        if (!(priv = lbs_add_card(cardp, &intf->dev)))
                goto err_prog_firmware;
@@ -349,14 +277,6 @@ static int if_usb_probe(struct usb_interface *intf,
        usb_get_dev(udev);
        usb_set_intfdata(intf, cardp);
 
-       if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_fw))
-               netdev_err(priv->dev,
-                          "cannot register lbs_flash_fw attribute\n");
-
-       if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_boot2))
-               netdev_err(priv->dev,
-                          "cannot register lbs_flash_boot2 attribute\n");
-
        /*
         * EHS_REMOVE_WAKEUP is not supported on all versions of the firmware.
         */
@@ -389,9 +309,6 @@ static void if_usb_disconnect(struct usb_interface *intf)
 
        lbs_deb_enter(LBS_DEB_MAIN);
 
-       device_remove_file(&priv->dev->dev, &dev_attr_lbs_flash_boot2);
-       device_remove_file(&priv->dev->dev, &dev_attr_lbs_flash_fw);
-
        cardp->surprise_removed = 1;
 
        if (priv) {
@@ -912,58 +829,12 @@ static int check_fwfile_format(const uint8_t *data, uint32_t totlen)
        return ret;
 }
 
-
-/**
-*  if_usb_prog_firmware - programs the firmware subject to cmd
-*
-*  @cardp:     the if_usb_card descriptor
-*  @fwname:    firmware or boot2 image file name
-*  @cmd:       either BOOT_CMD_FW_BY_USB, BOOT_CMD_UPDATE_FW,
-*              or BOOT_CMD_UPDATE_BOOT2.
-*  returns:    0 or error code
-*/
-static int if_usb_prog_firmware(struct if_usb_card *cardp,
-                               const char *fwname, int cmd)
-{
-       struct lbs_private *priv = cardp->priv;
-       unsigned long flags, caps;
-       int ret;
-
-       caps = priv->fwcapinfo;
-       if (((cmd == BOOT_CMD_UPDATE_FW) && !(caps & FW_CAPINFO_FIRMWARE_UPGRADE)) ||
-           ((cmd == BOOT_CMD_UPDATE_BOOT2) && !(caps & FW_CAPINFO_BOOT2_UPGRADE)))
-               return -EOPNOTSUPP;
-
-       /* Ensure main thread is idle. */
-       spin_lock_irqsave(&priv->driver_lock, flags);
-       while (priv->cur_cmd != NULL || priv->dnld_sent != DNLD_RES_RECEIVED) {
-               spin_unlock_irqrestore(&priv->driver_lock, flags);
-               if (wait_event_interruptible(priv->waitq,
-                               (priv->cur_cmd == NULL &&
-                               priv->dnld_sent == DNLD_RES_RECEIVED))) {
-                       return -ERESTARTSYS;
-               }
-               spin_lock_irqsave(&priv->driver_lock, flags);
-       }
-       priv->dnld_sent = DNLD_BOOTCMD_SENT;
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-       ret = __if_usb_prog_firmware(cardp, fwname, cmd);
-
-       spin_lock_irqsave(&priv->driver_lock, flags);
-       priv->dnld_sent = DNLD_RES_RECEIVED;
-       spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-       wake_up(&priv->waitq);
-
-       return ret;
-}
-
 /* table of firmware file names */
 static const struct {
        u32 model;
        const char *fwname;
 } fw_table[] = {
+       { MODEL_8388, "libertas/usb8388_olpc.bin" },
        { MODEL_8388, "libertas/usb8388_v9.bin" },
        { MODEL_8388, "libertas/usb8388_v5.bin" },
        { MODEL_8388, "libertas/usb8388.bin" },
@@ -971,35 +842,10 @@ static const struct {
        { MODEL_8682, "libertas/usb8682.bin" }
 };
 
-#ifdef CONFIG_OLPC
-
-static int try_olpc_fw(struct if_usb_card *cardp)
-{
-       int retval = -ENOENT;
-
-       /* try the OLPC firmware first; fall back to fw_table list */
-       if (machine_is_olpc() && cardp->model == MODEL_8388)
-               retval = request_firmware(&cardp->fw,
-                               "libertas/usb8388_olpc.bin", &cardp->udev->dev);
-       return retval;
-}
-
-#else
-static int try_olpc_fw(struct if_usb_card *cardp) { return -ENOENT; }
-#endif /* !CONFIG_OLPC */
-
-static int get_fw(struct if_usb_card *cardp, const char *fwname)
+static int get_fw(struct if_usb_card *cardp)
 {
        int i;
 
-       /* Try user-specified firmware first */
-       if (fwname)
-               return request_firmware(&cardp->fw, fwname, &cardp->udev->dev);
-
-       /* Handle OLPC firmware */
-       if (try_olpc_fw(cardp) == 0)
-               return 0;
-
        /* Otherwise search for firmware to use */
        for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
                if (fw_table[i].model != cardp->model)
@@ -1012,8 +858,7 @@ static int get_fw(struct if_usb_card *cardp, const char *fwname)
        return -ENOENT;
 }
 
-static int __if_usb_prog_firmware(struct if_usb_card *cardp,
-                                       const char *fwname, int cmd)
+static int if_usb_prog_firmware(struct if_usb_card *cardp)
 {
        int i = 0;
        static int reset_count = 10;
@@ -1021,7 +866,7 @@ static int __if_usb_prog_firmware(struct if_usb_card *cardp,
 
        lbs_deb_enter(LBS_DEB_USB);
 
-       ret = get_fw(cardp, fwname);
+       ret = get_fw(cardp);
        if (ret) {
                pr_err("failed to find firmware (%d)\n", ret);
                goto done;
@@ -1053,7 +898,7 @@ restart:
        do {
                int j = 0;
                i++;
-               if_usb_issue_boot_command(cardp, cmd);
+               if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB);
                /* wait for command response */
                do {
                        j++;
index 3b81b709bf9e33b412d99fd950d45cefe49aee2b..fa095851f214cffe2bb64eea8bce3e089c291a6b 100644 (file)
@@ -1177,107 +1177,6 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx)
 }
 EXPORT_SYMBOL_GPL(lbs_notify_command_response);
 
-/**
- *  lbs_get_firmware - Retrieves two-stage firmware
- *
- *  @dev:      A pointer to &device structure
- *  @user_helper: User-defined helper firmware file
- *  @user_mainfw: User-defined main firmware file
- *  @card_model: Bus-specific card model ID used to filter firmware table
- *             elements
- *  @fw_table: Table of firmware file names and device model numbers
- *             terminated by an entry with a NULL helper name
- *  @helper:   On success, the helper firmware; caller must free
- *  @mainfw:   On success, the main firmware; caller must free
- *
- *  returns:           0 on success, non-zero on failure
- */
-int lbs_get_firmware(struct device *dev, const char *user_helper,
-                       const char *user_mainfw, u32 card_model,
-                       const struct lbs_fw_table *fw_table,
-                       const struct firmware **helper,
-                       const struct firmware **mainfw)
-{
-       const struct lbs_fw_table *iter;
-       int ret;
-
-       BUG_ON(helper == NULL);
-       BUG_ON(mainfw == NULL);
-
-       /* Try user-specified firmware first */
-       if (user_helper) {
-               ret = request_firmware(helper, user_helper, dev);
-               if (ret) {
-                       dev_err(dev, "couldn't find helper firmware %s\n",
-                               user_helper);
-                       goto fail;
-               }
-       }
-       if (user_mainfw) {
-               ret = request_firmware(mainfw, user_mainfw, dev);
-               if (ret) {
-                       dev_err(dev, "couldn't find main firmware %s\n",
-                               user_mainfw);
-                       goto fail;
-               }
-       }
-
-       if (*helper && *mainfw)
-               return 0;
-
-       /* Otherwise search for firmware to use.  If neither the helper or
-        * the main firmware were specified by the user, then we need to
-        * make sure that found helper & main are from the same entry in
-        * fw_table.
-        */
-       iter = fw_table;
-       while (iter && iter->helper) {
-               if (iter->model != card_model)
-                       goto next;
-
-               if (*helper == NULL) {
-                       ret = request_firmware(helper, iter->helper, dev);
-                       if (ret)
-                               goto next;
-
-                       /* If the device has one-stage firmware (ie cf8305) and
-                        * we've got it then we don't need to bother with the
-                        * main firmware.
-                        */
-                       if (iter->fwname == NULL)
-                               return 0;
-               }
-
-               if (*mainfw == NULL) {
-                       ret = request_firmware(mainfw, iter->fwname, dev);
-                       if (ret && !user_helper) {
-                               /* Clear the helper if it wasn't user-specified
-                                * and the main firmware load failed, to ensure
-                                * we don't have mismatched firmware pairs.
-                                */
-                               release_firmware(*helper);
-                               *helper = NULL;
-                       }
-               }
-
-               if (*helper && *mainfw)
-                       return 0;
-
-  next:
-               iter++;
-       }
-
-  fail:
-       /* Failed */
-       release_firmware(*helper);
-       *helper = NULL;
-       release_firmware(*mainfw);
-       *mainfw = NULL;
-
-       return -ENOENT;
-}
-EXPORT_SYMBOL_GPL(lbs_get_firmware);
-
 static int __init lbs_init_module(void)
 {
        lbs_deb_enter(LBS_DEB_MAIN);