static void HTT_RX_FRAG_SET_LAST_MSDU( struct htt_pdev_t *pdev, adf_nbuf_t msg) { u_int32_t *msg_word; unsigned num_msdu_bytes; adf_nbuf_t msdu; struct htt_host_rx_desc_base *rx_desc; int start_idx; u_int8_t *p_fw_msdu_rx_desc = 0; msg_word = (u_int32_t *) adf_nbuf_data(msg); num_msdu_bytes = HTT_RX_FRAG_IND_FW_RX_DESC_BYTES_GET(*(msg_word + HTT_RX_FRAG_IND_HDR_PREFIX_SIZE32)); /* * 1 word for the message header, * 1 word to specify the number of MSDU bytes, * 1 word for every 4 MSDU bytes (round up), * 1 word for the MPDU range header */ pdev->rx_mpdu_range_offset_words = 3 + ((num_msdu_bytes + 3) >> 2); pdev->rx_ind_msdu_byte_idx = 0; p_fw_msdu_rx_desc = ((u_int8_t *)(msg_word) + HTT_ENDIAN_BYTE_IDX_SWAP(HTT_RX_FRAG_IND_FW_DESC_BYTE_OFFSET)); /* * Fix for EV126710, in which BSOD occurs due to last_msdu bit * not set while the next pointer is deliberately set to NULL * before calling ol_rx_pn_check_base() * * For fragment frames, the HW may not have set the last_msdu bit * in the rx descriptor, but the SW expects this flag to be set, * since each fragment is in a separate MPDU. Thus, set the flag here, * just in case the HW didn't. */ start_idx = pdev->rx_ring.sw_rd_idx.msdu_payld; msdu = pdev->rx_ring.buf.netbufs_ring[start_idx]; adf_nbuf_set_pktlen(msdu, HTT_RX_BUF_SIZE); adf_nbuf_unmap(pdev->osdev, msdu, ADF_OS_DMA_FROM_DEVICE); rx_desc = htt_rx_desc(msdu); *((u_int8_t *) &rx_desc->fw_desc.u.val) = *p_fw_msdu_rx_desc; rx_desc->msdu_end.last_msdu = 1; adf_nbuf_map(pdev->osdev, msdu, ADF_OS_DMA_FROM_DEVICE); }
htt_pdev_handle htt_attach( ol_txrx_pdev_handle txrx_pdev, ol_pdev_handle ctrl_pdev, HTC_HANDLE htc_pdev, adf_os_device_t osdev, int desc_pool_size) { struct htt_pdev_t *pdev; int i; pdev = adf_os_mem_alloc(osdev, sizeof(*pdev)); if (!pdev) { goto fail1; } pdev->osdev = osdev; pdev->ctrl_pdev = ctrl_pdev; pdev->txrx_pdev = txrx_pdev; pdev->htc_pdev = htc_pdev; adf_os_mem_set(&pdev->stats, 0, sizeof(pdev->stats)); pdev->htt_htc_pkt_freelist = NULL; /* for efficiency, store a local copy of the is_high_latency flag */ pdev->cfg.is_high_latency = ol_cfg_is_high_latency(pdev->ctrl_pdev); /* * Connect to HTC service. * This has to be done before calling htt_rx_attach, * since htt_rx_attach involves sending a rx ring configure * message to the target. */ //AR6004 don't need HTT layer. #ifndef AR6004_HW if (htt_htc_attach(pdev)) { goto fail2; } #endif if (htt_tx_attach(pdev, desc_pool_size)) { goto fail2; } if (htt_rx_attach(pdev)) { goto fail3; } HTT_TX_MUTEX_INIT(&pdev->htt_tx_mutex); HTT_TX_NBUF_QUEUE_MUTEX_INIT(pdev); /* pre-allocate some HTC_PACKET objects */ for (i = 0; i < HTT_HTC_PKT_POOL_INIT_SIZE; i++) { struct htt_htc_pkt_union *pkt; pkt = adf_os_mem_alloc(pdev->osdev, sizeof(*pkt)); if (! pkt) { break; } htt_htc_pkt_free(pdev, &pkt->u.pkt); } if (pdev->cfg.is_high_latency) { /* * HL - download the whole frame. * Specify a download length greater than the max MSDU size, * so the downloads will be limited by the actual frame sizes. */ pdev->download_len = 5000; if (ol_cfg_tx_free_at_download(pdev->ctrl_pdev)) { pdev->tx_send_complete_part2 = ol_tx_download_done_hl_free; } else { pdev->tx_send_complete_part2 = ol_tx_download_done_hl_retain; } /* * For LL, the FW rx desc directly referenced at its location * inside the rx indication message. */ /* * CHECK THIS LATER: does the HL HTT version of htt_rx_mpdu_desc_list_next * (which is not currently implemented) present the adf_nbuf_data(rx_ind_msg) * as the abstract rx descriptor? * If not, the rx_fw_desc_offset initialization here will have to be * adjusted accordingly. * NOTE: for HL, because fw rx desc is in ind msg, not in rx desc, so the * offset should be negtive value */ pdev->rx_fw_desc_offset = HTT_ENDIAN_BYTE_IDX_SWAP( HTT_RX_IND_FW_RX_DESC_BYTE_OFFSET - HTT_RX_IND_HL_BYTES); htt_h2t_rx_ring_cfg_msg = htt_h2t_rx_ring_cfg_msg_hl; } else { /* * LL - download just the initial portion of the frame. * Download enough to cover the encapsulation headers checked * by the target's tx classification descriptor engine. */ /* Get the packet download length */ pdev->download_len = htt_pkt_dl_len_get(pdev); /* * Account for the HTT tx descriptor, including the * HTC header + alignment padding. */ pdev->download_len += sizeof(struct htt_host_tx_desc_t); pdev->tx_send_complete_part2 = ol_tx_download_done_ll; /* * For LL, the FW rx desc is alongside the HW rx desc fields in * the htt_host_rx_desc_base struct/. */ pdev->rx_fw_desc_offset = RX_STD_DESC_FW_MSDU_OFFSET; htt_h2t_rx_ring_cfg_msg = htt_h2t_rx_ring_cfg_msg_ll; } return pdev; fail3: htt_tx_detach(pdev); fail2: adf_os_mem_free(pdev); fail1: return NULL; }