Merge tag 'iwlwifi-next-for-kalle-2017-06-28' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
More iwlwifi patches for 4.13 * Some changes in suspend/resume handling to support new FWs; * A bunch of RF-kill related fixes; * Continued work towards the A000 family; * Support for a new version of the TX flush FW API; * Some fixes in monitor interfaces; * A few fixes in the recovery flows; * Johannes' documentation fixes and FW API struct cleanups continue; * Remove some noise from the kernel logs; * Some other small improvements, fixes and cleanups;
This commit is contained in:
@@ -766,7 +766,6 @@ static int iwl_pci_resume(struct device *device)
|
||||
struct pci_dev *pdev = to_pci_dev(device);
|
||||
struct iwl_trans *trans = pci_get_drvdata(pdev);
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
bool hw_rfkill;
|
||||
|
||||
/* Before you put code here, think about WoWLAN. You cannot check here
|
||||
* whether WoWLAN is enabled or not, and your code will run even if
|
||||
@@ -783,16 +782,13 @@ static int iwl_pci_resume(struct device *device)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Enable rfkill interrupt (in order to keep track of
|
||||
* the rfkill status). Must be locked to avoid processing
|
||||
* a possible rfkill interrupt between reading the state
|
||||
* and calling iwl_trans_pcie_rf_kill() with it.
|
||||
* Enable rfkill interrupt (in order to keep track of the rfkill
|
||||
* status). Must be locked to avoid processing a possible rfkill
|
||||
* interrupt while in iwl_trans_check_hw_rf_kill().
|
||||
*/
|
||||
mutex_lock(&trans_pcie->mutex);
|
||||
iwl_enable_rfkill_int(trans);
|
||||
|
||||
hw_rfkill = iwl_is_rfkill_set(trans);
|
||||
iwl_trans_pcie_rf_kill(trans, hw_rfkill);
|
||||
iwl_trans_check_hw_rf_kill(trans);
|
||||
mutex_unlock(&trans_pcie->mutex);
|
||||
|
||||
return 0;
|
||||
|
@@ -403,7 +403,8 @@ struct iwl_trans_pcie {
|
||||
dma_addr_t ict_tbl_dma;
|
||||
int ict_index;
|
||||
bool use_ict;
|
||||
bool is_down;
|
||||
bool is_down, opmode_down;
|
||||
bool debug_rfkill;
|
||||
struct isr_statistics isr_stats;
|
||||
|
||||
spinlock_t irq_lock;
|
||||
@@ -515,7 +516,7 @@ int iwl_pcie_gen2_tx_init(struct iwl_trans *trans);
|
||||
void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr);
|
||||
int iwl_pcie_tx_stop(struct iwl_trans *trans);
|
||||
void iwl_pcie_tx_free(struct iwl_trans *trans);
|
||||
void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn,
|
||||
bool iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn,
|
||||
const struct iwl_trans_txq_scd_cfg *cfg,
|
||||
unsigned int wdg_timeout);
|
||||
void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue,
|
||||
@@ -675,6 +676,8 @@ static inline void iwl_enable_rfkill_int(struct iwl_trans *trans)
|
||||
}
|
||||
}
|
||||
|
||||
void iwl_pcie_handle_rfkill_irq(struct iwl_trans *trans);
|
||||
|
||||
static inline void iwl_wake_queue(struct iwl_trans *trans,
|
||||
struct iwl_txq *txq)
|
||||
{
|
||||
@@ -713,7 +716,12 @@ static inline u8 get_cmd_index(struct iwl_txq *q, u32 index)
|
||||
|
||||
static inline bool iwl_is_rfkill_set(struct iwl_trans *trans)
|
||||
{
|
||||
lockdep_assert_held(&IWL_TRANS_GET_PCIE_TRANS(trans)->mutex);
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
lockdep_assert_held(&trans_pcie->mutex);
|
||||
|
||||
if (trans_pcie->debug_rfkill)
|
||||
return true;
|
||||
|
||||
return !(iwl_read32(trans, CSR_GP_CNTRL) &
|
||||
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
|
||||
@@ -767,9 +775,11 @@ void iwl_pcie_apm_config(struct iwl_trans *trans);
|
||||
int iwl_pcie_prepare_card_hw(struct iwl_trans *trans);
|
||||
void iwl_pcie_synchronize_irqs(struct iwl_trans *trans);
|
||||
bool iwl_trans_check_hw_rf_kill(struct iwl_trans *trans);
|
||||
void iwl_trans_pcie_handle_stop_rfkill(struct iwl_trans *trans,
|
||||
bool was_in_rfkill);
|
||||
void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq);
|
||||
int iwl_queue_space(const struct iwl_txq *q);
|
||||
int iwl_pcie_apm_stop_master(struct iwl_trans *trans);
|
||||
void iwl_pcie_apm_stop_master(struct iwl_trans *trans);
|
||||
void iwl_pcie_conf_msix_hw(struct iwl_trans_pcie *trans_pcie);
|
||||
int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq,
|
||||
int slots_num, bool cmd_queue);
|
||||
|
@@ -845,14 +845,14 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans)
|
||||
* Set RX DMA chunk size to 64B for IOSF and 128B for PCIe
|
||||
* Default queue is 0
|
||||
*/
|
||||
iwl_write_prph_no_grab(trans, RFH_GEN_CFG, RFH_GEN_CFG_RFH_DMA_SNOOP |
|
||||
(DEFAULT_RXQ_NUM <<
|
||||
RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS) |
|
||||
iwl_write_prph_no_grab(trans, RFH_GEN_CFG,
|
||||
RFH_GEN_CFG_RFH_DMA_SNOOP |
|
||||
RFH_GEN_CFG_VAL(DEFAULT_RXQ_NUM, 0) |
|
||||
RFH_GEN_CFG_SERVICE_DMA_SNOOP |
|
||||
(trans->cfg->integrated ?
|
||||
RFH_GEN_CFG_RB_CHUNK_SIZE_64 :
|
||||
RFH_GEN_CFG_RB_CHUNK_SIZE_128) <<
|
||||
RFH_GEN_CFG_RB_CHUNK_SIZE_POS);
|
||||
RFH_GEN_CFG_VAL(RB_CHUNK_SIZE,
|
||||
trans->cfg->integrated ?
|
||||
RFH_GEN_CFG_RB_CHUNK_SIZE_64 :
|
||||
RFH_GEN_CFG_RB_CHUNK_SIZE_128));
|
||||
/* Enable the relevant rx queues */
|
||||
iwl_write_prph_no_grab(trans, RFH_RXF_RXQ_ACTIVE, enabled);
|
||||
|
||||
@@ -1413,18 +1413,16 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
|
||||
return;
|
||||
}
|
||||
|
||||
local_bh_disable();
|
||||
/* The STATUS_FW_ERROR bit is set in this function. This must happen
|
||||
* before we wake up the command caller, to ensure a proper cleanup. */
|
||||
iwl_trans_fw_error(trans);
|
||||
local_bh_enable();
|
||||
|
||||
for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) {
|
||||
if (!trans_pcie->txq[i])
|
||||
continue;
|
||||
del_timer(&trans_pcie->txq[i]->stuck_timer);
|
||||
}
|
||||
|
||||
/* The STATUS_FW_ERROR bit is set in this function. This must happen
|
||||
* before we wake up the command caller, to ensure a proper cleanup. */
|
||||
iwl_trans_fw_error(trans);
|
||||
|
||||
clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
|
||||
wake_up(&trans_pcie->wait_command_queue);
|
||||
}
|
||||
@@ -1509,6 +1507,46 @@ static u32 iwl_pcie_int_cause_ict(struct iwl_trans *trans)
|
||||
return inta;
|
||||
}
|
||||
|
||||
void iwl_pcie_handle_rfkill_irq(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
|
||||
bool hw_rfkill, prev, report;
|
||||
|
||||
mutex_lock(&trans_pcie->mutex);
|
||||
prev = test_bit(STATUS_RFKILL_OPMODE, &trans->status);
|
||||
hw_rfkill = iwl_is_rfkill_set(trans);
|
||||
if (hw_rfkill) {
|
||||
set_bit(STATUS_RFKILL_OPMODE, &trans->status);
|
||||
set_bit(STATUS_RFKILL_HW, &trans->status);
|
||||
}
|
||||
if (trans_pcie->opmode_down)
|
||||
report = hw_rfkill;
|
||||
else
|
||||
report = test_bit(STATUS_RFKILL_OPMODE, &trans->status);
|
||||
|
||||
IWL_WARN(trans, "RF_KILL bit toggled to %s.\n",
|
||||
hw_rfkill ? "disable radio" : "enable radio");
|
||||
|
||||
isr_stats->rfkill++;
|
||||
|
||||
if (prev != report)
|
||||
iwl_trans_pcie_rf_kill(trans, report);
|
||||
mutex_unlock(&trans_pcie->mutex);
|
||||
|
||||
if (hw_rfkill) {
|
||||
if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE,
|
||||
&trans->status))
|
||||
IWL_DEBUG_RF_KILL(trans,
|
||||
"Rfkill while SYNC HCMD in flight\n");
|
||||
wake_up(&trans_pcie->wait_command_queue);
|
||||
} else {
|
||||
clear_bit(STATUS_RFKILL_HW, &trans->status);
|
||||
if (trans_pcie->opmode_down)
|
||||
clear_bit(STATUS_RFKILL_OPMODE, &trans->status);
|
||||
}
|
||||
}
|
||||
|
||||
irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct iwl_trans *trans = dev_id;
|
||||
@@ -1632,30 +1670,7 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
|
||||
|
||||
/* HW RF KILL switch toggled */
|
||||
if (inta & CSR_INT_BIT_RF_KILL) {
|
||||
bool hw_rfkill;
|
||||
|
||||
mutex_lock(&trans_pcie->mutex);
|
||||
hw_rfkill = iwl_is_rfkill_set(trans);
|
||||
if (hw_rfkill)
|
||||
set_bit(STATUS_RFKILL, &trans->status);
|
||||
|
||||
IWL_WARN(trans, "RF_KILL bit toggled to %s.\n",
|
||||
hw_rfkill ? "disable radio" : "enable radio");
|
||||
|
||||
isr_stats->rfkill++;
|
||||
|
||||
iwl_trans_pcie_rf_kill(trans, hw_rfkill);
|
||||
mutex_unlock(&trans_pcie->mutex);
|
||||
if (hw_rfkill) {
|
||||
if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE,
|
||||
&trans->status))
|
||||
IWL_DEBUG_RF_KILL(trans,
|
||||
"Rfkill while SYNC HCMD in flight\n");
|
||||
wake_up(&trans_pcie->wait_command_queue);
|
||||
} else {
|
||||
clear_bit(STATUS_RFKILL, &trans->status);
|
||||
}
|
||||
|
||||
iwl_pcie_handle_rfkill_irq(trans);
|
||||
handled |= CSR_INT_BIT_RF_KILL;
|
||||
}
|
||||
|
||||
@@ -1982,31 +1997,8 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
/* HW RF KILL switch toggled */
|
||||
if (inta_hw & MSIX_HW_INT_CAUSES_REG_RF_KILL) {
|
||||
bool hw_rfkill;
|
||||
|
||||
mutex_lock(&trans_pcie->mutex);
|
||||
hw_rfkill = iwl_is_rfkill_set(trans);
|
||||
if (hw_rfkill)
|
||||
set_bit(STATUS_RFKILL, &trans->status);
|
||||
|
||||
IWL_WARN(trans, "RF_KILL bit toggled to %s.\n",
|
||||
hw_rfkill ? "disable radio" : "enable radio");
|
||||
|
||||
isr_stats->rfkill++;
|
||||
|
||||
iwl_trans_pcie_rf_kill(trans, hw_rfkill);
|
||||
mutex_unlock(&trans_pcie->mutex);
|
||||
if (hw_rfkill) {
|
||||
if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE,
|
||||
&trans->status))
|
||||
IWL_DEBUG_RF_KILL(trans,
|
||||
"Rfkill while SYNC HCMD in flight\n");
|
||||
wake_up(&trans_pcie->wait_command_queue);
|
||||
} else {
|
||||
clear_bit(STATUS_RFKILL, &trans->status);
|
||||
}
|
||||
}
|
||||
if (inta_hw & MSIX_HW_INT_CAUSES_REG_RF_KILL)
|
||||
iwl_pcie_handle_rfkill_irq(trans);
|
||||
|
||||
if (inta_hw & MSIX_HW_INT_CAUSES_REG_HW_ERR) {
|
||||
IWL_ERR(trans,
|
||||
|
@@ -150,7 +150,6 @@ static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave)
|
||||
void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
bool hw_rfkill, was_hw_rfkill;
|
||||
|
||||
lockdep_assert_held(&trans_pcie->mutex);
|
||||
|
||||
@@ -159,8 +158,6 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power)
|
||||
|
||||
trans_pcie->is_down = true;
|
||||
|
||||
was_hw_rfkill = iwl_is_rfkill_set(trans);
|
||||
|
||||
/* tell the device to stop sending interrupts */
|
||||
iwl_disable_interrupts(trans);
|
||||
|
||||
@@ -217,7 +214,6 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power)
|
||||
clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
|
||||
clear_bit(STATUS_INT_ENABLED, &trans->status);
|
||||
clear_bit(STATUS_TPOWER_PMI, &trans->status);
|
||||
clear_bit(STATUS_RFKILL, &trans->status);
|
||||
|
||||
/*
|
||||
* Even if we stop the HW, we still want the RF kill
|
||||
@@ -225,26 +221,6 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power)
|
||||
*/
|
||||
iwl_enable_rfkill_int(trans);
|
||||
|
||||
/*
|
||||
* Check again since the RF kill state may have changed while
|
||||
* all the interrupts were disabled, in this case we couldn't
|
||||
* receive the RF kill interrupt and update the state in the
|
||||
* op_mode.
|
||||
* Don't call the op_mode if the rkfill state hasn't changed.
|
||||
* This allows the op_mode to call stop_device from the rfkill
|
||||
* notification without endless recursion. Under very rare
|
||||
* circumstances, we might have a small recursion if the rfkill
|
||||
* state changed exactly now while we were called from stop_device.
|
||||
* This is very unlikely but can happen and is supported.
|
||||
*/
|
||||
hw_rfkill = iwl_is_rfkill_set(trans);
|
||||
if (hw_rfkill)
|
||||
set_bit(STATUS_RFKILL, &trans->status);
|
||||
else
|
||||
clear_bit(STATUS_RFKILL, &trans->status);
|
||||
if (hw_rfkill != was_hw_rfkill)
|
||||
iwl_trans_pcie_rf_kill(trans, hw_rfkill);
|
||||
|
||||
/* re-take ownership to prevent other users from stealing the device */
|
||||
iwl_pcie_prepare_card_hw(trans);
|
||||
}
|
||||
@@ -252,9 +228,13 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power)
|
||||
void iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
bool was_in_rfkill;
|
||||
|
||||
mutex_lock(&trans_pcie->mutex);
|
||||
trans_pcie->opmode_down = true;
|
||||
was_in_rfkill = test_bit(STATUS_RFKILL_OPMODE, &trans->status);
|
||||
_iwl_trans_pcie_gen2_stop_device(trans, low_power);
|
||||
iwl_trans_pcie_handle_stop_rfkill(trans, was_in_rfkill);
|
||||
mutex_unlock(&trans_pcie->mutex);
|
||||
}
|
||||
|
||||
|
@@ -224,9 +224,9 @@ void iwl_pcie_apm_config(struct iwl_trans *trans)
|
||||
|
||||
pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_DEVCTL2, &cap);
|
||||
trans->ltr_enabled = cap & PCI_EXP_DEVCTL2_LTR_EN;
|
||||
dev_info(trans->dev, "L1 %sabled - LTR %sabled\n",
|
||||
(lctl & PCI_EXP_LNKCTL_ASPM_L1) ? "En" : "Dis",
|
||||
trans->ltr_enabled ? "En" : "Dis");
|
||||
IWL_DEBUG_POWER(trans, "L1 %sabled - LTR %sabled\n",
|
||||
(lctl & PCI_EXP_LNKCTL_ASPM_L1) ? "En" : "Dis",
|
||||
trans->ltr_enabled ? "En" : "Dis");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -448,9 +448,9 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans)
|
||||
~SHR_APMG_XTAL_CFG_XTAL_ON_REQ);
|
||||
}
|
||||
|
||||
int iwl_pcie_apm_stop_master(struct iwl_trans *trans)
|
||||
void iwl_pcie_apm_stop_master(struct iwl_trans *trans)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
/* stop device's busmaster DMA activity */
|
||||
iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
|
||||
@@ -462,8 +462,6 @@ int iwl_pcie_apm_stop_master(struct iwl_trans *trans)
|
||||
IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n");
|
||||
|
||||
IWL_DEBUG_INFO(trans, "stop master\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave)
|
||||
@@ -996,14 +994,24 @@ static int iwl_pcie_load_given_ucode_8000(struct iwl_trans *trans,
|
||||
|
||||
bool iwl_trans_check_hw_rf_kill(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
bool hw_rfkill = iwl_is_rfkill_set(trans);
|
||||
bool prev = test_bit(STATUS_RFKILL_OPMODE, &trans->status);
|
||||
bool report;
|
||||
|
||||
if (hw_rfkill)
|
||||
set_bit(STATUS_RFKILL, &trans->status);
|
||||
else
|
||||
clear_bit(STATUS_RFKILL, &trans->status);
|
||||
if (hw_rfkill) {
|
||||
set_bit(STATUS_RFKILL_HW, &trans->status);
|
||||
set_bit(STATUS_RFKILL_OPMODE, &trans->status);
|
||||
} else {
|
||||
clear_bit(STATUS_RFKILL_HW, &trans->status);
|
||||
if (trans_pcie->opmode_down)
|
||||
clear_bit(STATUS_RFKILL_OPMODE, &trans->status);
|
||||
}
|
||||
|
||||
iwl_trans_pcie_rf_kill(trans, hw_rfkill);
|
||||
report = test_bit(STATUS_RFKILL_OPMODE, &trans->status);
|
||||
|
||||
if (prev != report)
|
||||
iwl_trans_pcie_rf_kill(trans, report);
|
||||
|
||||
return hw_rfkill;
|
||||
}
|
||||
@@ -1128,7 +1136,6 @@ static void iwl_pcie_init_msix(struct iwl_trans_pcie *trans_pcie)
|
||||
static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
bool hw_rfkill, was_hw_rfkill;
|
||||
|
||||
lockdep_assert_held(&trans_pcie->mutex);
|
||||
|
||||
@@ -1137,8 +1144,6 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
|
||||
|
||||
trans_pcie->is_down = true;
|
||||
|
||||
was_hw_rfkill = iwl_is_rfkill_set(trans);
|
||||
|
||||
/* tell the device to stop sending interrupts */
|
||||
iwl_disable_interrupts(trans);
|
||||
|
||||
@@ -1199,7 +1204,6 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
|
||||
clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
|
||||
clear_bit(STATUS_INT_ENABLED, &trans->status);
|
||||
clear_bit(STATUS_TPOWER_PMI, &trans->status);
|
||||
clear_bit(STATUS_RFKILL, &trans->status);
|
||||
|
||||
/*
|
||||
* Even if we stop the HW, we still want the RF kill
|
||||
@@ -1207,26 +1211,6 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
|
||||
*/
|
||||
iwl_enable_rfkill_int(trans);
|
||||
|
||||
/*
|
||||
* Check again since the RF kill state may have changed while
|
||||
* all the interrupts were disabled, in this case we couldn't
|
||||
* receive the RF kill interrupt and update the state in the
|
||||
* op_mode.
|
||||
* Don't call the op_mode if the rkfill state hasn't changed.
|
||||
* This allows the op_mode to call stop_device from the rfkill
|
||||
* notification without endless recursion. Under very rare
|
||||
* circumstances, we might have a small recursion if the rfkill
|
||||
* state changed exactly now while we were called from stop_device.
|
||||
* This is very unlikely but can happen and is supported.
|
||||
*/
|
||||
hw_rfkill = iwl_is_rfkill_set(trans);
|
||||
if (hw_rfkill)
|
||||
set_bit(STATUS_RFKILL, &trans->status);
|
||||
else
|
||||
clear_bit(STATUS_RFKILL, &trans->status);
|
||||
if (hw_rfkill != was_hw_rfkill)
|
||||
iwl_trans_pcie_rf_kill(trans, hw_rfkill);
|
||||
|
||||
/* re-take ownership to prevent other users from stealing the device */
|
||||
iwl_pcie_prepare_card_hw(trans);
|
||||
}
|
||||
@@ -1339,12 +1323,45 @@ static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr)
|
||||
iwl_pcie_tx_start(trans, scd_addr);
|
||||
}
|
||||
|
||||
void iwl_trans_pcie_handle_stop_rfkill(struct iwl_trans *trans,
|
||||
bool was_in_rfkill)
|
||||
{
|
||||
bool hw_rfkill;
|
||||
|
||||
/*
|
||||
* Check again since the RF kill state may have changed while
|
||||
* all the interrupts were disabled, in this case we couldn't
|
||||
* receive the RF kill interrupt and update the state in the
|
||||
* op_mode.
|
||||
* Don't call the op_mode if the rkfill state hasn't changed.
|
||||
* This allows the op_mode to call stop_device from the rfkill
|
||||
* notification without endless recursion. Under very rare
|
||||
* circumstances, we might have a small recursion if the rfkill
|
||||
* state changed exactly now while we were called from stop_device.
|
||||
* This is very unlikely but can happen and is supported.
|
||||
*/
|
||||
hw_rfkill = iwl_is_rfkill_set(trans);
|
||||
if (hw_rfkill) {
|
||||
set_bit(STATUS_RFKILL_HW, &trans->status);
|
||||
set_bit(STATUS_RFKILL_OPMODE, &trans->status);
|
||||
} else {
|
||||
clear_bit(STATUS_RFKILL_HW, &trans->status);
|
||||
clear_bit(STATUS_RFKILL_OPMODE, &trans->status);
|
||||
}
|
||||
if (hw_rfkill != was_in_rfkill)
|
||||
iwl_trans_pcie_rf_kill(trans, hw_rfkill);
|
||||
}
|
||||
|
||||
static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
bool was_in_rfkill;
|
||||
|
||||
mutex_lock(&trans_pcie->mutex);
|
||||
trans_pcie->opmode_down = true;
|
||||
was_in_rfkill = test_bit(STATUS_RFKILL_OPMODE, &trans->status);
|
||||
_iwl_trans_pcie_stop_device(trans, low_power);
|
||||
iwl_trans_pcie_handle_stop_rfkill(trans, was_in_rfkill);
|
||||
mutex_unlock(&trans_pcie->mutex);
|
||||
}
|
||||
|
||||
@@ -1355,6 +1372,8 @@ void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state)
|
||||
|
||||
lockdep_assert_held(&trans_pcie->mutex);
|
||||
|
||||
IWL_WARN(trans, "reporting RF_KILL (radio %s)\n",
|
||||
state ? "disabled" : "enabled");
|
||||
if (iwl_op_mode_hw_rf_kill(trans->op_mode, state)) {
|
||||
if (trans->cfg->gen2)
|
||||
_iwl_trans_pcie_gen2_stop_device(trans, true);
|
||||
@@ -1646,6 +1665,8 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power)
|
||||
/* From now on, the op_mode will be kept updated about RF kill state */
|
||||
iwl_enable_rfkill_int(trans);
|
||||
|
||||
trans_pcie->opmode_down = false;
|
||||
|
||||
/* Set is_down to false here so that...*/
|
||||
trans_pcie->is_down = false;
|
||||
|
||||
@@ -2405,17 +2426,12 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
|
||||
struct iwl_trans *trans = file->private_data;
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
|
||||
|
||||
char buf[8];
|
||||
int buf_size;
|
||||
u32 reset_flag;
|
||||
int ret;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf_size = min(count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, buf_size))
|
||||
return -EFAULT;
|
||||
if (sscanf(buf, "%x", &reset_flag) != 1)
|
||||
return -EFAULT;
|
||||
ret = kstrtou32_from_user(user_buf, count, 16, &reset_flag);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (reset_flag == 0)
|
||||
memset(isr_stats, 0, sizeof(*isr_stats));
|
||||
|
||||
@@ -2427,16 +2443,6 @@ static ssize_t iwl_dbgfs_csr_write(struct file *file,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_trans *trans = file->private_data;
|
||||
char buf[8];
|
||||
int buf_size;
|
||||
int csr;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf_size = min(count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, buf_size))
|
||||
return -EFAULT;
|
||||
if (sscanf(buf, "%d", &csr) != 1)
|
||||
return -EFAULT;
|
||||
|
||||
iwl_pcie_dump_csr(trans);
|
||||
|
||||
@@ -2461,11 +2467,50 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_rfkill_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_trans *trans = file->private_data;
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
char buf[100];
|
||||
int pos;
|
||||
|
||||
pos = scnprintf(buf, sizeof(buf), "debug: %d\nhw: %d\n",
|
||||
trans_pcie->debug_rfkill,
|
||||
!(iwl_read32(trans, CSR_GP_CNTRL) &
|
||||
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW));
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_rfkill_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_trans *trans = file->private_data;
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
bool old = trans_pcie->debug_rfkill;
|
||||
int ret;
|
||||
|
||||
ret = kstrtobool_from_user(user_buf, count, &trans_pcie->debug_rfkill);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (old == trans_pcie->debug_rfkill)
|
||||
return count;
|
||||
IWL_WARN(trans, "changing debug rfkill %d->%d\n",
|
||||
old, trans_pcie->debug_rfkill);
|
||||
iwl_pcie_handle_rfkill_irq(trans);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
|
||||
DEBUGFS_READ_FILE_OPS(fh_reg);
|
||||
DEBUGFS_READ_FILE_OPS(rx_queue);
|
||||
DEBUGFS_READ_FILE_OPS(tx_queue);
|
||||
DEBUGFS_WRITE_FILE_OPS(csr);
|
||||
DEBUGFS_READ_WRITE_FILE_OPS(rfkill);
|
||||
|
||||
/* Create the debugfs files and directories */
|
||||
int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans)
|
||||
@@ -2477,6 +2522,7 @@ int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans)
|
||||
DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(csr, dir, S_IWUSR);
|
||||
DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR);
|
||||
DEBUGFS_ADD_FILE(rfkill, dir, S_IWUSR | S_IRUSR);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
@@ -2965,6 +3011,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
|
||||
trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
trans_pcie->trans = trans;
|
||||
trans_pcie->opmode_down = true;
|
||||
spin_lock_init(&trans_pcie->irq_lock);
|
||||
spin_lock_init(&trans_pcie->reg_lock);
|
||||
mutex_init(&trans_pcie->mutex);
|
||||
@@ -3087,6 +3134,17 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 9000-series integrated A-step has a problem with suspend/resume
|
||||
* and sometimes even causes the whole platform to get stuck. This
|
||||
* workaround makes the hardware not go into the problematic state.
|
||||
*/
|
||||
if (trans->cfg->integrated &&
|
||||
trans->cfg->device_family == IWL_DEVICE_FAMILY_9000 &&
|
||||
CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP)
|
||||
iwl_set_bit(trans, CSR_HOST_CHICKEN,
|
||||
CSR_HOST_CHICKEN_PM_IDLE_SRC_DIS_SB_PME);
|
||||
|
||||
trans->hw_rf_id = iwl_read32(trans, CSR_HW_RF_ID);
|
||||
|
||||
iwl_pcie_set_interrupt_capa(pdev, trans);
|
||||
|
@@ -249,7 +249,7 @@ static int iwl_pcie_gen2_build_amsdu(struct iwl_trans *trans,
|
||||
IEEE80211_CCMP_HDR_LEN : 0;
|
||||
|
||||
trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd),
|
||||
&dev_cmd->hdr, start_len, NULL, 0);
|
||||
&dev_cmd->hdr, start_len, 0);
|
||||
|
||||
ip_hdrlen = skb_transport_header(skb) - skb_network_header(skb);
|
||||
snap_ip_tcp_hdrlen = 8 + ip_hdrlen + tcp_hdrlen(skb);
|
||||
@@ -467,10 +467,8 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans,
|
||||
}
|
||||
|
||||
trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd), &dev_cmd->hdr,
|
||||
IWL_FIRST_TB_SIZE + tb1_len,
|
||||
skb->data + hdr_len, tb2_len);
|
||||
trace_iwlwifi_dev_tx_data(trans->dev, skb, hdr_len,
|
||||
skb->len - hdr_len);
|
||||
IWL_FIRST_TB_SIZE + tb1_len, hdr_len);
|
||||
trace_iwlwifi_dev_tx_data(trans->dev, skb, hdr_len);
|
||||
|
||||
return tfd;
|
||||
|
||||
@@ -863,7 +861,7 @@ static int iwl_pcie_gen2_send_hcmd_sync(struct iwl_trans *trans,
|
||||
}
|
||||
|
||||
if (!(cmd->flags & CMD_SEND_IN_RFKILL) &&
|
||||
test_bit(STATUS_RFKILL, &trans->status)) {
|
||||
test_bit(STATUS_RFKILL_OPMODE, &trans->status)) {
|
||||
IWL_DEBUG_RF_KILL(trans, "RFKILL in SYNC CMD... no rsp\n");
|
||||
ret = -ERFKILL;
|
||||
goto cancel;
|
||||
@@ -900,7 +898,7 @@ int iwl_trans_pcie_gen2_send_hcmd(struct iwl_trans *trans,
|
||||
struct iwl_host_cmd *cmd)
|
||||
{
|
||||
if (!(cmd->flags & CMD_SEND_IN_RFKILL) &&
|
||||
test_bit(STATUS_RFKILL, &trans->status)) {
|
||||
test_bit(STATUS_RFKILL_OPMODE, &trans->status)) {
|
||||
IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n",
|
||||
cmd->id);
|
||||
return -ERFKILL;
|
||||
@@ -1076,7 +1074,7 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans,
|
||||
rsp = (void *)hcmd.resp_pkt->data;
|
||||
qid = le16_to_cpu(rsp->queue_number);
|
||||
|
||||
if (qid > ARRAY_SIZE(trans_pcie->txq)) {
|
||||
if (qid >= ARRAY_SIZE(trans_pcie->txq)) {
|
||||
WARN_ONCE(1, "queue index %d unsupported", qid);
|
||||
ret = -EIO;
|
||||
goto error_free_resp;
|
||||
|
@@ -1277,13 +1277,14 @@ static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid,
|
||||
* combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
|
||||
#define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid))
|
||||
|
||||
void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
|
||||
bool iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
|
||||
const struct iwl_trans_txq_scd_cfg *cfg,
|
||||
unsigned int wdg_timeout)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_txq *txq = trans_pcie->txq[txq_id];
|
||||
int fifo = -1;
|
||||
bool scd_bug = false;
|
||||
|
||||
if (test_and_set_bit(txq_id, trans_pcie->queue_used))
|
||||
WARN_ONCE(1, "queue %d already used - expect issues", txq_id);
|
||||
@@ -1324,6 +1325,23 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
|
||||
|
||||
ssn = txq->read_ptr;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* If we need to move the SCD write pointer by steps of
|
||||
* 0x40, 0x80 or 0xc0, it gets stuck. Avoids this and let
|
||||
* the op_mode know by returning true later.
|
||||
* Do this only in case cfg is NULL since this trick can
|
||||
* be done only if we have DQA enabled which is true for mvm
|
||||
* only. And mvm never sets a cfg pointer.
|
||||
* This is really ugly, but this is the easiest way out for
|
||||
* this sad hardware issue.
|
||||
* This bug has been fixed on devices 9000 and up.
|
||||
*/
|
||||
scd_bug = !trans->cfg->mq_rx_supported &&
|
||||
!((ssn - txq->write_ptr) & 0x3f) &&
|
||||
(ssn != txq->write_ptr);
|
||||
if (scd_bug)
|
||||
ssn++;
|
||||
}
|
||||
|
||||
/* Place first TFD at index corresponding to start sequence number.
|
||||
@@ -1344,10 +1362,8 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
|
||||
iwl_trans_write_mem32(trans,
|
||||
trans_pcie->scd_base_addr +
|
||||
SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
|
||||
((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
|
||||
SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
|
||||
((frame_limit << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
|
||||
SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
|
||||
SCD_QUEUE_CTX_REG2_VAL(WIN_SIZE, frame_limit) |
|
||||
SCD_QUEUE_CTX_REG2_VAL(FRAME_LIMIT, frame_limit));
|
||||
|
||||
/* Set up status area in SRAM, map to Tx DMA/FIFO, activate */
|
||||
iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
|
||||
@@ -1369,6 +1385,8 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
|
||||
"Activate queue %d WrPtr: %d\n",
|
||||
txq_id, ssn & 0xff);
|
||||
}
|
||||
|
||||
return scd_bug;
|
||||
}
|
||||
|
||||
void iwl_trans_pcie_txq_set_shared_mode(struct iwl_trans *trans, u32 txq_id,
|
||||
@@ -1708,7 +1726,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
|
||||
{
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
u16 sequence = le16_to_cpu(pkt->hdr.sequence);
|
||||
u8 group_id = iwl_cmd_groupid(pkt->hdr.group_id);
|
||||
u8 group_id;
|
||||
u32 cmd_id;
|
||||
int txq_id = SEQ_TO_QUEUE(sequence);
|
||||
int index = SEQ_TO_INDEX(sequence);
|
||||
@@ -1734,6 +1752,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
|
||||
cmd_index = get_cmd_index(txq, index);
|
||||
cmd = txq->entries[cmd_index].cmd;
|
||||
meta = &txq->entries[cmd_index].meta;
|
||||
group_id = cmd->hdr.group_id;
|
||||
cmd_id = iwl_cmd_id(cmd->hdr.cmd, group_id, 0);
|
||||
|
||||
iwl_pcie_tfd_unmap(trans, meta, txq, index);
|
||||
@@ -1876,7 +1895,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
|
||||
}
|
||||
|
||||
if (!(cmd->flags & CMD_SEND_IN_RFKILL) &&
|
||||
test_bit(STATUS_RFKILL, &trans->status)) {
|
||||
test_bit(STATUS_RFKILL_OPMODE, &trans->status)) {
|
||||
IWL_DEBUG_RF_KILL(trans, "RFKILL in SYNC CMD... no rsp\n");
|
||||
ret = -ERFKILL;
|
||||
goto cancel;
|
||||
@@ -1913,7 +1932,7 @@ cancel:
|
||||
int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
|
||||
{
|
||||
if (!(cmd->flags & CMD_SEND_IN_RFKILL) &&
|
||||
test_bit(STATUS_RFKILL, &trans->status)) {
|
||||
test_bit(STATUS_RFKILL_OPMODE, &trans->status)) {
|
||||
IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n",
|
||||
cmd->id);
|
||||
return -ERFKILL;
|
||||
@@ -1980,9 +1999,8 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb,
|
||||
iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr),
|
||||
trans_pcie->tfd_size,
|
||||
&dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len,
|
||||
skb->data + hdr_len, tb2_len);
|
||||
trace_iwlwifi_dev_tx_data(trans->dev, skb,
|
||||
hdr_len, skb->len - hdr_len);
|
||||
hdr_len);
|
||||
trace_iwlwifi_dev_tx_data(trans->dev, skb, hdr_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2054,8 +2072,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
|
||||
trace_iwlwifi_dev_tx(trans->dev, skb,
|
||||
iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr),
|
||||
trans_pcie->tfd_size,
|
||||
&dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len,
|
||||
NULL, 0);
|
||||
&dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, 0);
|
||||
|
||||
ip_hdrlen = skb_transport_header(skb) - skb_network_header(skb);
|
||||
snap_ip_tcp_hdrlen = 8 + ip_hdrlen + tcp_hdrlen(skb);
|
||||
|
Reference in New Issue
Block a user