mwl8k: don't forget to call pci_disable_device()
[deliverable/linux.git] / drivers / net / wireless / mwl8k.c
index c1cb20fceaff3552674b0a9a230e65a0e2d16398..76a6071aac8a9abe98867417b7b3afb4c73cded0 100644 (file)
@@ -571,7 +571,7 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw)
                               "helper image\n", pci_name(priv->pdev));
                        return rc;
                }
-               msleep(1);
+               msleep(5);
 
                rc = mwl8k_feed_fw_image(priv, fw->data, fw->size);
        } else {
@@ -588,9 +588,8 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw)
                iowrite32(MWL8K_MODE_AP, priv->regs + MWL8K_HIU_GEN_PTR);
        else
                iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR);
-       msleep(1);
 
-       loops = 200000;
+       loops = 500000;
        do {
                u32 ready_code;
 
@@ -782,6 +781,10 @@ struct mwl8k_rxd_8366 {
        __u8 rx_ctrl;
 } __attribute__((packed));
 
+#define MWL8K_8366_RATE_INFO_MCS_FORMAT                0x80
+#define MWL8K_8366_RATE_INFO_40MHZ             0x40
+#define MWL8K_8366_RATE_INFO_RATEID(x)         ((x) & 0x3f)
+
 #define MWL8K_8366_RX_CTRL_OWNED_BY_HOST       0x80
 
 static void mwl8k_rxd_8366_init(void *_rxd, dma_addr_t next_dma_addr)
@@ -817,9 +820,11 @@ mwl8k_rxd_8366_process(void *_rxd, struct ieee80211_rx_status *status,
        status->signal = -rxd->rssi;
        status->noise = -rxd->noise_floor;
 
-       if (rxd->rate & 0x80) {
+       if (rxd->rate & MWL8K_8366_RATE_INFO_MCS_FORMAT) {
                status->flag |= RX_FLAG_HT;
-               status->rate_idx = rxd->rate & 0x7f;
+               if (rxd->rate & MWL8K_8366_RATE_INFO_40MHZ)
+                       status->flag |= RX_FLAG_40MHZ;
+               status->rate_idx = MWL8K_8366_RATE_INFO_RATEID(rxd->rate);
        } else {
                int i;
 
@@ -1231,99 +1236,106 @@ static inline void mwl8k_tx_start(struct mwl8k_priv *priv)
        ioread32(priv->regs + MWL8K_HIU_INT_CODE);
 }
 
-struct mwl8k_txq_info {
-       u32 fw_owned;
-       u32 drv_owned;
-       u32 unused;
-       u32 len;
-       u32 head;
-       u32 tail;
-};
-
-static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv,
-                               struct mwl8k_txq_info *txinfo)
+static void mwl8k_dump_tx_rings(struct ieee80211_hw *hw)
 {
-       int count, desc, status;
-       struct mwl8k_tx_queue *txq;
-       struct mwl8k_tx_desc *tx_desc;
-       int ndescs = 0;
+       struct mwl8k_priv *priv = hw->priv;
+       int i;
 
-       memset(txinfo, 0, MWL8K_TX_QUEUES * sizeof(struct mwl8k_txq_info));
+       for (i = 0; i < MWL8K_TX_QUEUES; i++) {
+               struct mwl8k_tx_queue *txq = priv->txq + i;
+               int fw_owned = 0;
+               int drv_owned = 0;
+               int unused = 0;
+               int desc;
 
-       for (count = 0; count < MWL8K_TX_QUEUES; count++) {
-               txq = priv->txq + count;
-               txinfo[count].len = txq->stats.len;
-               txinfo[count].head = txq->head;
-               txinfo[count].tail = txq->tail;
                for (desc = 0; desc < MWL8K_TX_DESCS; desc++) {
-                       tx_desc = txq->txd + desc;
-                       status = le32_to_cpu(tx_desc->status);
+                       struct mwl8k_tx_desc *tx_desc = txq->txd + desc;
+                       u32 status;
 
+                       status = le32_to_cpu(tx_desc->status);
                        if (status & MWL8K_TXD_STATUS_FW_OWNED)
-                               txinfo[count].fw_owned++;
+                               fw_owned++;
                        else
-                               txinfo[count].drv_owned++;
+                               drv_owned++;
 
                        if (tx_desc->pkt_len == 0)
-                               txinfo[count].unused++;
+                               unused++;
                }
-       }
 
-       return ndescs;
+               printk(KERN_ERR "%s: txq[%d] len=%d head=%d tail=%d "
+                      "fw_owned=%d drv_owned=%d unused=%d\n",
+                      wiphy_name(hw->wiphy), i,
+                      txq->stats.len, txq->head, txq->tail,
+                      fw_owned, drv_owned, unused);
+       }
 }
 
 /*
  * Must be called with priv->fw_mutex held and tx queues stopped.
  */
+#define MWL8K_TX_WAIT_TIMEOUT_MS       1000
+
 static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
 {
        struct mwl8k_priv *priv = hw->priv;
        DECLARE_COMPLETION_ONSTACK(tx_wait);
-       u32 count;
-       unsigned long timeout;
+       int retry;
+       int rc;
 
        might_sleep();
 
+       /*
+        * The TX queues are stopped at this point, so this test
+        * doesn't need to take ->tx_lock.
+        */
+       if (!priv->pending_tx_pkts)
+               return 0;
+
+       retry = 0;
+       rc = 0;
+
        spin_lock_bh(&priv->tx_lock);
-       count = priv->pending_tx_pkts;
-       if (count)
-               priv->tx_wait = &tx_wait;
-       spin_unlock_bh(&priv->tx_lock);
+       priv->tx_wait = &tx_wait;
+       while (!rc) {
+               int oldcount;
+               unsigned long timeout;
 
-       if (count) {
-               struct mwl8k_txq_info txinfo[MWL8K_TX_QUEUES];
-               int index;
-               int newcount;
+               oldcount = priv->pending_tx_pkts;
 
+               spin_unlock_bh(&priv->tx_lock);
                timeout = wait_for_completion_timeout(&tx_wait,
-                                       msecs_to_jiffies(5000));
-               if (timeout)
-                       return 0;
-
+                           msecs_to_jiffies(MWL8K_TX_WAIT_TIMEOUT_MS));
                spin_lock_bh(&priv->tx_lock);
-               priv->tx_wait = NULL;
-               newcount = priv->pending_tx_pkts;
-               mwl8k_scan_tx_ring(priv, txinfo);
-               spin_unlock_bh(&priv->tx_lock);
 
-               printk(KERN_ERR "%s(%u) TIMEDOUT:5000ms Pend:%u-->%u\n",
-                      __func__, __LINE__, count, newcount);
+               if (timeout) {
+                       WARN_ON(priv->pending_tx_pkts);
+                       if (retry) {
+                               printk(KERN_NOTICE "%s: tx rings drained\n",
+                                      wiphy_name(hw->wiphy));
+                       }
+                       break;
+               }
+
+               if (priv->pending_tx_pkts < oldcount) {
+                       printk(KERN_NOTICE "%s: timeout waiting for tx "
+                              "rings to drain (%d -> %d pkts), retrying\n",
+                              wiphy_name(hw->wiphy), oldcount,
+                              priv->pending_tx_pkts);
+                       retry = 1;
+                       continue;
+               }
+
+               priv->tx_wait = NULL;
 
-               for (index = 0; index < MWL8K_TX_QUEUES; index++)
-                       printk(KERN_ERR "TXQ:%u L:%u H:%u T:%u FW:%u "
-                              "DRV:%u U:%u\n",
-                                       index,
-                                       txinfo[index].len,
-                                       txinfo[index].head,
-                                       txinfo[index].tail,
-                                       txinfo[index].fw_owned,
-                                       txinfo[index].drv_owned,
-                                       txinfo[index].unused);
+               printk(KERN_ERR "%s: tx rings stuck for %d ms\n",
+                      wiphy_name(hw->wiphy), MWL8K_TX_WAIT_TIMEOUT_MS);
+               mwl8k_dump_tx_rings(hw);
 
-               return -ETIMEDOUT;
+               rc = -ETIMEDOUT;
        }
+       spin_unlock_bh(&priv->tx_lock);
 
-       return 0;
+       return rc;
 }
 
 #define MWL8K_TXD_SUCCESS(status)                              \
@@ -1573,8 +1585,8 @@ static void mwl8k_fw_unlock(struct ieee80211_hw *hw)
  * Command processing.
  */
 
-/* Timeout firmware commands after 2000ms */
-#define MWL8K_CMD_TIMEOUT_MS   2000
+/* Timeout firmware commands after 10s */
+#define MWL8K_CMD_TIMEOUT_MS   10000
 
 static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
 {
@@ -1625,12 +1637,21 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
                       MWL8K_CMD_TIMEOUT_MS);
                rc = -ETIMEDOUT;
        } else {
+               int ms;
+
+               ms = MWL8K_CMD_TIMEOUT_MS - jiffies_to_msecs(timeout);
+
                rc = cmd->result ? -EINVAL : 0;
                if (rc)
                        printk(KERN_ERR "%s: Command %s error 0x%x\n",
                               wiphy_name(hw->wiphy),
                               mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
                               le16_to_cpu(cmd->result));
+               else if (ms > 2000)
+                       printk(KERN_NOTICE "%s: Command %s took %d ms\n",
+                              wiphy_name(hw->wiphy),
+                              mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
+                              ms);
        }
 
        return rc;
@@ -3357,7 +3378,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
        if (rc) {
                printk(KERN_ERR "%s: Cannot obtain PCI resources\n",
                       MWL8K_NAME);
-               return rc;
+               goto err_disable_device;
        }
 
        pci_set_master(pdev);
@@ -3588,6 +3609,8 @@ err_iounmap:
 
 err_free_reg:
        pci_release_regions(pdev);
+
+err_disable_device:
        pci_disable_device(pdev);
 
        return rc;
This page took 0.03081 seconds and 5 git commands to generate.