Commit b90a1685 authored by Kalle Valo's avatar Kalle Valo

Merge tag 'iwlwifi-next-for-kalle-2017-06-28' of...

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;
parents 57c00f2f 6d759b02
......@@ -1513,7 +1513,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
out_free_eeprom_blob:
kfree(priv->eeprom_blob);
out_free_eeprom:
iwl_free_nvm_data(priv->nvm_data);
kfree(priv->nvm_data);
out_free_hw:
ieee80211_free_hw(priv->hw);
out:
......@@ -1532,7 +1532,7 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
iwl_tt_exit(priv);
kfree(priv->eeprom_blob);
iwl_free_nvm_data(priv->nvm_data);
kfree(priv->nvm_data);
/*netif_stop_queue(dev); */
flush_workqueue(priv->workqueue);
......
......@@ -74,7 +74,7 @@
#define IWL_A000_JF_FW_PRE "iwlwifi-Qu-a0-jf-b0-"
#define IWL_A000_HR_FW_PRE "iwlwifi-Qu-a0-hr-a0-"
#define IWL_A000_HR_CDB_FW_PRE "iwlwifi-QuIcp-a0-hrcdb-a0-"
#define IWL_A000_HR_CDB_FW_PRE "iwlwifi-QuIcp-z0-hrcdb-a0-"
#define IWL_A000_HR_MODULE_FIRMWARE(api) \
IWL_A000_HR_FW_PRE "-" __stringify(api) ".ucode"
......
......@@ -131,6 +131,7 @@ enum iwl_led_mode {
/* Antenna presence definitions */
#define ANT_NONE 0x0
#define ANT_INVALID 0xff
#define ANT_A BIT(0)
#define ANT_B BIT(1)
#define ANT_C BIT(2)
......
......@@ -153,6 +153,10 @@
/* GIO Chicken Bits (PCI Express bus link power management) */
#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100)
/* host chicken bits */
#define CSR_HOST_CHICKEN (CSR_BASE + 0x204)
#define CSR_HOST_CHICKEN_PM_IDLE_SRC_DIS_SB_PME BIT(19)
/* Analog phase-lock-loop configuration */
#define CSR_ANA_PLL_CFG (CSR_BASE+0x20c)
......
......@@ -35,19 +35,20 @@
TRACE_EVENT(iwlwifi_dev_tx_data,
TP_PROTO(const struct device *dev,
struct sk_buff *skb,
u8 hdr_len, size_t data_len),
TP_ARGS(dev, skb, hdr_len, data_len),
struct sk_buff *skb, u8 hdr_len),
TP_ARGS(dev, skb, hdr_len),
TP_STRUCT__entry(
DEV_ENTRY
__dynamic_array(u8, data, iwl_trace_data(skb) ? data_len : 0)
__dynamic_array(u8, data,
iwl_trace_data(skb) ? skb->len - hdr_len : 0)
),
TP_fast_assign(
DEV_ASSIGN;
if (iwl_trace_data(skb))
skb_copy_bits(skb, hdr_len,
__get_dynamic_array(data), data_len);
__get_dynamic_array(data),
skb->len - hdr_len);
),
TP_printk("[%s] TX frame data", __get_str(dev))
);
......
......@@ -2,7 +2,7 @@
*
* Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
......@@ -91,8 +91,8 @@ TRACE_EVENT(iwlwifi_dev_tx,
TP_PROTO(const struct device *dev, struct sk_buff *skb,
void *tfd, size_t tfdlen,
void *buf0, size_t buf0_len,
void *buf1, size_t buf1_len),
TP_ARGS(dev, skb, tfd, tfdlen, buf0, buf0_len, buf1, buf1_len),
int hdr_len),
TP_ARGS(dev, skb, tfd, tfdlen, buf0, buf0_len, hdr_len),
TP_STRUCT__entry(
DEV_ENTRY
......@@ -105,15 +105,20 @@ TRACE_EVENT(iwlwifi_dev_tx,
* for the possible padding).
*/
__dynamic_array(u8, buf0, buf0_len)
__dynamic_array(u8, buf1, iwl_trace_data(skb) ? 0 : buf1_len)
__dynamic_array(u8, buf1, hdr_len > 0 && iwl_trace_data(skb) ?
0 : skb->len - hdr_len)
),
TP_fast_assign(
DEV_ASSIGN;
__entry->framelen = buf0_len + buf1_len;
__entry->framelen = buf0_len;
if (hdr_len > 0)
__entry->framelen += skb->len - hdr_len;
memcpy(__get_dynamic_array(tfd), tfd, tfdlen);
memcpy(__get_dynamic_array(buf0), buf0, buf0_len);
if (!iwl_trace_data(skb))
memcpy(__get_dynamic_array(buf1), buf1, buf1_len);
if (hdr_len > 0 && !iwl_trace_data(skb))
skb_copy_bits(skb, hdr_len,
__get_dynamic_array(buf1),
skb->len - hdr_len);
),
TP_printk("[%s] TX %.2x (%zu bytes)",
__get_str(dev), ((u8 *)__get_dynamic_array(buf0))[0],
......
......@@ -121,15 +121,6 @@ struct iwl_nvm_data *
iwl_parse_eeprom_data(struct device *dev, const struct iwl_cfg *cfg,
const u8 *eeprom, size_t eeprom_size);
/**
* iwl_free_nvm_data - free NVM data
* @data: the data to free
*/
static inline void iwl_free_nvm_data(struct iwl_nvm_data *data)
{
kfree(data);
}
int iwl_nvm_check_version(struct iwl_nvm_data *data,
struct iwl_trans *trans);
......
......@@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2015 - 2016 Intel Deutschland GmbH
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
......@@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2015 - 2016 Intel Deutschland GmbH
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -66,6 +66,7 @@
#define __iwl_fh_h__
#include <linux/types.h>
#include <linux/bitfield.h>
/****************************/
/* Flow Handler Definitions */
......@@ -478,13 +479,12 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans,
#define RFH_GEN_CFG 0xA09800
#define RFH_GEN_CFG_SERVICE_DMA_SNOOP BIT(0)
#define RFH_GEN_CFG_RFH_DMA_SNOOP BIT(1)
#define RFH_GEN_CFG_RB_CHUNK_SIZE_POS 4
#define RFH_GEN_CFG_RB_CHUNK_SIZE BIT(4)
#define RFH_GEN_CFG_RB_CHUNK_SIZE_128 1
#define RFH_GEN_CFG_RB_CHUNK_SIZE_64 0
#define RFH_GEN_CFG_DEFAULT_RXQ_NUM_MASK 0xF00
#define RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS 8
#define DEFAULT_RXQ_NUM 0
/* the driver assumes everywhere that the default RXQ is 0 */
#define RFH_GEN_CFG_DEFAULT_RXQ_NUM 0xF00
#define RFH_GEN_CFG_VAL(_n, _v) FIELD_PREP(RFH_GEN_CFG_ ## _n, _v)
/* end of 9000 rx series registers */
......@@ -655,6 +655,17 @@ static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr)
{
return (sizeof(addr) > sizeof(u32) ? upper_32_bits(addr) : 0) & 0xF;
}
/**
* enum iwl_tfd_tb_hi_n_len - TB hi_n_len bits
* @TB_HI_N_LEN_ADDR_HI_MSK: high 4 bits (to make it 36) of DMA address
* @TB_HI_N_LEN_LEN_MSK: length of the TB
*/
enum iwl_tfd_tb_hi_n_len {
TB_HI_N_LEN_ADDR_HI_MSK = 0xf,
TB_HI_N_LEN_LEN_MSK = 0xfff0,
};
/**
* struct iwl_tfd_tb transmit buffer descriptor within transmit frame descriptor
*
......@@ -662,8 +673,7 @@ static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr)
*
* @lo: low [31:0] portion of the dma address of TX buffer
* every even is unaligned on 16 bit boundary
* @hi_n_len 0-3 [35:32] portion of dma
* 4-15 length of the tx buffer
* @hi_n_len: &enum iwl_tfd_tb_hi_n_len
*/
struct iwl_tfd_tb {
__le32 lo;
......
......@@ -353,6 +353,7 @@ enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_STA_PM_NOTIF = (__force iwl_ucode_tlv_capa_t)38,
IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT = (__force iwl_ucode_tlv_capa_t)39,
IWL_UCODE_TLV_CAPA_CDB_SUPPORT = (__force iwl_ucode_tlv_capa_t)40,
IWL_UCODE_TLV_CAPA_D0I3_END_FIRST = (__force iwl_ucode_tlv_capa_t)41,
IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64,
IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = (__force iwl_ucode_tlv_capa_t)65,
IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT = (__force iwl_ucode_tlv_capa_t)67,
......
......@@ -640,6 +640,8 @@ static int iwl_set_hw_address(struct iwl_trans *trans,
return -EINVAL;
}
IWL_INFO(trans, "base HW address: %pM\n", data->hw_addr);
return 0;
}
......
......@@ -66,6 +66,7 @@
#ifndef __iwl_prph_h__
#define __iwl_prph_h__
#include <linux/bitfield.h>
/*
* Registers in this file are internal, not PCI bus memory mapped.
......@@ -247,14 +248,14 @@
#define SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (19)
#define SCD_QUEUE_STTS_REG_MSK (0x017F0000)
#define SCD_QUEUE_CTX_REG1_CREDIT_POS (8)
#define SCD_QUEUE_CTX_REG1_CREDIT_MSK (0x00FFFF00)
#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS (24)
#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK (0xFF000000)
#define SCD_QUEUE_CTX_REG2_WIN_SIZE_POS (0)
#define SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK (0x0000007F)
#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16)
#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000)
#define SCD_QUEUE_CTX_REG1_CREDIT (0x00FFFF00)
#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT (0xFF000000)
#define SCD_QUEUE_CTX_REG1_VAL(_n, _v) FIELD_PREP(SCD_QUEUE_CTX_REG1_ ## _n, _v)
#define SCD_QUEUE_CTX_REG2_WIN_SIZE (0x0000007F)
#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT (0x007F0000)
#define SCD_QUEUE_CTX_REG2_VAL(_n, _v) FIELD_PREP(SCD_QUEUE_CTX_REG2_ ## _n, _v)
#define SCD_GP_CTRL_ENABLE_31_QUEUES BIT(0)
#define SCD_GP_CTRL_AUTO_ACTIVE_MODE BIT(18)
......
......@@ -117,7 +117,7 @@ int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
int ret;
if (unlikely(!(cmd->flags & CMD_SEND_IN_RFKILL) &&
test_bit(STATUS_RFKILL, &trans->status)))
test_bit(STATUS_RFKILL_OPMODE, &trans->status)))
return -ERFKILL;
if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status)))
......@@ -143,6 +143,9 @@ int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
if (!(cmd->flags & CMD_ASYNC))
lock_map_release(&trans->sync_cmd_lockdep_map);
if (WARN_ON((cmd->flags & CMD_WANT_SKB) && !ret && !cmd->resp_pkt))
return -EIO;
return ret;
}
IWL_EXPORT_SYMBOL(iwl_trans_send_cmd);
......
......@@ -322,7 +322,8 @@ enum iwl_d3_status {
* @STATUS_DEVICE_ENABLED: APM is enabled
* @STATUS_TPOWER_PMI: the device might be asleep (need to wake it up)
* @STATUS_INT_ENABLED: interrupts are enabled
* @STATUS_RFKILL: the HW RFkill switch is in KILL position
* @STATUS_RFKILL_HW: the actual HW state of the RF-kill switch
* @STATUS_RFKILL_OPMODE: RF-kill state reported to opmode
* @STATUS_FW_ERROR: the fw is in error state
* @STATUS_TRANS_GOING_IDLE: shutting down the trans, only special commands
* are sent
......@@ -334,7 +335,8 @@ enum iwl_trans_status {
STATUS_DEVICE_ENABLED,
STATUS_TPOWER_PMI,
STATUS_INT_ENABLED,
STATUS_RFKILL,
STATUS_RFKILL_HW,
STATUS_RFKILL_OPMODE,
STATUS_FW_ERROR,
STATUS_TRANS_GOING_IDLE,
STATUS_TRANS_IDLE,
......@@ -480,7 +482,9 @@ struct iwl_trans_txq_scd_cfg {
* iwl_trans_ac_txq_enable wrapper. fw_alive must have been called before
* this one. The op_mode must not configure the HCMD queue. The scheduler
* configuration may be %NULL, in which case the hardware will not be
* configured. May sleep.
* configured. If true is returned, the operation mode needs to increment
* the sequence number of the packets routed to this queue because of a
* hardware scheduler bug. May sleep.
* @txq_disable: de-configure a Tx queue to send AMPDUs
* Must be atomic
* @txq_set_shared_mode: change Tx queue shared/unshared marking
......@@ -542,7 +546,7 @@ struct iwl_trans_ops {
void (*reclaim)(struct iwl_trans *trans, int queue, int ssn,
struct sk_buff_head *skbs);
void (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn,
bool (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn,
const struct iwl_trans_txq_scd_cfg *cfg,
unsigned int queue_wdg_timeout);
void (*txq_disable)(struct iwl_trans *trans, int queue,
......@@ -950,7 +954,7 @@ static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue,
trans->ops->txq_disable(trans, queue, configure_scd);
}
static inline void
static inline bool
iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn,
const struct iwl_trans_txq_scd_cfg *cfg,
unsigned int queue_wdg_timeout)
......@@ -959,10 +963,11 @@ iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn,
if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
return;
return false;
}
trans->ops->txq_enable(trans, queue, ssn, cfg, queue_wdg_timeout);
return trans->ops->txq_enable(trans, queue, ssn,
cfg, queue_wdg_timeout);
}
static inline void
......
......@@ -7,7 +7,7 @@
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
......@@ -34,7 +34,7 @@
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -1795,12 +1795,6 @@ iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
return ERR_PTR(ret);
}
/* RF-kill already asserted again... */
if (!cmd.resp_pkt) {
fw_status = ERR_PTR(-ERFKILL);
goto out_free_resp;
}
status_size = sizeof(*fw_status);
len = iwl_rx_packet_payload_len(cmd.resp_pkt);
......@@ -1925,12 +1919,6 @@ iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm,
return ret;
}
/* RF-kill already asserted again... */
if (!cmd.resp_pkt) {
ret = -ERFKILL;
goto out_free_resp;
}
len = iwl_rx_packet_payload_len(cmd.resp_pkt);
if (len < sizeof(*query)) {
IWL_ERR(mvm, "Invalid scan offload profiles query response!\n");
......@@ -2087,9 +2075,8 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
bool keep = false;
bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE |
CMD_WAKE_UP_TRANS;
bool d0i3_first = fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_D0I3_END_FIRST);
mutex_lock(&mvm->mutex);
......@@ -2110,6 +2097,15 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
/* query SRAM first in case we want event logging */
iwl_mvm_read_d3_sram(mvm);
if (d0i3_first) {
ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, 0, 0, NULL);
if (ret < 0) {
IWL_ERR(mvm, "Failed to send D0I3_END_CMD first (%d)\n",
ret);
goto err;
}
}
/*
* Query the current location and source from the D3 firmware so we
* can play it back when we re-intiailize the D0 firmware
......@@ -2155,9 +2151,14 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
iwl_mvm_d3_disconnect_iter, keep ? vif : NULL);
out:
/* no need to reset the device in unified images, if successful */
if (unified_image && !ret) {
ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, flags, 0, NULL);
if (!ret) /* D3 ended successfully - no need to reset device */
/* nothing else to do if we already sent D0I3_END_CMD */
if (d0i3_first)
return 0;
ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, 0, 0, NULL);
if (!ret)
return 0;
}
......
......@@ -7,7 +7,7 @@
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
......@@ -34,7 +34,7 @@
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -1304,11 +1304,11 @@ static ssize_t iwl_dbgfs_low_latency_read(struct file *file,
char buf[30] = {};
int len;
len = snprintf(buf, sizeof(buf) - 1,
"traffic=%d\ndbgfs=%d\nvcmd=%d\n",
mvmvif->low_latency_traffic,
mvmvif->low_latency_dbgfs,
mvmvif->low_latency_vcmd);
len = scnprintf(buf, sizeof(buf) - 1,
"traffic=%d\ndbgfs=%d\nvcmd=%d\n",
mvmvif->low_latency_traffic,
mvmvif->low_latency_dbgfs,
mvmvif->low_latency_vcmd);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
......@@ -1385,10 +1385,12 @@ static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file,
struct ieee80211_vif *vif = file->private_data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
char buf[8];
int len;
snprintf(buf, sizeof(buf), "0x%04x\n", mvmvif->mvm->dbgfs_rx_phyinfo);
len = scnprintf(buf, sizeof(buf), "0x%04x\n",
mvmvif->mvm->dbgfs_rx_phyinfo);
return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf));
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static void iwl_dbgfs_quota_check(void *data, u8 *mac,
......@@ -1439,7 +1441,7 @@ static ssize_t iwl_dbgfs_quota_min_read(struct file *file,
char buf[10];
int len;
len = snprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min);
len = scnprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
......
......@@ -119,19 +119,30 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf,
size_t count, loff_t *ppos)
{
int ret;
u32 scd_q_msk;
u32 flush_arg;
if (!iwl_mvm_firmware_running(mvm) ||
mvm->cur_ucode != IWL_UCODE_REGULAR)
return -EIO;
if (sscanf(buf, "%x", &scd_q_msk) != 1)
if (kstrtou32(buf, 0, &flush_arg))
return -EINVAL;
IWL_ERR(mvm, "FLUSHING queues: scd_q_msk = 0x%x\n", scd_q_msk);
if (iwl_mvm_has_new_tx_api(mvm)) {
IWL_DEBUG_TX_QUEUES(mvm,
"FLUSHING all tids queues on sta_id = %d\n",
flush_arg);
mutex_lock(&mvm->mutex);
ret = iwl_mvm_flush_sta_tids(mvm, flush_arg, 0xFF, 0) ? : count;
mutex_unlock(&mvm->mutex);
return ret;
}
IWL_DEBUG_TX_QUEUES(mvm, "FLUSHING queues mask to flush = 0x%x\n",
flush_arg);
mutex_lock(&mvm->mutex);
ret = iwl_mvm_flush_tx_path(mvm, scd_q_msk, 0) ? : count;
ret = iwl_mvm_flush_tx_path(mvm, flush_arg, 0) ? : count;
mutex_unlock(&mvm->mutex);
return ret;
......
......@@ -199,6 +199,7 @@ struct iwl_mac_data_ibss {
* @dtim_reciprocal: 2^32 / dtim_interval , applicable only when associated
* @listen_interval: in beacon intervals, applicable only when associated
* @assoc_id: unique ID assigned by the AP during association
* @assoc_beacon_arrive_time: TSF of first beacon after association
*/
struct iwl_mac_data_sta {
__le32 is_assoc;
......
......@@ -769,7 +769,7 @@ struct iwl_scan_offload_profiles_query {
* @last_channel: last channel that was scanned
* @start_tsf: TSF timer in usecs of the scan start time for the mac specified
* in &struct iwl_scan_req_umac.
* @results: array of scan results, only "scanned_channels" of them are valid
* @results: array of scan results, length in @scanned_channels
*/
struct iwl_umac_scan_iter_complete_notif {
__le32 uid;
......
......@@ -488,7 +488,7 @@ enum iwl_tx_agg_status {
/**
* struct agg_tx_status - per packet TX aggregation status
* @status: enum iwl_tx_agg_status
* @status: See &enum iwl_tx_agg_status
* @sequence: Sequence # for this frame's Tx cmd (not SSN!)
*/
struct agg_tx_status {
......@@ -513,7 +513,7 @@ struct agg_tx_status {
#define IWL_MVM_TX_RES_GET_RA(_ra_tid) ((_ra_tid) >> 4)
/**
* struct iwl_mvm_tx_resp - notifies that fw is TXing a packet
* struct iwl_mvm_tx_resp_v3 - notifies that fw is TXing a packet
* ( REPLY_TX = 0x1c )
* @frame_count: 1 no aggregation, >1 aggregation
* @bt_kill_count: num of times blocked by bluetooth (unused for agg)
......@@ -540,7 +540,63 @@ struct agg_tx_status {
* @tx_queue: TX queue for this response
* @status: for non-agg: frame status TX_STATUS_*
* for agg: status of 1st frame, AGG_TX_STATE_*; other frame status fields
* follow this one, up to frame_count.
* follow this one, up to frame_count. Length in @frame_count.
*
* After the array of statuses comes the SSN of the SCD. Look at
* %iwl_mvm_get_scd_ssn for more details.
*/
struct iwl_mvm_tx_resp_v3 {
u8 frame_count;
u8 bt_kill_count;
u8 failure_rts;
u8 failure_frame;
__le32 initial_rate;
__le16 wireless_media_time;
u8 pa_status;
u8 pa_integ_res_a[3];
u8 pa_integ_res_b[3];
u8 pa_integ_res_c[3];
__le16 measurement_req_id;
u8 reduced_tpc;
u8 reserved;
__le32 tfd_info;
__le16 seq_ctl;
__le16 byte_cnt;
u8 tlc_info;
u8 ra_tid;
__le16 frame_ctrl;
struct agg_tx_status status[];
} __packed; /* TX_RSP_API_S_VER_3 */
/**
* struct iwl_mvm_tx_resp - notifies that fw is TXing a packet
* ( REPLY_TX = 0x1c )
* @frame_count: 1 no aggregation, >1 aggregation
* @bt_kill_count: num of times blocked by bluetooth (unused for agg)
* @failure_rts: num of failures due to unsuccessful RTS
* @failure_frame: num failures due to no ACK (unused for agg)
* @initial_rate: for non-agg: rate of the successful Tx. For agg: rate of the
* Tx of all the batch. RATE_MCS_*
* @wireless_media_time: for non-agg: RTS + CTS + frame tx attempts time + ACK.
* for agg: RTS + CTS + aggregation tx time + block-ack time.
* in usec.
* @pa_status: tx power info
* @pa_integ_res_a: tx power info
* @pa_integ_res_b: tx power info
* @pa_integ_res_c: tx power info
* @measurement_req_id: tx power info
* @reduced_tpc: transmit power reduction used
* @reserved: reserved
* @tfd_info: TFD information set by the FH
* @seq_ctl: sequence control from the Tx cmd
* @byte_cnt: byte count from the Tx cmd
* @tlc_info: TLC rate info
* @ra_tid: bits [3:0] = ra, bits [7:4] = tid
* @frame_ctrl: frame control
* @tx_queue: TX queue for this response
* @status: for non-agg: frame status TX_STATUS_*
* For version 6 TX response isn't received for aggregation at all.
*
* After the array of statuses comes the SSN of the SCD. Look at
......@@ -568,16 +624,9 @@ struct iwl_mvm_tx_resp {
u8 tlc_info;
u8 ra_tid;
__le16 frame_ctrl;
union {
struct {
struct agg_tx_status status;
} v3;/* TX_RSP_API_S_VER_3 */
struct {
__le16 tx_queue;
__le16 reserved2;
struct agg_tx_status status;
} v6;
};
__le16 tx_queue;
__le16 reserved2;
struct agg_tx_status status;
} __packed; /* TX_RSP_API_S_VER_6 */
/**
......@@ -797,12 +846,24 @@ enum iwl_dump_control {
* @flush_ctl: control flags
* @reserved: reserved
*/
struct iwl_tx_path_flush_cmd {
struct iwl_tx_path_flush_cmd_v1 {
__le32 queues_ctl;
__le16 flush_ctl;
__le16 reserved;
} __packed; /* TX_PATH_FLUSH_CMD_API_S_VER_1 */
/**
* struct iwl_tx_path_flush_cmd -- queue/FIFO flush command
* @sta_id: station ID to flush
* @tid_mask: TID mask to flush
* @reserved: reserved
*/
struct iwl_tx_path_flush_cmd {
__le32 sta_id;
__le16 tid_mask;
__le16 reserved;
} __packed; /* TX_PATH_FLUSH_CMD_API_S_VER_2 */
/* Available options for the SCD_QUEUE_CFG HCMD */
enum iwl_scd_cfg_actions {
SCD_CFG_DISABLE_QUEUE = 0x0,
......
......@@ -216,7 +216,9 @@ enum iwl_legacy_cmds {
FW_GET_ITEM_CMD = 0x1a,
/**
* @TX_CMD: uses &struct iwl_tx_cmd or &struct iwl_tx_cmd_gen2
* @TX_CMD: uses &struct iwl_tx_cmd or &struct iwl_tx_cmd_gen2,
* response in &struct iwl_mvm_tx_resp or
* &struct iwl_mvm_tx_resp_v3
*/
TX_CMD = 0x1c,
......@@ -552,9 +554,26 @@ enum iwl_regulatory_and_nvm_subcmd_ids {
NVM_GET_INFO = 0x2,
};
/**
* enum iwl_debug_cmds - debug commands
*/
enum iwl_debug_cmds {
/**
* @LMAC_RD_WR:
* LMAC memory read/write, using &struct iwl_dbg_mem_access_cmd and
* &struct iwl_dbg_mem_access_rsp
*/
LMAC_RD_WR = 0x0,
/**
* @UMAC_RD_WR:
* UMAC memory read/write, using &struct iwl_dbg_mem_access_cmd and
* &struct iwl_dbg_mem_access_rsp
*/
UMAC_RD_WR = 0x1,
/**
* @MFU_ASSERT_DUMP_NTF:
* &struct iwl_mfu_assert_dump_notif
*/
MFU_ASSERT_DUMP_NTF = 0xFE,
};
......@@ -2111,7 +2130,7 @@ struct ct_kill_notif {
* enum ctdp_cmd_operation - CTDP command operations
* @CTDP_CMD_OPERATION_START: update the current budget
* @CTDP_CMD_OPERATION_STOP: stop ctdp
* @CTDP_CMD_OPERATION_REPORT: get the avgerage budget
* @CTDP_CMD_OPERATION_REPORT: get the average budget
*/
enum iwl_mvm_ctdp_cmd_operation {
CTDP_CMD_OPERATION_START = 0x1,
......
......@@ -319,10 +319,8 @@ static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm,
void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm)
{
if (mvm->fw_dump_desc == &iwl_mvm_dump_desc_assert)
return;
kfree(mvm->fw_dump_desc);
if (mvm->fw_dump_desc != &iwl_mvm_dump_desc_assert)
kfree(mvm->fw_dump_desc);
mvm->fw_dump_desc = NULL;
}
......@@ -915,6 +913,10 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,
if (trigger)
delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay));
if (WARN(mvm->trans->state == IWL_TRANS_NO_FW,
"Can't collect dbg data when FW isn't alive\n"))
return -EIO;
if (test_and_set_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status))
return -EBUSY;
......
......@@ -846,6 +846,8 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
cpu_to_le64(vif->bss_conf.sync_tsf + dtim_offs);
ctxt_sta->dtim_time =
cpu_to_le32(vif->bss_conf.sync_device_ts + dtim_offs);
ctxt_sta->assoc_beacon_arrive_time =
cpu_to_le32(vif->bss_conf.sync_device_ts);
IWL_DEBUG_INFO(mvm, "DTIM TBTT is 0x%llx/0x%x, offset %d\n",
le64_to_cpu(ctxt_sta->dtim_tsf),
......@@ -1457,6 +1459,7 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
beacon_notify_hdr = &beacon->beacon_notify_hdr;
mvm->ap_last_beacon_gp2 = le32_to_cpu(beacon->gp2);
mvm->ibss_manager = beacon->ibss_mgr_status != 0;
agg_status = iwl_mvm_get_agg_status(mvm, beacon_notify_hdr);
status = le16_to_cpu(agg_status->status) & TX_STATUS_MSK;
......
......@@ -1988,14 +1988,32 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
WARN_ONCE(iwl_mvm_sf_update(mvm, vif, false),
"Failed to update SF upon disassociation\n");
/* remove AP station now that the MAC is unassoc */
ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id);
if (ret)
IWL_ERR(mvm, "failed to remove AP station\n");
/*
* If we get an assert during the connection (after the
* station has been added, but before the vif is set
* to associated), mac80211 will re-add the station and
* then configure the vif. Since the vif is not
* associated, we would remove the station here and
* this would fail the recovery.
*/
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
&mvm->status)) {
/*
* Remove AP station now that
* the MAC is unassoc
*/
ret = iwl_mvm_rm_sta_id(mvm, vif,
mvmvif->ap_sta_id);
if (ret)
IWL_ERR(mvm,
"failed to remove AP station\n");
if (mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id)
mvm->d0i3_ap_sta_id =
IWL_MVM_INVALID_STA;
mvmvif->ap_sta_id = IWL_MVM_INVALID_STA;
}
if (mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id)
mvm->d0i3_ap_sta_id = IWL_MVM_INVALID_STA;
mvmvif->ap_sta_id = IWL_MVM_INVALID_STA;
/* remove quota for this interface */
ret = iwl_mvm_update_quotas(mvm, false, NULL);
if (ret)
......@@ -2395,7 +2413,7 @@ static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
__set_bit(tid_data->txq_id, &txqs);
if (iwl_mvm_tid_queued(tid_data) == 0)
if (iwl_mvm_tid_queued(mvm, tid_data) == 0)
continue;
__set_bit(tid, &tids);
......@@ -2883,7 +2901,8 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
if (!iwl_mvm_has_new_tx_api(mvm))
key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
......@@ -2929,8 +2948,13 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
ret = -EOPNOTSUPP;
else
ret = 0;
key->hw_key_idx = STA_KEY_IDX_INVALID;
break;
if (key->cipher != WLAN_CIPHER_SUITE_GCMP &&
key->cipher != WLAN_CIPHER_SUITE_GCMP_256 &&
!iwl_mvm_has_new_tx_api(mvm)) {
key->hw_key_idx = STA_KEY_IDX_INVALID;
break;
}
}
/* During FW restart, in order to restore the state as it was,
......@@ -3731,6 +3755,13 @@ static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw,
return ret;
}
static int iwl_mvm_tx_last_beacon(struct ieee80211_hw *hw)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
return mvm->ibss_manager;
}
static int iwl_mvm_set_tim(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
bool set)
......@@ -4264,11 +4295,13 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm,
goto out;
}
if (notif->sync)
if (notif->sync) {
ret = wait_event_timeout(mvm->rx_sync_waitq,
atomic_read(&mvm->queue_sync_counter) == 0,
atomic_read(&mvm->queue_sync_counter) == 0 ||
iwl_mvm_is_radio_killed(mvm),
HZ);
WARN_ON_ONCE(!ret);
WARN_ON_ONCE(!ret && !iwl_mvm_is_radio_killed(mvm));
}
out:
atomic_set(&mvm->queue_sync_counter, 0);
......@@ -4332,6 +4365,8 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {
.join_ibss = iwl_mvm_start_ap_ibss,
.leave_ibss = iwl_mvm_stop_ap_ibss,
.tx_last_beacon = iwl_mvm_tx_last_beacon,
.set_tim = iwl_mvm_set_tim,
.channel_switch = iwl_mvm_channel_switch,
......
......@@ -1021,6 +1021,9 @@ struct iwl_mvm {
/* system time of last beacon (for AP/GO interface) */
u32 ap_last_beacon_gp2;
/* indicates that we transmitted the last beacon */
bool ibss_manager;
bool lar_regdom_set;
enum iwl_mcc_source mcc_src;
......@@ -1078,6 +1081,18 @@ struct iwl_mvm {
#define IWL_MAC80211_GET_MVM(_hw) \
IWL_OP_MODE_GET_MVM((struct iwl_op_mode *)((_hw)->priv))
/**
* enum iwl_mvm_status - MVM status bits
* @IWL_MVM_STATUS_HW_RFKILL: HW RF-kill is asserted
* @IWL_MVM_STATUS_HW_CTKILL: CT-kill is active
* @IWL_MVM_STATUS_ROC_RUNNING: remain-on-channel is running
* @IWL_MVM_STATUS_IN_HW_RESTART: HW restart is active
* @IWL_MVM_STATUS_IN_D0I3: NIC is in D0i3
* @IWL_MVM_STATUS_ROC_AUX_RUNNING: AUX remain-on-channel is running
* @IWL_MVM_STATUS_D3_RECONFIG: D3 reconfiguration is being done
* @IWL_MVM_STATUS_DUMPING_FW_LOG: FW log is being dumped
* @IWL_MVM_STATUS_FIRMWARE_RUNNING: firmware is running
*/
enum iwl_mvm_status {
IWL_MVM_STATUS_HW_RFKILL,
IWL_MVM_STATUS_HW_CTKILL,
......@@ -1281,14 +1296,13 @@ static inline bool iwl_mvm_is_cdb_supported(struct iwl_mvm *mvm)
IWL_UCODE_TLV_CAPA_CDB_SUPPORT);
}
static inline struct agg_tx_status*
iwl_mvm_get_agg_status(struct iwl_mvm *mvm,
struct iwl_mvm_tx_resp *tx_resp)
static inline struct agg_tx_status *
iwl_mvm_get_agg_status(struct iwl_mvm *mvm, void *tx_resp)
{
if (iwl_mvm_has_new_tx_api(mvm))
return &tx_resp->v6.status;
return &((struct iwl_mvm_tx_resp *)tx_resp)->status;
else
return &tx_resp->v3.status;
return ((struct iwl_mvm_tx_resp_v3 *)tx_resp)->status;
}
static inline bool iwl_mvm_is_tt_in_fw(struct iwl_mvm *mvm)
......@@ -1370,7 +1384,9 @@ const char *iwl_mvm_get_tx_fail_reason(u32 status);
static inline const char *iwl_mvm_get_tx_fail_reason(u32 status) { return ""; }
#endif
int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, u32 flags);
int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool int_sta, u32 flags);
int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool internal, u32 flags);
int iwl_mvm_flush_sta_tids(struct iwl_mvm *mvm, u32 sta_id,
u16 tids, u32 flags);
void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm);
......@@ -1730,7 +1746,7 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif)
}
/* hw scheduler queue config */
void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg,
unsigned int wdg_timeout);
int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue,
......
......@@ -118,10 +118,6 @@ static int iwl_nvm_write_chunk(struct iwl_mvm *mvm, u16 section,
return ret;
pkt = cmd.resp_pkt;
if (!pkt) {
IWL_ERR(mvm, "Error in NVM_ACCESS response\n");
return -EINVAL;
}
/* Extract & check NVM write response */
nvm_resp = (void *)pkt->data;
if (le16_to_cpu(nvm_resp->status) != READ_NVM_CHUNK_SUCCEED) {
......@@ -600,9 +596,11 @@ int iwl_mvm_nvm_get_from_fw(struct iwl_mvm *mvm)
if (!is_valid_ether_addr(mvm->nvm_data->hw_addr)) {
IWL_ERR(trans, "no valid mac address was found\n");
ret = -EINVAL;
goto out;
goto err_free;
}
IWL_INFO(trans, "base HW address: %pM\n", mvm->nvm_data->hw_addr);
/* Initialize general data */
mvm->nvm_data->nvm_version = le16_to_cpu(rsp->general.nvm_version);
......@@ -632,7 +630,11 @@ int iwl_mvm_nvm_get_from_fw(struct iwl_mvm *mvm)
mvm->nvm_data->valid_rx_ant & mvm->fw->valid_rx_ant,
rsp->regulatory.lar_enabled && lar_fw_supported);
ret = 0;
iwl_free_resp(&hcmd);
return 0;
err_free:
kfree(mvm->nvm_data);
out:
iwl_free_resp(&hcmd);
return ret;
......@@ -783,6 +785,10 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
resp_len = sizeof(struct iwl_mcc_update_resp) +
n_channels * sizeof(__le32);
resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL);
if (!resp_cp) {
resp_cp = ERR_PTR(-ENOMEM);
goto exit;
}
} else {
struct iwl_mcc_update_resp_v1 *mcc_resp_v1 = (void *)pkt->data;
......@@ -790,21 +796,18 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
resp_len = sizeof(struct iwl_mcc_update_resp) +
n_channels * sizeof(__le32);
resp_cp = kzalloc(resp_len, GFP_KERNEL);
if (resp_cp) {
resp_cp->status = mcc_resp_v1->status;
resp_cp->mcc = mcc_resp_v1->mcc;
resp_cp->cap = mcc_resp_v1->cap;
resp_cp->source_id = mcc_resp_v1->source_id;
resp_cp->n_channels = mcc_resp_v1->n_channels;
memcpy(resp_cp->channels, mcc_resp_v1->channels,
n_channels * sizeof(__le32));
if (!resp_cp) {
resp_cp = ERR_PTR(-ENOMEM);
goto exit;
}
}
if (!resp_cp) {
ret = -ENOMEM;
goto exit;
resp_cp->status = mcc_resp_v1->status;
resp_cp->mcc = mcc_resp_v1->mcc;
resp_cp->cap = mcc_resp_v1->cap;
resp_cp->source_id = mcc_resp_v1->source_id;
resp_cp->n_channels = mcc_resp_v1->n_channels;
memcpy(resp_cp->channels, mcc_resp_v1->channels,
n_channels * sizeof(__le32));
}
status = le32_to_cpu(resp_cp->status);
......@@ -824,8 +827,6 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
exit:
iwl_free_resp(&cmd);
if (ret)
return ERR_PTR(ret);
return resp_cp;
}
......
......@@ -849,7 +849,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
iwl_phy_db_free(mvm->phy_db);
mvm->phy_db = NULL;
iwl_free_nvm_data(mvm->nvm_data);
kfree(mvm->nvm_data);
for (i = 0; i < NVM_MAX_NUM_SECTIONS; i++)
kfree(mvm->nvm_sections[i].data);
......@@ -1094,6 +1094,16 @@ static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int hw_queue)
iwl_mvm_start_mac_queues(mvm, mq);
}
static void iwl_mvm_set_rfkill_state(struct iwl_mvm *mvm)
{
bool state = iwl_mvm_is_radio_killed(mvm);
if (state)
wake_up(&mvm->rx_sync_waitq);
wiphy_rfkill_set_hw_state(mvm->hw->wiphy, state);
}
void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state)
{
if (state)
......@@ -1101,7 +1111,7 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state)
else
clear_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status);
wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm));
iwl_mvm_set_rfkill_state(mvm);
}
static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
......@@ -1114,7 +1124,7 @@ static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
else
clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status);
wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm));
iwl_mvm_set_rfkill_state(mvm);
/* iwl_run_init_mvm_ucode is waiting for results, abort it */
if (calibrating)
......@@ -1171,9 +1181,13 @@ static void iwl_mvm_fw_error_dump_wk(struct work_struct *work)
/* start recording again if the firmware is not crashed */
if (!test_bit(STATUS_FW_ERROR, &mvm->trans->status) &&
mvm->fw->dbg_dest_tlv)
mvm->fw->dbg_dest_tlv) {
iwl_clear_bits_prph(mvm->trans,
MON_BUFF_SAMPLE_CTL, 0x100);
iwl_clear_bits_prph(mvm->trans,
MON_BUFF_SAMPLE_CTL, 0x1);
iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x1);
}
} else {
u32 in_sample = iwl_read_prph(mvm->trans, DBGC_IN_SAMPLE);
u32 out_ctrl = iwl_read_prph(mvm->trans, DBGC_OUT_CTRL);
......@@ -1313,7 +1327,7 @@ static bool iwl_mvm_disallow_offloading(struct iwl_mvm *mvm,
* for offloading in order to prevent reuse of the same
* qos seq counters.
*/
if (iwl_mvm_tid_queued(tid_data))
if (iwl_mvm_tid_queued(mvm, tid_data))
continue;
if (tid_data->state != IWL_AGG_OFF)
......@@ -1463,9 +1477,15 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)
synchronize_net();
/* Flush the hw queues, in case something got queued during entry */
ret = iwl_mvm_flush_tx_path(mvm, iwl_mvm_flushable_queues(mvm), flags);
if (ret)
return ret;
/* TODO new tx api */
if (iwl_mvm_has_new_tx_api(mvm)) {
WARN_ONCE(1, "d0i3: Need to implement flush TX queue\n");
} else {
ret = iwl_mvm_flush_tx_path(mvm, iwl_mvm_flushable_queues(mvm),
flags);
if (ret)
return ret;
}
/* configure wowlan configuration only if needed */
if (mvm->d0i3_ap_sta_id != IWL_MVM_INVALID_STA) {
......@@ -1611,9 +1631,6 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk)
if (ret)
goto out;
if (!get_status_cmd.resp_pkt)
goto out;
status = (void *)get_status_cmd.resp_pkt->data;
wakeup_reasons = le32_to_cpu(status->wakeup_reasons);
qos_seq = status->qos_seq_ctr;
......
......@@ -2836,7 +2836,11 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
rs_get_initial_rate(mvm, sta, lq_sta, band, rate);
rs_init_optimal_rate(mvm, sta, lq_sta);
WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B);
WARN_ONCE(rate->ant != ANT_A && rate->ant != ANT_B,
"ant: 0x%x, chains 0x%x, fw tx ant: 0x%x, nvm tx ant: 0x%x\n",
rate->ant, lq_sta->pers.chains, mvm->fw->valid_tx_ant,
mvm->nvm_data ? mvm->nvm_data->valid_tx_ant : ANT_INVALID);
tbl->column = rs_get_column_from_rate(rate);
rs_set_expected_tpt_table(lq_sta, tbl);
......
......@@ -502,7 +502,7 @@ void iwl_mvm_reorder_timer_expired(unsigned long data)
buf->sta_id, sn);
iwl_mvm_release_frames(buf->mvm, sta, NULL, buf, sn);
rcu_read_unlock();
} else if (buf->num_stored) {
} else {
/*
* If no frame expired and there are stored frames, index is now
* pointing to the first unexpired frame - modify timer
......
......@@ -341,12 +341,6 @@ struct iwl_mvm_tid_data {
bool is_tid_active;
};
static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data)
{
return ieee80211_sn_sub(IEEE80211_SEQ_TO_SN(tid_data->seq_number),
tid_data->next_reclaimed);
}
struct iwl_mvm_key_pn {
struct rcu_head rcu_head;
struct {
......@@ -447,6 +441,8 @@ struct iwl_mvm_sta {
u8 avg_energy;
};
u16 iwl_mvm_tid_queued(struct iwl_mvm *mvm, struct iwl_mvm_tid_data *tid_data);
static inline struct iwl_mvm_sta *
iwl_mvm_sta_from_mac80211(struct ieee80211_sta *sta)
{
......
......@@ -473,7 +473,10 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
if (unlikely(!dev_cmd))
return NULL;
memset(dev_cmd, 0, sizeof(*dev_cmd));
/* Make sure we zero enough of dev_cmd */
BUILD_BUG_ON(sizeof(struct iwl_tx_cmd_gen2) > sizeof(*tx_cmd));
memset(dev_cmd, 0, sizeof(dev_cmd->hdr) + sizeof(*tx_cmd));
dev_cmd->hdr.cmd = TX_CMD;
if (iwl_mvm_has_new_tx_api(mvm)) {
......@@ -648,6 +651,9 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
info.control.vif->type == NL80211_IFTYPE_STATION &&
queue != mvm->aux_queue) {
queue = IWL_MVM_DQA_BSS_CLIENT_QUEUE;
} else if (iwl_mvm_is_dqa_supported(mvm) &&
info.control.vif->type == NL80211_IFTYPE_MONITOR) {
queue = mvm->aux_queue;
}
}
......@@ -1126,13 +1132,14 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
struct ieee80211_vif *vif = mvmsta->vif;
u16 normalized_ssn;
lockdep_assert_held(&mvmsta->lock);
if ((tid_data->state == IWL_AGG_ON ||
tid_data->state == IWL_EMPTYING_HW_QUEUE_DELBA ||
iwl_mvm_is_dqa_supported(mvm)) &&
iwl_mvm_tid_queued(tid_data) == 0) {
iwl_mvm_tid_queued(mvm, tid_data) == 0) {
/*
* Now that this aggregation or DQA queue is empty tell
* mac80211 so it knows we no longer have frames buffered for
......@@ -1141,7 +1148,15 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,
ieee80211_sta_set_buffered(sta, tid, false);
}
if (tid_data->ssn != tid_data->next_reclaimed)
/*
* In A000 HW, the next_reclaimed index is only 8 bit, so we'll need
* to align the wrap around of ssn so we compare relevant values.
*/
normalized_ssn = tid_data->ssn;
if (mvm->trans->cfg->gen2)
normalized_ssn &= 0xff;
if (normalized_ssn != tid_data->next_reclaimed)
return;
switch (tid_data->state) {
......@@ -1319,6 +1334,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
struct ieee80211_sta *sta;
u16 sequence = le16_to_cpu(pkt->hdr.sequence);
int txq_id = SEQ_TO_QUEUE(sequence);
/* struct iwl_mvm_tx_resp_v3 is almost the same */
struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data;
int sta_id = IWL_MVM_TX_RES_GET_RA(tx_resp->ra_tid);
int tid = IWL_MVM_TX_RES_GET_TID(tx_resp->ra_tid);
......@@ -1336,7 +1352,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
__skb_queue_head_init(&skbs);
if (iwl_mvm_has_new_tx_api(mvm))
txq_id = le16_to_cpu(tx_resp->v6.tx_queue);
txq_id = le16_to_cpu(tx_resp->tx_queue);
seq_ctl = le16_to_cpu(tx_resp->seq_ctl);
......@@ -1485,7 +1501,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
if (mvmsta->sleep_tx_count) {
mvmsta->sleep_tx_count--;
if (mvmsta->sleep_tx_count &&
!iwl_mvm_tid_queued(tid_data)) {
!iwl_mvm_tid_queued(mvm, tid_data)) {
/*
* The number of frames in the queue
* dropped to 0 even if we sent less
......@@ -1889,11 +1905,13 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, u32 flags)
{
int ret;
struct iwl_tx_path_flush_cmd flush_cmd = {
struct iwl_tx_path_flush_cmd_v1 flush_cmd = {
.queues_ctl = cpu_to_le32(tfd_msk),
.flush_ctl = cpu_to_le16(DUMP_TX_FIFO_FLUSH),
};
WARN_ON(iwl_mvm_has_new_tx_api(mvm));
ret = iwl_mvm_send_cmd_pdu(mvm, TXPATH_FLUSH, flags,
sizeof(flush_cmd), &flush_cmd);
if (ret)
......@@ -1901,19 +1919,41 @@ int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, u32 flags)
return ret;
}
int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool int_sta, u32 flags)
int iwl_mvm_flush_sta_tids(struct iwl_mvm *mvm, u32 sta_id,
u16 tids, u32 flags)
{
u32 mask;
int ret;
struct iwl_tx_path_flush_cmd flush_cmd = {
.sta_id = cpu_to_le32(sta_id),
.tid_mask = cpu_to_le16(tids),
};
if (int_sta) {
struct iwl_mvm_int_sta *int_sta = sta;
WARN_ON(!iwl_mvm_has_new_tx_api(mvm));
mask = int_sta->tfd_queue_msk;
} else {
struct iwl_mvm_sta *mvm_sta = sta;
ret = iwl_mvm_send_cmd_pdu(mvm, TXPATH_FLUSH, flags,
sizeof(flush_cmd), &flush_cmd);
if (ret)
IWL_ERR(mvm, "Failed to send flush command (%d)\n", ret);
return ret;
}
mask = mvm_sta->tfd_queue_msk;
int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool internal, u32 flags)
{
struct iwl_mvm_int_sta *int_sta = sta;
struct iwl_mvm_sta *mvm_sta = sta;
if (iwl_mvm_has_new_tx_api(mvm)) {
if (internal)
return iwl_mvm_flush_sta_tids(mvm, int_sta->sta_id,
BIT(IWL_MGMT_TID), flags);
return iwl_mvm_flush_sta_tids(mvm, mvm_sta->sta_id,
0xFF, flags);
}
return iwl_mvm_flush_tx_path(mvm, mask, flags);
if (internal)
return iwl_mvm_flush_tx_path(mvm, int_sta->tfd_queue_msk,
flags);
return iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, flags);
}
......@@ -69,6 +69,7 @@
#include "iwl-debug.h"
#include "iwl-io.h"
#include "iwl-prph.h"
#include "iwl-csr.h"
#include "fw-dbg.h"
#include "mvm.h"
#include "fw-api-rs.h"
......@@ -168,11 +169,6 @@ int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd,
}
pkt = cmd->resp_pkt;
/* Can happen if RFKILL is asserted */
if (!pkt) {
ret = 0;
goto out_free_resp;
}
resp_len = iwl_rx_packet_payload_len(pkt);
if (WARN_ON_ONCE(resp_len != sizeof(*resp))) {
......@@ -502,6 +498,7 @@ static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u32 base)
{
struct iwl_trans *trans = mvm->trans;
struct iwl_error_event_table table;
u32 val;
if (mvm->cur_ucode == IWL_UCODE_INIT) {
if (!base)
......@@ -520,6 +517,36 @@ static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u32 base)
return;
}
/* check if there is a HW error */
val = iwl_trans_read_mem32(trans, base);
if (((val & ~0xf) == 0xa5a5a5a0) || ((val & ~0xf) == 0x5a5a5a50)) {
int err;
IWL_ERR(trans, "HW error, resetting before reading\n");
/* reset the device */
iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
usleep_range(1000, 2000);
/* set INIT_DONE flag */
iwl_set_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
/* and wait for clock stabilization */
if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
udelay(2);
err = iwl_poll_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
25000);
if (err < 0) {
IWL_DEBUG_INFO(trans,
"Failed to reset the card for the dump\n");
return;
}
}
iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
......@@ -730,35 +757,39 @@ int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue,
return queue;
}
void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg,
unsigned int wdg_timeout)
{
struct iwl_scd_txq_cfg_cmd cmd = {
.scd_queue = queue,
.action = SCD_CFG_ENABLE_QUEUE,
.window = cfg->frame_limit,
.sta_id = cfg->sta_id,
.ssn = cpu_to_le16(ssn),
.tx_fifo = cfg->fifo,
.aggregate = cfg->aggregate,
.tid = cfg->tid,
};
bool inc_ssn;
if (WARN_ON(iwl_mvm_has_new_tx_api(mvm)))
return;
return false;
/* Send the enabling command if we need to */
if (iwl_mvm_update_txq_mapping(mvm, queue, mac80211_queue,
cfg->sta_id, cfg->tid)) {
struct iwl_scd_txq_cfg_cmd cmd = {
.scd_queue = queue,
.action = SCD_CFG_ENABLE_QUEUE,
.window = cfg->frame_limit,
.sta_id = cfg->sta_id,
.ssn = cpu_to_le16(ssn),
.tx_fifo = cfg->fifo,
.aggregate = cfg->aggregate,
.tid = cfg->tid,
};
iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, NULL,
wdg_timeout);
WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0,
sizeof(struct iwl_scd_txq_cfg_cmd),
&cmd),
"Failed to configure queue %d on FIFO %d\n", queue,
cfg->fifo);
}
if (!iwl_mvm_update_txq_mapping(mvm, queue, mac80211_queue,
cfg->sta_id, cfg->tid))
return false;
inc_ssn = iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn,
NULL, wdg_timeout);
if (inc_ssn)
le16_add_cpu(&cmd.ssn, 1);
WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd),
"Failed to configure queue %d on FIFO %d\n", queue, cfg->fifo);
return inc_ssn;
}
int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
......@@ -1186,7 +1217,11 @@ static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm,
/* Go over all non-active TIDs, incl. IWL_MAX_TID_COUNT (for mgmt) */
for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) {
/* If some TFDs are still queued - don't mark TID as inactive */
if (iwl_mvm_tid_queued(&mvmsta->tid_data[tid]))
if (iwl_mvm_tid_queued(mvm, &mvmsta->tid_data[tid]))
tid_bitmap &= ~BIT(tid);
/* Don't mark as inactive any TID that has an active BA */
if (mvmsta->tid_data[tid].state != IWL_AGG_OFF)
tid_bitmap &= ~BIT(tid);
}
......
......@@ -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);
}
......
......@@ -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 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment