+/*
+ * Firmware access.
+ *
+ * We have the following requirements for issuing firmware commands:
+ * - Some commands require that the packet transmit path is idle when
+ * the command is issued. (For simplicity, we'll just quiesce the
+ * transmit path for every command.)
+ * - There are certain sequences of commands that need to be issued to
+ * the hardware sequentially, with no other intervening commands.
+ *
+ * This leads to an implementation of a "firmware lock" as a mutex that
+ * can be taken recursively, and which is taken by both the low-level
+ * command submission function (mwl8k_post_cmd) as well as any users of
+ * that function that require issuing of an atomic sequence of commands,
+ * and quiesces the transmit path whenever it's taken.
+ */
+static int mwl8k_fw_lock(struct ieee80211_hw *hw)
+{
+ struct mwl8k_priv *priv = hw->priv;
+
+ if (priv->fw_mutex_owner != current) {
+ int rc;
+
+ mutex_lock(&priv->fw_mutex);
+ ieee80211_stop_queues(hw);
+
+ rc = mwl8k_tx_wait_empty(hw);
+ if (rc) {
+ ieee80211_wake_queues(hw);
+ mutex_unlock(&priv->fw_mutex);
+
+ return rc;
+ }
+
+ priv->fw_mutex_owner = current;
+ }
+
+ priv->fw_mutex_depth++;
+
+ return 0;
+}
+
+static void mwl8k_fw_unlock(struct ieee80211_hw *hw)
+{
+ struct mwl8k_priv *priv = hw->priv;
+
+ if (!--priv->fw_mutex_depth) {
+ ieee80211_wake_queues(hw);
+ priv->fw_mutex_owner = NULL;
+ mutex_unlock(&priv->fw_mutex);
+ }
+}
+
+