123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548 |
- /*
- * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
- *
- * 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.
- */
- #include <htt.h>
- #include "dp_types.h"
- #include "dp_internal.h"
- #include "dp_rh_htt.h"
- #include "dp_rh_rx.h"
- #include "qdf_mem.h"
- #include "cdp_txrx_cmn_struct.h"
- #include "dp_tx_desc.h"
- #include "dp_rh.h"
- #define HTT_MSG_BUF_SIZE(msg_bytes) \
- ((msg_bytes) + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING)
- #define HTT_T2H_MSG_BUF_REINIT(_buf, dev) \
- do { \
- qdf_nbuf_push_head(_buf, (HTC_HEADER_LEN) + \
- HTC_HDR_ALIGNMENT_PADDING); \
- qdf_nbuf_init_fast((_buf)); \
- qdf_mem_dma_sync_single_for_device(dev, \
- (QDF_NBUF_CB_PADDR(_buf)), \
- (skb_end_pointer(_buf) - \
- (_buf)->data), \
- PCI_DMA_FROMDEVICE); \
- } while (0)
- /**
- * dp_htt_flow_pool_map_handler_rh() - HTT_T2H_MSG_TYPE_FLOW_POOL_MAP handler
- * @soc: Handle to DP Soc structure
- * @flow_id: flow id
- * @flow_type: flow type
- * @flow_pool_id: pool id
- * @flow_pool_size: pool size
- *
- * Return: QDF_STATUS_SUCCESS - success, others - failure
- */
- static QDF_STATUS
- dp_htt_flow_pool_map_handler_rh(struct dp_soc *soc, uint8_t flow_id,
- uint8_t flow_type, uint8_t flow_pool_id,
- uint32_t flow_pool_size)
- {
- struct dp_vdev *vdev;
- struct dp_pdev *pdev;
- QDF_STATUS status;
- if (flow_pool_id >= MAX_TXDESC_POOLS) {
- dp_err("invalid flow_pool_id %d", flow_pool_id);
- return QDF_STATUS_E_INVAL;
- }
- vdev = dp_vdev_get_ref_by_id(soc, flow_id, DP_MOD_ID_HTT);
- if (vdev) {
- pdev = vdev->pdev;
- dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_HTT);
- } else {
- pdev = soc->pdev_list[0];
- }
- status = dp_tx_flow_pool_map_handler(pdev, flow_id, flow_type,
- flow_pool_id, flow_pool_size);
- if (QDF_IS_STATUS_ERROR(status)) {
- dp_err("failed to create tx flow pool %d", flow_pool_id);
- goto err_out;
- }
- return QDF_STATUS_SUCCESS;
- err_out:
- /* TODO: is assert needed ? */
- qdf_assert_always(0);
- return status;
- }
- /**
- * dp_htt_flow_pool_unmap_handler_rh() - HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP handler
- * @soc: Handle to DP Soc structure
- * @flow_id: flow id
- * @flow_type: flow type
- * @flow_pool_id: pool id
- *
- * Return: none
- */
- static void
- dp_htt_flow_pool_unmap_handler_rh(struct dp_soc *soc, uint8_t flow_id,
- uint8_t flow_type, uint8_t flow_pool_id)
- {
- struct dp_vdev *vdev;
- struct dp_pdev *pdev;
- if (flow_pool_id >= MAX_TXDESC_POOLS) {
- dp_err("invalid flow_pool_id %d", flow_pool_id);
- return;
- }
- vdev = dp_vdev_get_ref_by_id(soc, flow_id, DP_MOD_ID_HTT);
- if (vdev) {
- pdev = vdev->pdev;
- dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_HTT);
- } else {
- pdev = soc->pdev_list[0];
- }
- dp_tx_flow_pool_unmap_handler(pdev, flow_id, flow_type,
- flow_pool_id);
- }
- /*
- * dp_htt_h2t_send_complete_free_netbuf() - Free completed buffer
- * @soc: SOC handle
- * @status: Completion status
- * @netbuf: HTT buffer
- */
- static void
- dp_htt_h2t_send_complete_free_netbuf(
- void *soc, A_STATUS status, qdf_nbuf_t netbuf)
- {
- qdf_nbuf_free(netbuf);
- }
- QDF_STATUS dp_htt_h2t_rx_ring_rfs_cfg(struct htt_soc *soc)
- {
- struct dp_htt_htc_pkt *pkt;
- qdf_nbuf_t msg;
- uint32_t *msg_word;
- QDF_STATUS status;
- uint8_t *htt_logger_bufp;
- /*
- * TODO check do we need ini support in Evros
- * Receive flow steering configuration,
- * disable gEnableFlowSteering(=0) in ini if
- * FW doesn't support it
- */
- /* reserve room for the HTC header */
- msg = qdf_nbuf_alloc(soc->osdev,
- HTT_MSG_BUF_SIZE(HTT_RFS_CFG_REQ_BYTES),
- HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4,
- true);
- if (!msg) {
- dp_err("htt_msg alloc failed for RFS config");
- return QDF_STATUS_E_NOMEM;
- }
- /*
- * Set the length of the message.
- * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added
- * separately during the below call to qdf_nbuf_push_head.
- * The contribution from the HTC header is added separately inside HTC.
- */
- qdf_nbuf_put_tail(msg, HTT_RFS_CFG_REQ_BYTES);
- /* fill in the message contents */
- msg_word = (uint32_t *)qdf_nbuf_data(msg);
- /* rewind beyond alignment pad to get to the HTC header reserved area */
- qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING);
- /* word 0 */
- *msg_word = 0;
- htt_logger_bufp = (uint8_t *)msg_word;
- HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_RFS_CONFIG);
- HTT_RX_RFS_CONFIG_SET(*msg_word, 1);
- /*
- * TODO value should be obtained from ini maxMSDUsPerRxInd
- * currently this ini is legacy ol and available only from cds
- * make this ini common to HL and evros DP
- */
- *msg_word |= ((32 & 0xff) << 16);
- dp_htt_info("RFS sent to F.W: 0x%08x", *msg_word);
- /*start*/
- pkt = htt_htc_pkt_alloc(soc);
- if (!pkt) {
- qdf_nbuf_free(msg);
- return QDF_STATUS_E_NOMEM;
- }
- pkt->soc_ctxt = NULL; /* not used during send-done callback */
- SET_HTC_PACKET_INFO_TX(
- &pkt->htc_pkt,
- dp_htt_h2t_send_complete_free_netbuf,
- qdf_nbuf_data(msg),
- qdf_nbuf_len(msg),
- soc->htc_endpoint,
- HTC_TX_PACKET_TAG_RUNTIME_PUT); /* tag for no FW response msg */
- SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg);
- status = DP_HTT_SEND_HTC_PKT(soc, pkt, HTT_H2T_MSG_TYPE_RFS_CONFIG,
- htt_logger_bufp);
- if (status != QDF_STATUS_SUCCESS) {
- qdf_nbuf_free(msg);
- htt_htc_pkt_free(soc, pkt);
- }
- return status;
- }
- static void
- dp_htt_rx_addba_handler_rh(struct dp_soc *soc, uint16_t peer_id,
- uint8_t tid, uint16_t win_sz)
- {
- }
- static QDF_STATUS
- dp_htt_rx_delba_ind_handler_rh(void *soc_handle, uint16_t peer_id,
- uint8_t tid, uint16_t win_sz)
- {
- return QDF_STATUS_SUCCESS;
- }
- /**
- * dp_htt_t2h_msg_handler_fast() - Fastpath specific message handler
- * @context: HTT context
- * @cmpl_msdus: netbuf completions
- * @num_cmpls: number of completions to be handled
- *
- * Return: None
- */
- static void
- dp_htt_t2h_msg_handler_fast(void *context, qdf_nbuf_t *cmpl_msdus,
- uint32_t num_cmpls)
- {
- struct htt_soc *soc = (struct htt_soc *)context;
- qdf_nbuf_t htt_t2h_msg;
- uint32_t *msg_word;
- uint32_t i;
- enum htt_t2h_msg_type msg_type;
- uint32_t msg_len;
- for (i = 0; i < num_cmpls; i++) {
- htt_t2h_msg = cmpl_msdus[i];
- msg_len = qdf_nbuf_len(htt_t2h_msg);
- /*
- * Move the data pointer to point to HTT header
- * past the HTC header + HTC header alignment padding
- */
- qdf_nbuf_pull_head(htt_t2h_msg, HTC_HEADER_LEN +
- HTC_HDR_ALIGNMENT_PADDING);
- msg_word = (uint32_t *)qdf_nbuf_data(htt_t2h_msg);
- msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word);
- switch (msg_type) {
- case HTT_T2H_MSG_TYPE_RX_DATA_IND:
- {
- uint16_t vdev_id, msdu_cnt;
- uint16_t peer_id, frag_ind;
- peer_id = HTT_RX_DATA_IND_PEER_ID_GET(*msg_word);
- frag_ind = HTT_RX_DATA_IND_FRAG_GET(*(msg_word + 1));
- vdev_id = HTT_RX_DATA_IND_VDEV_ID_GET(*msg_word);
- if (qdf_unlikely(frag_ind)) {
- dp_rx_frag_indication_handler(soc->dp_soc,
- htt_t2h_msg,
- vdev_id, peer_id);
- break;
- }
- msdu_cnt =
- HTT_RX_DATA_IND_MSDU_CNT_GET(*(msg_word + 1));
- dp_rx_data_indication_handler(soc->dp_soc, htt_t2h_msg,
- vdev_id, peer_id,
- msdu_cnt);
- break;
- }
- case HTT_T2H_MSG_TYPE_SOFT_UMAC_TX_COMPL_IND:
- {
- uint32_t num_msdus;
- num_msdus = HTT_SOFT_UMAC_TX_COMP_IND_MSDU_COUNT_GET(*msg_word);
- if ((num_msdus * HTT_TX_MSDU_INFO_SIZE +
- HTT_SOFT_UMAC_TX_COMPL_IND_SIZE) > msg_len) {
- dp_htt_err("Invalid msdu count in tx compl indication %d", num_msdus);
- break;
- }
- dp_tx_compl_handler_rh(soc->dp_soc, htt_t2h_msg);
- break;
- }
- case HTT_T2H_MSG_TYPE_RX_PN_IND:
- {
- /* TODO check and add PN IND handling */
- break;
- }
- case HTT_T2H_MSG_TYPE_RX_ADDBA:
- {
- uint16_t peer_id;
- uint8_t tid;
- uint16_t win_sz;
- /*
- * Update REO Queue Desc with new values
- */
- peer_id = HTT_RX_ADDBA_PEER_ID_GET(*msg_word);
- tid = HTT_RX_ADDBA_TID_GET(*msg_word);
- win_sz = HTT_RX_ADDBA_WIN_SIZE_GET(*msg_word);
- /*
- * Window size needs to be incremented by 1
- * since fw needs to represent a value of 256
- * using just 8 bits
- */
- dp_htt_rx_addba_handler_rh(soc->dp_soc, peer_id,
- tid, win_sz + 1);
- break;
- }
- case HTT_T2H_MSG_TYPE_RX_DELBA:
- {
- uint16_t peer_id;
- uint8_t tid;
- uint8_t win_sz;
- QDF_STATUS status;
- peer_id = HTT_RX_DELBA_PEER_ID_GET(*msg_word);
- tid = HTT_RX_DELBA_TID_GET(*msg_word);
- win_sz = HTT_RX_DELBA_WIN_SIZE_GET(*msg_word);
- status = dp_htt_rx_delba_ind_handler_rh(soc->dp_soc,
- peer_id, tid,
- win_sz);
- dp_htt_info("DELBA PeerID %d BAW %d TID %d stat %d",
- peer_id, win_sz, tid, status);
- break;
- }
- case HTT_T2H_MSG_TYPE_PPDU_STATS_IND:
- {
- qdf_nbuf_t nbuf_copy;
- HTC_PACKET htc_pkt = {0};
- nbuf_copy = qdf_nbuf_copy(htt_t2h_msg);
- if (qdf_unlikely(!nbuf_copy)) {
- dp_htt_err("NBUF copy failed for PPDU stats msg");
- break;
- }
- htc_pkt.Status = QDF_STATUS_SUCCESS;
- htc_pkt.pPktContext = (void *)nbuf_copy;
- dp_htt_t2h_msg_handler(context, &htc_pkt);
- break;
- }
- case HTT_T2H_MSG_TYPE_FLOW_POOL_MAP:
- {
- uint8_t num_flows;
- struct htt_flow_pool_map_payload_t *pool_map;
- num_flows = HTT_FLOW_POOL_MAP_NUM_FLOWS_GET(*msg_word);
- if (((HTT_FLOW_POOL_MAP_PAYLOAD_SZ /
- HTT_FLOW_POOL_MAP_HEADER_SZ) * num_flows + 1) * sizeof(*msg_word) > msg_len) {
- dp_htt_err("Invalid flow count in flow pool map message");
- WARN_ON(1);
- break;
- }
- msg_word++;
- while (num_flows) {
- pool_map = (struct htt_flow_pool_map_payload_t *)msg_word;
- dp_htt_flow_pool_map_handler_rh(
- soc->dp_soc, pool_map->flow_id,
- pool_map->flow_type,
- pool_map->flow_pool_id,
- pool_map->flow_pool_size);
- msg_word += (HTT_FLOW_POOL_MAP_PAYLOAD_SZ /
- HTT_FLOW_POOL_MAP_HEADER_SZ);
- num_flows--;
- }
- break;
- }
- case HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP:
- {
- struct htt_flow_pool_unmap_t *pool_unmap;
- if (msg_len < sizeof(struct htt_flow_pool_unmap_t)) {
- dp_htt_err("Invalid length in flow pool unmap message %d", msg_len);
- WARN_ON(1);
- break;
- }
- pool_unmap = (struct htt_flow_pool_unmap_t *)msg_word;
- dp_htt_flow_pool_unmap_handler_rh(
- soc->dp_soc, pool_unmap->flow_id,
- pool_unmap->flow_type,
- pool_unmap->flow_pool_id);
- break;
- }
- default:
- {
- HTC_PACKET htc_pkt = {0};
- htc_pkt.Status = QDF_STATUS_SUCCESS;
- htc_pkt.pPktContext = (void *)htt_t2h_msg;
- /*
- * Increment user count to protect buffer
- * from generic handler free count will be
- * reset to 1 during MSG_BUF_REINIT
- */
- qdf_nbuf_inc_users(htt_t2h_msg);
- dp_htt_t2h_msg_handler(context, &htc_pkt);
- break;
- }
- }
- /* Re-initialize the indication buffer */
- HTT_T2H_MSG_BUF_REINIT(htt_t2h_msg, soc->osdev);
- qdf_nbuf_set_pktlen(htt_t2h_msg, 0);
- }
- }
- static QDF_STATUS
- dp_htt_htc_attach(struct htt_soc *soc, uint16_t service_id)
- {
- struct dp_soc_rh *rh_soc = dp_get_rh_soc_from_dp_soc(soc->dp_soc);
- struct htc_service_connect_req connect;
- struct htc_service_connect_resp response;
- QDF_STATUS status;
- qdf_mem_zero(&connect, sizeof(connect));
- qdf_mem_zero(&response, sizeof(response));
- connect.pMetaData = NULL;
- connect.MetaDataLength = 0;
- connect.EpCallbacks.pContext = soc;
- connect.EpCallbacks.EpTxComplete = dp_htt_h2t_send_complete;
- connect.EpCallbacks.EpTxCompleteMultiple = NULL;
- /* fastpath handler will be used instead */
- connect.EpCallbacks.EpRecv = NULL;
- /* rx buffers currently are provided by HIF, not by EpRecvRefill */
- connect.EpCallbacks.EpRecvRefill = NULL;
- /* N/A, fill is done by HIF */
- connect.EpCallbacks.RecvRefillWaterMark = 1;
- connect.EpCallbacks.EpSendFull = dp_htt_h2t_full;
- /*
- * Specify how deep to let a queue get before htc_send_pkt will
- * call the EpSendFull function due to excessive send queue depth.
- */
- connect.MaxSendQueueDepth = DP_HTT_MAX_SEND_QUEUE_DEPTH;
- /* disable flow control for HTT data message service */
- connect.ConnectionFlags |= HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL;
- /* connect to control service */
- connect.service_id = service_id;
- status = htc_connect_service(soc->htc_soc, &connect, &response);
- if (status != QDF_STATUS_SUCCESS) {
- dp_htt_err("HTC connect svc failed for id:%u", service_id);
- return status;
- }
- if (service_id == HTT_DATA_MSG_SVC)
- soc->htc_endpoint = response.Endpoint;
- /* Save the EP_ID of the TX pipe that to be used during TX enqueue */
- if (service_id == HTT_DATA2_MSG_SVC)
- rh_soc->tx_endpoint = response.Endpoint;
- return QDF_STATUS_SUCCESS;
- }
- static QDF_STATUS
- dp_htt_htc_soc_attach_all(struct htt_soc *soc)
- {
- struct dp_soc *dp_soc = soc->dp_soc;
- int svc_list[3] = {HTT_DATA_MSG_SVC, HTT_DATA2_MSG_SVC,
- HTT_DATA3_MSG_SVC};
- QDF_STATUS status;
- int i;
- for (i = 0; i < QDF_ARRAY_SIZE(svc_list); i++) {
- status = dp_htt_htc_attach(soc, svc_list[i]);
- if (QDF_IS_STATUS_ERROR(status))
- return status;
- }
- dp_hif_update_pipe_callback(dp_soc, (void *)soc,
- dp_htt_hif_t2h_hp_callback,
- DP_HTT_T2H_HP_PIPE);
- /* Register fastpath cb handlers for RX CE's */
- if (hif_ce_fastpath_cb_register(dp_soc->hif_handle,
- dp_htt_t2h_msg_handler_fast, soc)) {
- dp_htt_err("failed to register fastpath callback");
- return QDF_STATUS_E_FAILURE;
- }
- return QDF_STATUS_SUCCESS;
- }
- /*
- * dp_htt_soc_initialize_rh() - SOC level HTT initialization
- * @htt_soc: Opaque htt SOC handle
- * @ctrl_psoc: Opaque ctrl SOC handle
- * @htc_soc: SOC level HTC handle
- * @hal_soc: Opaque HAL SOC handle
- * @osdev: QDF device
- *
- * Return: HTT handle on success; NULL on failure
- */
- void *
- dp_htt_soc_initialize_rh(struct htt_soc *htt_soc,
- struct cdp_ctrl_objmgr_psoc *ctrl_psoc,
- HTC_HANDLE htc_soc,
- hal_soc_handle_t hal_soc_hdl, qdf_device_t osdev)
- {
- struct htt_soc *soc = (struct htt_soc *)htt_soc;
- soc->osdev = osdev;
- soc->ctrl_psoc = ctrl_psoc;
- soc->htc_soc = htc_soc;
- soc->hal_soc = hal_soc_hdl;
- if (dp_htt_htc_soc_attach_all(soc))
- goto fail2;
- return soc;
- fail2:
- return NULL;
- }
|