[2/3] libertas_tf: don't defer firmware loading until start()
diff mbox series

Message ID 20190210195217.18817-3-lkundrak@v3.sk
State Changes Requested
Delegated to: Kalle Valo
Headers show
Series
  • libertas_tf: fix setting the hardware address
Related show

Commit Message

Lubomir Rintel Feb. 10, 2019, 7:52 p.m. UTC
In order to be able to get a MAC address before we register the device
with ieee80211 we'll need to load the firmware way earlier.

There seems to be one problem with this: the device seems to start
with radio enabled and starts sending in frames right after the firmware
load finishes. This might be a firmware bug. Disable the radio as soon
as possible.

Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
 .../net/wireless/marvell/libertas_tf/if_usb.c | 24 +++++------
 .../marvell/libertas_tf/libertas_tf.h         |  5 +--
 .../net/wireless/marvell/libertas_tf/main.c   | 41 +++++++++++--------
 3 files changed, 38 insertions(+), 32 deletions(-)

Comments

Steve deRosier Feb. 11, 2019, 2:10 p.m. UTC | #1
On Sun, Feb 10, 2019 at 11:52 AM Lubomir Rintel <lkundrak@v3.sk> wrote:
>
> In order to be able to get a MAC address before we register the device
> with ieee80211 we'll need to load the firmware way earlier.
>
> There seems to be one problem with this: the device seems to start
> with radio enabled and starts sending in frames right after the firmware
> load finishes. This might be a firmware bug. Disable the radio as soon
> as possible.
>

I've got a quibble with calling the behavior a bug. As far as I
remember, it's behaving as designed/specified and was quite
appropriate back when this driver originally went upstream. This is a
10 year old fw and driver and needs have changed - which doesn't mean
it was wrong to do originally.

Now, I'm not saying there's no bugs in the fw. Nor that it wouldn't be
nice to change the behavior to accommodate this change. If I still had
access to the firmware source I even might do so.

...
> @@ -648,6 +642,19 @@ struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev,
>
>         INIT_WORK(&priv->cmd_work, lbtf_cmd_work);
>         INIT_WORK(&priv->tx_work, lbtf_tx_work);
> +
> +       if (priv->ops->hw_prog_firmware(priv)) {
> +               lbtf_deb_usbd(&udev->dev, "Error programming the firmware\n");
> +               priv->ops->hw_reset_device(priv);
> +               goto err_init_adapter;
> +       }
> +
> +       /* The firmware seems to start with the radio enabled. Turn it
> +        * off before an actual mac80211 start callback is invoked.
> +        */
> +       priv->radioon = RADIO_OFF;

Maybe move this up a few lines to before you program the fw? Seems
appropriate to initialize it first. While I expect there's no chance
of a race as the
mac80211 start callback hasn't been invoked yet, superficially it
looks like there could be.


> +       lbtf_set_radio_control(priv);
> +
>         if (ieee80211_register_hw(hw))
>                 goto err_init_adapter;
>
> --
> 2.20.1
>

Reviewed-by: Steve deRosier <derosier@cal-sierra.com>

Patch
diff mbox series

diff --git a/drivers/net/wireless/marvell/libertas_tf/if_usb.c b/drivers/net/wireless/marvell/libertas_tf/if_usb.c
index 7a5a1a85dcf7..a4b9ede70705 100644
--- a/drivers/net/wireless/marvell/libertas_tf/if_usb.c
+++ b/drivers/net/wireless/marvell/libertas_tf/if_usb.c
@@ -42,14 +42,14 @@  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 int if_usb_prog_firmware(struct lbtf_private *priv);
 static int if_usb_host_to_card(struct lbtf_private *priv, uint8_t type,
 			       uint8_t *payload, uint16_t nb);
 static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
 			uint16_t nb, u8 data);
 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);
+static int if_usb_reset_device(struct lbtf_private *priv);
 
 /**
  *  if_usb_wrike_bulk_callback -  call back to handle URB status
@@ -222,13 +222,11 @@  static int if_usb_probe(struct usb_interface *intf,
 		goto dealloc;
 	}
 
+	cardp->boot2_version = udev->descriptor.bcdDevice;
 	priv = lbtf_add_card(cardp, &udev->dev, &if_usb_ops);
 	if (!priv)
 		goto dealloc;
 
-	cardp->priv = priv;
-	cardp->boot2_version = udev->descriptor.bcdDevice;
-
 	usb_get_dev(udev);
 	usb_set_intfdata(intf, cardp);
 
@@ -253,7 +251,7 @@  static void if_usb_disconnect(struct usb_interface *intf)
 
 	lbtf_deb_enter(LBTF_DEB_MAIN);
 
-	if_usb_reset_device(cardp);
+	if_usb_reset_device(priv);
 
 	if (priv)
 		lbtf_remove_card(priv);
@@ -336,8 +334,9 @@  static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
 	return 0;
 }
 
-static int if_usb_reset_device(struct if_usb_card *cardp)
+static int if_usb_reset_device(struct lbtf_private *priv)
 {
+	struct if_usb_card *cardp = priv->card;
 	struct cmd_ds_802_11_reset *cmd = cardp->ep_out_buf + 4;
 	int ret;
 
@@ -808,14 +807,17 @@  static int check_fwfile_format(const u8 *data, u32 totlen)
 }
 
 
-static int if_usb_prog_firmware(struct if_usb_card *cardp)
+static int if_usb_prog_firmware(struct lbtf_private *priv)
 {
+	struct if_usb_card *cardp = priv->card;
 	int i = 0;
 	static int reset_count = 10;
 	int ret = 0;
 
 	lbtf_deb_enter(LBTF_DEB_USB);
 
+	cardp->priv = priv;
+
 	kernel_param_lock(THIS_MODULE);
 	ret = request_firmware(&cardp->fw, lbtf_fw_name, &cardp->udev->dev);
 	if (ret < 0) {
@@ -851,7 +853,7 @@  static int if_usb_prog_firmware(struct if_usb_card *cardp)
 
 	if (cardp->bootcmdresp <= 0) {
 		if (--reset_count >= 0) {
-			if_usb_reset_device(cardp);
+			if_usb_reset_device(priv);
 			goto restart;
 		}
 		return -1;
@@ -880,7 +882,7 @@  static int if_usb_prog_firmware(struct if_usb_card *cardp)
 	if (!cardp->fwdnldover) {
 		pr_info("failed to load fw, resetting device!\n");
 		if (--reset_count >= 0) {
-			if_usb_reset_device(cardp);
+			if_usb_reset_device(priv);
 			goto restart;
 		}
 
@@ -889,8 +891,6 @@  static int if_usb_prog_firmware(struct if_usb_card *cardp)
 		goto release_fw;
 	}
 
-	cardp->priv->fw_ready = 1;
-
  release_fw:
 	release_firmware(cardp->fw);
 	cardp->fw = NULL;
diff --git a/drivers/net/wireless/marvell/libertas_tf/libertas_tf.h b/drivers/net/wireless/marvell/libertas_tf/libertas_tf.h
index 11d5ff68bc5e..3ed1fbe28798 100644
--- a/drivers/net/wireless/marvell/libertas_tf/libertas_tf.h
+++ b/drivers/net/wireless/marvell/libertas_tf/libertas_tf.h
@@ -177,8 +177,8 @@  struct lbtf_ops {
 	/** Hardware access */
 	int (*hw_host_to_card)(struct lbtf_private *priv, u8 type,
 			       u8 *payload, u16 nb);
-	int (*hw_prog_firmware)(struct if_usb_card *cardp);
-	int (*hw_reset_device)(struct if_usb_card *cardp);
+	int (*hw_prog_firmware)(struct lbtf_private *priv);
+	int (*hw_reset_device)(struct lbtf_private *priv);
 };
 
 /** Private structure for the MV device */
@@ -254,7 +254,6 @@  struct lbtf_private {
 	struct ieee80211_supported_band band;
 	struct lbtf_offset_value offsetvalue;
 
-	u8 fw_ready;
 	u8 surpriseremoved;
 	struct sk_buff_head bc_ps_buf;
 
diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c
index 8ed3cd158cf5..b4bd3047eb4e 100644
--- a/drivers/net/wireless/marvell/libertas_tf/main.c
+++ b/drivers/net/wireless/marvell/libertas_tf/main.c
@@ -118,11 +118,6 @@  static void lbtf_cmd_work(struct work_struct *work)
 	priv->cmd_timed_out = 0;
 	spin_unlock_irq(&priv->driver_lock);
 
-	if (!priv->fw_ready) {
-		lbtf_deb_leave_args(LBTF_DEB_CMD, "fw not ready");
-		return;
-	}
-
 	/* Execute the next command */
 	if (!priv->cur_cmd)
 		lbtf_execute_next_command(priv);
@@ -294,36 +289,29 @@  static void lbtf_tx_work(struct work_struct *work)
 static int lbtf_op_start(struct ieee80211_hw *hw)
 {
 	struct lbtf_private *priv = hw->priv;
-	void *card = priv->card;
 	int ret = -1;
 
 	lbtf_deb_enter(LBTF_DEB_MACOPS);
 
-	if (!priv->fw_ready)
-		/* Upload firmware */
-		if (priv->ops->hw_prog_firmware(card))
-			goto err_prog_firmware;
-
 	/* poke the firmware */
 	priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
 	priv->radioon = RADIO_ON;
 	priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
 	ret = lbtf_setup_firmware(priv);
 	if (ret)
-		goto err_prog_firmware;
+		goto err_setup_firmware;
 
 	if ((priv->fwrelease < LBTF_FW_VER_MIN) ||
 	    (priv->fwrelease > LBTF_FW_VER_MAX)) {
 		ret = -1;
-		goto err_prog_firmware;
+		goto err_setup_firmware;
 	}
 
 	lbtf_deb_leave(LBTF_DEB_MACOPS);
 	return 0;
 
-err_prog_firmware:
-	priv->ops->hw_reset_device(card);
-	lbtf_deb_leave_args(LBTF_DEB_MACOPS, "error programming fw; ret=%d", ret);
+err_setup_firmware:
+	lbtf_deb_leave_args(LBTF_DEB_MACOPS, "fw setup error; ret=%d", ret);
 	return ret;
 }
 
@@ -555,6 +543,11 @@  int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
 
 	lbtf_deb_enter(LBTF_DEB_RX);
 
+	if (priv->radioon != RADIO_ON) {
+		lbtf_deb_rx("rx before we turned on the radio");
+		goto done;
+	}
+
 	prxpd = (struct rxpd *) skb->data;
 
 	memset(&stats, 0, sizeof(stats));
@@ -593,13 +586,14 @@  int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
 
 	ieee80211_rx_irqsafe(priv->hw, skb);
 
+done:
 	lbtf_deb_leave(LBTF_DEB_RX);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(lbtf_rx);
 
 /**
- * lbtf_add_card: Add and initialize the card, no fw upload yet.
+ * lbtf_add_card: Add and initialize the card.
  *
  *  @card    A pointer to card
  *
@@ -648,6 +642,19 @@  struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev,
 
 	INIT_WORK(&priv->cmd_work, lbtf_cmd_work);
 	INIT_WORK(&priv->tx_work, lbtf_tx_work);
+
+	if (priv->ops->hw_prog_firmware(priv)) {
+		lbtf_deb_usbd(&udev->dev, "Error programming the firmware\n");
+		priv->ops->hw_reset_device(priv);
+		goto err_init_adapter;
+	}
+
+	/* The firmware seems to start with the radio enabled. Turn it
+	 * off before an actual mac80211 start callback is invoked.
+	 */
+	priv->radioon = RADIO_OFF;
+	lbtf_set_radio_control(priv);
+
 	if (ieee80211_register_hw(hw))
 		goto err_init_adapter;