aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorBrian Cavagnolo <brian@cozybit.com>2008-07-21 14:02:46 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-08-22 16:29:49 -0400
commit1556c0f22df77800d2e99342ce354a4ce94c5a0f (patch)
tree76c8af4251f78f1afc4504135c9d355ca15d4127 /drivers/net/wireless
parent38e3b0d86eaa0bf90a74677b6d6c442ec66daa0c (diff)
libertas: support boot commands to write persistent firmware and bootloader
Add locking and non-locking versions of if_usb_prog_firmware to support programming firmware after and before driver bring-up respectively. Add more suitable error codes for firmware programming process. Add capability checks for persistent features before attempting to use them. Based on patches from Brajesh Dave and Priyank Singh. Signed-off-by: Brian Cavagnolo <brian@cozybit.com> Acked-by: Dan Williams <dcbw@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/libertas/cmd.c21
-rw-r--r--drivers/net/wireless/libertas/defs.h6
-rw-r--r--drivers/net/wireless/libertas/if_usb.c112
-rw-r--r--drivers/net/wireless/libertas/if_usb.h5
4 files changed, 119 insertions, 25 deletions
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 75427e61898d..af5fd709887f 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -1033,9 +1033,9 @@ int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
1033 return ret; 1033 return ret;
1034} 1034}
1035 1035
1036int lbs_mesh_config_send(struct lbs_private *priv, 1036static int __lbs_mesh_config_send(struct lbs_private *priv,
1037 struct cmd_ds_mesh_config *cmd, 1037 struct cmd_ds_mesh_config *cmd,
1038 uint16_t action, uint16_t type) 1038 uint16_t action, uint16_t type)
1039{ 1039{
1040 int ret; 1040 int ret;
1041 1041
@@ -1054,6 +1054,19 @@ int lbs_mesh_config_send(struct lbs_private *priv,
1054 return ret; 1054 return ret;
1055} 1055}
1056 1056
1057int lbs_mesh_config_send(struct lbs_private *priv,
1058 struct cmd_ds_mesh_config *cmd,
1059 uint16_t action, uint16_t type)
1060{
1061 int ret;
1062
1063 if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
1064 return -EOPNOTSUPP;
1065
1066 ret = __lbs_mesh_config_send(priv, cmd, action, type);
1067 return ret;
1068}
1069
1057/* This function is the CMD_MESH_CONFIG legacy function. It only handles the 1070/* This function is the CMD_MESH_CONFIG legacy function. It only handles the
1058 * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG 1071 * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG
1059 * are all handled by preparing a struct cmd_ds_mesh_config and passing it to 1072 * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
@@ -1095,7 +1108,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
1095 action, priv->mesh_tlv, chan, 1108 action, priv->mesh_tlv, chan,
1096 escape_essid(priv->mesh_ssid, priv->mesh_ssid_len)); 1109 escape_essid(priv->mesh_ssid, priv->mesh_ssid_len));
1097 1110
1098 return lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); 1111 return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
1099} 1112}
1100 1113
1101static int lbs_cmd_bcn_ctrl(struct lbs_private * priv, 1114static int lbs_cmd_bcn_ctrl(struct lbs_private * priv,
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index 12e687550bce..4b2428ac2223 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -243,6 +243,9 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
243 243
244#define CMD_F_HOSTCMD (1 << 0) 244#define CMD_F_HOSTCMD (1 << 0)
245#define FW_CAPINFO_WPA (1 << 0) 245#define FW_CAPINFO_WPA (1 << 0)
246#define FW_CAPINFO_FIRMWARE_UPGRADE (1 << 13)
247#define FW_CAPINFO_BOOT2_UPGRADE (1<<14)
248#define FW_CAPINFO_PERSISTENT_CONFIG (1<<15)
246 249
247#define KEY_LEN_WPA_AES 16 250#define KEY_LEN_WPA_AES 16
248#define KEY_LEN_WPA_TKIP 32 251#define KEY_LEN_WPA_TKIP 32
@@ -316,7 +319,8 @@ enum PS_STATE {
316enum DNLD_STATE { 319enum DNLD_STATE {
317 DNLD_RES_RECEIVED, 320 DNLD_RES_RECEIVED,
318 DNLD_DATA_SENT, 321 DNLD_DATA_SENT,
319 DNLD_CMD_SENT 322 DNLD_CMD_SENT,
323 DNLD_BOOTCMD_SENT,
320}; 324};
321 325
322/** LBS_MEDIA_STATE */ 326/** LBS_MEDIA_STATE */
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 632c291404ab..b5013ce31b9a 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -39,7 +39,10 @@ MODULE_DEVICE_TABLE(usb, if_usb_table);
39 39
40static void if_usb_receive(struct urb *urb); 40static void if_usb_receive(struct urb *urb);
41static void if_usb_receive_fwload(struct urb *urb); 41static void if_usb_receive_fwload(struct urb *urb);
42static int if_usb_prog_firmware(struct if_usb_card *cardp); 42static int __if_usb_prog_firmware(struct if_usb_card *cardp,
43 const char *fwname, int cmd);
44static int if_usb_prog_firmware(struct if_usb_card *cardp,
45 const char *fwname, int cmd);
43static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type, 46static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
44 uint8_t *payload, uint16_t nb); 47 uint8_t *payload, uint16_t nb);
45static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, 48static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
@@ -66,10 +69,10 @@ static void if_usb_write_bulk_callback(struct urb *urb)
66 lbs_deb_usb2(&urb->dev->dev, "Actual length transmitted %d\n", 69 lbs_deb_usb2(&urb->dev->dev, "Actual length transmitted %d\n",
67 urb->actual_length); 70 urb->actual_length);
68 71
69 /* Used for both firmware TX and regular TX. priv isn't 72 /* Boot commands such as UPDATE_FW and UPDATE_BOOT2 are not
70 * valid at firmware load time. 73 * passed up to the lbs level.
71 */ 74 */
72 if (priv) 75 if (priv && priv->dnld_sent != DNLD_BOOTCMD_SENT)
73 lbs_host_to_card_done(priv); 76 lbs_host_to_card_done(priv);
74 } else { 77 } else {
75 /* print the failure status number for debug */ 78 /* print the failure status number for debug */
@@ -231,7 +234,7 @@ static int if_usb_probe(struct usb_interface *intf,
231 } 234 }
232 235
233 /* Upload firmware */ 236 /* Upload firmware */
234 if (if_usb_prog_firmware(cardp)) { 237 if (__if_usb_prog_firmware(cardp, lbs_fw_name, BOOT_CMD_FW_BY_USB)) {
235 lbs_deb_usbd(&udev->dev, "FW upload failed\n"); 238 lbs_deb_usbd(&udev->dev, "FW upload failed\n");
236 goto err_prog_firmware; 239 goto err_prog_firmware;
237 } 240 }
@@ -510,7 +513,7 @@ static void if_usb_receive_fwload(struct urb *urb)
510 if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) { 513 if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) {
511 kfree_skb(skb); 514 kfree_skb(skb);
512 if_usb_submit_rx_urb_fwload(cardp); 515 if_usb_submit_rx_urb_fwload(cardp);
513 cardp->bootcmdresp = 1; 516 cardp->bootcmdresp = BOOT_CMD_RESP_OK;
514 lbs_deb_usbd(&cardp->udev->dev, 517 lbs_deb_usbd(&cardp->udev->dev,
515 "Received valid boot command response\n"); 518 "Received valid boot command response\n");
516 return; 519 return;
@@ -526,7 +529,9 @@ static void if_usb_receive_fwload(struct urb *urb)
526 lbs_pr_info("boot cmd response wrong magic number (0x%x)\n", 529 lbs_pr_info("boot cmd response wrong magic number (0x%x)\n",
527 le32_to_cpu(bootcmdresp.magic)); 530 le32_to_cpu(bootcmdresp.magic));
528 } 531 }
529 } else if (bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) { 532 } else if ((bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) &&
533 (bootcmdresp.cmd != BOOT_CMD_UPDATE_FW) &&
534 (bootcmdresp.cmd != BOOT_CMD_UPDATE_BOOT2)) {
530 lbs_pr_info("boot cmd response cmd_tag error (%d)\n", 535 lbs_pr_info("boot cmd response cmd_tag error (%d)\n",
531 bootcmdresp.cmd); 536 bootcmdresp.cmd);
532 } else if (bootcmdresp.result != BOOT_CMD_RESP_OK) { 537 } else if (bootcmdresp.result != BOOT_CMD_RESP_OK) {
@@ -564,8 +569,8 @@ static void if_usb_receive_fwload(struct urb *urb)
564 569
565 kfree_skb(skb); 570 kfree_skb(skb);
566 571
567 /* reschedule timer for 200ms hence */ 572 /* Give device 5s to either write firmware to its RAM or eeprom */
568 mod_timer(&cardp->fw_timeout, jiffies + (HZ/5)); 573 mod_timer(&cardp->fw_timeout, jiffies + (HZ*5));
569 574
570 if (cardp->fwfinalblk) { 575 if (cardp->fwfinalblk) {
571 cardp->fwdnldover = 1; 576 cardp->fwdnldover = 1;
@@ -809,7 +814,54 @@ static int check_fwfile_format(const uint8_t *data, uint32_t totlen)
809} 814}
810 815
811 816
812static int if_usb_prog_firmware(struct if_usb_card *cardp) 817/**
818* @brief This function programs the firmware subject to cmd
819*
820* @param cardp the if_usb_card descriptor
821* fwname firmware or boot2 image file name
822* cmd either BOOT_CMD_FW_BY_USB, BOOT_CMD_UPDATE_FW,
823* or BOOT_CMD_UPDATE_BOOT2.
824* @return 0 or error code
825*/
826static int if_usb_prog_firmware(struct if_usb_card *cardp,
827 const char *fwname, int cmd)
828{
829 struct lbs_private *priv = cardp->priv;
830 unsigned long flags, caps;
831 int ret;
832
833 caps = priv->fwcapinfo;
834 if (((cmd == BOOT_CMD_UPDATE_FW) && !(caps & FW_CAPINFO_FIRMWARE_UPGRADE)) ||
835 ((cmd == BOOT_CMD_UPDATE_BOOT2) && !(caps & FW_CAPINFO_BOOT2_UPGRADE)))
836 return -EOPNOTSUPP;
837
838 /* Ensure main thread is idle. */
839 spin_lock_irqsave(&priv->driver_lock, flags);
840 while (priv->cur_cmd != NULL || priv->dnld_sent != DNLD_RES_RECEIVED) {
841 spin_unlock_irqrestore(&priv->driver_lock, flags);
842 if (wait_event_interruptible(priv->waitq,
843 (priv->cur_cmd == NULL &&
844 priv->dnld_sent == DNLD_RES_RECEIVED))) {
845 return -ERESTARTSYS;
846 }
847 spin_lock_irqsave(&priv->driver_lock, flags);
848 }
849 priv->dnld_sent = DNLD_BOOTCMD_SENT;
850 spin_unlock_irqrestore(&priv->driver_lock, flags);
851
852 ret = __if_usb_prog_firmware(cardp, fwname, cmd);
853
854 spin_lock_irqsave(&priv->driver_lock, flags);
855 priv->dnld_sent = DNLD_RES_RECEIVED;
856 spin_unlock_irqrestore(&priv->driver_lock, flags);
857
858 wake_up_interruptible(&priv->waitq);
859
860 return ret;
861}
862
863static int __if_usb_prog_firmware(struct if_usb_card *cardp,
864 const char *fwname, int cmd)
813{ 865{
814 int i = 0; 866 int i = 0;
815 static int reset_count = 10; 867 static int reset_count = 10;
@@ -817,20 +869,32 @@ static int if_usb_prog_firmware(struct if_usb_card *cardp)
817 869
818 lbs_deb_enter(LBS_DEB_USB); 870 lbs_deb_enter(LBS_DEB_USB);
819 871
820 if ((ret = request_firmware(&cardp->fw, lbs_fw_name, 872 ret = request_firmware(&cardp->fw, fwname, &cardp->udev->dev);
821 &cardp->udev->dev)) < 0) { 873 if (ret < 0) {
822 lbs_pr_err("request_firmware() failed with %#x\n", ret); 874 lbs_pr_err("request_firmware() failed with %#x\n", ret);
823 lbs_pr_err("firmware %s not found\n", lbs_fw_name); 875 lbs_pr_err("firmware %s not found\n", fwname);
824 goto done; 876 goto done;
825 } 877 }
826 878
827 if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) 879 if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) {
880 ret = -EINVAL;
828 goto release_fw; 881 goto release_fw;
882 }
883
884 /* Cancel any pending usb business */
885 usb_kill_urb(cardp->rx_urb);
886 usb_kill_urb(cardp->tx_urb);
887
888 cardp->fwlastblksent = 0;
889 cardp->fwdnldover = 0;
890 cardp->totalbytes = 0;
891 cardp->fwfinalblk = 0;
892 cardp->bootcmdresp = 0;
829 893
830restart: 894restart:
831 if (if_usb_submit_rx_urb_fwload(cardp) < 0) { 895 if (if_usb_submit_rx_urb_fwload(cardp) < 0) {
832 lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n"); 896 lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n");
833 ret = -1; 897 ret = -EIO;
834 goto release_fw; 898 goto release_fw;
835 } 899 }
836 900
@@ -838,8 +902,7 @@ restart:
838 do { 902 do {
839 int j = 0; 903 int j = 0;
840 i++; 904 i++;
841 /* Issue Boot command = 1, Boot from Download-FW */ 905 if_usb_issue_boot_command(cardp, cmd);
842 if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB);
843 /* wait for command response */ 906 /* wait for command response */
844 do { 907 do {
845 j++; 908 j++;
@@ -847,12 +910,21 @@ restart:
847 } while (cardp->bootcmdresp == 0 && j < 10); 910 } while (cardp->bootcmdresp == 0 && j < 10);
848 } while (cardp->bootcmdresp == 0 && i < 5); 911 } while (cardp->bootcmdresp == 0 && i < 5);
849 912
850 if (cardp->bootcmdresp <= 0) { 913 if (cardp->bootcmdresp == BOOT_CMD_RESP_NOT_SUPPORTED) {
914 /* Return to normal operation */
915 ret = -EOPNOTSUPP;
916 usb_kill_urb(cardp->rx_urb);
917 usb_kill_urb(cardp->tx_urb);
918 if (if_usb_submit_rx_urb(cardp) < 0)
919 ret = -EIO;
920 goto release_fw;
921 } else if (cardp->bootcmdresp <= 0) {
851 if (--reset_count >= 0) { 922 if (--reset_count >= 0) {
852 if_usb_reset_device(cardp); 923 if_usb_reset_device(cardp);
853 goto restart; 924 goto restart;
854 } 925 }
855 return -1; 926 ret = -EIO;
927 goto release_fw;
856 } 928 }
857 929
858 i = 0; 930 i = 0;
@@ -882,7 +954,7 @@ restart:
882 } 954 }
883 955
884 lbs_pr_info("FW download failure, time = %d ms\n", i * 100); 956 lbs_pr_info("FW download failure, time = %d ms\n", i * 100);
885 ret = -1; 957 ret = -EIO;
886 goto release_fw; 958 goto release_fw;
887 } 959 }
888 960
diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h
index 5771a83a43f0..5ba0aee0eb2f 100644
--- a/drivers/net/wireless/libertas/if_usb.h
+++ b/drivers/net/wireless/libertas/if_usb.h
@@ -30,6 +30,7 @@ struct bootcmd
30 30
31#define BOOT_CMD_RESP_OK 0x0001 31#define BOOT_CMD_RESP_OK 0x0001
32#define BOOT_CMD_RESP_FAIL 0x0000 32#define BOOT_CMD_RESP_FAIL 0x0000
33#define BOOT_CMD_RESP_NOT_SUPPORTED 0x0002
33 34
34struct bootcmdresp 35struct bootcmdresp
35{ 36{
@@ -50,6 +51,10 @@ struct if_usb_card {
50 uint8_t ep_in; 51 uint8_t ep_in;
51 uint8_t ep_out; 52 uint8_t ep_out;
52 53
54 /* bootcmdresp == 0 means command is pending
55 * bootcmdresp < 0 means error
56 * bootcmdresp > 0 is a BOOT_CMD_RESP_* from firmware
57 */
53 int8_t bootcmdresp; 58 int8_t bootcmdresp;
54 59
55 int ep_in_size; 60 int ep_in_size;