blob: ed7dbb42f5fea7eb2209194d06de6c899f4480fa [file] [log] [blame]
/******************************************************************************
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
* Copyright(c) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
#ifndef SRC_CONNECTIVITY_WLAN_DRIVERS_THIRD_PARTY_INTEL_IWLWIFI_XVT_XVT_H_
#define SRC_CONNECTIVITY_WLAN_DRIVERS_THIRD_PARTY_INTEL_IWLWIFI_XVT_XVT_H_
#include <linux/if_ether.h>
#include <linux/spinlock.h>
#include "constants.h"
#include "fw-api.h"
#include "fw/img.h"
#include "fw/notif-wait.h"
#include "fw/runtime.h"
#include "iwl-config.h"
#include "iwl-drv.h"
#include "iwl-op-mode.h"
#include "iwl-trans.h"
enum iwl_xvt_state {
IWL_XVT_STATE_UNINITIALIZED = 0,
IWL_XVT_STATE_NO_FW,
IWL_XVT_STATE_INIT_STARTED,
IWL_XVT_STATE_OPERATIONAL,
};
#define IWL_XVT_LOAD_MASK_INIT BIT(0)
#define IWL_XVT_LOAD_MASK_RUNTIME BIT(1)
#define NUM_OF_LMACS (2)
#define IWL_XVT_DBG_FLAGS_NO_DEFAULT_TXQ (BIT(2))
#define IWL_XVT_MAX_PAYLOADS_AMOUNT (16)
#define IWL_MAX_BAID 32
#define IWL_XVT_INVALID_STA 0xFF
/**
* tx_meta_data - Holds data and member needed for tx
* @tx_mod_thread: thread dedicated for tx traffic
* @mod_tx_wq: send packets queue
* @tx_task_operating: whether tx is active
* @queue: FW queue ID for TX_CMD
* @tx_counter: counts number of sent packets
* @tot_tx: total number of packets required to sent
* @mod_tx_done_wq: queue to wait on until all packets are sent and received
* @txq_full: set to true when mod_tx_wq is full
* @seq_num: sequence number of qos frames (per-tid)
*/
struct tx_meta_data {
struct task_struct* tx_mod_thread;
wait_queue_head_t mod_tx_wq;
bool tx_task_operating;
int queue;
uint64_t tx_counter;
uint32_t tot_tx;
wait_queue_head_t mod_tx_done_wq;
bool txq_full;
uint16_t seq_num[IWL_MAX_TID_COUNT];
};
/*
* struct iwl_xvt_reorder_statistics - reorder buffer statistics
* @dropped: number of frames dropped (e.g. too old)
* @released: total number of frames released (either in-order or
* out of order (after passing the reorder buffer)
* @skipped: number of frames skipped the reorder buffer (in-order)
* @reordered: number of frames gone through the reorder buffer (unordered)
*/
struct iwl_xvt_reorder_statistics {
uint32_t dropped;
uint32_t released;
uint32_t skipped;
uint32_t reordered;
};
/**
* struct iwl_xvt_reorder_buffer - per ra/tid/queue reorder buffer
* @head_sn: reorder window head sn
* @num_stored: number of mpdus stored in the buffer
* @buf_size: the reorder buffer size as set by the last addba request
* @sta_id: sta id of this reorder buffer
* @tid: tid of this reorder buffer
* @queue: queue of this reorder buffer
* @last_amsdu: track last ASMDU SN for duplication detection
* @last_sub_index: track ASMDU sub frame index for duplication detection
* @entries: number of pending frames (for each index)
* @lock: protect reorder buffer internal state
* @stats: reorder buffer statistics
*/
struct iwl_xvt_reorder_buffer {
uint16_t head_sn;
uint16_t num_stored;
uint8_t buf_size;
uint8_t sta_id;
uint8_t tid;
int queue;
uint16_t last_amsdu;
uint8_t last_sub_index;
/*
* we don't care about the actual frames, only their count.
* avoid messing with reorder timer for that reason as well
*/
uint16_t entries[IEEE80211_MAX_AMPDU_BUF_HT];
spinlock_t lock; /* protect reorder buffer internal state */
struct iwl_xvt_reorder_statistics stats;
};
/**
* tx_queue_data - Holds tx data per tx queue
* @tx_wq: TX sw queue
* @tx_counter: Number of packets that were sent from this queue. Counts TX_RSP
* @txq_full: Set to true when tx_wq is full
* @allocated_queue: Whether queue is allocated
*/
struct tx_queue_data {
wait_queue_head_t tx_wq;
uint64_t tx_counter;
bool txq_full;
bool allocated_queue;
};
/**
* tx_payload - Holds tx payload
* @length: Payload length in bytes
* @payload: Payload buffer
*/
struct tx_payload {
uint16_t length;
uint8_t payload[];
};
/**
* iwl_sw_stack_config - Holds active SW stack config as set from user space
* @load_mask: Which FW are to be loaded during SW stack up
* @iwl_phy_cfg_cmd: Which calibrations should be done
*/
struct iwl_sw_stack_config {
uint32_t load_mask;
uint32_t calib_override_mask;
uint32_t fw_dbg_flags;
struct iwl_phy_cfg_cmd fw_calib_cmd_cfg[IWL_UCODE_TYPE_MAX];
};
/* Note: This structure is read from the device with IO accesses,
* and the reading already does the endian conversion. As it is
* read with uint32_t-sized accesses, any members with a different size
* need to be ordered correctly though!
*/
struct iwl_error_event_table_v1 {
uint32_t valid; /* (nonzero) valid, (0) log is empty */
uint32_t error_id; /* type of error */
uint32_t pc; /* program counter */
uint32_t blink1; /* branch link */
uint32_t blink2; /* branch link */
uint32_t ilink1; /* interrupt link */
uint32_t ilink2; /* interrupt link */
uint32_t data1; /* error-specific data */
uint32_t data2; /* error-specific data */
uint32_t data3; /* error-specific data */
uint32_t bcon_time; /* beacon timer */
uint32_t tsf_low; /* network timestamp function timer */
uint32_t tsf_hi; /* network timestamp function timer */
uint32_t gp1; /* GP1 timer register */
uint32_t gp2; /* GP2 timer register */
uint32_t gp3; /* GP3 timer register */
uint32_t ucode_ver; /* uCode version */
uint32_t hw_ver; /* HW Silicon version */
uint32_t brd_ver; /* HW board version */
uint32_t log_pc; /* log program counter */
uint32_t frame_ptr; /* frame pointer */
uint32_t stack_ptr; /* stack pointer */
uint32_t hcmd; /* last host command header */
uint32_t isr0; /* isr status register LMPM_NIC_ISR0:
* rxtx_flag
*/
uint32_t isr1; /* isr status register LMPM_NIC_ISR1:
* host_flag
*/
uint32_t isr2; /* isr status register LMPM_NIC_ISR2:
* enc_flag
*/
uint32_t isr3; /* isr status register LMPM_NIC_ISR3:
* time_flag
*/
uint32_t isr4; /* isr status register LMPM_NIC_ISR4:
* wico interrupt
*/
uint32_t isr_pref; /* isr status register LMPM_NIC_PREF_STAT */
uint32_t wait_event; /* wait event() caller address */
uint32_t l2p_control; /* L2pControlField */
uint32_t l2p_duration; /* L2pDurationField */
uint32_t l2p_mhvalid; /* L2pMhValidBits */
uint32_t l2p_addr_match; /* L2pAddrMatchStat */
uint32_t lmpm_pmg_sel; /* indicate which clocks are turned on
* (LMPM_PMG_SEL)
*/
uint32_t u_timestamp; /* indicate when the date and time of the
* compilation
*/
uint32_t flow_handler; /* FH read/write pointers, RX credit */
} __packed;
/* Note: This structure is read from the device with IO accesses,
* and the reading already does the endian conversion. As it is
* read with uint32_t-sized accesses, any members with a different size
* need to be ordered correctly though!
*/
struct iwl_error_event_table_v2 {
uint32_t valid; /* (nonzero) valid, (0) log is empty */
uint32_t error_id; /* type of error */
uint32_t trm_hw_status0; /* TRM HW status */
uint32_t trm_hw_status1; /* TRM HW status */
uint32_t blink2; /* branch link */
uint32_t ilink1; /* interrupt link */
uint32_t ilink2; /* interrupt link */
uint32_t data1; /* error-specific data */
uint32_t data2; /* error-specific data */
uint32_t data3; /* error-specific data */
uint32_t bcon_time; /* beacon timer */
uint32_t tsf_low; /* network timestamp function timer */
uint32_t tsf_hi; /* network timestamp function timer */
uint32_t gp1; /* GP1 timer register */
uint32_t gp2; /* GP2 timer register */
uint32_t fw_rev_type; /* firmware revision type */
uint32_t major; /* uCode version major */
uint32_t minor; /* uCode version minor */
uint32_t hw_ver; /* HW Silicon version */
uint32_t brd_ver; /* HW board version */
uint32_t log_pc; /* log program counter */
uint32_t frame_ptr; /* frame pointer */
uint32_t stack_ptr; /* stack pointer */
uint32_t hcmd; /* last host command header */
uint32_t isr0; /* isr status register LMPM_NIC_ISR0:
* rxtx_flag
*/
uint32_t isr1; /* isr status register LMPM_NIC_ISR1:
* host_flag
*/
uint32_t isr2; /* isr status register LMPM_NIC_ISR2:
* enc_flag
*/
uint32_t isr3; /* isr status register LMPM_NIC_ISR3:
* time_flag
*/
uint32_t isr4; /* isr status register LMPM_NIC_ISR4:
* wico interrupt
*/
uint32_t last_cmd_id; /* last HCMD id handled by the firmware */
uint32_t wait_event; /* wait event() caller address */
uint32_t l2p_control; /* L2pControlField */
uint32_t l2p_duration; /* L2pDurationField */
uint32_t l2p_mhvalid; /* L2pMhValidBits */
uint32_t l2p_addr_match; /* L2pAddrMatchStat */
uint32_t lmpm_pmg_sel; /* indicate which clocks are turned on
* (LMPM_PMG_SEL)
*/
uint32_t u_timestamp; /* indicate when the date and time of the
* compilation
*/
uint32_t flow_handler; /* FH read/write pointers, RX credit */
} __packed /* LOG_ERROR_TABLE_API_S_VER_3 */;
/* UMAC error struct - relevant starting from family 8000 chip.
* Note: This structure is read from the device with IO accesses,
* and the reading already does the endian conversion. As it is
* read with uint32_t-sized accesses, any members with a different size
* need to be ordered correctly though!
*/
struct iwl_umac_error_event_table {
uint32_t valid; /* (nonzero) valid, (0) log is empty */
uint32_t error_id; /* type of error */
uint32_t blink1; /* branch link */
uint32_t blink2; /* branch link */
uint32_t ilink1; /* interrupt link */
uint32_t ilink2; /* interrupt link */
uint32_t data1; /* error-specific data */
uint32_t data2; /* error-specific data */
uint32_t data3; /* error-specific data */
uint32_t umac_major;
uint32_t umac_minor;
uint32_t frame_pointer; /* core register 27*/
uint32_t stack_pointer; /* core register 28 */
uint32_t cmd_header; /* latest host cmd sent to UMAC */
uint32_t nic_isr_pref; /* ISR status register */
} __packed;
/**
* struct iwl_xvt_skb_info - driver data per skb
* @dev_cmd: a pointer to the iwl_dev_cmd associated with this skb
* @trans: transport data
*/
struct iwl_xvt_skb_info {
struct iwl_device_cmd* dev_cmd;
void* trans[2];
};
/**
* struct iwl_xvt - the xvt op_mode
*
* @trans: pointer to the transport layer
* @cfg: pointer to the driver's configuration
* @fw: a pointer to the fw object
* @dev: pointer to struct device for printing purposes
*/
struct iwl_xvt {
struct iwl_trans* trans;
const struct iwl_cfg* cfg;
struct iwl_phy_db* phy_db;
const struct iwl_fw* fw;
struct device* dev;
struct dentry* debugfs_dir;
struct mutex mutex; /* Protects access to xVT struct */
spinlock_t notif_lock;
; /* Protects notifications processing */
enum iwl_xvt_state state;
bool fw_error;
struct iwl_notif_wait_data notif_wait;
uint32_t error_event_table[2];
bool fw_running;
uint32_t umac_error_event_table;
bool support_umac_log;
struct iwl_sw_stack_config sw_stack_cfg;
bool rx_hdr_enabled;
bool apmg_pd_en;
/* DMA buffer information */
uint32_t dma_buffer_size;
uint8_t* dma_cpu_addr;
dma_addr_t dma_addr;
struct iwl_fw_runtime fwrt;
bool is_nvm_mac_override;
uint8_t nvm_hw_addr[ETH_ALEN];
uint8_t nvm_mac_addr[ETH_ALEN];
struct tx_meta_data tx_meta_data[NUM_OF_LMACS];
struct iwl_xvt_reorder_buffer reorder_bufs[IWL_MAX_BAID];
/* members for enhanced tx command */
struct tx_payload* payloads[IWL_XVT_MAX_PAYLOADS_AMOUNT];
struct task_struct* tx_task;
bool is_enhanced_tx;
bool send_tx_resp;
bool send_rx_mpdu;
uint64_t num_of_tx_resp;
uint64_t expected_tx_amount;
wait_queue_head_t tx_done_wq;
struct tx_queue_data queue_data[IWL_MAX_HW_QUEUES];
};
#define IWL_OP_MODE_GET_XVT(_op_mode) ((struct iwl_xvt*)((_op_mode)->op_mode_specific))
/******************
* XVT Methods
******************/
/* Host Commands */
int __must_check iwl_xvt_send_cmd(struct iwl_xvt* xvt, struct iwl_host_cmd* cmd);
int __must_check iwl_xvt_send_cmd_pdu(struct iwl_xvt* xvt, uint32_t id, uint32_t flags,
uint16_t len, const void* data);
/* Utils */
void iwl_xvt_get_nic_error_log_v1(struct iwl_xvt* xvt, struct iwl_error_event_table_v1* table);
void iwl_xvt_dump_nic_error_log_v1(struct iwl_xvt* xvt, struct iwl_error_event_table_v1* table);
void iwl_xvt_get_nic_error_log_v2(struct iwl_xvt* xvt, struct iwl_error_event_table_v2* table);
void iwl_xvt_dump_nic_error_log_v2(struct iwl_xvt* xvt, struct iwl_error_event_table_v2* table);
void iwl_xvt_get_umac_error_log(struct iwl_xvt* xvt, struct iwl_umac_error_event_table* table);
void iwl_xvt_dump_umac_error_log(struct iwl_xvt* xvt, struct iwl_umac_error_event_table* table);
/* User interface */
int iwl_xvt_user_cmd_execute(struct iwl_testmode* testmode, uint32_t cmd,
struct iwl_tm_data* data_in, struct iwl_tm_data* data_out,
bool* supported_cmd);
/* FW */
int iwl_xvt_run_fw(struct iwl_xvt* xvt, uint32_t ucode_type, bool cont_run);
/* NVM */
int iwl_xvt_nvm_init(struct iwl_xvt* xvt);
/* RX */
bool iwl_xvt_reorder(struct iwl_xvt* xvt, struct iwl_rx_packet* pkt);
void iwl_xvt_rx_frame_release(struct iwl_xvt* xvt, struct iwl_rx_packet* pkt);
void iwl_xvt_destroy_reorder_buffer(struct iwl_xvt* xvt, struct iwl_xvt_reorder_buffer* buf);
/* Based on mvm function: iwl_mvm_has_new_tx_api */
static inline bool iwl_xvt_is_unified_fw(struct iwl_xvt* xvt) {
/* TODO - replace with TLV once defined */
return xvt->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22000;
}
static inline bool iwl_xvt_is_cdb_supported(struct iwl_xvt* xvt) {
/*
* TODO:
* The issue of how to determine CDB APIs and usage is still not fully
* defined.
* There is a compilation for CDB and non-CDB FW, but there may
* be also runtime check.
* For now there is a TLV for checking compilation mode, but a
* runtime check will also have to be here - once defined.
*/
return fw_has_capa(&xvt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CDB_SUPPORT);
}
static inline struct agg_tx_status* iwl_xvt_get_agg_status(struct iwl_xvt* xvt,
struct iwl_mvm_tx_resp* tx_resp) {
if (iwl_xvt_is_unified_fw(xvt)) {
return &((struct iwl_mvm_tx_resp*)tx_resp)->status;
} else {
return ((struct iwl_mvm_tx_resp_v3*)tx_resp)->status;
}
}
static inline uint32_t iwl_xvt_get_scd_ssn(struct iwl_xvt* xvt, struct iwl_mvm_tx_resp* tx_resp) {
return le32_to_cpup((__le32*)iwl_xvt_get_agg_status(xvt, tx_resp) + tx_resp->frame_count) & 0xfff;
}
static inline bool iwl_xvt_has_default_txq(struct iwl_xvt* xvt) {
return !(xvt->sw_stack_cfg.fw_dbg_flags & IWL_XVT_DBG_FLAGS_NO_DEFAULT_TXQ);
}
void iwl_xvt_free_tx_queue(struct iwl_xvt* xvt, uint8_t lmac_id);
int iwl_xvt_allocate_tx_queue(struct iwl_xvt* xvt, uint8_t sta_id, uint8_t lmac_id);
void iwl_xvt_txq_disable(struct iwl_xvt* xvt);
/* XVT debugfs */
#ifdef CPTCFG_IWLWIFI_DEBUGFS
int iwl_xvt_dbgfs_register(struct iwl_xvt* xvt, struct dentry* dbgfs_dir);
#else
static inline int iwl_xvt_dbgfs_register(struct iwl_xvt* xvt, struct dentry* dbgfs_dir) {
return 0;
}
#endif /* CPTCFG_IWLWIFI_DEBUGFS */
#endif // SRC_CONNECTIVITY_WLAN_DRIVERS_THIRD_PARTY_INTEL_IWLWIFI_XVT_XVT_H_