diff options
| -rw-r--r-- | CORE/CLD_TXRX/TXRX/ol_tx.c | 58 | ||||
| -rw-r--r-- | CORE/CLD_TXRX/TXRX/ol_tx_desc.c | 2 | ||||
| -rw-r--r-- | CORE/HDD/src/wlan_hdd_tx_rx.c | 38 | ||||
| -rw-r--r-- | CORE/SERVICES/COMMON/ol_htt_tx_api.h | 178 |
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(ð_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], ð_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, |
