summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CORE/CLD_TXRX/TXRX/ol_tx.c58
-rw-r--r--CORE/CLD_TXRX/TXRX/ol_tx_desc.c2
-rw-r--r--CORE/HDD/src/wlan_hdd_tx_rx.c38
-rw-r--r--CORE/SERVICES/COMMON/ol_htt_tx_api.h178
4 files changed, 231 insertions, 45 deletions
diff --git a/CORE/CLD_TXRX/TXRX/ol_tx.c b/CORE/CLD_TXRX/TXRX/ol_tx.c
index 20419839b69a..4de014f2d5eb 100644
--- a/CORE/CLD_TXRX/TXRX/ol_tx.c
+++ b/CORE/CLD_TXRX/TXRX/ol_tx.c
@@ -505,6 +505,48 @@ ol_tx_non_std_ll(
/* tx filtering is handled within the target FW */
#define TX_FILTER_CHECK(tx_msdu_info) 0 /* don't filter */
+
+/**
+ * parse_ocb_tx_header() - Function to check for OCB
+ * TX control header on a packet and extract it if present
+ *
+ * @msdu: Pointer to OS packet (adf_nbuf_t)
+ */
+#define HDD_ETHERTYPE_OCB_TX 0x8151
+#define OCB_HEADER_VERSION 1
+static bool parse_ocb_tx_header(adf_nbuf_t msdu,
+ struct ocb_tx_ctrl_hdr_t *tx_ctrl)
+{
+ struct ether_header *eth_hdr_p;
+ struct ocb_tx_ctrl_hdr_t *tx_ctrl_hdr;
+
+ /* Check if TX control header is present */
+ eth_hdr_p = (struct ether_header *) adf_nbuf_data(msdu);
+ if (eth_hdr_p->ether_type != adf_os_htons(HDD_ETHERTYPE_OCB_TX)) {
+ /* TX control header is not present. Nothing to do.. */
+ return true;
+ }
+
+ /* Remove the ethernet header */
+ adf_nbuf_pull_head(msdu, sizeof(struct ether_header));
+
+ /* Parse the TX control header */
+ tx_ctrl_hdr = (struct ocb_tx_ctrl_hdr_t*) adf_nbuf_data(msdu);
+
+ if (tx_ctrl_hdr->version == OCB_HEADER_VERSION) {
+ if (tx_ctrl) {
+ adf_os_mem_copy(tx_ctrl, tx_ctrl_hdr, sizeof(*tx_ctrl_hdr));
+ }
+ } else {
+ /* The TX control header is invalid. */
+ return false;
+ }
+
+ /* Remove the TX control header */
+ adf_nbuf_pull_head(msdu, tx_ctrl_hdr->length);
+ return true;
+}
+
static inline adf_nbuf_t
ol_tx_hl_base(
ol_txrx_vdev_handle vdev,
@@ -515,6 +557,8 @@ ol_tx_hl_base(
struct ol_txrx_pdev_t *pdev = vdev->pdev;
adf_nbuf_t msdu = msdu_list;
struct ol_txrx_msdu_info_t tx_msdu_info;
+ struct ocb_tx_ctrl_hdr_t tx_ctrl;
+
htt_pdev_handle htt_pdev = pdev->htt_pdev;
tx_msdu_info.peer = NULL;
@@ -529,6 +573,8 @@ ol_tx_hl_base(
struct ol_tx_frms_queue_t *txq;
struct ol_tx_desc_t *tx_desc = NULL;
+ adf_os_mem_zero(&tx_ctrl, sizeof(tx_ctrl));
+
/*
* The netbuf will get stored into a (peer-TID) tx queue list
* inside the ol_tx_classify_store function or else dropped,
@@ -586,6 +632,14 @@ ol_tx_hl_base(
tx_msdu_info.htt.info.l2_hdr_type = pdev->htt_pkt_type;
tx_msdu_info.htt.action.tx_comp_req = tx_comp_req;
+ /* If the vdev is in OCB mode, parse the tx control header. */
+ if (vdev->opmode == wlan_op_mode_ocb) {
+ if (!parse_ocb_tx_header(msdu, &tx_ctrl)) {
+ /* There was an error parsing the header. Skip this packet. */
+ goto MSDU_LOOP_BOTTOM;
+ }
+ }
+
txq = ol_tx_classify(vdev, tx_desc, msdu, &tx_msdu_info);
if ((!txq) || TX_FILTER_CHECK(&tx_msdu_info)) {
@@ -643,7 +697,7 @@ ol_tx_hl_base(
tx_desc->htt_tx_desc_paddr,
ol_tx_desc_id(pdev, tx_desc),
msdu,
- &tx_msdu_info.htt);
+ &tx_msdu_info.htt, &tx_ctrl, vdev->opmode == wlan_op_mode_ocb);
/*
* If debug display is enabled, show the meta-data being
* downloaded to the target via the HTT tx descriptor.
@@ -849,7 +903,7 @@ ol_txrx_mgmt_send(
tx_desc->htt_tx_desc_paddr,
ol_tx_desc_id(pdev, tx_desc),
tx_mgmt_frm,
- &tx_msdu_info.htt);
+ &tx_msdu_info.htt, NULL, 0);
htt_tx_desc_display(tx_desc->htt_tx_desc);
htt_tx_desc_set_chanfreq(tx_desc->htt_tx_desc, chanfreq);
diff --git a/CORE/CLD_TXRX/TXRX/ol_tx_desc.c b/CORE/CLD_TXRX/TXRX/ol_tx_desc.c
index 45fbc598fbd4..710732a4b6f2 100644
--- a/CORE/CLD_TXRX/TXRX/ol_tx_desc.c
+++ b/CORE/CLD_TXRX/TXRX/ol_tx_desc.c
@@ -200,7 +200,7 @@ ol_tx_desc_ll(
tx_desc->htt_tx_desc_paddr,
ol_tx_desc_id(pdev, tx_desc),
netbuf,
- &msdu_info->htt);
+ &msdu_info->htt, NULL, vdev->opmode == wlan_op_mode_ocb);
/*
* Initialize the fragmentation descriptor.
diff --git a/CORE/HDD/src/wlan_hdd_tx_rx.c b/CORE/HDD/src/wlan_hdd_tx_rx.c
index f9d9f491a41a..91cb6145eeff 100644
--- a/CORE/HDD/src/wlan_hdd_tx_rx.c
+++ b/CORE/HDD/src/wlan_hdd_tx_rx.c
@@ -741,40 +741,6 @@ void hdd_tx_resume_cb(void *adapter_context,
}
#endif /* QCA_LL_TX_FLOW_CT */
-/**
- * hdd_remove_ocb_tx_header() - Function to check for OCB
- * TX control header on a packet and extract it if present
- *
- * @skb: Pointer to OS packet (sk_buff)
- */
-static void hdd_remove_ocb_tx_header(struct sk_buff *skb)
-{
- struct ethhdr *eth_hdr_p;
- struct ethhdr eth_hdr;
-
- /* Check if TX control header is present */
- eth_hdr_p = (struct ethhdr *) &skb->data[0];
- if (eth_hdr_p->h_proto != htons(HDD_ETHERTYPE_OCB_TX)) {
- /* TX control header is not present. Nothing to do.. */
- return;
- }
-
- /* Copy and remove the ethernet header */
- memcpy(&eth_hdr, eth_hdr_p, HDD_ETH_HEADER_LEN);
- skb_pull(skb, HDD_ETH_HEADER_LEN);
-
- /* Remove the TX control header */
- skb_pull(skb, HDD_OCB_TX_HEADER_LEN);
-
- /* Convert Ethernet header to 802.3 header by changing ethertype
- field to length field */
- eth_hdr.h_proto = htons(skb->len);
-
- /* Push the now 802.3 header back */
- skb_push(skb, HDD_ETH_HEADER_LEN);
- memcpy(&skb->data[0], &eth_hdr, HDD_ETH_HEADER_LEN);
-}
-
/**============================================================================
@brief hdd_hard_start_xmit() - Function registered with the Linux OS for
transmitting packets. This version of the function directly passes the packet
@@ -838,10 +804,6 @@ int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
STAId = pHddStaCtx->conn_info.staId[0];
}
- if (pAdapter->device_mode == WLAN_HDD_OCB) {
- hdd_remove_ocb_tx_header(skb);
- }
-
#ifdef QCA_LL_TX_FLOW_CT
if (VOS_FALSE ==
WLANTL_GetTxResource((WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
diff --git a/CORE/SERVICES/COMMON/ol_htt_tx_api.h b/CORE/SERVICES/COMMON/ol_htt_tx_api.h
index 06527bd594b3..7e208012333a 100644
--- a/CORE/SERVICES/COMMON/ol_htt_tx_api.h
+++ b/CORE/SERVICES/COMMON/ol_htt_tx_api.h
@@ -48,6 +48,22 @@
#include <htt_types.h>
#include <vos_trace.h>
+/* Remove these macros when they get added to htt.h. */
+#ifndef HTT_TX_DESC_EXTENSION_GET
+#define HTT_TX_DESC_EXTENSION_OFFSET_BYTES 0
+#define HTT_TX_DESC_EXTENSION_OFFSET_DWORD 0
+#define HTT_TX_DESC_EXTENSION_M 0x10000000
+#define HTT_TX_DESC_EXTENSION_S 28
+
+#define HTT_TX_DESC_EXTENSION_GET(_var) \
+ (((_var) & HTT_TX_DESC_EXTENSION_M) >> HTT_TX_DESC_EXTENSION_S)
+#define HTT_TX_DESC_EXTENSION_SET(_var, _val) \
+ do { \
+ HTT_CHECK_SET_VAL(HTT_TX_DESC_EXTENSION, _val); \
+ ((_var) |= ((_val) << HTT_TX_DESC_EXTENSION_S)); \
+ } while (0)
+#endif
+
/*================ meta-info about tx MSDUs =================================*/
/*
@@ -95,6 +111,111 @@ enum htt_frm_subtype {
htt_frm_subtype_data_QoS_cf_ack_cf_poll = 15,
};
+enum htt_ofdm_datarate { // Value MBPS Modulation Coding
+ htt_ofdm_datarate_6_mbps = 0, // 0 6 BPSK 1/2
+ htt_ofdm_datarate_9_mbps = 1, // 1 9 BPSK 3/4
+ htt_ofdm_datarate_12_mbps = 2, // 2 12 QPSK 1/2
+ htt_ofdm_datarate_18_mbps = 3, // 3 18 QPSK 3/4
+ htt_ofdm_datarate_24_mbps = 4, // 4 24 16-QAM 1/2
+ htt_ofdm_datarate_36_mbps = 5, // 5 36 16-QAM 3/4
+ htt_ofdm_datarate_48_mbps = 6, // 6 48 64-QAM 1/2
+ htt_ofdm_datarate_54_mbps = 7, // 7 54 64-QAM 3/4
+ htt_ofdm_datarate_max = 7,
+};
+
+/**
+ * @brief TX control header
+ * @details
+ * When sending an OCB packet, the user application has
+ * the option of including the following struct following an ethernet header
+ * with the proto field set to 0x8151. This struct includes various TX
+ * paramaters including the TX power and MCS.
+ */
+PREPACK struct ocb_tx_ctrl_hdr_t {
+ /* The version must be 1. */
+ A_UINT16 version;
+ A_UINT16 length;
+ A_UINT16 channel_freq;
+
+ /* flags */
+ union {
+ struct {
+ A_UINT16
+ /* bit 0: if set, tx pwr spec is valid */
+ valid_pwr: 1,
+ /* bit 1: if set, tx MCS mask spec is valid */
+ valid_datarate: 1,
+ /* bit 2: if set, tx retries spec is valid */
+ valid_retries: 1,
+ /* bit 3: if set, chain mask is valid */
+ valid_chain_mask: 1,
+ /* bit 4: if set, tx expire TSF spec is valid*/
+ valid_expire_tsf: 1,
+ /* bit 5: if set, TID is valid */
+ valid_tid: 1,
+ reserved0_15_6: 10; /* bits 15:6 - unused, set to 0x0 */
+ };
+ A_UINT16 all_flags;
+ };
+
+ /* TX expiry time (TSF) LSBs */
+ A_UINT32 expire_tsf_lo;
+
+ /* TX expiry time (TSF) MSBs */
+ A_UINT32 expire_tsf_hi;
+
+ /* pwr -
+ * Specify what power the tx frame needs to be transmitted at.
+ * The power a signed (two's complement) value is in units of 0.5 dBm.
+ * The value needs to be appropriately sign-extended when extracting
+ * the value from the message and storing it in a variable that is
+ * larger than A_INT8.
+ * If the transmission uses multiple tx chains, this power spec is
+ * the total transmit power, assuming incoherent combination of
+ * per-chain power to produce the total power.
+ */
+ A_INT8 pwr;
+
+ /* datarate -
+ * The desired modulation and coding scheme.
+ *
+ * VALUE DATA RATE MODULATION CODING RATE
+ * @ 20 MHz
+ * (MBPS)
+ * 0 6 BPSK 1/2
+ * 1 9 BPSK 3/4
+ * 2 12 QPSK 1/2
+ * 3 18 QPSK 3/4
+ * 4 24 16-QAM 1/2
+ * 5 36 16-QAM 3/4
+ * 6 48 64-QAM 1/2
+ * 7 54 64-QAM 3/4
+ */
+ A_UINT8 datarate;
+
+ /* retry_limit -
+ * Specify the maximum number of transmissions, including the
+ * initial transmission, to attempt before giving up if no ack
+ * is received.
+ * If the tx rate is specified, then all retries shall use the
+ * same rate as the initial transmission.
+ * If no tx rate is specified, the target can choose whether to
+ * retain the original rate during the retransmissions, or to
+ * fall back to a more robust rate.
+ */
+ A_UINT8 retry_limit;
+
+ /* Chain mask - specify which chains to transmit from. */
+ A_UINT8 chain_mask;
+
+ /* Extended Traffic ID (0-15) */
+ A_UINT8 ext_tid;
+
+ /* Ensure that the size of the structure is a multiple of 4. */
+ A_UINT8 reserved[3];
+
+} POSTPACK;
+
/**
* @brief tx MSDU meta-data that HTT may use to program the FW/HW tx descriptor
*/
@@ -393,12 +514,15 @@ htt_tx_desc_init(
u_int32_t htt_tx_desc_paddr_lo,
u_int16_t msdu_id,
adf_nbuf_t msdu,
- struct htt_msdu_info_t *msdu_info)
+ struct htt_msdu_info_t *msdu_info,
+ struct ocb_tx_ctrl_hdr_t *tx_ctrl,
+ u_int8_t is_dsrc)
{
u_int32_t *word0, *word1, *word3;
- u_int32_t local_word0, local_word1;
+ u_int32_t local_word0, local_word1, local_word3;
struct htt_host_tx_desc_t *htt_host_tx_desc = (struct htt_host_tx_desc_t *)
(((char *) htt_tx_desc) - HTT_TX_DESC_VADDR_OFFSET);
+ bool desc_ext_required = (tx_ctrl && tx_ctrl->all_flags != 0);
word0 = (u_int32_t *) htt_tx_desc;
word1 = word0 + 1;
@@ -417,8 +541,13 @@ htt_tx_desc_init(
HTT_H2T_MSG_TYPE_SET(local_word0, HTT_H2T_MSG_TYPE_TX_FRM);
HTT_TX_DESC_PKT_TYPE_SET(local_word0, msdu_info->info.l2_hdr_type);
HTT_TX_DESC_VDEV_ID_SET(local_word0, msdu_info->info.vdev_id);
- HTT_TX_DESC_EXT_TID_SET(local_word0, msdu_info->info.ext_tid);
+ if (tx_ctrl && tx_ctrl->valid_tid) {
+ HTT_TX_DESC_EXT_TID_SET(local_word0, tx_ctrl->ext_tid);
+ } else {
+ HTT_TX_DESC_EXT_TID_SET(local_word0, msdu_info->info.ext_tid);
+ }
HTT_TX_DESC_CKSUM_OFFLOAD_SET(local_word0, msdu_info->action.cksum_offload);
+ HTT_TX_DESC_EXTENSION_SET(local_word0, desc_ext_required);
if (pdev->cfg.is_high_latency)
HTT_TX_DESC_TX_COMP_SET(local_word0, msdu_info->action.tx_comp_req);
HTT_TX_DESC_NO_ENCRYPT_SET(local_word0, msdu_info->action.do_encrypt ? 0 : 1);
@@ -427,10 +556,51 @@ htt_tx_desc_init(
local_word1 = 0;
HTT_TX_DESC_FRM_LEN_SET(local_word1, adf_nbuf_len(msdu));
HTT_TX_DESC_FRM_ID_SET(local_word1, msdu_id);
+
*word1 = local_word1;
/* Initialize peer_id to INVALID_PEER bcoz this is NOT Reinjection path*/
- *word3 = HTT_INVALID_PEER;
+ local_word3 = HTT_INVALID_PEER;
+ if (tx_ctrl && tx_ctrl->channel_freq) {
+ HTT_TX_DESC_CHAN_FREQ_SET(local_word3, tx_ctrl->channel_freq);
+ }
+ *word3 = local_word3;
+
+ /*
+ * If any of the tx control flags are set, then we need the extended
+ * HTT header.
+ */
+ if (desc_ext_required)
+ {
+ struct htt_tx_msdu_desc_ext_t local_desc_ext = {0};
+
+ /*
+ * Copy the info that was read from TX control header from the user
+ * application to the extended HTT header.
+ * First copy everything
+ * to a local temp structure, and then copy everything to the
+ * actual uncached structure in one go to save memory writes.
+ */
+ local_desc_ext.valid_pwr = tx_ctrl->valid_pwr;
+ local_desc_ext.valid_mcs_mask = tx_ctrl->valid_datarate;
+ local_desc_ext.valid_retries = tx_ctrl->valid_retries;
+ local_desc_ext.valid_expire_tsf = tx_ctrl->valid_expire_tsf;
+ local_desc_ext.valid_chainmask = tx_ctrl->valid_chain_mask;
+
+ local_desc_ext.pwr = tx_ctrl->pwr;
+ if (tx_ctrl->valid_datarate &&
+ tx_ctrl->datarate <= htt_ofdm_datarate_max)
+ local_desc_ext.mcs_mask = (1 << (tx_ctrl->datarate + 4));
+ local_desc_ext.retry_limit = tx_ctrl->retry_limit;
+ local_desc_ext.expire_tsf_lo = tx_ctrl->expire_tsf_lo;
+ local_desc_ext.expire_tsf_hi = tx_ctrl->expire_tsf_hi;
+ local_desc_ext.chain_mask = tx_ctrl->chain_mask;
+
+ local_desc_ext.is_dsrc = (is_dsrc != 0);
+
+ adf_nbuf_push_head(msdu, sizeof(local_desc_ext));
+ adf_os_mem_copy(adf_nbuf_data(msdu), &local_desc_ext,
+ sizeof(local_desc_ext)); }
/*
* Specify that the data provided by the OS is a bytestream,