aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/pcie/tx.c
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2013-12-22 08:09:40 -0500
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2013-12-31 12:03:43 -0500
commitb9439491055a18ee075614139abadfd74c1b887f (patch)
tree41845bfb442438e01acb78c3181adbd72a1ce761 /drivers/net/wireless/iwlwifi/pcie/tx.c
parenta4a1247847ca9ae2fd96e0684a74acd551791000 (diff)
iwlwifi: pcie: keep the NIC awake when commands are in flight
Under very specific circumstances, the firmware might ignore a host command. This was debugged and we ended up seeing that the power management hardware was faulty. In order to workaround this issue, we keep the NIC awake as long as we have host commands in flight. This will avoid to put the hardware into buggy condition. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/pcie/tx.c')
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/tx.c71
1 files changed, 45 insertions, 26 deletions
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index b49a185355e4..2417af9ad2c6 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -1001,6 +1001,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
1001 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 1001 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
1002 struct iwl_txq *txq = &trans_pcie->txq[txq_id]; 1002 struct iwl_txq *txq = &trans_pcie->txq[txq_id];
1003 struct iwl_queue *q = &txq->q; 1003 struct iwl_queue *q = &txq->q;
1004 unsigned long flags;
1004 int nfreed = 0; 1005 int nfreed = 0;
1005 1006
1006 lockdep_assert_held(&txq->lock); 1007 lockdep_assert_held(&txq->lock);
@@ -1023,6 +1024,16 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
1023 } 1024 }
1024 } 1025 }
1025 1026
1027 if (q->read_ptr == q->write_ptr) {
1028 spin_lock_irqsave(&trans_pcie->reg_lock, flags);
1029 WARN_ON(!trans_pcie->cmd_in_flight);
1030 trans_pcie->cmd_in_flight = false;
1031 __iwl_trans_pcie_clear_bit(trans,
1032 CSR_GP_CNTRL,
1033 CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
1034 spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
1035 }
1036
1026 iwl_pcie_txq_progress(trans_pcie, txq); 1037 iwl_pcie_txq_progress(trans_pcie, txq);
1027} 1038}
1028 1039
@@ -1174,12 +1185,13 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
1174 struct iwl_queue *q = &txq->q; 1185 struct iwl_queue *q = &txq->q;
1175 struct iwl_device_cmd *out_cmd; 1186 struct iwl_device_cmd *out_cmd;
1176 struct iwl_cmd_meta *out_meta; 1187 struct iwl_cmd_meta *out_meta;
1188 unsigned long flags;
1177 void *dup_buf = NULL; 1189 void *dup_buf = NULL;
1178 dma_addr_t phys_addr; 1190 dma_addr_t phys_addr;
1179 int idx; 1191 int idx;
1180 u16 copy_size, cmd_size, scratch_size; 1192 u16 copy_size, cmd_size, scratch_size;
1181 bool had_nocopy = false; 1193 bool had_nocopy = false;
1182 int i; 1194 int i, ret;
1183 u32 cmd_pos; 1195 u32 cmd_pos;
1184 const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD]; 1196 const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD];
1185 u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD]; 1197 u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD];
@@ -1377,10 +1389,38 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
1377 if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout) 1389 if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout)
1378 mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); 1390 mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
1379 1391
1392 spin_lock_irqsave(&trans_pcie->reg_lock, flags);
1393
1394 /*
1395 * wake up the NIC to make sure that the firmware will see the host
1396 * command - we will let the NIC sleep once all the host commands
1397 * returned.
1398 */
1399 if (!trans_pcie->cmd_in_flight) {
1400 trans_pcie->cmd_in_flight = true;
1401 __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
1402 CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
1403 ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
1404 CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
1405 (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
1406 CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP),
1407 15000);
1408 if (ret < 0) {
1409 __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
1410 CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
1411 spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
1412 trans_pcie->cmd_in_flight = false;
1413 idx = -EIO;
1414 goto out;
1415 }
1416 }
1417
1380 /* Increment and update queue's write index */ 1418 /* Increment and update queue's write index */
1381 q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); 1419 q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
1382 iwl_pcie_txq_inc_wr_ptr(trans, txq); 1420 iwl_pcie_txq_inc_wr_ptr(trans, txq);
1383 1421
1422 spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
1423
1384 out: 1424 out:
1385 spin_unlock_bh(&txq->lock); 1425 spin_unlock_bh(&txq->lock);
1386 free_dup_buf: 1426 free_dup_buf:
@@ -1462,7 +1502,6 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
1462} 1502}
1463 1503
1464#define HOST_COMPLETE_TIMEOUT (2 * HZ) 1504#define HOST_COMPLETE_TIMEOUT (2 * HZ)
1465#define COMMAND_POKE_TIMEOUT (HZ / 10)
1466 1505
1467static int iwl_pcie_send_hcmd_async(struct iwl_trans *trans, 1506static int iwl_pcie_send_hcmd_async(struct iwl_trans *trans,
1468 struct iwl_host_cmd *cmd) 1507 struct iwl_host_cmd *cmd)
@@ -1490,7 +1529,6 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
1490 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 1529 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
1491 int cmd_idx; 1530 int cmd_idx;
1492 int ret; 1531 int ret;
1493 int timeout = HOST_COMPLETE_TIMEOUT;
1494 1532
1495 IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n", 1533 IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n",
1496 get_cmd_string(trans_pcie, cmd->id)); 1534 get_cmd_string(trans_pcie, cmd->id));
@@ -1514,29 +1552,10 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
1514 return ret; 1552 return ret;
1515 } 1553 }
1516 1554
1517 while (timeout > 0) { 1555 ret = wait_event_timeout(trans_pcie->wait_command_queue,
1518 unsigned long flags; 1556 !test_bit(STATUS_SYNC_HCMD_ACTIVE,
1519 1557 &trans->status),
1520 timeout -= COMMAND_POKE_TIMEOUT; 1558 HOST_COMPLETE_TIMEOUT);
1521 ret = wait_event_timeout(trans_pcie->wait_command_queue,
1522 !test_bit(STATUS_SYNC_HCMD_ACTIVE,
1523 &trans->status),
1524 COMMAND_POKE_TIMEOUT);
1525 if (ret)
1526 break;
1527 /* poke the device - it may have lost the command */
1528 if (iwl_trans_grab_nic_access(trans, true, &flags)) {
1529 iwl_trans_release_nic_access(trans, &flags);
1530 IWL_DEBUG_INFO(trans,
1531 "Tried to wake NIC for command %s\n",
1532 get_cmd_string(trans_pcie, cmd->id));
1533 } else {
1534 IWL_ERR(trans, "Failed to poke NIC for command %s\n",
1535 get_cmd_string(trans_pcie, cmd->id));
1536 break;
1537 }
1538 }
1539
1540 if (!ret) { 1559 if (!ret) {
1541 struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; 1560 struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
1542 struct iwl_queue *q = &txq->q; 1561 struct iwl_queue *q = &txq->q;