diff options
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/internal.h | 29 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/trans.c | 35 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/tx.c | 71 |
3 files changed, 82 insertions, 53 deletions
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 9dfee7ed2e3e..809052442e91 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h | |||
@@ -262,6 +262,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) | |||
262 | * @rx_page_order: page order for receive buffer size | 262 | * @rx_page_order: page order for receive buffer size |
263 | * @wd_timeout: queue watchdog timeout (jiffies) | 263 | * @wd_timeout: queue watchdog timeout (jiffies) |
264 | * @reg_lock: protect hw register access | 264 | * @reg_lock: protect hw register access |
265 | * @cmd_in_flight: true when we have a host command in flight | ||
265 | */ | 266 | */ |
266 | struct iwl_trans_pcie { | 267 | struct iwl_trans_pcie { |
267 | struct iwl_rxq rxq; | 268 | struct iwl_rxq rxq; |
@@ -310,6 +311,7 @@ struct iwl_trans_pcie { | |||
310 | 311 | ||
311 | /*protect hw register */ | 312 | /*protect hw register */ |
312 | spinlock_t reg_lock; | 313 | spinlock_t reg_lock; |
314 | bool cmd_in_flight; | ||
313 | }; | 315 | }; |
314 | 316 | ||
315 | #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \ | 317 | #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \ |
@@ -459,4 +461,31 @@ static inline bool iwl_is_rfkill_set(struct iwl_trans *trans) | |||
459 | CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW); | 461 | CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW); |
460 | } | 462 | } |
461 | 463 | ||
464 | static inline void __iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, | ||
465 | u32 reg, u32 mask, u32 value) | ||
466 | { | ||
467 | u32 v; | ||
468 | |||
469 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
470 | WARN_ON_ONCE(value & ~mask); | ||
471 | #endif | ||
472 | |||
473 | v = iwl_read32(trans, reg); | ||
474 | v &= ~mask; | ||
475 | v |= value; | ||
476 | iwl_write32(trans, reg, v); | ||
477 | } | ||
478 | |||
479 | static inline void __iwl_trans_pcie_clear_bit(struct iwl_trans *trans, | ||
480 | u32 reg, u32 mask) | ||
481 | { | ||
482 | __iwl_trans_pcie_set_bits_mask(trans, reg, mask, 0); | ||
483 | } | ||
484 | |||
485 | static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans, | ||
486 | u32 reg, u32 mask) | ||
487 | { | ||
488 | __iwl_trans_pcie_set_bits_mask(trans, reg, mask, mask); | ||
489 | } | ||
490 | |||
462 | #endif /* __iwl_trans_int_pcie_h__ */ | 491 | #endif /* __iwl_trans_int_pcie_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 9a07cf3062ea..d9ccb4edc602 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c | |||
@@ -75,33 +75,6 @@ | |||
75 | #include "iwl-agn-hw.h" | 75 | #include "iwl-agn-hw.h" |
76 | #include "internal.h" | 76 | #include "internal.h" |
77 | 77 | ||
78 | static void __iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, | ||
79 | u32 reg, u32 mask, u32 value) | ||
80 | { | ||
81 | u32 v; | ||
82 | |||
83 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
84 | WARN_ON_ONCE(value & ~mask); | ||
85 | #endif | ||
86 | |||
87 | v = iwl_read32(trans, reg); | ||
88 | v &= ~mask; | ||
89 | v |= value; | ||
90 | iwl_write32(trans, reg, v); | ||
91 | } | ||
92 | |||
93 | static inline void __iwl_trans_pcie_clear_bit(struct iwl_trans *trans, | ||
94 | u32 reg, u32 mask) | ||
95 | { | ||
96 | __iwl_trans_pcie_set_bits_mask(trans, reg, mask, 0); | ||
97 | } | ||
98 | |||
99 | static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans, | ||
100 | u32 reg, u32 mask) | ||
101 | { | ||
102 | __iwl_trans_pcie_set_bits_mask(trans, reg, mask, mask); | ||
103 | } | ||
104 | |||
105 | static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux) | 78 | static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux) |
106 | { | 79 | { |
107 | if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold)) | 80 | if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold)) |
@@ -929,6 +902,9 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent, | |||
929 | 902 | ||
930 | spin_lock_irqsave(&trans_pcie->reg_lock, *flags); | 903 | spin_lock_irqsave(&trans_pcie->reg_lock, *flags); |
931 | 904 | ||
905 | if (trans_pcie->cmd_in_flight) | ||
906 | goto out; | ||
907 | |||
932 | /* this bit wakes up the NIC */ | 908 | /* this bit wakes up the NIC */ |
933 | __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, | 909 | __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, |
934 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | 910 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); |
@@ -968,6 +944,7 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent, | |||
968 | } | 944 | } |
969 | } | 945 | } |
970 | 946 | ||
947 | out: | ||
971 | /* | 948 | /* |
972 | * Fool sparse by faking we release the lock - sparse will | 949 | * Fool sparse by faking we release the lock - sparse will |
973 | * track nic_access anyway. | 950 | * track nic_access anyway. |
@@ -989,6 +966,9 @@ static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans, | |||
989 | */ | 966 | */ |
990 | __acquire(&trans_pcie->reg_lock); | 967 | __acquire(&trans_pcie->reg_lock); |
991 | 968 | ||
969 | if (trans_pcie->cmd_in_flight) | ||
970 | goto out; | ||
971 | |||
992 | __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, | 972 | __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, |
993 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | 973 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); |
994 | /* | 974 | /* |
@@ -998,6 +978,7 @@ static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans, | |||
998 | * scheduled on different CPUs (after we drop reg_lock). | 978 | * scheduled on different CPUs (after we drop reg_lock). |
999 | */ | 979 | */ |
1000 | mmiowb(); | 980 | mmiowb(); |
981 | out: | ||
1001 | spin_unlock_irqrestore(&trans_pcie->reg_lock, *flags); | 982 | spin_unlock_irqrestore(&trans_pcie->reg_lock, *flags); |
1002 | } | 983 | } |
1003 | 984 | ||
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 | ||
1467 | static int iwl_pcie_send_hcmd_async(struct iwl_trans *trans, | 1506 | static 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; |