Commit 98497bb2 authored by John W. Linville's avatar John W. Linville

Merge branch 'for-linville' of git://github.com/kvalo/ath

parents b75ff5e8 763b8cd3
This diff is collapsed.
...@@ -36,16 +36,9 @@ ...@@ -36,16 +36,9 @@
* how to use copy engines. * how to use copy engines.
*/ */
struct ce_state; struct ath10k_ce_pipe;
/* Copy Engine operational state */
enum ce_op_state {
CE_UNUSED,
CE_PAUSED,
CE_RUNNING,
};
#define CE_DESC_FLAGS_GATHER (1 << 0) #define CE_DESC_FLAGS_GATHER (1 << 0)
#define CE_DESC_FLAGS_BYTE_SWAP (1 << 1) #define CE_DESC_FLAGS_BYTE_SWAP (1 << 1)
#define CE_DESC_FLAGS_META_DATA_MASK 0xFFFC #define CE_DESC_FLAGS_META_DATA_MASK 0xFFFC
...@@ -57,8 +50,7 @@ struct ce_desc { ...@@ -57,8 +50,7 @@ struct ce_desc {
__le16 flags; /* %CE_DESC_FLAGS_ */ __le16 flags; /* %CE_DESC_FLAGS_ */
}; };
/* Copy Engine Ring internal state */ struct ath10k_ce_ring {
struct ce_ring_state {
/* Number of entries in this ring; must be power of 2 */ /* Number of entries in this ring; must be power of 2 */
unsigned int nentries; unsigned int nentries;
unsigned int nentries_mask; unsigned int nentries_mask;
...@@ -116,22 +108,20 @@ struct ce_ring_state { ...@@ -116,22 +108,20 @@ struct ce_ring_state {
void **per_transfer_context; void **per_transfer_context;
}; };
/* Copy Engine internal state */ struct ath10k_ce_pipe {
struct ce_state {
struct ath10k *ar; struct ath10k *ar;
unsigned int id; unsigned int id;
unsigned int attr_flags; unsigned int attr_flags;
u32 ctrl_addr; u32 ctrl_addr;
enum ce_op_state state;
void (*send_cb) (struct ce_state *ce_state, void (*send_cb) (struct ath10k_ce_pipe *ce_state,
void *per_transfer_send_context, void *per_transfer_send_context,
u32 buffer, u32 buffer,
unsigned int nbytes, unsigned int nbytes,
unsigned int transfer_id); unsigned int transfer_id);
void (*recv_cb) (struct ce_state *ce_state, void (*recv_cb) (struct ath10k_ce_pipe *ce_state,
void *per_transfer_recv_context, void *per_transfer_recv_context,
u32 buffer, u32 buffer,
unsigned int nbytes, unsigned int nbytes,
...@@ -139,8 +129,8 @@ struct ce_state { ...@@ -139,8 +129,8 @@ struct ce_state {
unsigned int flags); unsigned int flags);
unsigned int src_sz_max; unsigned int src_sz_max;
struct ce_ring_state *src_ring; struct ath10k_ce_ring *src_ring;
struct ce_ring_state *dest_ring; struct ath10k_ce_ring *dest_ring;
}; };
struct ce_sendlist_item { struct ce_sendlist_item {
...@@ -182,7 +172,7 @@ struct ce_attr; ...@@ -182,7 +172,7 @@ struct ce_attr;
* *
* Implementation note: pushes 1 buffer to Source ring * Implementation note: pushes 1 buffer to Source ring
*/ */
int ath10k_ce_send(struct ce_state *ce_state, int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,
void *per_transfer_send_context, void *per_transfer_send_context,
u32 buffer, u32 buffer,
unsigned int nbytes, unsigned int nbytes,
...@@ -190,12 +180,12 @@ int ath10k_ce_send(struct ce_state *ce_state, ...@@ -190,12 +180,12 @@ int ath10k_ce_send(struct ce_state *ce_state,
unsigned int transfer_id, unsigned int transfer_id,
unsigned int flags); unsigned int flags);
void ath10k_ce_send_cb_register(struct ce_state *ce_state, void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
void (*send_cb) (struct ce_state *ce_state, void (*send_cb)(struct ath10k_ce_pipe *ce_state,
void *transfer_context, void *transfer_context,
u32 buffer, u32 buffer,
unsigned int nbytes, unsigned int nbytes,
unsigned int transfer_id), unsigned int transfer_id),
int disable_interrupts); int disable_interrupts);
/* Append a simple buffer (address/length) to a sendlist. */ /* Append a simple buffer (address/length) to a sendlist. */
...@@ -215,7 +205,7 @@ void ath10k_ce_sendlist_buf_add(struct ce_sendlist *sendlist, ...@@ -215,7 +205,7 @@ void ath10k_ce_sendlist_buf_add(struct ce_sendlist *sendlist,
* *
* Implemenation note: Pushes multiple buffers with Gather to Source ring. * Implemenation note: Pushes multiple buffers with Gather to Source ring.
*/ */
int ath10k_ce_sendlist_send(struct ce_state *ce_state, int ath10k_ce_sendlist_send(struct ath10k_ce_pipe *ce_state,
void *per_transfer_send_context, void *per_transfer_send_context,
struct ce_sendlist *sendlist, struct ce_sendlist *sendlist,
/* 14 bits */ /* 14 bits */
...@@ -233,17 +223,17 @@ int ath10k_ce_sendlist_send(struct ce_state *ce_state, ...@@ -233,17 +223,17 @@ int ath10k_ce_sendlist_send(struct ce_state *ce_state,
* *
* Implemenation note: Pushes a buffer to Dest ring. * Implemenation note: Pushes a buffer to Dest ring.
*/ */
int ath10k_ce_recv_buf_enqueue(struct ce_state *ce_state, int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state,
void *per_transfer_recv_context, void *per_transfer_recv_context,
u32 buffer); u32 buffer);
void ath10k_ce_recv_cb_register(struct ce_state *ce_state, void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state,
void (*recv_cb) (struct ce_state *ce_state, void (*recv_cb)(struct ath10k_ce_pipe *ce_state,
void *transfer_context, void *transfer_context,
u32 buffer, u32 buffer,
unsigned int nbytes, unsigned int nbytes,
unsigned int transfer_id, unsigned int transfer_id,
unsigned int flags)); unsigned int flags));
/* recv flags */ /* recv flags */
/* Data is byte-swapped */ /* Data is byte-swapped */
...@@ -253,7 +243,7 @@ void ath10k_ce_recv_cb_register(struct ce_state *ce_state, ...@@ -253,7 +243,7 @@ void ath10k_ce_recv_cb_register(struct ce_state *ce_state,
* Supply data for the next completed unprocessed receive descriptor. * Supply data for the next completed unprocessed receive descriptor.
* Pops buffer from Dest ring. * Pops buffer from Dest ring.
*/ */
int ath10k_ce_completed_recv_next(struct ce_state *ce_state, int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state,
void **per_transfer_contextp, void **per_transfer_contextp,
u32 *bufferp, u32 *bufferp,
unsigned int *nbytesp, unsigned int *nbytesp,
...@@ -263,7 +253,7 @@ int ath10k_ce_completed_recv_next(struct ce_state *ce_state, ...@@ -263,7 +253,7 @@ int ath10k_ce_completed_recv_next(struct ce_state *ce_state,
* Supply data for the next completed unprocessed send descriptor. * Supply data for the next completed unprocessed send descriptor.
* Pops 1 completed send buffer from Source ring. * Pops 1 completed send buffer from Source ring.
*/ */
int ath10k_ce_completed_send_next(struct ce_state *ce_state, int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state,
void **per_transfer_contextp, void **per_transfer_contextp,
u32 *bufferp, u32 *bufferp,
unsigned int *nbytesp, unsigned int *nbytesp,
...@@ -272,7 +262,7 @@ int ath10k_ce_completed_send_next(struct ce_state *ce_state, ...@@ -272,7 +262,7 @@ int ath10k_ce_completed_send_next(struct ce_state *ce_state,
/*==================CE Engine Initialization=======================*/ /*==================CE Engine Initialization=======================*/
/* Initialize an instance of a CE */ /* Initialize an instance of a CE */
struct ce_state *ath10k_ce_init(struct ath10k *ar, struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
unsigned int ce_id, unsigned int ce_id,
const struct ce_attr *attr); const struct ce_attr *attr);
...@@ -282,7 +272,7 @@ struct ce_state *ath10k_ce_init(struct ath10k *ar, ...@@ -282,7 +272,7 @@ struct ce_state *ath10k_ce_init(struct ath10k *ar,
* receive buffers. Target DMA must be stopped before using * receive buffers. Target DMA must be stopped before using
* this API. * this API.
*/ */
int ath10k_ce_revoke_recv_next(struct ce_state *ce_state, int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state,
void **per_transfer_contextp, void **per_transfer_contextp,
u32 *bufferp); u32 *bufferp);
...@@ -291,13 +281,13 @@ int ath10k_ce_revoke_recv_next(struct ce_state *ce_state, ...@@ -291,13 +281,13 @@ int ath10k_ce_revoke_recv_next(struct ce_state *ce_state,
* pending sends. Target DMA must be stopped before using * pending sends. Target DMA must be stopped before using
* this API. * this API.
*/ */
int ath10k_ce_cancel_send_next(struct ce_state *ce_state, int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state,
void **per_transfer_contextp, void **per_transfer_contextp,
u32 *bufferp, u32 *bufferp,
unsigned int *nbytesp, unsigned int *nbytesp,
unsigned int *transfer_idp); unsigned int *transfer_idp);
void ath10k_ce_deinit(struct ce_state *ce_state); void ath10k_ce_deinit(struct ath10k_ce_pipe *ce_state);
/*==================CE Interrupt Handlers====================*/ /*==================CE Interrupt Handlers====================*/
void ath10k_ce_per_engine_service_any(struct ath10k *ar); void ath10k_ce_per_engine_service_any(struct ath10k *ar);
...@@ -322,9 +312,6 @@ struct ce_attr { ...@@ -322,9 +312,6 @@ struct ce_attr {
/* CE_ATTR_* values */ /* CE_ATTR_* values */
unsigned int flags; unsigned int flags;
/* currently not in use */
unsigned int priority;
/* #entries in source ring - Must be a power of 2 */ /* #entries in source ring - Must be a power of 2 */
unsigned int src_nentries; unsigned int src_nentries;
...@@ -336,9 +323,6 @@ struct ce_attr { ...@@ -336,9 +323,6 @@ struct ce_attr {
/* #entries in destination ring - Must be a power of 2 */ /* #entries in destination ring - Must be a power of 2 */
unsigned int dest_nentries; unsigned int dest_nentries;
/* Future use */
void *reserved;
}; };
/* /*
......
...@@ -38,17 +38,6 @@ MODULE_PARM_DESC(uart_print, "Uart target debugging"); ...@@ -38,17 +38,6 @@ MODULE_PARM_DESC(uart_print, "Uart target debugging");
MODULE_PARM_DESC(p2p, "Enable ath10k P2P support"); MODULE_PARM_DESC(p2p, "Enable ath10k P2P support");
static const struct ath10k_hw_params ath10k_hw_params_list[] = { static const struct ath10k_hw_params ath10k_hw_params_list[] = {
{
.id = QCA988X_HW_1_0_VERSION,
.name = "qca988x hw1.0",
.patch_load_addr = QCA988X_HW_1_0_PATCH_LOAD_ADDR,
.fw = {
.dir = QCA988X_HW_1_0_FW_DIR,
.fw = QCA988X_HW_1_0_FW_FILE,
.otp = QCA988X_HW_1_0_OTP_FILE,
.board = QCA988X_HW_1_0_BOARD_DATA_FILE,
},
},
{ {
.id = QCA988X_HW_2_0_VERSION, .id = QCA988X_HW_2_0_VERSION,
.name = "qca988x hw2.0", .name = "qca988x hw2.0",
...@@ -717,10 +706,43 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ...@@ -717,10 +706,43 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
return 0; return 0;
} }
int ath10k_core_register(struct ath10k *ar) static int ath10k_core_check_chip_id(struct ath10k *ar)
{
u32 hw_revision = MS(ar->chip_id, SOC_CHIP_ID_REV);
/* Check that we are not using hw1.0 (some of them have same pci id
* as hw2.0) before doing anything else as ath10k crashes horribly
* due to missing hw1.0 workarounds. */
switch (hw_revision) {
case QCA988X_HW_1_0_CHIP_ID_REV:
ath10k_err("ERROR: qca988x hw1.0 is not supported\n");
return -EOPNOTSUPP;
case QCA988X_HW_2_0_CHIP_ID_REV:
/* known hardware revision, continue normally */
return 0;
default:
ath10k_warn("Warning: hardware revision unknown (0x%x), expect problems\n",
ar->chip_id);
return 0;
}
return 0;
}
int ath10k_core_register(struct ath10k *ar, u32 chip_id)
{ {
int status; int status;
ar->chip_id = chip_id;
status = ath10k_core_check_chip_id(ar);
if (status) {
ath10k_err("Unsupported chip id 0x%08x\n", ar->chip_id);
return status;
}
status = ath10k_core_probe_fw(ar); status = ath10k_core_probe_fw(ar);
if (status) { if (status) {
ath10k_err("could not probe fw (%d)\n", status); ath10k_err("could not probe fw (%d)\n", status);
......
...@@ -270,12 +270,21 @@ enum ath10k_state { ...@@ -270,12 +270,21 @@ enum ath10k_state {
ATH10K_STATE_WEDGED, ATH10K_STATE_WEDGED,
}; };
enum ath10k_fw_features {
/* wmi_mgmt_rx_hdr contains extra RSSI information */
ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX = 0,
/* keep last */
ATH10K_FW_FEATURE_COUNT,
};
struct ath10k { struct ath10k {
struct ath_common ath_common; struct ath_common ath_common;
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
struct device *dev; struct device *dev;
u8 mac_addr[ETH_ALEN]; u8 mac_addr[ETH_ALEN];
u32 chip_id;
u32 target_version; u32 target_version;
u8 fw_version_major; u8 fw_version_major;
u32 fw_version_minor; u32 fw_version_minor;
...@@ -288,6 +297,8 @@ struct ath10k { ...@@ -288,6 +297,8 @@ struct ath10k {
u32 vht_cap_info; u32 vht_cap_info;
u32 num_rf_chains; u32 num_rf_chains;
DECLARE_BITMAP(fw_features, ATH10K_FW_FEATURE_COUNT);
struct targetdef *targetdef; struct targetdef *targetdef;
struct hostdef *hostdef; struct hostdef *hostdef;
...@@ -393,7 +404,7 @@ void ath10k_core_destroy(struct ath10k *ar); ...@@ -393,7 +404,7 @@ void ath10k_core_destroy(struct ath10k *ar);
int ath10k_core_start(struct ath10k *ar); int ath10k_core_start(struct ath10k *ar);
void ath10k_core_stop(struct ath10k *ar); void ath10k_core_stop(struct ath10k *ar);
int ath10k_core_register(struct ath10k *ar); int ath10k_core_register(struct ath10k *ar, u32 chip_id);
void ath10k_core_unregister(struct ath10k *ar); void ath10k_core_unregister(struct ath10k *ar);
#endif /* _CORE_H_ */ #endif /* _CORE_H_ */
...@@ -260,7 +260,6 @@ void ath10k_debug_read_target_stats(struct ath10k *ar, ...@@ -260,7 +260,6 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,
} }
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
mutex_unlock(&ar->conf_mutex);
complete(&ar->debug.event_stats_compl); complete(&ar->debug.event_stats_compl);
} }
...@@ -499,6 +498,25 @@ static const struct file_operations fops_simulate_fw_crash = { ...@@ -499,6 +498,25 @@ static const struct file_operations fops_simulate_fw_crash = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
static ssize_t ath10k_read_chip_id(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
unsigned int len;
char buf[50];
len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->chip_id);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_chip_id = {
.read = ath10k_read_chip_id,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
int ath10k_debug_create(struct ath10k *ar) int ath10k_debug_create(struct ath10k *ar)
{ {
ar->debug.debugfs_phy = debugfs_create_dir("ath10k", ar->debug.debugfs_phy = debugfs_create_dir("ath10k",
...@@ -518,6 +536,9 @@ int ath10k_debug_create(struct ath10k *ar) ...@@ -518,6 +536,9 @@ int ath10k_debug_create(struct ath10k *ar)
debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy, debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_simulate_fw_crash); ar, &fops_simulate_fw_crash);
debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_chip_id);
return 0; return 0;
} }
#endif /* CONFIG_ATH10K_DEBUGFS */ #endif /* CONFIG_ATH10K_DEBUGFS */
......
...@@ -772,16 +772,16 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc, ...@@ -772,16 +772,16 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
flags |= SM(tx_alloc, ATH10K_HTC_CONN_FLAGS_RECV_ALLOC); flags |= SM(tx_alloc, ATH10K_HTC_CONN_FLAGS_RECV_ALLOC);
req_msg = &msg->connect_service;
req_msg->flags = __cpu_to_le16(flags);
req_msg->service_id = __cpu_to_le16(conn_req->service_id);
/* Only enable credit flow control for WMI ctrl service */ /* Only enable credit flow control for WMI ctrl service */
if (conn_req->service_id != ATH10K_HTC_SVC_ID_WMI_CONTROL) { if (conn_req->service_id != ATH10K_HTC_SVC_ID_WMI_CONTROL) {
flags |= ATH10K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL; flags |= ATH10K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL;
disable_credit_flow_ctrl = true; disable_credit_flow_ctrl = true;
} }
req_msg = &msg->connect_service;
req_msg->flags = __cpu_to_le16(flags);
req_msg->service_id = __cpu_to_le16(conn_req->service_id);
INIT_COMPLETION(htc->ctl_resp); INIT_COMPLETION(htc->ctl_resp);
status = ath10k_htc_send(htc, ATH10K_HTC_EP_0, skb); status = ath10k_htc_send(htc, ATH10K_HTC_EP_0, skb);
......
...@@ -104,21 +104,16 @@ int ath10k_htt_attach(struct ath10k *ar) ...@@ -104,21 +104,16 @@ int ath10k_htt_attach(struct ath10k *ar)
static int ath10k_htt_verify_version(struct ath10k_htt *htt) static int ath10k_htt_verify_version(struct ath10k_htt *htt)
{ {
ath10k_dbg(ATH10K_DBG_HTT, ath10k_info("htt target version %d.%d\n",
"htt target version %d.%d; host version %d.%d\n", htt->target_version_major, htt->target_version_minor);
htt->target_version_major,
htt->target_version_minor, if (htt->target_version_major != 2 &&
HTT_CURRENT_VERSION_MAJOR, htt->target_version_major != 3) {
HTT_CURRENT_VERSION_MINOR); ath10k_err("unsupported htt major version %d. supported versions are 2 and 3\n",
htt->target_version_major);
if (htt->target_version_major != HTT_CURRENT_VERSION_MAJOR) {
ath10k_err("htt major versions are incompatible!\n");
return -ENOTSUPP; return -ENOTSUPP;
} }
if (htt->target_version_minor != HTT_CURRENT_VERSION_MINOR)
ath10k_warn("htt minor version differ but still compatible\n");
return 0; return 0;
} }
......
...@@ -23,9 +23,6 @@ ...@@ -23,9 +23,6 @@
#include "htc.h" #include "htc.h"
#include "rx_desc.h" #include "rx_desc.h"
#define HTT_CURRENT_VERSION_MAJOR 2
#define HTT_CURRENT_VERSION_MINOR 1
enum htt_dbg_stats_type { enum htt_dbg_stats_type {
HTT_DBG_STATS_WAL_PDEV_TXRX = 1 << 0, HTT_DBG_STATS_WAL_PDEV_TXRX = 1 << 0,
HTT_DBG_STATS_RX_REORDER = 1 << 1, HTT_DBG_STATS_RX_REORDER = 1 << 1,
...@@ -45,6 +42,9 @@ enum htt_h2t_msg_type { /* host-to-target */ ...@@ -45,6 +42,9 @@ enum htt_h2t_msg_type { /* host-to-target */
HTT_H2T_MSG_TYPE_SYNC = 4, HTT_H2T_MSG_TYPE_SYNC = 4,
HTT_H2T_MSG_TYPE_AGGR_CFG = 5, HTT_H2T_MSG_TYPE_AGGR_CFG = 5,
HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG = 6, HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG = 6,
/* This command is used for sending management frames in HTT < 3.0.
* HTT >= 3.0 uses TX_FRM for everything. */
HTT_H2T_MSG_TYPE_MGMT_TX = 7, HTT_H2T_MSG_TYPE_MGMT_TX = 7,
HTT_H2T_NUM_MSGS /* keep this last */ HTT_H2T_NUM_MSGS /* keep this last */
......
...@@ -610,8 +610,7 @@ static int ath10k_htt_rx_amsdu(struct ath10k_htt *htt, ...@@ -610,8 +610,7 @@ static int ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
RX_MPDU_START_INFO0_ENCRYPT_TYPE); RX_MPDU_START_INFO0_ENCRYPT_TYPE);
/* FIXME: No idea what assumptions are safe here. Need logs */ /* FIXME: No idea what assumptions are safe here. Need logs */
if ((fmt == RX_MSDU_DECAP_RAW && skb->next) || if ((fmt == RX_MSDU_DECAP_RAW && skb->next)) {
(fmt == RX_MSDU_DECAP_8023_SNAP_LLC)) {
ath10k_htt_rx_free_msdu_chain(skb->next); ath10k_htt_rx_free_msdu_chain(skb->next);
skb->next = NULL; skb->next = NULL;
return -ENOTSUPP; return -ENOTSUPP;
...@@ -659,6 +658,15 @@ static int ath10k_htt_rx_amsdu(struct ath10k_htt *htt, ...@@ -659,6 +658,15 @@ static int ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
decap_hdr += roundup(crypto_len, 4); decap_hdr += roundup(crypto_len, 4);
} }
/* When fmt == RX_MSDU_DECAP_8023_SNAP_LLC:
*
* SNAP 802.3 consists of:
* [dst:6][src:6][len:2][dsap:1][ssap:1][ctl:1][snap:5]
* [data][fcs:4].
*
* Since this overlaps with A-MSDU header (da, sa, len)
* there's nothing extra to do. */
if (fmt == RX_MSDU_DECAP_ETHERNET2_DIX) { if (fmt == RX_MSDU_DECAP_ETHERNET2_DIX) {
/* Ethernet2 decap inserts ethernet header in place of /* Ethernet2 decap inserts ethernet header in place of
* A-MSDU subframe header. */ * A-MSDU subframe header. */
......
...@@ -401,10 +401,16 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ...@@ -401,10 +401,16 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
goto err; goto err;
} }
txfrag = dev_alloc_skb(frag_len); /* Since HTT 3.0 there is no separate mgmt tx command. However in case
if (!txfrag) { * of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
res = -ENOMEM; * fragment list host driver specifies directly frame pointer. */
goto err; if (htt->target_version_major < 3 ||
!ieee80211_is_mgmt(hdr->frame_control)) {
txfrag = dev_alloc_skb(frag_len);
if (!txfrag) {
res = -ENOMEM;
goto err;
}
} }
if (!IS_ALIGNED((unsigned long)txdesc->data, 4)) { if (!IS_ALIGNED((unsigned long)txdesc->data, 4)) {
...@@ -427,23 +433,31 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ...@@ -427,23 +433,31 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
if (res) if (res)
goto err; goto err;
/* tx fragment list must be terminated with zero-entry */ /* Since HTT 3.0 there is no separate mgmt tx command. However in case
skb_put(txfrag, frag_len); * of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
tx_frags = (struct htt_data_tx_desc_frag *)txfrag->data; * fragment list host driver specifies directly frame pointer. */
tx_frags[0].paddr = __cpu_to_le32(ATH10K_SKB_CB(msdu)->paddr); if (htt->target_version_major < 3 ||
tx_frags[0].len = __cpu_to_le32(msdu->len); !ieee80211_is_mgmt(hdr->frame_control)) {
tx_frags[1].paddr = __cpu_to_le32(0); /* tx fragment list must be terminated with zero-entry */
tx_frags[1].len = __cpu_to_le32(0); skb_put(txfrag, frag_len);
tx_frags = (struct htt_data_tx_desc_frag *)txfrag->data;
res = ath10k_skb_map(dev, txfrag); tx_frags[0].paddr = __cpu_to_le32(ATH10K_SKB_CB(msdu)->paddr);
if (res) tx_frags[0].len = __cpu_to_le32(msdu->len);
goto err; tx_frags[1].paddr = __cpu_to_le32(0);
tx_frags[1].len = __cpu_to_le32(0);
res = ath10k_skb_map(dev, txfrag);
if (res)
goto err;
ath10k_dbg(ATH10K_DBG_HTT, "txfrag 0x%llx\n",
(unsigned long long) ATH10K_SKB_CB(txfrag)->paddr);
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "txfrag: ",
txfrag->data, frag_len);
}
ath10k_dbg(ATH10K_DBG_HTT, "txfrag 0x%llx msdu 0x%llx\n", ath10k_dbg(ATH10K_DBG_HTT, "msdu 0x%llx\n",
(unsigned long long) ATH10K_SKB_CB(txfrag)->paddr,
(unsigned long long) ATH10K_SKB_CB(msdu)->paddr); (unsigned long long) ATH10K_SKB_CB(msdu)->paddr);
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "txfrag: ",
txfrag->data, frag_len);
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "msdu: ", ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "msdu: ",
msdu->data, msdu->len); msdu->data, msdu->len);
...@@ -459,8 +473,17 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ...@@ -459,8 +473,17 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
if (!ieee80211_has_protected(hdr->frame_control)) if (!ieee80211_has_protected(hdr->frame_control))
flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT; flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT;
flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI,
HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); /* Since HTT 3.0 there is no separate mgmt tx command. However in case
* of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
* fragment list host driver specifies directly frame pointer. */
if (htt->target_version_major >= 3 &&
ieee80211_is_mgmt(hdr->frame_control))
flags0 |= SM(ATH10K_HW_TXRX_MGMT,
HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
else
flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI,
HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
flags1 = 0; flags1 = 0;
flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID); flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID);
...@@ -468,7 +491,14 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ...@@ -468,7 +491,14 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD;
flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD;
frags_paddr = ATH10K_SKB_CB(txfrag)->paddr; /* Since HTT 3.0 there is no separate mgmt tx command. However in case
* of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
* fragment list host driver specifies directly frame pointer. */
if (htt->target_version_major >= 3 &&
ieee80211_is_mgmt(hdr->frame_control))
frags_paddr = ATH10K_SKB_CB(msdu)->paddr;
else
frags_paddr = ATH10K_SKB_CB(txfrag)->paddr;
cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM; cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM;
cmd->data_tx.flags0 = flags0; cmd->data_tx.flags0 = flags0;
......
...@@ -24,18 +24,14 @@ ...@@ -24,18 +24,14 @@
#define SUPPORTED_FW_MAJOR 1 #define SUPPORTED_FW_MAJOR 1
#define SUPPORTED_FW_MINOR 0 #define SUPPORTED_FW_MINOR 0
#define SUPPORTED_FW_RELEASE 0 #define SUPPORTED_FW_RELEASE 0
#define SUPPORTED_FW_BUILD 629 #define SUPPORTED_FW_BUILD 636
/* QCA988X 1.0 definitions */ /* QCA988X 1.0 definitions (unsupported) */
#define QCA988X_HW_1_0_VERSION 0x4000002c #define QCA988X_HW_1_0_CHIP_ID_REV 0x0
#define QCA988X_HW_1_0_FW_DIR "ath10k/QCA988X/hw1.0"
#define QCA988X_HW_1_0_FW_FILE "firmware.bin"
#define QCA988X_HW_1_0_OTP_FILE "otp.bin"
#define QCA988X_HW_1_0_BOARD_DATA_FILE "board.bin"
#define QCA988X_HW_1_0_PATCH_LOAD_ADDR 0x1234
/* QCA988X 2.0 definitions */ /* QCA988X 2.0 definitions */
#define QCA988X_HW_2_0_VERSION 0x4100016c #define QCA988X_HW_2_0_VERSION 0x4100016c
#define QCA988X_HW_2_0_CHIP_ID_REV 0x2
#define QCA988X_HW_2_0_FW_DIR "ath10k/QCA988X/hw2.0" #define QCA988X_HW_2_0_FW_DIR "ath10k/QCA988X/hw2.0"
#define QCA988X_HW_2_0_FW_FILE "firmware.bin" #define QCA988X_HW_2_0_FW_FILE "firmware.bin"
#define QCA988X_HW_2_0_OTP_FILE "otp.bin" #define QCA988X_HW_2_0_OTP_FILE "otp.bin"
...@@ -53,6 +49,9 @@ enum ath10k_hw_txrx_mode { ...@@ -53,6 +49,9 @@ enum ath10k_hw_txrx_mode {
ATH10K_HW_TXRX_RAW = 0, ATH10K_HW_TXRX_RAW = 0,
ATH10K_HW_TXRX_NATIVE_WIFI = 1, ATH10K_HW_TXRX_NATIVE_WIFI = 1,
ATH10K_HW_TXRX_ETHERNET = 2, ATH10K_HW_TXRX_ETHERNET = 2,
/* Valid for HTT >= 3.0. Used for management frames in TX_FRM. */
ATH10K_HW_TXRX_MGMT = 3,
}; };
enum ath10k_mcast2ucast_mode { enum ath10k_mcast2ucast_mode {
...@@ -169,6 +168,10 @@ enum ath10k_mcast2ucast_mode { ...@@ -169,6 +168,10 @@ enum ath10k_mcast2ucast_mode {
#define SOC_LPO_CAL_ENABLE_LSB 20 #define SOC_LPO_CAL_ENABLE_LSB 20
#define SOC_LPO_CAL_ENABLE_MASK 0x00100000 #define SOC_LPO_CAL_ENABLE_MASK 0x00100000
#define SOC_CHIP_ID_ADDRESS 0x000000ec
#define SOC_CHIP_ID_REV_LSB 8
#define SOC_CHIP_ID_REV_MASK 0x00000f00
#define WLAN_RESET_CONTROL_COLD_RST_MASK 0x00000008 #define WLAN_RESET_CONTROL_COLD_RST_MASK 0x00000008
#define WLAN_RESET_CONTROL_WARM_RST_MASK 0x00000004 #define WLAN_RESET_CONTROL_WARM_RST_MASK 0x00000004
#define WLAN_SYSTEM_SLEEP_DISABLE_LSB 0 #define WLAN_SYSTEM_SLEEP_DISABLE_LSB 0
......
...@@ -503,13 +503,10 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) ...@@ -503,13 +503,10 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
{ {
struct ieee80211_channel *channel = ar->hw->conf.chandef.chan; struct ieee80211_channel *channel = ar->hw->conf.chandef.chan;
struct wmi_vdev_start_request_arg arg = {}; struct wmi_vdev_start_request_arg arg = {};
enum nl80211_channel_type type;
int ret = 0; int ret = 0;
lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->conf_mutex);
type = cfg80211_get_chandef_type(&ar->hw->conf.chandef);
arg.vdev_id = vdev_id; arg.vdev_id = vdev_id;
arg.channel.freq = channel->center_freq; arg.channel.freq = channel->center_freq;
arg.channel.band_center_freq1 = ar->hw->conf.chandef.center_freq1; arg.channel.band_center_freq1 = ar->hw->conf.chandef.center_freq1;
...@@ -973,7 +970,7 @@ static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar, ...@@ -973,7 +970,7 @@ static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar,
sta->uapsd_queues, sta->max_sp); sta->uapsd_queues, sta->max_sp);
arg->peer_flags |= WMI_PEER_APSD; arg->peer_flags |= WMI_PEER_APSD;
arg->peer_flags |= WMI_RC_UAPSD_FLAG; arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG;
if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN | uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN |
...@@ -1421,10 +1418,6 @@ static void ath10k_tx_h_update_wep_key(struct sk_buff *skb) ...@@ -1421,10 +1418,6 @@ static void ath10k_tx_h_update_wep_key(struct sk_buff *skb)
struct ieee80211_key_conf *key = info->control.hw_key; struct ieee80211_key_conf *key = info->control.hw_key;
int ret; int ret;
/* TODO AP mode should be implemented */
if (vif->type != NL80211_IFTYPE_STATION)
return;
if (!ieee80211_has_protected(hdr->frame_control)) if (!ieee80211_has_protected(hdr->frame_control))
return; return;
...@@ -1480,6 +1473,12 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb) ...@@ -1480,6 +1473,12 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
int ret; int ret;
if (ar->htt.target_version_major >= 3) {
/* Since HTT 3.0 there is no separate mgmt tx command */
ret = ath10k_htt_tx(&ar->htt, skb);
goto exit;
}
if (ieee80211_is_mgmt(hdr->frame_control)) if (ieee80211_is_mgmt(hdr->frame_control))
ret = ath10k_htt_mgmt_tx(&ar->htt, skb); ret = ath10k_htt_mgmt_tx(&ar->htt, skb);
else if (ieee80211_is_nullfunc(hdr->frame_control)) else if (ieee80211_is_nullfunc(hdr->frame_control))
...@@ -1491,6 +1490,7 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb) ...@@ -1491,6 +1490,7 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
else else
ret = ath10k_htt_tx(&ar->htt, skb); ret = ath10k_htt_tx(&ar->htt, skb);
exit:
if (ret) { if (ret) {
ath10k_warn("tx failed (%d). dropping packet.\n", ret); ath10k_warn("tx failed (%d). dropping packet.\n", ret);
ieee80211_free_txskb(ar->hw, skb); ieee80211_free_txskb(ar->hw, skb);
...@@ -1727,8 +1727,10 @@ static void ath10k_tx(struct ieee80211_hw *hw, ...@@ -1727,8 +1727,10 @@ static void ath10k_tx(struct ieee80211_hw *hw,
/* we must calculate tid before we apply qos workaround /* we must calculate tid before we apply qos workaround
* as we'd lose the qos control field */ * as we'd lose the qos control field */
tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST; tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
if (ieee80211_is_data_qos(hdr->frame_control) && if (ieee80211_is_mgmt(hdr->frame_control)) {
is_unicast_ether_addr(ieee80211_get_DA(hdr))) { tid = HTT_DATA_TX_EXT_TID_MGMT;
} else if (ieee80211_is_data_qos(hdr->frame_control) &&
is_unicast_ether_addr(ieee80211_get_DA(hdr))) {
u8 *qc = ieee80211_get_qos_ctl(hdr); u8 *qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
} }
......
This diff is collapsed.
...@@ -43,22 +43,23 @@ struct bmi_xfer { ...@@ -43,22 +43,23 @@ struct bmi_xfer {
u32 resp_len; u32 resp_len;
}; };
enum ath10k_pci_compl_state {
ATH10K_PCI_COMPL_FREE = 0,
ATH10K_PCI_COMPL_SEND,
ATH10K_PCI_COMPL_RECV,
};
struct ath10k_pci_compl { struct ath10k_pci_compl {
struct list_head list; struct list_head list;
int send_or_recv; enum ath10k_pci_compl_state state;
struct ce_state *ce_state; struct ath10k_ce_pipe *ce_state;
struct hif_ce_pipe_info *pipe_info; struct ath10k_pci_pipe *pipe_info;
void *transfer_context; struct sk_buff *skb;
unsigned int nbytes; unsigned int nbytes;
unsigned int transfer_id; unsigned int transfer_id;
unsigned int flags; unsigned int flags;
}; };
/* compl_state.send_or_recv */
#define HIF_CE_COMPLETE_FREE 0
#define HIF_CE_COMPLETE_SEND 1
#define HIF_CE_COMPLETE_RECV 2
/* /*
* PCI-specific Target state * PCI-specific Target state
* *
...@@ -152,17 +153,16 @@ struct service_to_pipe { ...@@ -152,17 +153,16 @@ struct service_to_pipe {
enum ath10k_pci_features { enum ath10k_pci_features {
ATH10K_PCI_FEATURE_MSI_X = 0, ATH10K_PCI_FEATURE_MSI_X = 0,
ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND = 1, ATH10K_PCI_FEATURE_SOC_POWER_SAVE = 1,
ATH10K_PCI_FEATURE_SOC_POWER_SAVE = 2,
/* keep last */ /* keep last */
ATH10K_PCI_FEATURE_COUNT ATH10K_PCI_FEATURE_COUNT
}; };
/* Per-pipe state. */ /* Per-pipe state. */
struct hif_ce_pipe_info { struct ath10k_pci_pipe {
/* Handle of underlying Copy Engine */ /* Handle of underlying Copy Engine */
struct ce_state *ce_hdl; struct ath10k_ce_pipe *ce_hdl;
/* Our pipe number; facilitiates use of pipe_info ptrs. */ /* Our pipe number; facilitiates use of pipe_info ptrs. */
u8 pipe_num; u8 pipe_num;
...@@ -190,7 +190,6 @@ struct ath10k_pci { ...@@ -190,7 +190,6 @@ struct ath10k_pci {
struct device *dev; struct device *dev;
struct ath10k *ar; struct ath10k *ar;
void __iomem *mem; void __iomem *mem;
int cacheline_sz;
DECLARE_BITMAP(features, ATH10K_PCI_FEATURE_COUNT); DECLARE_BITMAP(features, ATH10K_PCI_FEATURE_COUNT);
...@@ -219,7 +218,7 @@ struct ath10k_pci { ...@@ -219,7 +218,7 @@ struct ath10k_pci {
bool compl_processing; bool compl_processing;
struct hif_ce_pipe_info pipe_info[CE_COUNT_MAX]; struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX];
struct ath10k_hif_cb msg_callbacks_current; struct ath10k_hif_cb msg_callbacks_current;
...@@ -227,16 +226,13 @@ struct ath10k_pci { ...@@ -227,16 +226,13 @@ struct ath10k_pci {
u32 fw_indicator_address; u32 fw_indicator_address;
/* Copy Engine used for Diagnostic Accesses */ /* Copy Engine used for Diagnostic Accesses */
struct ce_state *ce_diag; struct ath10k_ce_pipe *ce_diag;
/* FIXME: document what this really protects */ /* FIXME: document what this really protects */
spinlock_t ce_lock; spinlock_t ce_lock;
/* Map CE id to ce_state */ /* Map CE id to ce_state */
struct ce_state *ce_id_to_state[CE_COUNT_MAX]; struct ath10k_ce_pipe ce_states[CE_COUNT_MAX];
/* makes sure that dummy reads are atomic */
spinlock_t hw_v1_workaround_lock;
}; };
static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
...@@ -244,14 +240,18 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) ...@@ -244,14 +240,18 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
return ar->hif.priv; return ar->hif.priv;
} }
static inline u32 ath10k_pci_reg_read32(void __iomem *mem, u32 addr) static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr)
{ {
return ioread32(mem + PCIE_LOCAL_BASE_ADDRESS + addr); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
return ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
} }
static inline void ath10k_pci_reg_write32(void __iomem *mem, u32 addr, u32 val) static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
{ {
iowrite32(val, mem + PCIE_LOCAL_BASE_ADDRESS + addr); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
} }
#define ATH_PCI_RESET_WAIT_MAX 10 /* ms */ #define ATH_PCI_RESET_WAIT_MAX 10 /* ms */
...@@ -310,23 +310,8 @@ static inline void ath10k_pci_write32(struct ath10k *ar, u32 offset, ...@@ -310,23 +310,8 @@ static inline void ath10k_pci_write32(struct ath10k *ar, u32 offset,
u32 value) u32 value)
{ {
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
void __iomem *addr = ar_pci->mem;
if (test_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features)) {
unsigned long irq_flags;
spin_lock_irqsave(&ar_pci->hw_v1_workaround_lock, irq_flags); iowrite32(value, ar_pci->mem + offset);
ioread32(addr+offset+4); /* 3rd read prior to write */
ioread32(addr+offset+4); /* 2nd read prior to write */
ioread32(addr+offset+4); /* 1st read prior to write */
iowrite32(value, addr+offset);
spin_unlock_irqrestore(&ar_pci->hw_v1_workaround_lock,
irq_flags);
} else {
iowrite32(value, addr+offset);
}
} }
static inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset) static inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
...@@ -336,15 +321,17 @@ static inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset) ...@@ -336,15 +321,17 @@ static inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
return ioread32(ar_pci->mem + offset); return ioread32(ar_pci->mem + offset);
} }
void ath10k_do_pci_wake(struct ath10k *ar); int ath10k_do_pci_wake(struct ath10k *ar);
void ath10k_do_pci_sleep(struct ath10k *ar); void ath10k_do_pci_sleep(struct ath10k *ar);
static inline void ath10k_pci_wake(struct ath10k *ar) static inline int ath10k_pci_wake(struct ath10k *ar)
{ {
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
ath10k_do_pci_wake(ar); return ath10k_do_pci_wake(ar);
return 0;
} }
static inline void ath10k_pci_sleep(struct ath10k *ar) static inline void ath10k_pci_sleep(struct ath10k *ar)
......
...@@ -110,6 +110,7 @@ static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, ...@@ -110,6 +110,7 @@ static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb,
if (atomic_add_return(1, &ar->wmi.pending_tx_count) > if (atomic_add_return(1, &ar->wmi.pending_tx_count) >
WMI_MAX_PENDING_TX_COUNT) { WMI_MAX_PENDING_TX_COUNT) {
/* avoid using up memory when FW hangs */ /* avoid using up memory when FW hangs */
dev_kfree_skb(skb);
atomic_dec(&ar->wmi.pending_tx_count); atomic_dec(&ar->wmi.pending_tx_count);
return -EBUSY; return -EBUSY;
} }
...@@ -315,7 +316,9 @@ static inline u8 get_rate_idx(u32 rate, enum ieee80211_band band) ...@@ -315,7 +316,9 @@ static inline u8 get_rate_idx(u32 rate, enum ieee80211_band band)
static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
{ {
struct wmi_mgmt_rx_event *event = (struct wmi_mgmt_rx_event *)skb->data; struct wmi_mgmt_rx_event_v1 *ev_v1;
struct wmi_mgmt_rx_event_v2 *ev_v2;
struct wmi_mgmt_rx_hdr_v1 *ev_hdr;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
u32 rx_status; u32 rx_status;
...@@ -325,13 +328,24 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) ...@@ -325,13 +328,24 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
u32 rate; u32 rate;
u32 buf_len; u32 buf_len;
u16 fc; u16 fc;
int pull_len;
if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features)) {
ev_v2 = (struct wmi_mgmt_rx_event_v2 *)skb->data;
ev_hdr = &ev_v2->hdr.v1;
pull_len = sizeof(*ev_v2);
} else {
ev_v1 = (struct wmi_mgmt_rx_event_v1 *)skb->data;
ev_hdr = &ev_v1->hdr;
pull_len = sizeof(*ev_v1);
}
channel = __le32_to_cpu(event->hdr.channel); channel = __le32_to_cpu(ev_hdr->channel);
buf_len = __le32_to_cpu(event->hdr.buf_len); buf_len = __le32_to_cpu(ev_hdr->buf_len);
rx_status = __le32_to_cpu(event->hdr.status); rx_status = __le32_to_cpu(ev_hdr->status);
snr = __le32_to_cpu(event->hdr.snr); snr = __le32_to_cpu(ev_hdr->snr);
phy_mode = __le32_to_cpu(event->hdr.phy_mode); phy_mode = __le32_to_cpu(ev_hdr->phy_mode);
rate = __le32_to_cpu(event->hdr.rate); rate = __le32_to_cpu(ev_hdr->rate);
memset(status, 0, sizeof(*status)); memset(status, 0, sizeof(*status));
...@@ -358,7 +372,7 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) ...@@ -358,7 +372,7 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR; status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR;
status->rate_idx = get_rate_idx(rate, status->band); status->rate_idx = get_rate_idx(rate, status->band);
skb_pull(skb, sizeof(event->hdr)); skb_pull(skb, pull_len);
hdr = (struct ieee80211_hdr *)skb->data; hdr = (struct ieee80211_hdr *)skb->data;
fc = le16_to_cpu(hdr->frame_control); fc = le16_to_cpu(hdr->frame_control);
...@@ -943,6 +957,9 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar, ...@@ -943,6 +957,9 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
ar->phy_capability = __le32_to_cpu(ev->phy_capability); ar->phy_capability = __le32_to_cpu(ev->phy_capability);
ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains); ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains);
if (ar->fw_version_build > 636)
set_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features);
if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) { if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) {
ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n", ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n",
ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM); ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM);
......
...@@ -1268,7 +1268,7 @@ struct wmi_scan_event { ...@@ -1268,7 +1268,7 @@ struct wmi_scan_event {
* good idea to pass all the fields in the RX status * good idea to pass all the fields in the RX status
* descriptor up to the host. * descriptor up to the host.
*/ */
struct wmi_mgmt_rx_hdr { struct wmi_mgmt_rx_hdr_v1 {
__le32 channel; __le32 channel;
__le32 snr; __le32 snr;
__le32 rate; __le32 rate;
...@@ -1277,8 +1277,18 @@ struct wmi_mgmt_rx_hdr { ...@@ -1277,8 +1277,18 @@ struct wmi_mgmt_rx_hdr {
__le32 status; /* %WMI_RX_STATUS_ */ __le32 status; /* %WMI_RX_STATUS_ */
} __packed; } __packed;
struct wmi_mgmt_rx_event { struct wmi_mgmt_rx_hdr_v2 {
struct wmi_mgmt_rx_hdr hdr; struct wmi_mgmt_rx_hdr_v1 v1;
__le32 rssi_ctl[4];
} __packed;
struct wmi_mgmt_rx_event_v1 {
struct wmi_mgmt_rx_hdr_v1 hdr;
u8 buf[0];
} __packed;
struct wmi_mgmt_rx_event_v2 {
struct wmi_mgmt_rx_hdr_v2 hdr;
u8 buf[0]; u8 buf[0];
} __packed; } __packed;
......
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