aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2013-08-09 04:13:34 -0400
committerKalle Valo <kvalo@qca.qualcomm.com>2013-08-15 09:04:41 -0400
commit961d4c38961a0f61e43edbb1fb579f28475a88bd (patch)
treeac9d8b74316fe4c9e79571c2b89b1b790ac50056
parent0d9b0438b616479e4decadf2cb7d39a5f4e5360f (diff)
ath10k: add support for HTT 3.0
New firmware comes with new HTT protocol version. In 3.0 the separate mgmt tx command has been removed. All traffic is to be pushed through data tx (tx_frm) command with a twist - FW seems to not be able (yet?) to access tx fragment table so for manamgement frames frame pointer is passed directly. Signed-off-by: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.c19
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.h6
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_tx.c74
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h3
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c13
5 files changed, 76 insertions, 39 deletions
diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c
index 39342c5cfcb2..5f7eeebc5432 100644
--- a/drivers/net/wireless/ath/ath10k/htt.c
+++ b/drivers/net/wireless/ath/ath10k/htt.c
@@ -104,21 +104,16 @@ err_htc_attach:
104 104
105static int ath10k_htt_verify_version(struct ath10k_htt *htt) 105static int ath10k_htt_verify_version(struct ath10k_htt *htt)
106{ 106{
107 ath10k_dbg(ATH10K_DBG_HTT, 107 ath10k_info("htt target version %d.%d\n",
108 "htt target version %d.%d; host version %d.%d\n", 108 htt->target_version_major, htt->target_version_minor);
109 htt->target_version_major, 109
110 htt->target_version_minor, 110 if (htt->target_version_major != 2 &&
111 HTT_CURRENT_VERSION_MAJOR, 111 htt->target_version_major != 3) {
112 HTT_CURRENT_VERSION_MINOR); 112 ath10k_err("unsupported htt major version %d. supported versions are 2 and 3\n",
113 113 htt->target_version_major);
114 if (htt->target_version_major != HTT_CURRENT_VERSION_MAJOR) {
115 ath10k_err("htt major versions are incompatible!\n");
116 return -ENOTSUPP; 114 return -ENOTSUPP;
117 } 115 }
118 116
119 if (htt->target_version_minor != HTT_CURRENT_VERSION_MINOR)
120 ath10k_warn("htt minor version differ but still compatible\n");
121
122 return 0; 117 return 0;
123} 118}
124 119
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 318be4629cde..26c78a907f97 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -23,9 +23,6 @@
23#include "htc.h" 23#include "htc.h"
24#include "rx_desc.h" 24#include "rx_desc.h"
25 25
26#define HTT_CURRENT_VERSION_MAJOR 2
27#define HTT_CURRENT_VERSION_MINOR 1
28
29enum htt_dbg_stats_type { 26enum htt_dbg_stats_type {
30 HTT_DBG_STATS_WAL_PDEV_TXRX = 1 << 0, 27 HTT_DBG_STATS_WAL_PDEV_TXRX = 1 << 0,
31 HTT_DBG_STATS_RX_REORDER = 1 << 1, 28 HTT_DBG_STATS_RX_REORDER = 1 << 1,
@@ -45,6 +42,9 @@ enum htt_h2t_msg_type { /* host-to-target */
45 HTT_H2T_MSG_TYPE_SYNC = 4, 42 HTT_H2T_MSG_TYPE_SYNC = 4,
46 HTT_H2T_MSG_TYPE_AGGR_CFG = 5, 43 HTT_H2T_MSG_TYPE_AGGR_CFG = 5,
47 HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG = 6, 44 HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG = 6,
45
46 /* This command is used for sending management frames in HTT < 3.0.
47 * HTT >= 3.0 uses TX_FRM for everything. */
48 HTT_H2T_MSG_TYPE_MGMT_TX = 7, 48 HTT_H2T_MSG_TYPE_MGMT_TX = 7,
49 49
50 HTT_H2T_NUM_MSGS /* keep this last */ 50 HTT_H2T_NUM_MSGS /* keep this last */
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 656c2546b294..d4fb3875c918 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -401,10 +401,16 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
401 goto err; 401 goto err;
402 } 402 }
403 403
404 txfrag = dev_alloc_skb(frag_len); 404 /* Since HTT 3.0 there is no separate mgmt tx command. However in case
405 if (!txfrag) { 405 * of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
406 res = -ENOMEM; 406 * fragment list host driver specifies directly frame pointer. */
407 goto err; 407 if (htt->target_version_major < 3 ||
408 !ieee80211_is_mgmt(hdr->frame_control)) {
409 txfrag = dev_alloc_skb(frag_len);
410 if (!txfrag) {
411 res = -ENOMEM;
412 goto err;
413 }
408 } 414 }
409 415
410 if (!IS_ALIGNED((unsigned long)txdesc->data, 4)) { 416 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 if (res) 433 if (res)
428 goto err; 434 goto err;
429 435
430 /* tx fragment list must be terminated with zero-entry */ 436 /* Since HTT 3.0 there is no separate mgmt tx command. However in case
431 skb_put(txfrag, frag_len); 437 * of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
432 tx_frags = (struct htt_data_tx_desc_frag *)txfrag->data; 438 * fragment list host driver specifies directly frame pointer. */
433 tx_frags[0].paddr = __cpu_to_le32(ATH10K_SKB_CB(msdu)->paddr); 439 if (htt->target_version_major < 3 ||
434 tx_frags[0].len = __cpu_to_le32(msdu->len); 440 !ieee80211_is_mgmt(hdr->frame_control)) {
435 tx_frags[1].paddr = __cpu_to_le32(0); 441 /* tx fragment list must be terminated with zero-entry */
436 tx_frags[1].len = __cpu_to_le32(0); 442 skb_put(txfrag, frag_len);
437 443 tx_frags = (struct htt_data_tx_desc_frag *)txfrag->data;
438 res = ath10k_skb_map(dev, txfrag); 444 tx_frags[0].paddr = __cpu_to_le32(ATH10K_SKB_CB(msdu)->paddr);
439 if (res) 445 tx_frags[0].len = __cpu_to_le32(msdu->len);
440 goto err; 446 tx_frags[1].paddr = __cpu_to_le32(0);
447 tx_frags[1].len = __cpu_to_le32(0);
448
449 res = ath10k_skb_map(dev, txfrag);
450 if (res)
451 goto err;
452
453 ath10k_dbg(ATH10K_DBG_HTT, "txfrag 0x%llx\n",
454 (unsigned long long) ATH10K_SKB_CB(txfrag)->paddr);
455 ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "txfrag: ",
456 txfrag->data, frag_len);
457 }
441 458
442 ath10k_dbg(ATH10K_DBG_HTT, "txfrag 0x%llx msdu 0x%llx\n", 459 ath10k_dbg(ATH10K_DBG_HTT, "msdu 0x%llx\n",
443 (unsigned long long) ATH10K_SKB_CB(txfrag)->paddr,
444 (unsigned long long) ATH10K_SKB_CB(msdu)->paddr); 460 (unsigned long long) ATH10K_SKB_CB(msdu)->paddr);
445 ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "txfrag: ",
446 txfrag->data, frag_len);
447 ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "msdu: ", 461 ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "msdu: ",
448 msdu->data, msdu->len); 462 msdu->data, msdu->len);
449 463
@@ -459,8 +473,17 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
459 if (!ieee80211_has_protected(hdr->frame_control)) 473 if (!ieee80211_has_protected(hdr->frame_control))
460 flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT; 474 flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT;
461 flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; 475 flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
462 flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI, 476
463 HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); 477 /* Since HTT 3.0 there is no separate mgmt tx command. However in case
478 * of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
479 * fragment list host driver specifies directly frame pointer. */
480 if (htt->target_version_major >= 3 &&
481 ieee80211_is_mgmt(hdr->frame_control))
482 flags0 |= SM(ATH10K_HW_TXRX_MGMT,
483 HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
484 else
485 flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI,
486 HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
464 487
465 flags1 = 0; 488 flags1 = 0;
466 flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID); 489 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 flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; 491 flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD;
469 flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; 492 flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD;
470 493
471 frags_paddr = ATH10K_SKB_CB(txfrag)->paddr; 494 /* Since HTT 3.0 there is no separate mgmt tx command. However in case
495 * of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
496 * fragment list host driver specifies directly frame pointer. */
497 if (htt->target_version_major >= 3 &&
498 ieee80211_is_mgmt(hdr->frame_control))
499 frags_paddr = ATH10K_SKB_CB(msdu)->paddr;
500 else
501 frags_paddr = ATH10K_SKB_CB(txfrag)->paddr;
472 502
473 cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM; 503 cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM;
474 cmd->data_tx.flags0 = flags0; 504 cmd->data_tx.flags0 = flags0;
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 98687059ad9e..5708888486eb 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -45,6 +45,9 @@ enum ath10k_hw_txrx_mode {
45 ATH10K_HW_TXRX_RAW = 0, 45 ATH10K_HW_TXRX_RAW = 0,
46 ATH10K_HW_TXRX_NATIVE_WIFI = 1, 46 ATH10K_HW_TXRX_NATIVE_WIFI = 1,
47 ATH10K_HW_TXRX_ETHERNET = 2, 47 ATH10K_HW_TXRX_ETHERNET = 2,
48
49 /* Valid for HTT >= 3.0. Used for management frames in TX_FRM. */
50 ATH10K_HW_TXRX_MGMT = 3,
48}; 51};
49 52
50enum ath10k_mcast2ucast_mode { 53enum ath10k_mcast2ucast_mode {
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 7eab8a429e7c..248248b5c196 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1473,6 +1473,12 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
1473 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 1473 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
1474 int ret; 1474 int ret;
1475 1475
1476 if (ar->htt.target_version_major >= 3) {
1477 /* Since HTT 3.0 there is no separate mgmt tx command */
1478 ret = ath10k_htt_tx(&ar->htt, skb);
1479 goto exit;
1480 }
1481
1476 if (ieee80211_is_mgmt(hdr->frame_control)) 1482 if (ieee80211_is_mgmt(hdr->frame_control))
1477 ret = ath10k_htt_mgmt_tx(&ar->htt, skb); 1483 ret = ath10k_htt_mgmt_tx(&ar->htt, skb);
1478 else if (ieee80211_is_nullfunc(hdr->frame_control)) 1484 else if (ieee80211_is_nullfunc(hdr->frame_control))
@@ -1484,6 +1490,7 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
1484 else 1490 else
1485 ret = ath10k_htt_tx(&ar->htt, skb); 1491 ret = ath10k_htt_tx(&ar->htt, skb);
1486 1492
1493exit:
1487 if (ret) { 1494 if (ret) {
1488 ath10k_warn("tx failed (%d). dropping packet.\n", ret); 1495 ath10k_warn("tx failed (%d). dropping packet.\n", ret);
1489 ieee80211_free_txskb(ar->hw, skb); 1496 ieee80211_free_txskb(ar->hw, skb);
@@ -1720,8 +1727,10 @@ static void ath10k_tx(struct ieee80211_hw *hw,
1720 /* we must calculate tid before we apply qos workaround 1727 /* we must calculate tid before we apply qos workaround
1721 * as we'd lose the qos control field */ 1728 * as we'd lose the qos control field */
1722 tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST; 1729 tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
1723 if (ieee80211_is_data_qos(hdr->frame_control) && 1730 if (ieee80211_is_mgmt(hdr->frame_control)) {
1724 is_unicast_ether_addr(ieee80211_get_DA(hdr))) { 1731 tid = HTT_DATA_TX_EXT_TID_MGMT;
1732 } else if (ieee80211_is_data_qos(hdr->frame_control) &&
1733 is_unicast_ether_addr(ieee80211_get_DA(hdr))) {
1725 u8 *qc = ieee80211_get_qos_ctl(hdr); 1734 u8 *qc = ieee80211_get_qos_ctl(hdr);
1726 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; 1735 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
1727 } 1736 }