text: /*
   * Copyright (c) 2011-2014, 2017 The Linux Foundation. All rights reserved.
   *
   * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
   *
   *
   * Permission to use, copy, modify, and/or distribute this software for
   * any purpose with or without fee is hereby granted, provided that the
   * above copyright notice and this permission notice appear in all
   * copies.
   *
   * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
   * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
   * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
   * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
   * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
   * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
   * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
   * PERFORMANCE OF THIS SOFTWARE.
   */
  
  /*
   * This file was originally distributed by Qualcomm Atheros, Inc.
   * under proprietary terms before Copyright ownership was assigned
   * to the Linux Foundation.
   */
  
  /**
   * @file ol_htt_tx_api.h
   * @brief Specify the tx HTT API functions called by the host data SW.
   * @details
   *  This file declares the HTT API functions that are specifically
   *  related to transmit processing.
   *  In particular, the methods of the abstract HTT tx descriptor are
   *  specified.
   */
  #ifndef _OL_HTT_TX_API__H_
  #define _OL_HTT_TX_API__H_
  
  //#include <osapi_linux.h>    /* u_int16_t, etc. */
  #include <osdep.h>      /* u_int16_t, etc. */
  #include <adf_nbuf.h>   /* adf_nbuf_t */
  #include <ol_cfg.h>     /* wlan_frm_fmt */
  
  #include <htt.h>        /* needed by inline functions */
  #include <adf_net_types.h>
  #include <ol_htt_api.h> /* htt_pdev_handle */
  #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 =================================*/
  
  /*
   * For simplicity, use the IEEE 802.11 frame type values.
   */
  enum htt_frm_type {
  	htt_frm_type_mgmt = 0,
  	htt_frm_type_ctrl = 1,
  	htt_frm_type_data = 2
  };
  
  /*
   * For simplicity, use the IEEE 802.11 frame sub-type values.
   */
  enum htt_frm_subtype {
      htt_frm_subtype_mgmt_assoc_req = 0,
      htt_frm_subtype_mgmt_assoc_resp = 1,
      htt_frm_subtype_mgmt_reassoc_req = 2,
      htt_frm_subtype_mgmt_reassoc_resp = 3,
      htt_frm_subtype_mgmt_probe_req = 4,
      htt_frm_subtype_mgmt_probe_resp = 5,
      htt_frm_subtype_mgmt_timing_adv = 6,
      htt_frm_subtype_mgmt_beacon = 8,
      htt_frm_subtype_mgmt_atim = 9,
      htt_frm_subtype_mgmt_disassoc = 10,
      htt_frm_subtype_mgmt_auth = 11,
      htt_frm_subtype_mgmt_deauth = 12,
      htt_frm_subtype_mgmt_action = 13,
      htt_frm_subtype_mgmt_action_no_ack = 14,
  
      htt_frm_subtype_data_data = 0,
      htt_frm_subtype_data_data_cf_ack = 1,
      htt_frm_subtype_data_data_cf_poll = 2,
      htt_frm_subtype_data_data_cf_ack_cf_poll = 3,
      htt_frm_subtype_data_null = 4,
      htt_frm_subtype_data_cf_ack = 5,
      htt_frm_subtype_data_cf_poll = 6,
      htt_frm_subtype_data_cf_ack_cf_poll = 7,
      htt_frm_subtype_data_QoS_data = 8,
      htt_frm_subtype_data_QoS_data_cf_ack = 9,
      htt_frm_subtype_data_QoS_data_cf_poll = 10,
      htt_frm_subtype_data_QoS_data_cf_ack_cf_poll = 11,
      htt_frm_subtype_data_QoS_null = 12,
      htt_frm_subtype_data_QoS_cf_poll = 14,
      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,
                  /* bit 6: if set, tx frame with 802.3 ethernet header */
                  valid_eth_mode:       1,
                  /* bits 15:7 - unused, set to 0x0 */
                  reserved0_15_7:       9;
          };
          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
   */
  struct htt_msdu_info_t {
      /* the info sub-struct specifies the characteristics of the MSDU */
      struct {
          u_int16_t ethertype;
          #define HTT_INVALID_PEER_ID 0xffff
          u_int16_t peer_id;
          u_int8_t vdev_id;
          u_int8_t ext_tid;
          /*
           * l2_hdr_type - L2 format (802.3, native WiFi 802.11, or raw 802.11)
           * Based on attach-time configuration, the tx frames provided by the
           * OS to the tx data SW are expected to be either 802.3 format or
           * the "native WiFi" variant of 802.11 format.
           * Internally, the driver may also inject tx frames into the tx
           * datapath, and these frames may be either 802.3 format, or 802.11
           * "raw" format, with no further 802.11 encapsulation needed.
           * The tx frames are tagged with their frame format, so the target
           * FW/HW will know how to interpret the packet's encapsulation
           * headers when doing tx classification, and what form of 802.11
           * header encapsulation is needed, if any.
           */
          u_int8_t l2_hdr_type; /* enum htt_pkt_type */
          /*
           * frame_type - is the tx frame management or data?
           * Just to avoid confusion, the enum values for this frame type field
           * use the 802.11 frame type values, although it is unexpected for
           * control frames to be sent through the host data path.
           */
          u_int8_t frame_type; /* enum htt_frm_type */
          /*
           * frame subtype - this field specifies the sub-type of management
           * frames
           * Just to avoid confusion, the enum values for this frame subtype
           * field use the 802.11 management frame subtype values.
           */
          u_int8_t frame_subtype; /* enum htt_frm_subtype */
          u_int8_t is_unicast;
  
          /* dest_addr is not currently used.
           * It could be used as an input to a Tx BD (Riva tx descriptor)
           * signature computation.
          u_int8_t *dest_addr;
           */
  
          u_int8_t l3_hdr_offset; // w.r.t. adf_nbuf_data(msdu), in bytes
  
          /* l4_hdr_offset is not currently used.
           * It could be used to specify to a TCP/UDP checksum computation
           * engine where the TCP/UDP header starts.
          u_int8_t l4_hdr_offset; // w.r.t. adf_nbuf_data(msdu), in bytes
           */
      } info;
      /* the action sub-struct specifies how to process the MSDU */
      struct {
          u_int8_t use_6mbps; /* mgmt frames: option to force 6 Mbps rate */
          u_int8_t do_encrypt;
          u_int8_t do_tx_complete;
          u_int8_t tx_comp_req;
  
          /*
           * cksum_offload - Specify whether checksum offload is enabled or not
           * Target FW uses this flag to turn on HW checksumming
           * 0x0 - No checksum offload
           * 0x1 - L3 header checksum only
           * 0x2 - L4 checksum only
           * 0x3 - L3 header checksum + L4 checksum
           */
          adf_nbuf_tx_cksum_t cksum_offload;
      } action;
  };
  
  static inline void
  htt_msdu_info_dump(struct htt_msdu_info_t *msdu_info)
  {
      VOS_TRACE(VOS_MODULE_ID_TXRX, VOS_TRACE_LEVEL_INFO_LOW,
          "HTT MSDU info object (%pK)\n", msdu_info);
      VOS_TRACE(VOS_MODULE_ID_TXRX, VOS_TRACE_LEVEL_INFO_LOW,
          "  ethertype: %#x\n", msdu_info->info.ethertype);
      VOS_TRACE(VOS_MODULE_ID_TXRX, VOS_TRACE_LEVEL_INFO_LOW,
          "  peer_id: %d\n", msdu_info->info.peer_id);
      VOS_TRACE(VOS_MODULE_ID_TXRX, VOS_TRACE_LEVEL_INFO_LOW,
          "  vdev_id: %d\n", msdu_info->info.vdev_id);
      VOS_TRACE(VOS_MODULE_ID_TXRX, VOS_TRACE_LEVEL_INFO_LOW,
          "  ext_tid: %d\n", msdu_info->info.ext_tid);
      VOS_TRACE(VOS_MODULE_ID_TXRX, VOS_TRACE_LEVEL_INFO_LOW,
          "  l2_hdr_type: %d\n", msdu_info->info.l2_hdr_type);
      VOS_TRACE(VOS_MODULE_ID_TXRX, VOS_TRACE_LEVEL_INFO_LOW,
          "  frame_type: %d\n", msdu_info->info.frame_type);
      VOS_TRACE(VOS_MODULE_ID_TXRX, VOS_TRACE_LEVEL_INFO_LOW,
          "  frame_subtype: %d\n", msdu_info->info.frame_subtype);
      VOS_TRACE(VOS_MODULE_ID_TXRX, VOS_TRACE_LEVEL_INFO_LOW,
          "  is_unicast: %u\n", msdu_info->info.is_unicast);
      VOS_TRACE(VOS_MODULE_ID_TXRX, VOS_TRACE_LEVEL_INFO_LOW,
          "  l3_hdr_offset: %u\n", msdu_info->info.l3_hdr_offset);
      VOS_TRACE(VOS_MODULE_ID_TXRX, VOS_TRACE_LEVEL_INFO_LOW,
          "  use 6 Mbps: %d\n", msdu_info->action.use_6mbps);
      VOS_TRACE(VOS_MODULE_ID_TXRX, VOS_TRACE_LEVEL_INFO_LOW,
          "  do_encrypt: %d\n",  msdu_info->action.do_encrypt);
      VOS_TRACE(VOS_MODULE_ID_TXRX, VOS_TRACE_LEVEL_INFO_LOW,
          "  do_tx_complete: %d\n", msdu_info->action.do_tx_complete);
      VOS_TRACE(VOS_MODULE_ID_TXRX, VOS_TRACE_LEVEL_INFO_LOW,
          "  is_unicast: %u\n", msdu_info->info.is_unicast);
      VOS_TRACE(VOS_MODULE_ID_TXRX, VOS_TRACE_LEVEL_INFO_LOW,
          "  is_unicast: %u\n", msdu_info->info.is_unicast);
  }
  
  
  /*================ tx completion message field access methods ===============*/
  
  
  /**
   * @brief Look up the descriptor ID of the nth MSDU from a tx completion msg.
   * @details
   *  A tx completion message tells the host that the target is done
   *  transmitting a series of MSDUs.  The message uses a descriptor ID
   *  to identify each such MSDU.  This function/macro is used to
   *  find the ID of one such MSDU referenced by the tx completion message.
   *
   * @param iterator - tx completion message context provided by HTT to the
   *      tx completion message handler.  This abstract reference to the
   *      HTT tx completion message's payload allows the data SW's tx
   *      completion handler to not care about the format of the HTT
   *      tx completion message.
   * @param num - (zero-based) index to specify a single MSDU within the
   *      series of MSDUs referenced by the tx completion message
   * @return descriptor ID for the specified MSDU
   */
  u_int16_t
  htt_tx_compl_desc_id(void *iterator, int num);
  
  
  /*========================= tx descriptor operations ========================*/
  
  
  /**
   * @brief Allocate a HTT abstract tx descriptor.
   * @details
   *  Allocate a HTT abstract tx descriptor from a pool within "consistent"
   *  memory, which is accessible by HIF and/or MAC DMA as well as by the
   *  host CPU.
   *  It is expected that the tx datapath will allocate HTT tx descriptors
   *  and link them with datapath SW tx descriptors up front as the driver
   *  is loaded.  Thereafter, the link from datapath SW tx descriptor to
   *  HTT tx descriptor will be maintained until the driver is unloaded.
   *
   * @param htt_pdev - handle to the HTT instance making the allocation
   * @param[OUT] paddr_lo - physical address of the HTT descriptor
   * @return success -> descriptor handle, -OR- failure -> NULL
   */
  void *
  htt_tx_desc_alloc(htt_pdev_handle htt_pdev, u_int32_t *paddr_lo);
  
  /**
   * @brief Free a HTT abstract tx descriptor.
   *
   * @param htt_pdev - handle to the HTT instance that made the allocation
   * @param htt_tx_desc - the descriptor to free
   */
  void
  htt_tx_desc_free(htt_pdev_handle htt_pdev, void *htt_tx_desc);
  
  /**
  * @brief Discard all tx frames in the process of being downloaded.
  * @details
  * This function dicards any tx frames queued in HTT or the layers
  * under HTT.
  * The download completion callback is invoked on these frames.
  *
  * @param htt_pdev - handle to the HTT instance
  */
  #if defined(CONFIG_HL_SUPPORT)
  #define htt_tx_pending_discard(pdev) /* no-op */
  #else
  void
  htt_tx_pending_discard(htt_pdev_handle pdev);
  #endif
  
  /**
   * @brief Download a MSDU descriptor and (a portion of) the MSDU payload.
   * @details
   *  This function is used within LL systems to download a tx descriptor and
   *  the initial portion of the tx MSDU payload, and within HL systems to
   *  download the tx descriptor and the entire tx MSDU payload.
   *  The HTT layer determines internally how much of the tx descriptor
   *  actually needs to be downloaded. In particular, the HTT layer does not
   *  download the fragmentation descriptor, and only for the LL case downloads
   *  the physical address of the fragmentation descriptor.
   *  In HL systems, the tx descriptor and the entire frame are downloaded.
   *  In LL systems, only the tx descriptor and the header of the frame are
   *  downloaded.  To determine how much of the tx frame to download, this
   *  function assumes the tx frame is the default frame type, as specified
   *  by ol_cfg_frame_type.  "Raw" frames need to be transmitted through the
   *  alternate htt_tx_send_nonstd function.
   *  The tx descriptor has already been attached to the adf_nbuf object during
   *  a preceding call to htt_tx_desc_init.
   *
   * @param htt_pdev - the handle of the physical device sending the tx data
   * @param msdu - the frame being transmitted
   * @param msdu_id - unique ID for the frame being transmitted
   * @return 0 -> success, -OR- 1 -> failure
   */
  int
  htt_tx_send_std(
      htt_pdev_handle htt_pdev,
      adf_nbuf_t msdu,
      u_int16_t msdu_id);
  
  /**
   * @brief Download a Batch Of Tx MSDUs
   * @details
   *     Each MSDU already has the MSDU ID stored in the headroom of the
   *     netbuf data buffer, and has the HTT tx descriptor already attached
   *     as a prefix fragment to the netbuf.
   *
   * @param htt_pdev - the handle of the physical device sending the tx data
   * @param head_msdu - the MSDU Head for Tx batch being transmitted
   * @param num_msdus - The total Number of MSDU's provided for batch tx
   * @return null-terminated linked-list of unaccepted frames
   */
  adf_nbuf_t
  htt_tx_send_batch(
      htt_pdev_handle htt_pdev,
      adf_nbuf_t head_msdu,
      int num_msdus);
  
  
  
  /* The htt scheduler for queued packets in htt
   * htt when unable to send to HTC because of lack of resource
   * forms a nbuf queue which is flushed when tx completion event from
   * target is recieved
   */
  
  void
  htt_tx_sched(htt_pdev_handle pdev);
  
  
  /**
   * @brief Same as htt_tx_send_std, but can handle raw frames.
   */
  int
  htt_tx_send_nonstd(
      htt_pdev_handle htt_pdev,
      adf_nbuf_t msdu,
      u_int16_t msdu_id,
      enum htt_pkt_type pkt_type);
  
  /**
   * @brief Initialize the tx descriptor.
   * @details
   *  This function initializes the tx descriptor.
   *  The values for the standard tx descriptor fields are provided as
   *  function arguments.  Non-standard descriptor fields, which don't
   *  have function arguments to specify their value, are set to zero.
   *  An exception to this initialization of non-standard fields to zero
   *  is the "extended TID" field, which is initialized to the "invalid"
   *  value (0x1f).
   *
   * @param pdev - the handle of the physical device sending the tx data
   * @param htt_tx_desc - abstract handle to the tx descriptor
   * @param htt_tx_desc_paddr_lo - physical address of the HTT tx descriptor
   * @param desc_id - ID to tag the descriptor with.
   *      The target FW uses this ID to identify to the host which MSDUs
   *      the target is referring to in its tx completion / postpone / drop
   *      messages.
   *      This ID is abstract - it is only interpreted inside the host
   *      tx datapath SW.  In practice, though, the ID is an index into an
   *      array of tx descriptor structs.
   *      This ID is used for both HL and LL systems, since in both systems
   *      the target may need to refer to a particular MSDU to explicitly tell
   *      the host when it may free the MSDU descriptor and network buffer.
   * @param msdu - the MSDU that is being prepared for transmission
   * @param msdu_info - tx MSDU meta-data
   */
  
  /*
   * Provide a constant to specify the offset of the HTT portion of the
   * HTT tx descriptor, to avoid having to export the descriptor defintion.
   * The htt module checks internally that this exported offset is consistent
   * with the private tx descriptor definition.
   *
   * Similarly, export a definition of the HTT tx descriptor size, and then
   * check internally that this exported constant matches the private tx
   * descriptor definition.
   */
  #define HTT_TX_DESC_VADDR_OFFSET 8
  #define HTT_TX_DESC_SIZE 24
  static inline
  void
  htt_tx_desc_init(
      htt_pdev_handle pdev,
      void *htt_tx_desc,
      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 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, 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;
      /*
       * word2 is frag desc pointer
       * word3 is peer_id
       */
      word3 = word0 + 3; // Dword 3
  
      /*
       * HTT Tx Desc is in uncached memory. Used cached writes per word, to
       * reduce unnecessary memory access.
       */
  
      local_word0 = 0;
      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);
      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);
      *word0 = local_word0;
  
      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*/
      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,
       * and thus should not be byte-swapped during the HIF download
       * even if the host is big-endian.
       * There could be extra fragments added before the OS's fragments,
       * e.g. for TSO, so it's incorrect to clear the frag 0 wordstream flag.
       * Instead, clear the wordstream flag for the final fragment, which
       * is certain to be (one of the) fragment(s) provided by the OS.
       * Setting the flag for this final fragment suffices for specifying
       * all fragments provided by the OS rather than added by the driver.
       */
      adf_nbuf_set_frag_is_wordstream(msdu, adf_nbuf_get_num_frags(msdu) - 1, 0);
  
      /* store a link to the HTT tx descriptor within the netbuf */
      adf_nbuf_frag_push_head(
          msdu,
          HTT_TX_DESC_SIZE,
          (char *) htt_host_tx_desc, /* virtual addr */
          htt_tx_desc_paddr_lo, 0 /* phys addr MSBs - n/a */);
  
      /*
       * Indicate that the HTT header (and HTC header) is a meta-data
       * "wordstream", i.e. series of u_int32_t, rather than a data
       * bytestream.
       * This allows the HIF download to byteswap the HTT + HTC headers if
       * the host is big-endian, to convert to the target's little-endian
       * format.
       */
      adf_nbuf_set_frag_is_wordstream(msdu, 0, 1);
  }
  
  /**
   * @brief Set a flag to indicate that the MSDU in question was postponed.
   * @details
   *  In systems in which the host retains its tx frame until the target sends
   *  a tx completion, the target has the option of discarding it's copy of
   *  the tx descriptor (and frame, for HL) and sending a "postpone" message
   *  to the host, to inform the host that it must eventually download the
   *  tx descriptor (and frame, for HL).
   *  Before the host downloads the postponed tx desc/frame again, it will use
   *  this function to set a flag in the HTT tx descriptor indicating that this
   *  is a re-send of a postponed frame, rather than a new frame.  The target
   *  uses this flag to keep the correct order between re-sent and new tx frames.
   *  This function is relevant for LL systems.
   *
   * @param pdev - the handle of the physical device sending the tx data
   * @param desc - abstract handle to the tx descriptor
   */
  void
  htt_tx_desc_flag_postponed(htt_pdev_handle pdev, void *desc);
  
  /**
   * @brief Set a flag to tell the target that more tx downloads are en route.
   * @details
   *  At times, particularly in response to a U-APSD trigger in a HL system, the
   *  host will download multiple tx descriptors (+ frames, in HL) in a batch.
   *  The host will use this function to set a "more" flag in the initial
   *  and interior frames of the batch, to tell the target that more tx frame
   *  downloads within the batch are imminent.
   *
   * @param pdev - the handle of the physical device sending the tx data
   * @param desc - abstract handle to the tx descriptor
   */
  void
  htt_tx_desc_flag_batch_more(htt_pdev_handle pdev, void *desc);
  
  /**
   * @brief Specify the number of fragments in the fragmentation descriptor.
   * @details
   *  Specify the number of fragments within the MSDU, i.e. the number of
   *  elements within the fragmentation descriptor.
   *  For LL, this is used to terminate the list of fragments used by the
   *  HW's tx MAC DMA.
   *  For HL, this is used to terminate the list of fragments provided to
   *  HTC for download.
   *
   * @param pdev - the handle of the physical device sending the tx data
   * @param desc - abstract handle to the tx descriptor
   * @param num_frags - the number of fragments comprising the MSDU
   */
  static inline
  void
  htt_tx_desc_num_frags(htt_pdev_handle pdev, void *desc, u_int32_t num_frags)
  {
      /*
       * Set the element after the valid frag elems to 0x0,
       * to terminate the list of fragments.
       */
      *((u_int32_t *)
          (((char *) desc) + HTT_TX_DESC_LEN + num_frags * 8)) = 0;
  }
  
  /**
   * @brief Specify the location and size of a fragment of a tx MSDU.
   * @details
   *  In LL systems, the tx MAC DMA needs to know how the MSDU is constructed
   *  from fragments.
   *  In LL and HL systems, the HIF's download DMA to the target (LL: tx desc
   *  + header of tx payload; HL: tx desc + entire tx payload) needs to know
   *  where to find the fragments to download.
   *  The tx data SW uses this function to specify the location and size of
   *  each of the MSDU's fragments.
   *
   * @param pdev - the handle of the physical device sending the tx data
   * @param desc - abstract handle to the HTT tx descriptor
   * @param frag_num - which fragment is being specified (zero-based indexing)
   * @param frag_phys_addr - DMA/physical address of the fragment
   * @param frag_len - number of bytes within the fragment
   */
  static inline
  void
  htt_tx_desc_frag(
      htt_pdev_handle pdev,
      void *desc,
      int frag_num,
      u_int32_t frag_phys_addr,
      u_int16_t frag_len)
  {
      u_int32_t *word =
          (u_int32_t *) (((char *) desc) + HTT_TX_DESC_LEN + frag_num * 8);
      *word = frag_phys_addr;
      word++;
      *word = frag_len;
  }
  
  void htt_tx_desc_frags_table_set(
      htt_pdev_handle pdev,
      void *desc,
      u_int32_t paddr,
      int reset);
  
  /**
   * @brief Specify the type and subtype of a tx frame.
   *
   * @param pdev - the handle of the physical device sending the tx data
   * @param type - format of the MSDU (802.3, native WiFi, raw, or mgmt)
   * @param sub_type - sub_type (relevant for raw frames)
   */
  static inline
  void
  htt_tx_desc_type(
      htt_pdev_handle pdev,
      void *htt_tx_desc,
      enum wlan_frm_fmt type,
      u_int8_t sub_type)
  {
      u_int32_t *word0;
  
      word0 = (u_int32_t *) htt_tx_desc;
      /* clear old values */
      *word0 &= ~(HTT_TX_DESC_PKT_TYPE_M | HTT_TX_DESC_PKT_SUBTYPE_M);
      /* write new values */
      HTT_TX_DESC_PKT_TYPE_SET(*word0, type);
      HTT_TX_DESC_PKT_SUBTYPE_SET(*word0, sub_type);
  }
  
  /***** TX MGMT DESC management APIs ****/
  
  /* Number of mgmt descriptors in the pool */
  #define HTT_MAX_NUM_MGMT_DESCS 32
  
  /** htt_tx_mgmt_desc_pool_alloc
   * @description - allocates the memory for mgmt frame descriptors
   * @param  - htt pdev object
   * @param  - num of descriptors to be allocated in the pool
   */
  void
  htt_tx_mgmt_desc_pool_alloc(struct htt_pdev_t *pdev, A_UINT32 num_elems);
  
  /** htt_tx_mgmt_desc_alloc
   * @description - reserves a mgmt descriptor from the pool
   * @param  - htt pdev object
   * @param  - pointer to variable to hold the allocated desc id
   * @param  - pointer to the mamangement from UMAC
   * @return - pointer the allocated mgmt descriptor
   */
  adf_nbuf_t
  htt_tx_mgmt_desc_alloc(struct htt_pdev_t *pdev, A_UINT32 *desc_id, adf_nbuf_t mgmt_frm);
  
  /** htt_tx_mgmt_desc_free
   * @description - releases the management descriptor back to the pool
   * @param  - htt pdev object
   * @param  - descriptor ID
   */
  void
  htt_tx_mgmt_desc_free(struct htt_pdev_t *pdev, A_UINT8 desc_id, A_UINT32 status);
  
  /** htt_tx_mgmt_desc_pool_free
   * @description - releases all the resources allocated for mgmt desc pool
   * @param  - htt pdev object
   */
  void
  htt_tx_mgmt_desc_pool_free(struct htt_pdev_t *pdev);
  
  
  /**
   * @brief Provide a buffer to store a 802.11 header added by SW tx encap
   *
   * @param htt_tx_desc - which frame the 802.11 header is being added to
   * @param new_l2_hdr_size - how large the buffer needs to be
   */
  #define htt_tx_desc_mpdu_header(htt_tx_desc, new_l2_hdr_size) /*NULL*/
  
  /**
   * @brief How many tx credits would be consumed by the specified tx frame.
   *
   * @param msdu - the tx frame in question
   * @return number of credits used for this tx frame
   */
  #define htt_tx_msdu_credit(msdu) 1 /* 1 credit per buffer */
  
  
  
  #ifdef HTT_DBG
  void
  htt_tx_desc_display(void *tx_desc);
  #else
  #define htt_tx_desc_display(tx_desc)
  #endif
  
  static inline
  void htt_tx_desc_set_peer_id(void *htt_tx_desc, u_int16_t peer_id)
  {
      u_int16_t *peer_id_field_ptr;
  
      peer_id_field_ptr = (u_int16_t *)
          (htt_tx_desc + HTT_TX_DESC_PEERID_DESC_PADDR_OFFSET_BYTES);
  
      *peer_id_field_ptr = peer_id;
  }
  static inline
  void htt_tx_desc_set_chanfreq(void *htt_tx_desc, u_int16_t chanfreq)
  {
      u_int16_t *chanfreq_field_ptr;
  
      chanfreq_field_ptr = (u_int16_t *)
          (htt_tx_desc + HTT_TX_DESC_CHAN_FREQ_OFFSET_BYTES);
  
      *chanfreq_field_ptr = chanfreq;
  }
  
  #endif /* _OL_HTT_TX_API__H_ */
  