diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2013-08-09 04:13:34 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2013-08-15 09:04:41 -0400 |
commit | 961d4c38961a0f61e43edbb1fb579f28475a88bd (patch) | |
tree | ac9d8b74316fe4c9e79571c2b89b1b790ac50056 | |
parent | 0d9b0438b616479e4decadf2cb7d39a5f4e5360f (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.c | 19 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/htt.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/htt_tx.c | 74 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/hw.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/mac.c | 13 |
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 | ||
105 | static int ath10k_htt_verify_version(struct ath10k_htt *htt) | 105 | static 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 | |||
29 | enum htt_dbg_stats_type { | 26 | enum 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 | ||
50 | enum ath10k_mcast2ucast_mode { | 53 | enum 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 | ||
1493 | exit: | ||
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 | } |