summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: a7426c1)
raw | patch | inline | side by side (parent: a7426c1)
author | Andreas Müller <schnitzeltony@googlemail.com> | |
Fri, 25 May 2012 09:11:57 +0000 (11:11 +0200) | ||
committer | Denys Dmytriyenko <denys@ti.com> | |
Tue, 29 May 2012 22:11:01 +0000 (18:11 -0400) |
When using udev >=177 libertas driver does not load properly the firmware [1].
The patches 0001-0016 were taken from [2] and can be viewed at [3]. Patch 0017
I created to fix compiler complaining for missing symbol is_interrupt when
DEBUG set.
The patch series was tested with meta-gumstix on overo with udev-175 and
udev-182.
[1] http://www.spinics.net/lists/linux-wireless/msg85541.html
[2] git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next.git
[3] http://git.kernel.org/?p=linux/kernel/git/linville/wireless-next.git;a=history;f=drivers/net/wireless/libertas;hb=HEAD
Signed-off-by: Andreas Müller <schnitzeltony@googlemail.com>
Signed-off-by: Denys Dmytriyenko <denys@ti.com>
The patches 0001-0016 were taken from [2] and can be viewed at [3]. Patch 0017
I created to fix compiler complaining for missing symbol is_interrupt when
DEBUG set.
The patch series was tested with meta-gumstix on overo with udev-175 and
udev-182.
[1] http://www.spinics.net/lists/linux-wireless/msg85541.html
[2] git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next.git
[3] http://git.kernel.org/?p=linux/kernel/git/linville/wireless-next.git;a=history;f=drivers/net/wireless/libertas;hb=HEAD
Signed-off-by: Andreas Müller <schnitzeltony@googlemail.com>
Signed-off-by: Denys Dmytriyenko <denys@ti.com>
17 files changed:
diff --git a/recipes-kernel/linux/linux-mainline-3.2/libertas/0001-USB-convert-drivers-net-to-use-module_usb_driver.patch b/recipes-kernel/linux/linux-mainline-3.2/libertas/0001-USB-convert-drivers-net-to-use-module_usb_driver.patch
--- /dev/null
@@ -0,0 +1,80 @@
+From d632eb1bf22e11def74e4e53cc47d790fbdba105 Mon Sep 17 00:00:00 2001
+From: Greg Kroah-Hartman <gregkh@suse.de>
+Date: Fri, 18 Nov 2011 09:44:20 -0800
+Subject: [PATCH 01/17] USB: convert drivers/net/* to use module_usb_driver()
+
+This converts the drivers in drivers/net/* to use the
+module_usb_driver() macro which makes the code smaller and a bit
+simpler.
+
+Added bonus is that it removes some unneeded kernel log messages about
+drivers loading and/or unloading.
+
+Cc: Wolfgang Grandegger <wg@grandegger.com>
+Cc: Samuel Ortiz <samuel@sortiz.org>
+Cc: Oliver Neukum <oliver@neukum.name>
+Cc: Peter Korsgaard <jacmet@sunsite.dk>
+Cc: Petko Manolov <petkan@users.sourceforge.net>
+Cc: Steve Glendinning <steve.glendinning@smsc.com>
+Cc: Christian Lamparter <chunkeey@googlemail.com>
+Cc: "John W. Linville" <linville@tuxdriver.com>
+Cc: Dan Williams <dcbw@redhat.com>
+Cc: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+Cc: Ivo van Doorn <IvDoorn@gmail.com>
+Cc: Gertjan van Wingerde <gwingerde@gmail.com>
+Cc: Helmut Schaa <helmut.schaa@googlemail.com>
+Cc: Herton Ronaldo Krzesinski <herton@canonical.com>
+Cc: Hin-Tak Leung <htl10@users.sourceforge.net>
+Cc: Larry Finger <Larry.Finger@lwfinger.net>
+Cc: Chaoming Li <chaoming_li@realsil.com.cn>
+Cc: Lucas De Marchi <lucas.demarchi@profusion.mobi>
+Cc: "David S. Miller" <davem@davemloft.net>
+Cc: Roel Kluin <roel.kluin@gmail.com>
+Cc: Paul Gortmaker <paul.gortmaker@windriver.com>
+Cc: Jiri Pirko <jpirko@redhat.com>
+Cc: Pavel Roskin <proski@gnu.org>
+Cc: Yoann DI-RUZZA <y.diruzza@lim.eu>
+Cc: George <george0505@realtek.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/net/wireless/libertas/if_usb.c | 24 +-----------------------
+ 1 files changed, 1 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
+index db879c3..b5fbbc7 100644
+--- a/drivers/net/wireless/libertas/if_usb.c
++++ b/drivers/net/wireless/libertas/if_usb.c
+@@ -1184,29 +1184,7 @@ static struct usb_driver if_usb_driver = {
+ .reset_resume = if_usb_resume,
+ };
+
+-static int __init if_usb_init_module(void)
+-{
+- int ret = 0;
+-
+- lbs_deb_enter(LBS_DEB_MAIN);
+-
+- ret = usb_register(&if_usb_driver);
+-
+- lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
+- return ret;
+-}
+-
+-static void __exit if_usb_exit_module(void)
+-{
+- lbs_deb_enter(LBS_DEB_MAIN);
+-
+- usb_deregister(&if_usb_driver);
+-
+- lbs_deb_leave(LBS_DEB_MAIN);
+-}
+-
+-module_init(if_usb_init_module);
+-module_exit(if_usb_exit_module);
++module_usb_driver(if_usb_driver);
+
+ MODULE_DESCRIPTION("8388 USB WLAN Driver");
+ MODULE_AUTHOR("Marvell International Ltd. and Red Hat, Inc.");
+--
+1.7.4.4
+
diff --git a/recipes-kernel/linux/linux-mainline-3.2/libertas/0002-net-fix-assignment-of-0-1-to-bool-variables.patch b/recipes-kernel/linux/linux-mainline-3.2/libertas/0002-net-fix-assignment-of-0-1-to-bool-variables.patch
--- /dev/null
@@ -0,0 +1,55 @@
+From 3db1cd5c05f35fb43eb134df6f321de4e63141f2 Mon Sep 17 00:00:00 2001
+From: Rusty Russell <rusty@rustcorp.com.au>
+Date: Mon, 19 Dec 2011 13:56:45 +0000
+Subject: [PATCH 02/17] net: fix assignment of 0/1 to bool variables.
+
+DaveM said:
+ Please, this kind of stuff rots forever and not using bool properly
+ drives me crazy.
+
+Joe Perches <joe@perches.com> gave me the spatch script:
+
+ @@
+ bool b;
+ @@
+ -b = 0
+ +b = false
+ @@
+ bool b;
+ @@
+ -b = 1
+ +b = true
+
+I merely installed coccinelle, read the documentation and took credit.
+
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/wireless/libertas/if_cs.c | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
+index e269351..3f7bf4d 100644
+--- a/drivers/net/wireless/libertas/if_cs.c
++++ b/drivers/net/wireless/libertas/if_cs.c
+@@ -859,7 +859,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
+ * Most of the libertas cards can do unaligned register access, but some
+ * weird ones cannot. That's especially true for the CF8305 card.
+ */
+- card->align_regs = 0;
++ card->align_regs = false;
+
+ card->model = get_model(p_dev->manf_id, p_dev->card_id);
+ if (card->model == MODEL_UNKNOWN) {
+@@ -871,7 +871,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
+ /* Check if we have a current silicon */
+ prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID);
+ if (card->model == MODEL_8305) {
+- card->align_regs = 1;
++ card->align_regs = true;
+ if (prod_id < IF_CS_CF8305_B1_REV) {
+ pr_err("8305 rev B0 and older are not supported\n");
+ ret = -ENODEV;
+--
+1.7.4.4
+
diff --git a/recipes-kernel/linux/linux-mainline-3.2/libertas/0003-switch-debugfs-to-umode_t.patch b/recipes-kernel/linux/linux-mainline-3.2/libertas/0003-switch-debugfs-to-umode_t.patch
--- /dev/null
@@ -0,0 +1,26 @@
+From f4ae40a6a50a98ac23d4b285f739455e926a473e Mon Sep 17 00:00:00 2001
+From: Al Viro <viro@zeniv.linux.org.uk>
+Date: Sun, 24 Jul 2011 04:33:43 -0400
+Subject: [PATCH 03/17] switch debugfs to umode_t
+
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+---
+ drivers/net/wireless/libertas/debugfs.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
+index d8d8f0d..c192671 100644
+--- a/drivers/net/wireless/libertas/debugfs.c
++++ b/drivers/net/wireless/libertas/debugfs.c
+@@ -704,7 +704,7 @@ out_unlock:
+
+ struct lbs_debugfs_files {
+ const char *name;
+- int perm;
++ umode_t perm;
+ struct file_operations fops;
+ };
+
+--
+1.7.4.4
+
diff --git a/recipes-kernel/linux/linux-mainline-3.2/libertas/0004-drivers-net-Remove-unnecessary-k.alloc-v.alloc-OOM-m.patch b/recipes-kernel/linux/linux-mainline-3.2/libertas/0004-drivers-net-Remove-unnecessary-k.alloc-v.alloc-OOM-m.patch
--- /dev/null
@@ -0,0 +1,54 @@
+From e404decb0fb017be80552adee894b35307b6c7b4 Mon Sep 17 00:00:00 2001
+From: Joe Perches <joe@perches.com>
+Date: Sun, 29 Jan 2012 12:56:23 +0000
+Subject: [PATCH 04/17] drivers/net: Remove unnecessary k.alloc/v.alloc OOM
+ messages
+
+alloc failures use dump_stack so emitting an additional
+out-of-memory message is an unnecessary duplication.
+
+Remove the allocation failure messages.
+
+Signed-off-by: Joe Perches <joe@perches.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/wireless/libertas/if_cs.c | 5 ++---
+ drivers/net/wireless/libertas/if_usb.c | 4 +---
+ 2 files changed, 3 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
+index 3f7bf4d..234ee88 100644
+--- a/drivers/net/wireless/libertas/if_cs.c
++++ b/drivers/net/wireless/libertas/if_cs.c
+@@ -815,10 +815,9 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
+ lbs_deb_enter(LBS_DEB_CS);
+
+ card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL);
+- if (!card) {
+- pr_err("error in kzalloc\n");
++ if (!card)
+ goto out;
+- }
++
+ card->p_dev = p_dev;
+ p_dev->priv = card;
+
+diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
+index b5fbbc7..74da5f1 100644
+--- a/drivers/net/wireless/libertas/if_usb.c
++++ b/drivers/net/wireless/libertas/if_usb.c
+@@ -261,10 +261,8 @@ static int if_usb_probe(struct usb_interface *intf,
+ udev = interface_to_usbdev(intf);
+
+ cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL);
+- if (!cardp) {
+- pr_err("Out of memory allocating private data\n");
++ if (!cardp)
+ goto error;
+- }
+
+ setup_timer(&cardp->fw_timeout, if_usb_fw_timeo, (unsigned long)cardp);
+ init_waitqueue_head(&cardp->fw_wq);
+--
+1.7.4.4
+
diff --git a/recipes-kernel/linux/linux-mainline-3.2/libertas/0005-libertas-remove-dump_survey-implementation.patch b/recipes-kernel/linux/linux-mainline-3.2/libertas/0005-libertas-remove-dump_survey-implementation.patch
--- /dev/null
@@ -0,0 +1,80 @@
+From 377526578f2c343ea281a918b18ece1fca65005c Mon Sep 17 00:00:00 2001
+From: Daniel Drake <dsd@laptop.org>
+Date: Wed, 14 Mar 2012 22:34:33 +0000
+Subject: [PATCH 05/17] libertas: remove dump_survey implementation
+
+libertas provides a dump_survey implementation based on reading of
+a RSSI value. However, this RSSI value is calculated based on the
+last received beacon from the associated AP - it is not a good
+way of surveying a channel in general, and even causes an error
+if the card is not associated to a network.
+
+As this is not appropriate as a survey, remove it. This fixes an
+issue where something in userspace is repeatedly calling site-survey
+during boot, resulting in many repeated errors as the RSSI value cannot
+be read before associating.
+
+Signed-off-by: Daniel Drake <dsd@laptop.org>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+---
+ drivers/net/wireless/libertas/cfg.c | 37 -----------------------------------
+ 1 files changed, 0 insertions(+), 37 deletions(-)
+
+diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
+index a7cd311..3fa1ece 100644
+--- a/drivers/net/wireless/libertas/cfg.c
++++ b/drivers/net/wireless/libertas/cfg.c
+@@ -1631,42 +1631,6 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev,
+
+
+ /*
+- * "Site survey", here just current channel and noise level
+- */
+-
+-static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev,
+- int idx, struct survey_info *survey)
+-{
+- struct lbs_private *priv = wiphy_priv(wiphy);
+- s8 signal, noise;
+- int ret;
+-
+- if (dev == priv->mesh_dev)
+- return -EOPNOTSUPP;
+-
+- if (idx != 0)
+- ret = -ENOENT;
+-
+- lbs_deb_enter(LBS_DEB_CFG80211);
+-
+- survey->channel = ieee80211_get_channel(wiphy,
+- ieee80211_channel_to_frequency(priv->channel,
+- IEEE80211_BAND_2GHZ));
+-
+- ret = lbs_get_rssi(priv, &signal, &noise);
+- if (ret == 0) {
+- survey->filled = SURVEY_INFO_NOISE_DBM;
+- survey->noise = noise;
+- }
+-
+- lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+- return ret;
+-}
+-
+-
+-
+-
+-/*
+ * Change interface
+ */
+
+@@ -2068,7 +2032,6 @@ static struct cfg80211_ops lbs_cfg80211_ops = {
+ .del_key = lbs_cfg_del_key,
+ .set_default_key = lbs_cfg_set_default_key,
+ .get_station = lbs_cfg_get_station,
+- .dump_survey = lbs_get_survey,
+ .change_virtual_intf = lbs_change_intf,
+ .join_ibss = lbs_join_ibss,
+ .leave_ibss = lbs_leave_ibss,
+--
+1.7.4.4
+
diff --git a/recipes-kernel/linux/linux-mainline-3.2/libertas/0007-wireless-libertas-remove-redundant-NULL-tests-before.patch b/recipes-kernel/linux/linux-mainline-3.2/libertas/0007-wireless-libertas-remove-redundant-NULL-tests-before.patch
--- /dev/null
@@ -0,0 +1,95 @@
+From a7b957a277215da1830596c0791307a999fe5153 Mon Sep 17 00:00:00 2001
+From: Jesper Juhl <jj@chaosbits.net>
+Date: Mon, 9 Apr 2012 22:51:07 +0200
+Subject: [PATCH 07/17] wireless, libertas: remove redundant NULL tests before
+ calling release_firmware()
+
+release_firmware() tests for, and deals gracefully with, NULL
+pointers. Remove redundant explicit tests before calling the function.
+
+Signed-off-by: Jesper Juhl <jj@chaosbits.net>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+---
+ drivers/net/wireless/libertas/if_cs.c | 6 ++----
+ drivers/net/wireless/libertas/if_sdio.c | 6 ++----
+ drivers/net/wireless/libertas/if_spi.c | 6 ++----
+ drivers/net/wireless/libertas/main.c | 12 ++++--------
+ 4 files changed, 10 insertions(+), 20 deletions(-)
+
+diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
+index 234ee88..171a06b 100644
+--- a/drivers/net/wireless/libertas/if_cs.c
++++ b/drivers/net/wireless/libertas/if_cs.c
+@@ -951,10 +951,8 @@ out2:
+ out1:
+ pcmcia_disable_device(p_dev);
+ out:
+- if (helper)
+- release_firmware(helper);
+- if (mainfw)
+- release_firmware(mainfw);
++ release_firmware(helper);
++ release_firmware(mainfw);
+
+ lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+ return ret;
+diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
+index 9804ebc..15bfe2f 100644
+--- a/drivers/net/wireless/libertas/if_sdio.c
++++ b/drivers/net/wireless/libertas/if_sdio.c
+@@ -751,10 +751,8 @@ success:
+ ret = 0;
+
+ out:
+- if (helper)
+- release_firmware(helper);
+- if (mainfw)
+- release_firmware(mainfw);
++ release_firmware(helper);
++ release_firmware(mainfw);
+
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+ return ret;
+diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
+index 50b1ee7..7a5df4f 100644
+--- a/drivers/net/wireless/libertas/if_spi.c
++++ b/drivers/net/wireless/libertas/if_spi.c
+@@ -1095,10 +1095,8 @@ static int if_spi_init_card(struct if_spi_card *card)
+ goto out;
+
+ out:
+- if (helper)
+- release_firmware(helper);
+- if (mainfw)
+- release_firmware(mainfw);
++ release_firmware(helper);
++ release_firmware(mainfw);
+
+ lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err);
+
+diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
+index 957681d..3b81b70 100644
+--- a/drivers/net/wireless/libertas/main.c
++++ b/drivers/net/wireless/libertas/main.c
+@@ -1269,14 +1269,10 @@ int lbs_get_firmware(struct device *dev, const char *user_helper,
+
+ fail:
+ /* Failed */
+- if (*helper) {
+- release_firmware(*helper);
+- *helper = NULL;
+- }
+- if (*mainfw) {
+- release_firmware(*mainfw);
+- *mainfw = NULL;
+- }
++ release_firmware(*helper);
++ *helper = NULL;
++ release_firmware(*mainfw);
++ *mainfw = NULL;
+
+ return -ENOENT;
+ }
+--
+1.7.4.4
+
diff --git a/recipes-kernel/linux/linux-mainline-3.2/libertas/0008-libertas-fix-signedness-bug-in-lbs_auth_to_authtype.patch b/recipes-kernel/linux/linux-mainline-3.2/libertas/0008-libertas-fix-signedness-bug-in-lbs_auth_to_authtype.patch
--- /dev/null
@@ -0,0 +1,48 @@
+From effcc625eb4ab3b10b4744237fd37e8f7dcd6511 Mon Sep 17 00:00:00 2001
+From: Amitkumar Karwar <akarwar@marvell.com>
+Date: Wed, 28 Mar 2012 11:38:01 -0700
+Subject: [PATCH 08/17] libertas: fix signedness bug in lbs_auth_to_authtype()
+
+Return type for lbs_auth_to_authtype() is changed from "u8" to
+"int" to return negative error code correctly.
+Also an error check is added in connect handler for invalid auth
+type.
+
+Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
+Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
+Signed-off-by: Kiran Divekar <dkiran@marvell.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+---
+ drivers/net/wireless/libertas/cfg.c | 9 +++++++--
+ 1 files changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
+index 3fa1ece..2fa879b 100644
+--- a/drivers/net/wireless/libertas/cfg.c
++++ b/drivers/net/wireless/libertas/cfg.c
+@@ -103,7 +103,7 @@ static const u32 cipher_suites[] = {
+ * Convert NL80211's auth_type to the one from Libertas, see chapter 5.9.1
+ * in the firmware spec
+ */
+-static u8 lbs_auth_to_authtype(enum nl80211_auth_type auth_type)
++static int lbs_auth_to_authtype(enum nl80211_auth_type auth_type)
+ {
+ int ret = -ENOTSUPP;
+
+@@ -1411,7 +1411,12 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
+ goto done;
+ }
+
+- lbs_set_authtype(priv, sme);
++ ret = lbs_set_authtype(priv, sme);
++ if (ret == -ENOTSUPP) {
++ wiphy_err(wiphy, "unsupported authtype 0x%x\n", sme->auth_type);
++ goto done;
++ }
++
+ lbs_set_radio(priv, preamble, 1);
+
+ /* Do the actual association */
+--
+1.7.4.4
+
diff --git a/recipes-kernel/linux/linux-mainline-3.2/libertas/0009-drivers-net-wireless-libertas-if_usb.c-add-missing-d.patch b/recipes-kernel/linux/linux-mainline-3.2/libertas/0009-drivers-net-wireless-libertas-if_usb.c-add-missing-d.patch
--- /dev/null
@@ -0,0 +1,35 @@
+From 1e66eda1d40c9ce3ff38782da066a14e1b88ac50 Mon Sep 17 00:00:00 2001
+From: Julia Lawall <Julia.Lawall@lip6.fr>
+Date: Mon, 16 Apr 2012 17:44:00 +0200
+Subject: [PATCH 09/17] drivers/net/wireless/libertas/if_usb.c: add missing
+ debugging code
+
+Add a corresponding leave call on error failure.
+
+Signed-off-by: Julia Lawall <Julia.Lawall@lip6.fr>
+Acked-by: Dan Williams <dcbw@redhat.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+---
+ drivers/net/wireless/libertas/if_usb.c | 6 ++++--
+ 1 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
+index 74da5f1..ce4938d 100644
+--- a/drivers/net/wireless/libertas/if_usb.c
++++ b/drivers/net/wireless/libertas/if_usb.c
+@@ -1128,8 +1128,10 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
+
+ lbs_deb_enter(LBS_DEB_USB);
+
+- if (priv->psstate != PS_STATE_FULL_POWER)
+- return -1;
++ if (priv->psstate != PS_STATE_FULL_POWER) {
++ ret = -1;
++ goto out;
++ }
+
+ #ifdef CONFIG_OLPC
+ if (machine_is_olpc()) {
+--
+1.7.4.4
+
diff --git a/recipes-kernel/linux/linux-mainline-3.2/libertas/0010-libertas-Firmware-loading-simplifications.patch b/recipes-kernel/linux/linux-mainline-3.2/libertas/0010-libertas-Firmware-loading-simplifications.patch
--- /dev/null
@@ -0,0 +1,618 @@
+From 370803c25dd77332ee4ca97884c3a5e1e1eafbca Mon Sep 17 00:00:00 2001
+From: Daniel Drake <dsd@laptop.org>
+Date: Mon, 16 Apr 2012 23:52:42 +0100
+Subject: [PATCH 10/17] libertas: Firmware loading simplifications
+
+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 | 1 +
+ drivers/net/wireless/libertas/decl.h | 3 +-
+ drivers/net/wireless/libertas/firmware.c | 79 ++++++++++++++
+ drivers/net/wireless/libertas/if_cs.c | 4 +-
+ drivers/net/wireless/libertas/if_sdio.c | 25 +----
+ drivers/net/wireless/libertas/if_spi.c | 5 +-
+ drivers/net/wireless/libertas/if_usb.c | 169 ++----------------------------
+ drivers/net/wireless/libertas/main.c | 101 ------------------
+ 8 files changed, 94 insertions(+), 293 deletions(-)
+ create mode 100644 drivers/net/wireless/libertas/firmware.c
+
+diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
+index f7d01bf..eac72f7 100644
+--- a/drivers/net/wireless/libertas/Makefile
++++ b/drivers/net/wireless/libertas/Makefile
+@@ -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
+diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
+index bc951ab..2fb2e31 100644
+--- a/drivers/net/wireless/libertas/decl.h
++++ b/drivers/net/wireless/libertas/decl.h
+@@ -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
+index 0000000..0c8c845
+--- /dev/null
++++ b/drivers/net/wireless/libertas/firmware.c
+@@ -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);
+diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
+index 171a06b..cee5052 100644
+--- a/drivers/net/wireless/libertas/if_cs.c
++++ b/drivers/net/wireless/libertas/if_cs.c
+@@ -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;
+diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
+index 15bfe2f..6590feb 100644
+--- a/drivers/net/wireless/libertas/if_sdio.c
++++ b/drivers/net/wireless/libertas/if_sdio.c
+@@ -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);
+ }
+
+diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
+index 7a5df4f..9604a1c 100644
+--- a/drivers/net/wireless/libertas/if_spi.c
++++ b/drivers/net/wireless/libertas/if_spi.c
+@@ -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);
+diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
+index ce4938d..f29471b 100644
+--- a/drivers/net/wireless/libertas/if_usb.c
++++ b/drivers/net/wireless/libertas/if_usb.c
+@@ -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++;
+diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
+index 3b81b70..fa09585 100644
+--- a/drivers/net/wireless/libertas/main.c
++++ b/drivers/net/wireless/libertas/main.c
+@@ -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);
+--
+1.7.4.4
+
diff --git a/recipes-kernel/linux/linux-mainline-3.2/libertas/0011-libertas-harden-up-exit-paths.patch b/recipes-kernel/linux/linux-mainline-3.2/libertas/0011-libertas-harden-up-exit-paths.patch
--- /dev/null
@@ -0,0 +1,46 @@
+From 0beecac8abb3af890d470df541142d55343382d6 Mon Sep 17 00:00:00 2001
+From: Daniel Drake <dsd@laptop.org>
+Date: Mon, 16 Apr 2012 23:53:02 +0100
+Subject: [PATCH 11/17] libertas: harden-up exit paths
+
+These simple sanity check avoids extra complexity in error paths when
+moving to asynchronous firmware loading (which means the device may fail to
+init some time after its creation).
+
+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/main.c | 9 ++++++++-
+ 1 files changed, 8 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
+index fa09585..7eaf992 100644
+--- a/drivers/net/wireless/libertas/main.c
++++ b/drivers/net/wireless/libertas/main.c
+@@ -1033,7 +1033,9 @@ void lbs_remove_card(struct lbs_private *priv)
+ lbs_deb_enter(LBS_DEB_MAIN);
+
+ lbs_remove_mesh(priv);
+- lbs_scan_deinit(priv);
++
++ if (priv->wiphy_registered)
++ lbs_scan_deinit(priv);
+
+ /* worker thread destruction blocks on the in-flight command which
+ * should have been cleared already in lbs_stop_card().
+@@ -1128,6 +1130,11 @@ void lbs_stop_card(struct lbs_private *priv)
+ goto out;
+ dev = priv->dev;
+
++ /* If the netdev isn't registered, it means that lbs_start_card() was
++ * never called so we have nothing to do here. */
++ if (dev->reg_state != NETREG_REGISTERED)
++ goto out;
++
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
+
+--
+1.7.4.4
+
diff --git a/recipes-kernel/linux/linux-mainline-3.2/libertas/0012-libertas-add-asynchronous-firmware-loading-capabilit.patch b/recipes-kernel/linux/linux-mainline-3.2/libertas/0012-libertas-add-asynchronous-firmware-loading-capabilit.patch
--- /dev/null
@@ -0,0 +1,269 @@
+From 534111c78c59a8db89c570fd07489243dc366a05 Mon Sep 17 00:00:00 2001
+From: Daniel Drake <dsd@laptop.org>
+Date: Mon, 16 Apr 2012 23:53:26 +0100
+Subject: [PATCH 12/17] libertas: add asynchronous firmware loading capability
+
+As described at
+http://article.gmane.org/gmane.linux.kernel.wireless.general/86084
+libertas is taking a long time to load because it loads firmware
+during module loading.
+
+Add a new API for interface drivers to load their firmware
+asynchronously. The same semantics of the firmware table are followed
+like before.
+
+Interface drivers will be converted in follow-up patches, then we can
+remove the old, synchronous firmware loading function.
+
+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/decl.h | 8 ++
+ drivers/net/wireless/libertas/dev.h | 10 ++
+ drivers/net/wireless/libertas/firmware.c | 143 ++++++++++++++++++++++++++++++
+ drivers/net/wireless/libertas/main.c | 3 +
+ 4 files changed, 164 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
+index 2fb2e31..84a3aa7 100644
+--- a/drivers/net/wireless/libertas/decl.h
++++ b/drivers/net/wireless/libertas/decl.h
+@@ -19,6 +19,10 @@ struct lbs_fw_table {
+ };
+
+ struct lbs_private;
++typedef void (*lbs_fw_cb)(struct lbs_private *priv, int ret,
++ const struct firmware *helper, const struct firmware *mainfw);
++
++struct lbs_private;
+ struct sk_buff;
+ struct net_device;
+ struct cmd_ds_command;
+@@ -70,5 +74,9 @@ 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);
++int lbs_get_firmware_async(struct lbs_private *priv, struct device *device,
++ u32 card_model, const struct lbs_fw_table *fw_table,
++ lbs_fw_cb callback);
++void lbs_wait_for_firmware_load(struct lbs_private *priv);
+
+ #endif
+diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
+index f3fd447..6720054 100644
+--- a/drivers/net/wireless/libertas/dev.h
++++ b/drivers/net/wireless/libertas/dev.h
+@@ -7,6 +7,7 @@
+ #define _LBS_DEV_H_
+
+ #include "defs.h"
++#include "decl.h"
+ #include "host.h"
+
+ #include <linux/kfifo.h>
+@@ -180,6 +181,15 @@ struct lbs_private {
+ wait_queue_head_t scan_q;
+ /* Whether the scan was initiated internally and not by cfg80211 */
+ bool internal_scan;
++
++ /* Firmware load */
++ u32 fw_model;
++ wait_queue_head_t fw_waitq;
++ struct device *fw_device;
++ const struct firmware *helper_fw;
++ const struct lbs_fw_table *fw_table;
++ const struct lbs_fw_table *fw_iter;
++ lbs_fw_cb fw_callback;
+ };
+
+ extern struct cmd_confirm_sleep confirm_sleep;
+diff --git a/drivers/net/wireless/libertas/firmware.c b/drivers/net/wireless/libertas/firmware.c
+index 0c8c845..cd23f1a 100644
+--- a/drivers/net/wireless/libertas/firmware.c
++++ b/drivers/net/wireless/libertas/firmware.c
+@@ -3,10 +3,151 @@
+ */
+
+ #include <linux/firmware.h>
++#include <linux/firmware.h>
+ #include <linux/module.h>
+
++#include "dev.h"
+ #include "decl.h"
+
++static void load_next_firmware_from_table(struct lbs_private *private);
++
++static void lbs_fw_loaded(struct lbs_private *priv, int ret,
++ const struct firmware *helper, const struct firmware *mainfw)
++{
++ unsigned long flags;
++
++ lbs_deb_fw("firmware load complete, code %d\n", ret);
++
++ /* User must free helper/mainfw */
++ priv->fw_callback(priv, ret, helper, mainfw);
++
++ spin_lock_irqsave(&priv->driver_lock, flags);
++ priv->fw_callback = NULL;
++ wake_up(&priv->fw_waitq);
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
++}
++
++static void do_load_firmware(struct lbs_private *priv, const char *name,
++ void (*cb)(const struct firmware *fw, void *context))
++{
++ int ret;
++
++ lbs_deb_fw("Requesting %s\n", name);
++ ret = request_firmware_nowait(THIS_MODULE, true, name,
++ priv->fw_device, GFP_KERNEL, priv, cb);
++ if (ret) {
++ lbs_deb_fw("request_firmware_nowait error %d\n", ret);
++ lbs_fw_loaded(priv, ret, NULL, NULL);
++ }
++}
++
++static void main_firmware_cb(const struct firmware *firmware, void *context)
++{
++ struct lbs_private *priv = context;
++
++ if (!firmware) {
++ /* Failed to find firmware: try next table entry */
++ load_next_firmware_from_table(priv);
++ return;
++ }
++
++ /* Firmware found! */
++ lbs_fw_loaded(priv, 0, priv->helper_fw, firmware);
++}
++
++static void helper_firmware_cb(const struct firmware *firmware, void *context)
++{
++ struct lbs_private *priv = context;
++
++ if (!firmware) {
++ /* Failed to find firmware: try next table entry */
++ load_next_firmware_from_table(priv);
++ return;
++ }
++
++ /* Firmware found! */
++ if (priv->fw_iter->fwname) {
++ priv->helper_fw = firmware;
++ do_load_firmware(priv, priv->fw_iter->fwname, main_firmware_cb);
++ } else {
++ /* No main firmware needed for this helper --> success! */
++ lbs_fw_loaded(priv, 0, firmware, NULL);
++ }
++}
++
++static void load_next_firmware_from_table(struct lbs_private *priv)
++{
++ const struct lbs_fw_table *iter;
++
++ if (!priv->fw_iter)
++ iter = priv->fw_table;
++ else
++ iter = ++priv->fw_iter;
++
++ if (priv->helper_fw) {
++ release_firmware(priv->helper_fw);
++ priv->helper_fw = NULL;
++ }
++
++next:
++ if (!iter->helper) {
++ /* End of table hit. */
++ lbs_fw_loaded(priv, -ENOENT, NULL, NULL);
++ return;
++ }
++
++ if (iter->model != priv->fw_model) {
++ iter++;
++ goto next;
++ }
++
++ priv->fw_iter = iter;
++ do_load_firmware(priv, iter->helper, helper_firmware_cb);
++}
++
++void lbs_wait_for_firmware_load(struct lbs_private *priv)
++{
++ wait_event(priv->fw_waitq, priv->fw_callback == NULL);
++}
++
++/**
++ * lbs_get_firmware_async - Retrieves firmware asynchronously. Can load
++ * either a helper firmware and a main firmware (2-stage), or just the helper.
++ *
++ * @priv: Pointer to lbs_private instance
++ * @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
++ * @callback: User callback to invoke when firmware load succeeds or fails.
++ */
++int lbs_get_firmware_async(struct lbs_private *priv, struct device *device,
++ u32 card_model, const struct lbs_fw_table *fw_table,
++ lbs_fw_cb callback)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&priv->driver_lock, flags);
++ if (priv->fw_callback) {
++ lbs_deb_fw("firmware load already in progress\n");
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
++ return -EBUSY;
++ }
++
++ priv->fw_device = device;
++ priv->fw_callback = callback;
++ priv->fw_table = fw_table;
++ priv->fw_iter = NULL;
++ priv->fw_model = card_model;
++ spin_unlock_irqrestore(&priv->driver_lock, flags);
++
++ lbs_deb_fw("Starting async firmware load\n");
++ load_next_firmware_from_table(priv);
++ return 0;
++}
++EXPORT_SYMBOL_GPL(lbs_get_firmware_async);
++
+ /**
+ * lbs_get_firmware - Retrieves two-stage firmware
+ *
+@@ -18,6 +159,8 @@
+ * @helper: On success, the helper firmware; caller must free
+ * @mainfw: On success, the main firmware; caller must free
+ *
++ * Deprecated: use lbs_get_firmware_async() instead.
++ *
+ * returns: 0 on success, non-zero on failure
+ */
+ int lbs_get_firmware(struct device *dev, u32 card_model,
+diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
+index 7eaf992..e96ee0a 100644
+--- a/drivers/net/wireless/libertas/main.c
++++ b/drivers/net/wireless/libertas/main.c
+@@ -878,6 +878,7 @@ static int lbs_init_adapter(struct lbs_private *priv)
+ priv->is_host_sleep_configured = 0;
+ priv->is_host_sleep_activated = 0;
+ init_waitqueue_head(&priv->host_sleep_q);
++ init_waitqueue_head(&priv->fw_waitq);
+ mutex_init(&priv->lock);
+
+ setup_timer(&priv->command_timer, lbs_cmd_timeout_handler,
+@@ -1037,6 +1038,8 @@ void lbs_remove_card(struct lbs_private *priv)
+ if (priv->wiphy_registered)
+ lbs_scan_deinit(priv);
+
++ lbs_wait_for_firmware_load(priv);
++
+ /* worker thread destruction blocks on the in-flight command which
+ * should have been cleared already in lbs_stop_card().
+ */
+--
+1.7.4.4
+
diff --git a/recipes-kernel/linux/linux-mainline-3.2/libertas/0013-libertas-SDIO-convert-to-asynchronous-firmware-loadi.patch b/recipes-kernel/linux/linux-mainline-3.2/libertas/0013-libertas-SDIO-convert-to-asynchronous-firmware-loadi.patch
--- /dev/null
@@ -0,0 +1,320 @@
+From 66d647efe5e845c77f745478480c5e96218b7f3d Mon Sep 17 00:00:00 2001
+From: Daniel Drake <dsd@laptop.org>
+Date: Mon, 16 Apr 2012 23:53:43 +0100
+Subject: [PATCH 13/17] libertas SDIO: convert to asynchronous firmware
+ loading
+
+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/if_sdio.c | 206 ++++++++++++++++++-------------
+ 1 files changed, 121 insertions(+), 85 deletions(-)
+
+diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
+index 6590feb..76caeba 100644
+--- a/drivers/net/wireless/libertas/if_sdio.c
++++ b/drivers/net/wireless/libertas/if_sdio.c
+@@ -117,6 +117,8 @@ struct if_sdio_card {
+ int model;
+ unsigned long ioport;
+ unsigned int scratch_reg;
++ bool started;
++ wait_queue_head_t pwron_waitq;
+
+ u8 buffer[65536] __attribute__((aligned(4)));
+
+@@ -129,6 +131,9 @@ struct if_sdio_card {
+ u8 rx_unit;
+ };
+
++static void if_sdio_finish_power_on(struct if_sdio_card *card);
++static int if_sdio_power_off(struct if_sdio_card *card);
++
+ /********************************************************************/
+ /* I/O */
+ /********************************************************************/
+@@ -669,12 +674,39 @@ out:
+ return ret;
+ }
+
++static void if_sdio_do_prog_firmware(struct lbs_private *priv, int ret,
++ const struct firmware *helper,
++ const struct firmware *mainfw)
++{
++ struct if_sdio_card *card = priv->card;
++
++ if (ret) {
++ pr_err("failed to find firmware (%d)\n", ret);
++ return;
++ }
++
++ ret = if_sdio_prog_helper(card, helper);
++ if (ret)
++ goto out;
++
++ lbs_deb_sdio("Helper firmware loaded\n");
++
++ ret = if_sdio_prog_real(card, mainfw);
++ if (ret)
++ goto out;
++
++ lbs_deb_sdio("Firmware loaded\n");
++ if_sdio_finish_power_on(card);
++
++out:
++ release_firmware(helper);
++ release_firmware(mainfw);
++}
++
+ static int if_sdio_prog_firmware(struct if_sdio_card *card)
+ {
+ int ret;
+ u16 scratch;
+- const struct firmware *helper = NULL;
+- const struct firmware *mainfw = NULL;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+@@ -708,41 +740,18 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
+ */
+ if (scratch == IF_SDIO_FIRMWARE_OK) {
+ lbs_deb_sdio("firmware already loaded\n");
+- goto success;
++ if_sdio_finish_power_on(card);
++ return 0;
+ } else if ((card->model == MODEL_8686) && (scratch & 0x7fff)) {
+ lbs_deb_sdio("firmware may be running\n");
+- goto success;
+- }
+-
+- 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;
++ if_sdio_finish_power_on(card);
++ return 0;
+ }
+
+- ret = if_sdio_prog_helper(card, helper);
+- if (ret)
+- goto out;
+-
+- lbs_deb_sdio("Helper firmware loaded\n");
+-
+- ret = if_sdio_prog_real(card, mainfw);
+- if (ret)
+- goto out;
+-
+- lbs_deb_sdio("Firmware loaded\n");
+-
+-success:
+- sdio_claim_host(card->func);
+- sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
+- sdio_release_host(card->func);
+- ret = 0;
++ ret = lbs_get_firmware_async(card->priv, &card->func->dev, card->model,
++ fw_table, if_sdio_do_prog_firmware);
+
+ out:
+- release_firmware(helper);
+- release_firmware(mainfw);
+-
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+ return ret;
+ }
+@@ -751,55 +760,15 @@ out:
+ /* Power management */
+ /********************************************************************/
+
+-static int if_sdio_power_on(struct if_sdio_card *card)
++/* Finish power on sequence (after firmware is loaded) */
++static void if_sdio_finish_power_on(struct if_sdio_card *card)
+ {
+ struct sdio_func *func = card->func;
+ struct lbs_private *priv = card->priv;
+- struct mmc_host *host = func->card->host;
+ int ret;
+
+ sdio_claim_host(func);
+-
+- ret = sdio_enable_func(func);
+- if (ret)
+- goto release;
+-
+- /* For 1-bit transfers to the 8686 model, we need to enable the
+- * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
+- * bit to allow access to non-vendor registers. */
+- if ((card->model == MODEL_8686) &&
+- (host->caps & MMC_CAP_SDIO_IRQ) &&
+- (host->ios.bus_width == MMC_BUS_WIDTH_1)) {
+- u8 reg;
+-
+- func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
+- reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret);
+- if (ret)
+- goto disable;
+-
+- reg |= SDIO_BUS_ECSI;
+- sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret);
+- if (ret)
+- goto disable;
+- }
+-
+- card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
+- if (ret)
+- goto disable;
+-
+- card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;
+- if (ret)
+- goto disable;
+-
+- card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;
+- if (ret)
+- goto disable;
+-
+- sdio_release_host(func);
+- ret = if_sdio_prog_firmware(card);
+- sdio_claim_host(func);
+- if (ret)
+- goto disable;
++ sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
+
+ /*
+ * Get rx_unit if the chip is SD8688 or newer.
+@@ -824,7 +793,7 @@ static int if_sdio_power_on(struct if_sdio_card *card)
+ */
+ ret = sdio_claim_irq(func, if_sdio_interrupt);
+ if (ret)
+- goto disable;
++ goto release;
+
+ /*
+ * Enable interrupts now that everything is set up
+@@ -850,11 +819,79 @@ static int if_sdio_power_on(struct if_sdio_card *card)
+ }
+
+ priv->fw_ready = 1;
++ wake_up(&card->pwron_waitq);
+
+- return 0;
++ if (!card->started) {
++ ret = lbs_start_card(priv);
++ if_sdio_power_off(card);
++ if (ret == 0) {
++ card->started = true;
++ /* Tell PM core that we don't need the card to be
++ * powered now */
++ pm_runtime_put_noidle(&func->dev);
++ }
++ }
++
++ return;
+
+ release_irq:
+ sdio_release_irq(func);
++release:
++ sdio_release_host(func);
++}
++
++static int if_sdio_power_on(struct if_sdio_card *card)
++{
++ struct sdio_func *func = card->func;
++ struct mmc_host *host = func->card->host;
++ int ret;
++
++ sdio_claim_host(func);
++
++ ret = sdio_enable_func(func);
++ if (ret)
++ goto release;
++
++ /* For 1-bit transfers to the 8686 model, we need to enable the
++ * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
++ * bit to allow access to non-vendor registers. */
++ if ((card->model == MODEL_8686) &&
++ (host->caps & MMC_CAP_SDIO_IRQ) &&
++ (host->ios.bus_width == MMC_BUS_WIDTH_1)) {
++ u8 reg;
++
++ func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
++ reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret);
++ if (ret)
++ goto disable;
++
++ reg |= SDIO_BUS_ECSI;
++ sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret);
++ if (ret)
++ goto disable;
++ }
++
++ card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
++ if (ret)
++ goto disable;
++
++ card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;
++ if (ret)
++ goto disable;
++
++ card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;
++ if (ret)
++ goto disable;
++
++ sdio_release_host(func);
++ ret = if_sdio_prog_firmware(card);
++ if (ret) {
++ sdio_disable_func(func);
++ return ret;
++ }
++
++ return 0;
++
+ disable:
+ sdio_disable_func(func);
+ release:
+@@ -1061,11 +1098,17 @@ static int if_sdio_power_save(struct lbs_private *priv)
+ static int if_sdio_power_restore(struct lbs_private *priv)
+ {
+ struct if_sdio_card *card = priv->card;
++ int r;
+
+ /* Make sure the card will not be powered off by runtime PM */
+ pm_runtime_get_sync(&card->func->dev);
+
+- return if_sdio_power_on(card);
++ r = if_sdio_power_on(card);
++ if (r)
++ return r;
++
++ wait_event(card->pwron_waitq, priv->fw_ready);
++ return 0;
+ }
+
+
+@@ -1166,6 +1209,7 @@ static int if_sdio_probe(struct sdio_func *func,
+ spin_lock_init(&card->lock);
+ card->workqueue = create_workqueue("libertas_sdio");
+ INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
++ init_waitqueue_head(&card->pwron_waitq);
+
+ /* Check if we support this card */
+ for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
+@@ -1207,14 +1251,6 @@ static int if_sdio_probe(struct sdio_func *func,
+ if (ret)
+ goto err_activate_card;
+
+- ret = lbs_start_card(priv);
+- if_sdio_power_off(card);
+- if (ret)
+- goto err_activate_card;
+-
+- /* Tell PM core that we don't need the card to be powered now */
+- pm_runtime_put_noidle(&func->dev);
+-
+ out:
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+
+--
+1.7.4.4
+
diff --git a/recipes-kernel/linux/linux-mainline-3.2/libertas/0014-libertas-USB-convert-to-asynchronous-firmware-loadin.patch b/recipes-kernel/linux/linux-mainline-3.2/libertas/0014-libertas-USB-convert-to-asynchronous-firmware-loadin.patch
--- /dev/null
@@ -0,0 +1,201 @@
+From ce84bb69f50e6f6cfeabc9b965365290f4184417 Mon Sep 17 00:00:00 2001
+From: Daniel Drake <dsd@laptop.org>
+Date: Mon, 16 Apr 2012 23:53:55 +0100
+Subject: [PATCH 14/17] libertas USB: convert to asynchronous firmware loading
+
+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/if_usb.c | 102 +++++++++++++------------------
+ 1 files changed, 43 insertions(+), 59 deletions(-)
+
+diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
+index f29471b..75403e6 100644
+--- a/drivers/net/wireless/libertas/if_usb.c
++++ b/drivers/net/wireless/libertas/if_usb.c
+@@ -41,6 +41,16 @@ enum {
+ MODEL_8682 = 0x2
+ };
+
++/* table of firmware file names */
++static const struct lbs_fw_table fw_table[] = {
++ { MODEL_8388, "libertas/usb8388_olpc.bin", NULL },
++ { MODEL_8388, "libertas/usb8388_v9.bin", NULL },
++ { MODEL_8388, "libertas/usb8388_v5.bin", NULL },
++ { MODEL_8388, "libertas/usb8388.bin", NULL },
++ { MODEL_8388, "usb8388.bin", NULL },
++ { MODEL_8682, "libertas/usb8682.bin", NULL }
++};
++
+ static struct usb_device_id if_usb_table[] = {
+ /* Enter the device signature inside */
+ { USB_DEVICE(0x1286, 0x2001), .driver_info = MODEL_8388 },
+@@ -52,7 +62,9 @@ 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);
++static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
++ const struct firmware *fw,
++ const struct firmware *unused);
+ 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,
+@@ -187,6 +199,7 @@ static int if_usb_probe(struct usb_interface *intf,
+ struct usb_endpoint_descriptor *endpoint;
+ struct lbs_private *priv;
+ struct if_usb_card *cardp;
++ int r = -ENOMEM;
+ int i;
+
+ udev = interface_to_usbdev(intf);
+@@ -244,17 +257,10 @@ static int if_usb_probe(struct usb_interface *intf,
+ goto dealloc;
+ }
+
+- /* Upload firmware */
+- if (if_usb_prog_firmware(cardp)) {
+- lbs_deb_usbd(&udev->dev, "FW upload failed\n");
+- goto err_prog_firmware;
+- }
+-
+ if (!(priv = lbs_add_card(cardp, &intf->dev)))
+- goto err_prog_firmware;
++ goto err_add_card;
+
+ cardp->priv = priv;
+- cardp->priv->fw_ready = 1;
+
+ priv->hw_host_to_card = if_usb_host_to_card;
+ priv->enter_deep_sleep = NULL;
+@@ -267,34 +273,25 @@ static int if_usb_probe(struct usb_interface *intf,
+
+ cardp->boot2_version = udev->descriptor.bcdDevice;
+
+- if_usb_submit_rx_urb(cardp);
+-
+- if (lbs_start_card(priv))
+- goto err_start_card;
+-
+- if_usb_setup_firmware(priv);
+-
+ usb_get_dev(udev);
+ usb_set_intfdata(intf, cardp);
+
+- /*
+- * EHS_REMOVE_WAKEUP is not supported on all versions of the firmware.
+- */
+- priv->wol_criteria = EHS_REMOVE_WAKEUP;
+- if (lbs_host_sleep_cfg(priv, priv->wol_criteria, NULL))
+- priv->ehs_remove_supported = false;
++ r = lbs_get_firmware_async(priv, &udev->dev, cardp->model,
++ fw_table, if_usb_prog_firmware);
++ if (r)
++ goto err_get_fw;
+
+ return 0;
+
+-err_start_card:
++err_get_fw:
+ lbs_remove_card(priv);
+-err_prog_firmware:
++err_add_card:
+ if_usb_reset_device(cardp);
+ dealloc:
+ if_usb_free(cardp);
+
+ error:
+- return -ENOMEM;
++ return r;
+ }
+
+ /**
+@@ -829,49 +826,22 @@ static int check_fwfile_format(const uint8_t *data, uint32_t totlen)
+ 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" },
+- { MODEL_8388, "usb8388.bin" },
+- { MODEL_8682, "libertas/usb8682.bin" }
+-};
+-
+-static int get_fw(struct if_usb_card *cardp)
+-{
+- int i;
+-
+- /* Otherwise search for firmware to use */
+- for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
+- if (fw_table[i].model != cardp->model)
+- continue;
+- if (request_firmware(&cardp->fw, fw_table[i].fwname,
+- &cardp->udev->dev) == 0)
+- return 0;
+- }
+-
+- return -ENOENT;
+-}
+-
+-static int if_usb_prog_firmware(struct if_usb_card *cardp)
++static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
++ const struct firmware *fw,
++ const struct firmware *unused)
+ {
++ struct if_usb_card *cardp = priv->card;
+ int i = 0;
+ static int reset_count = 10;
+- int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_USB);
+
+- ret = get_fw(cardp);
+ if (ret) {
+ pr_err("failed to find firmware (%d)\n", ret);
+ goto done;
+ }
+
++ cardp->fw = fw;
+ if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) {
+ ret = -EINVAL;
+ goto release_fw;
+@@ -954,13 +924,27 @@ restart:
+ goto release_fw;
+ }
+
++ cardp->priv->fw_ready = 1;
++ if_usb_submit_rx_urb(cardp);
++
++ if (lbs_start_card(priv))
++ goto release_fw;
++
++ if_usb_setup_firmware(priv);
++
++ /*
++ * EHS_REMOVE_WAKEUP is not supported on all versions of the firmware.
++ */
++ priv->wol_criteria = EHS_REMOVE_WAKEUP;
++ if (lbs_host_sleep_cfg(priv, priv->wol_criteria, NULL))
++ priv->ehs_remove_supported = false;
++
+ release_fw:
+ release_firmware(cardp->fw);
+ cardp->fw = NULL;
+
+ done:
+- lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
+- return ret;
++ lbs_deb_leave(LBS_DEB_USB);
+ }
+
+
+--
+1.7.4.4
+
diff --git a/recipes-kernel/linux/linux-mainline-3.2/libertas/0015-libertas-CS-convert-to-asynchronous-firmware-loading.patch b/recipes-kernel/linux/linux-mainline-3.2/libertas/0015-libertas-CS-convert-to-asynchronous-firmware-loading.patch
--- /dev/null
@@ -0,0 +1,154 @@
+From 488c3ee77ea0e63c9ae4736b1610aaf39c6527ee Mon Sep 17 00:00:00 2001
+From: Daniel Drake <dsd@laptop.org>
+Date: Wed, 18 Apr 2012 20:09:44 +0100
+Subject: [PATCH 15/17] libertas CS: convert to asynchronous firmware loading
+
+Signed-off-by: Daniel Drake <dsd@laptop.org>
+Tested-by: Dan Williams <dcbw@redhat.com>
+Acked-by: Dan Williams <dcbw@redhat.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+---
+ drivers/net/wireless/libertas/if_cs.c | 88 ++++++++++++++++++--------------
+ 1 files changed, 49 insertions(+), 39 deletions(-)
+
+diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
+index cee5052..16beaf3 100644
+--- a/drivers/net/wireless/libertas/if_cs.c
++++ b/drivers/net/wireless/libertas/if_cs.c
+@@ -738,6 +738,50 @@ done:
+ return ret;
+ }
+
++static void if_cs_prog_firmware(struct lbs_private *priv, int ret,
++ const struct firmware *helper,
++ const struct firmware *mainfw)
++{
++ struct if_cs_card *card = priv->card;
++
++ if (ret) {
++ pr_err("failed to find firmware (%d)\n", ret);
++ return;
++ }
++
++ /* Load the firmware */
++ ret = if_cs_prog_helper(card, helper);
++ if (ret == 0 && (card->model != MODEL_8305))
++ ret = if_cs_prog_real(card, mainfw);
++ if (ret)
++ goto out;
++
++ /* Now actually get the IRQ */
++ ret = request_irq(card->p_dev->irq, if_cs_interrupt,
++ IRQF_SHARED, DRV_NAME, card);
++ if (ret) {
++ pr_err("error in request_irq\n");
++ goto out;
++ }
++
++ /*
++ * Clear any interrupt cause that happened while sending
++ * firmware/initializing card
++ */
++ if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK);
++ if_cs_enable_ints(card);
++
++ /* And finally bring the card up */
++ priv->fw_ready = 1;
++ if (lbs_start_card(priv) != 0) {
++ pr_err("could not activate card\n");
++ free_irq(card->p_dev->irq, card);
++ }
++
++out:
++ release_firmware(helper);
++ release_firmware(mainfw);
++}
+
+
+ /********************************************************************/
+@@ -809,8 +853,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
+ unsigned int prod_id;
+ struct lbs_private *priv;
+ struct if_cs_card *card;
+- const struct firmware *helper = NULL;
+- const struct firmware *mainfw = NULL;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+@@ -890,20 +932,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
+ goto out2;
+ }
+
+- 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;
+- }
+-
+- /* Load the firmware early, before calling into libertas.ko */
+- ret = if_cs_prog_helper(card, helper);
+- if (ret == 0 && (card->model != MODEL_8305))
+- ret = if_cs_prog_real(card, mainfw);
+- if (ret)
+- goto out2;
+-
+ /* Make this card known to the libertas driver */
+ priv = lbs_add_card(card, &p_dev->dev);
+ if (!priv) {
+@@ -911,37 +939,22 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
+ goto out2;
+ }
+
+- /* Finish setting up fields in lbs_private */
++ /* Set up fields in lbs_private */
+ card->priv = priv;
+ priv->card = card;
+ priv->hw_host_to_card = if_cs_host_to_card;
+ priv->enter_deep_sleep = NULL;
+ priv->exit_deep_sleep = NULL;
+ priv->reset_deep_sleep_wakeup = NULL;
+- priv->fw_ready = 1;
+
+- /* Now actually get the IRQ */
+- ret = request_irq(p_dev->irq, if_cs_interrupt,
+- IRQF_SHARED, DRV_NAME, card);
++ /* Get firmware */
++ ret = lbs_get_firmware_async(priv, &p_dev->dev, card->model, fw_table,
++ if_cs_prog_firmware);
+ if (ret) {
+- pr_err("error in request_irq\n");
+- goto out3;
+- }
+-
+- /*
+- * Clear any interrupt cause that happened while sending
+- * firmware/initializing card
+- */
+- if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK);
+- if_cs_enable_ints(card);
+-
+- /* And finally bring the card up */
+- if (lbs_start_card(priv) != 0) {
+- pr_err("could not activate card\n");
++ pr_err("failed to find firmware (%d)\n", ret);
+ goto out3;
+ }
+
+- ret = 0;
+ goto out;
+
+ out3:
+@@ -951,9 +964,6 @@ out2:
+ out1:
+ pcmcia_disable_device(p_dev);
+ out:
+- release_firmware(helper);
+- release_firmware(mainfw);
+-
+ lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+ return ret;
+ }
+--
+1.7.4.4
+
diff --git a/recipes-kernel/linux/linux-mainline-3.2/libertas/0016-libertas-add-missing-include.patch b/recipes-kernel/linux/linux-mainline-3.2/libertas/0016-libertas-add-missing-include.patch
--- /dev/null
@@ -0,0 +1,30 @@
+From 7608f165734eaeb530ba2442c0413e6e9630ad83 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Thu, 19 Apr 2012 13:54:12 +0200
+Subject: [PATCH 16/17] libertas: add missing include
+
+Without it, I get compile errors due to missing TASK_NORMAL,
+TASK_UNINTERRUPTIBLE and schedule.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+Acked-by: Dan Williams <dcbw@redhat.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+---
+ drivers/net/wireless/libertas/firmware.c | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/net/wireless/libertas/firmware.c b/drivers/net/wireless/libertas/firmware.c
+index cd23f1a..77f6504 100644
+--- a/drivers/net/wireless/libertas/firmware.c
++++ b/drivers/net/wireless/libertas/firmware.c
+@@ -5,6 +5,7 @@
+ #include <linux/firmware.h>
+ #include <linux/firmware.h>
+ #include <linux/module.h>
++#include <linux/sched.h>
+
+ #include "dev.h"
+ #include "decl.h"
+--
+1.7.4.4
+
diff --git a/recipes-kernel/linux/linux-mainline-3.2/libertas/0017-remove-debug-msgs-due-to-missing-in_interrupt.patch b/recipes-kernel/linux/linux-mainline-3.2/libertas/0017-remove-debug-msgs-due-to-missing-in_interrupt.patch
--- /dev/null
@@ -0,0 +1,36 @@
+From 94938a2b8b1db241843abfe98168b81bf9273165 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Andreas=20M=C3=BCller?= <schnitzeltony@googlemail.com>
+Date: Mon, 21 May 2012 17:01:23 +0200
+Subject: [PATCH] remove debug msgs due to missing in_interrupt
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+
+Signed-off-by: Andreas M??ller <schnitzeltony@googlemail.com>
+---
+ drivers/net/wireless/libertas/defs.h | 7 -------
+ 1 files changed, 0 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
+index ab966f0..a80b40e 100644
+--- a/drivers/net/wireless/libertas/defs.h
++++ b/drivers/net/wireless/libertas/defs.h
+@@ -46,14 +46,7 @@
+
+ extern unsigned int lbs_debug;
+
+-#ifdef DEBUG
+-#define LBS_DEB_LL(grp, grpnam, fmt, args...) \
+-do { if ((lbs_debug & (grp)) == (grp)) \
+- printk(KERN_DEBUG DRV_NAME grpnam "%s: " fmt, \
+- in_interrupt() ? " (INT)" : "", ## args); } while (0)
+-#else
+ #define LBS_DEB_LL(grp, grpnam, fmt, args...) do {} while (0)
+-#endif
+
+ #define lbs_deb_enter(grp) \
+ LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s()\n", __func__);
+--
+1.7.4.4
+
diff --git a/recipes-kernel/linux/linux-mainline_3.2.bb b/recipes-kernel/linux/linux-mainline_3.2.bb
index 69eb7e5f5c6e3ec7829977132c4eac7b258a277a..69344ff83f7012bf06d3458c191fe611a3b376c3 100644 (file)
SRCREV_pn-${PN} = "52c6b95f8a2edaff98b779f15b2f4d69b61b18b9"
# The main PR is now using MACHINE_KERNEL_PR, for omap3 see conf/machine/include/omap3.inc
-MACHINE_KERNEL_PR_append = "a"
+MACHINE_KERNEL_PR_append = "b"
FILESPATH =. "${FILE_DIRNAME}/linux-mainline-3.2:${FILE_DIRNAME}/linux-mainline-3.2/${MACHINE}:"
file://omap_fixes/0006-OMAP-HWMOD-add-es3plus-to-am36xx-am35xx.patch \
file://sgx/0001-Revert-OMAP-DSS2-remove-update_mode-from-omapdss-v3.2.patch \
file://led/0001-leds-heartbeat-stop-on-shutdown-reboot-or-panic.patch \
- \
+ file://libertas/0001-USB-convert-drivers-net-to-use-module_usb_driver.patch \
+ file://libertas/0002-net-fix-assignment-of-0-1-to-bool-variables.patch \
+ file://libertas/0003-switch-debugfs-to-umode_t.patch \
+ file://libertas/0004-drivers-net-Remove-unnecessary-k.alloc-v.alloc-OOM-m.patch \
+ file://libertas/0005-libertas-remove-dump_survey-implementation.patch \
+ file://libertas/0007-wireless-libertas-remove-redundant-NULL-tests-before.patch \
+ file://libertas/0008-libertas-fix-signedness-bug-in-lbs_auth_to_authtype.patch \
+ file://libertas/0009-drivers-net-wireless-libertas-if_usb.c-add-missing-d.patch \
+ file://libertas/0010-libertas-Firmware-loading-simplifications.patch \
+ file://libertas/0011-libertas-harden-up-exit-paths.patch \
+ file://libertas/0012-libertas-add-asynchronous-firmware-loading-capabilit.patch \
+ file://libertas/0013-libertas-SDIO-convert-to-asynchronous-firmware-loadi.patch \
+ file://libertas/0014-libertas-USB-convert-to-asynchronous-firmware-loadin.patch \
+ file://libertas/0015-libertas-CS-convert-to-asynchronous-firmware-loading.patch \
+ file://libertas/0016-libertas-add-missing-include.patch \
+ file://libertas/0017-remove-debug-msgs-due-to-missing-in_interrupt.patch \
+ \
file://defconfig"
SRC_URI_append_beagleboard = " file://logo_linux_clut224.ppm \