Path: blob/main/sys/contrib/dev/iwlwifi/pcie/gen1_2/tx-gen2.c
48406 views
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause1/*2* Copyright (C) 2017 Intel Deutschland GmbH3* Copyright (C) 2018-2020, 2023-2025 Intel Corporation4*/5#ifdef CONFIG_INET6#include <net/tso.h>7#endif8#include <linux/tcp.h>910#include "iwl-debug.h"11#include "iwl-csr.h"12#include "iwl-io.h"13#include "internal.h"14#include "fw/api/tx.h"15#include "fw/api/commands.h"16#include "fw/api/datapath.h"17#include "iwl-scd.h"1819static struct page *get_workaround_page(struct iwl_trans *trans,20struct sk_buff *skb)21{22struct iwl_tso_page_info *info;23struct page **page_ptr;24struct page *ret;25dma_addr_t phys;2627page_ptr = (void *)((u8 *)skb->cb + trans->conf.cb_data_offs);2829ret = alloc_page(GFP_ATOMIC);30if (!ret)31return NULL;3233info = IWL_TSO_PAGE_INFO(page_address(ret));3435/* Create a DMA mapping for the page */36phys = dma_map_page_attrs(trans->dev, ret, 0, PAGE_SIZE,37DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);38if (unlikely(dma_mapping_error(trans->dev, phys))) {39__free_page(ret);40return NULL;41}4243/* Store physical address and set use count */44info->dma_addr = phys;45refcount_set(&info->use_count, 1);4647/* set the chaining pointer to the previous page if there */48info->next = *page_ptr;49*page_ptr = ret;5051return ret;52}5354/*55* Add a TB and if needed apply the FH HW bug workaround;56* meta != NULL indicates that it's a page mapping and we57* need to dma_unmap_page() and set the meta->tbs bit in58* this case.59*/60static int iwl_txq_gen2_set_tb_with_wa(struct iwl_trans *trans,61struct sk_buff *skb,62struct iwl_tfh_tfd *tfd,63dma_addr_t phys, void *virt,64u16 len, struct iwl_cmd_meta *meta,65bool unmap)66{67dma_addr_t oldphys = phys;68struct page *page;69int ret;7071if (unlikely(dma_mapping_error(trans->dev, phys)))72return -ENOMEM;7374if (likely(!iwl_txq_crosses_4g_boundary(phys, len))) {75ret = iwl_txq_gen2_set_tb(trans, tfd, phys, len);7677if (ret < 0)78goto unmap;7980if (meta)81meta->tbs |= BIT(ret);8283ret = 0;84goto trace;85}8687/*88* Work around a hardware bug. If (as expressed in the89* condition above) the TB ends on a 32-bit boundary,90* then the next TB may be accessed with the wrong91* address.92* To work around it, copy the data elsewhere and make93* a new mapping for it so the device will not fail.94*/9596if (WARN_ON(len > IWL_TSO_PAGE_DATA_SIZE)) {97ret = -ENOBUFS;98goto unmap;99}100101page = get_workaround_page(trans, skb);102if (!page) {103ret = -ENOMEM;104goto unmap;105}106107memcpy(page_address(page), virt, len);108109/*110* This is a bit odd, but performance does not matter here, what111* matters are the expectations of the calling code and TB cleanup112* function.113*114* As such, if unmap is set, then create another mapping for the TB115* entry as it will be unmapped later. On the other hand, if it is not116* set, then the TB entry will not be unmapped and instead we simply117* reference and sync the mapping that get_workaround_page() created.118*/119if (unmap) {120phys = dma_map_single(trans->dev, page_address(page), len,121DMA_TO_DEVICE);122if (unlikely(dma_mapping_error(trans->dev, phys)))123return -ENOMEM;124} else {125phys = iwl_pcie_get_tso_page_phys(page_address(page));126dma_sync_single_for_device(trans->dev, phys, len,127DMA_TO_DEVICE);128}129130ret = iwl_txq_gen2_set_tb(trans, tfd, phys, len);131if (ret < 0) {132/* unmap the new allocation as single */133oldphys = phys;134meta = NULL;135goto unmap;136}137138IWL_DEBUG_TX(trans,139"TB bug workaround: copied %d bytes from 0x%llx to 0x%llx\n",140len, (unsigned long long)oldphys,141(unsigned long long)phys);142143ret = 0;144unmap:145if (!unmap)146goto trace;147148if (meta)149dma_unmap_page(trans->dev, oldphys, len, DMA_TO_DEVICE);150else151dma_unmap_single(trans->dev, oldphys, len, DMA_TO_DEVICE);152trace:153trace_iwlwifi_dev_tx_tb(trans->dev, skb, virt, phys, len);154155return ret;156}157158static int iwl_txq_gen2_build_amsdu(struct iwl_trans *trans,159struct sk_buff *skb,160struct iwl_tfh_tfd *tfd,161struct iwl_cmd_meta *out_meta,162int start_len,163u8 hdr_len,164struct iwl_device_tx_cmd *dev_cmd)165{166#ifdef CONFIG_INET167struct iwl_tx_cmd_v9 *tx_cmd = (void *)dev_cmd->payload;168struct ieee80211_hdr *hdr = (void *)skb->data;169unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room;170unsigned int mss = skb_shinfo(skb)->gso_size;171unsigned int data_offset = 0;172dma_addr_t start_hdr_phys;173u16 length, amsdu_pad;174u8 *start_hdr;175struct sg_table *sgt;176struct tso_t tso;177178trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd),179&dev_cmd->hdr, start_len, 0);180181ip_hdrlen = skb_network_header_len(skb);182snap_ip_tcp_hdrlen = 8 + ip_hdrlen + tcp_hdrlen(skb);183total_len = skb->len - snap_ip_tcp_hdrlen - hdr_len;184amsdu_pad = 0;185186/* total amount of header we may need for this A-MSDU */187hdr_room = DIV_ROUND_UP(total_len, mss) *188(3 + snap_ip_tcp_hdrlen + sizeof(struct ethhdr));189190/* Our device supports 9 segments at most, it will fit in 1 page */191sgt = iwl_pcie_prep_tso(trans, skb, out_meta, &start_hdr, hdr_room,192snap_ip_tcp_hdrlen + hdr_len);193if (!sgt)194return -ENOMEM;195196start_hdr_phys = iwl_pcie_get_tso_page_phys(start_hdr);197198/*199* Pull the ieee80211 header to be able to use TSO core,200* we will restore it for the tx_status flow.201*/202skb_pull(skb, hdr_len);203204/*205* Remove the length of all the headers that we don't actually206* have in the MPDU by themselves, but that we duplicate into207* all the different MSDUs inside the A-MSDU.208*/209le16_add_cpu(&tx_cmd->len, -snap_ip_tcp_hdrlen);210211tso_start(skb, &tso);212213while (total_len) {214/* this is the data left for this subframe */215unsigned int data_left = min_t(unsigned int, mss, total_len);216unsigned int tb_len;217dma_addr_t tb_phys;218u8 *pos_hdr = start_hdr;219220total_len -= data_left;221222memset(pos_hdr, 0, amsdu_pad);223pos_hdr += amsdu_pad;224amsdu_pad = (4 - (sizeof(struct ethhdr) + snap_ip_tcp_hdrlen +225data_left)) & 0x3;226ether_addr_copy(pos_hdr, ieee80211_get_DA(hdr));227pos_hdr += ETH_ALEN;228ether_addr_copy(pos_hdr, ieee80211_get_SA(hdr));229pos_hdr += ETH_ALEN;230231length = snap_ip_tcp_hdrlen + data_left;232*((__be16 *)pos_hdr) = cpu_to_be16(length);233pos_hdr += sizeof(length);234235/*236* This will copy the SNAP as well which will be considered237* as MAC header.238*/239tso_build_hdr(skb, pos_hdr, &tso, data_left, !total_len);240241pos_hdr += snap_ip_tcp_hdrlen;242243tb_len = pos_hdr - start_hdr;244tb_phys = iwl_pcie_get_tso_page_phys(start_hdr);245246/*247* No need for _with_wa, this is from the TSO page and248* we leave some space at the end of it so can't hit249* the buggy scenario.250*/251iwl_txq_gen2_set_tb(trans, tfd, tb_phys, tb_len);252trace_iwlwifi_dev_tx_tb(trans->dev, skb, start_hdr,253tb_phys, tb_len);254/* add this subframe's headers' length to the tx_cmd */255le16_add_cpu(&tx_cmd->len, tb_len);256257/* prepare the start_hdr for the next subframe */258start_hdr = pos_hdr;259260/* put the payload */261while (data_left) {262int ret;263264tb_len = min_t(unsigned int, tso.size, data_left);265tb_phys = iwl_pcie_get_sgt_tb_phys(sgt, data_offset,266tb_len);267/* Not a real mapping error, use direct comparison */268if (unlikely(tb_phys == DMA_MAPPING_ERROR))269goto out_err;270271ret = iwl_txq_gen2_set_tb_with_wa(trans, skb, tfd,272tb_phys, tso.data,273tb_len, NULL, false);274if (ret)275goto out_err;276277data_left -= tb_len;278data_offset += tb_len;279tso_build_data(skb, &tso, tb_len);280}281}282283dma_sync_single_for_device(trans->dev, start_hdr_phys, hdr_room,284DMA_TO_DEVICE);285286/* re -add the WiFi header */287skb_push(skb, hdr_len);288289return 0;290291out_err:292#endif293return -EINVAL;294}295296static struct297iwl_tfh_tfd *iwl_txq_gen2_build_tx_amsdu(struct iwl_trans *trans,298struct iwl_txq *txq,299struct iwl_device_tx_cmd *dev_cmd,300struct sk_buff *skb,301struct iwl_cmd_meta *out_meta,302int hdr_len,303int tx_cmd_len)304{305int idx = iwl_txq_get_cmd_index(txq, txq->write_ptr);306struct iwl_tfh_tfd *tfd = iwl_txq_get_tfd(trans, txq, idx);307dma_addr_t tb_phys;308int len;309void *tb1_addr;310311tb_phys = iwl_txq_get_first_tb_dma(txq, idx);312313/*314* No need for _with_wa, the first TB allocation is aligned up315* to a 64-byte boundary and thus can't be at the end or cross316* a page boundary (much less a 2^32 boundary).317*/318iwl_txq_gen2_set_tb(trans, tfd, tb_phys, IWL_FIRST_TB_SIZE);319320/*321* The second TB (tb1) points to the remainder of the TX command322* and the 802.11 header - dword aligned size323* (This calculation modifies the TX command, so do it before the324* setup of the first TB)325*/326len = tx_cmd_len + sizeof(struct iwl_cmd_header) + hdr_len -327IWL_FIRST_TB_SIZE;328329/* do not align A-MSDU to dword as the subframe header aligns it */330331/* map the data for TB1 */332tb1_addr = ((u8 *)&dev_cmd->hdr) + IWL_FIRST_TB_SIZE;333tb_phys = dma_map_single(trans->dev, tb1_addr, len, DMA_TO_DEVICE);334if (unlikely(dma_mapping_error(trans->dev, tb_phys)))335goto out_err;336/*337* No need for _with_wa(), we ensure (via alignment) that the data338* here can never cross or end at a page boundary.339*/340iwl_txq_gen2_set_tb(trans, tfd, tb_phys, len);341342if (iwl_txq_gen2_build_amsdu(trans, skb, tfd, out_meta,343len + IWL_FIRST_TB_SIZE, hdr_len, dev_cmd))344goto out_err;345346/* building the A-MSDU might have changed this data, memcpy it now */347memcpy(&txq->first_tb_bufs[idx], dev_cmd, IWL_FIRST_TB_SIZE);348return tfd;349350out_err:351iwl_pcie_free_tso_pages(trans, skb, out_meta);352iwl_txq_gen2_tfd_unmap(trans, out_meta, tfd);353return NULL;354}355356static int iwl_txq_gen2_tx_add_frags(struct iwl_trans *trans,357struct sk_buff *skb,358struct iwl_tfh_tfd *tfd,359struct iwl_cmd_meta *out_meta)360{361int i;362363for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {364const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];365dma_addr_t tb_phys;366unsigned int fragsz = skb_frag_size(frag);367int ret;368369if (!fragsz)370continue;371372tb_phys = skb_frag_dma_map(trans->dev, frag, 0,373fragsz, DMA_TO_DEVICE);374ret = iwl_txq_gen2_set_tb_with_wa(trans, skb, tfd, tb_phys,375skb_frag_address(frag),376fragsz, out_meta, true);377if (ret)378return ret;379}380381return 0;382}383384static struct385iwl_tfh_tfd *iwl_txq_gen2_build_tx(struct iwl_trans *trans,386struct iwl_txq *txq,387struct iwl_device_tx_cmd *dev_cmd,388struct sk_buff *skb,389struct iwl_cmd_meta *out_meta,390int hdr_len,391int tx_cmd_len,392bool pad)393{394int idx = iwl_txq_get_cmd_index(txq, txq->write_ptr);395struct iwl_tfh_tfd *tfd = iwl_txq_get_tfd(trans, txq, idx);396dma_addr_t tb_phys;397int len, tb1_len, tb2_len;398void *tb1_addr;399struct sk_buff *frag;400401tb_phys = iwl_txq_get_first_tb_dma(txq, idx);402403/* The first TB points to bi-directional DMA data */404memcpy(&txq->first_tb_bufs[idx], dev_cmd, IWL_FIRST_TB_SIZE);405406/*407* No need for _with_wa, the first TB allocation is aligned up408* to a 64-byte boundary and thus can't be at the end or cross409* a page boundary (much less a 2^32 boundary).410*/411iwl_txq_gen2_set_tb(trans, tfd, tb_phys, IWL_FIRST_TB_SIZE);412413/*414* The second TB (tb1) points to the remainder of the TX command415* and the 802.11 header - dword aligned size416* (This calculation modifies the TX command, so do it before the417* setup of the first TB)418*/419len = tx_cmd_len + sizeof(struct iwl_cmd_header) + hdr_len -420IWL_FIRST_TB_SIZE;421422if (pad)423tb1_len = ALIGN(len, 4);424else425tb1_len = len;426427/* map the data for TB1 */428tb1_addr = ((u8 *)&dev_cmd->hdr) + IWL_FIRST_TB_SIZE;429tb_phys = dma_map_single(trans->dev, tb1_addr, tb1_len, DMA_TO_DEVICE);430if (unlikely(dma_mapping_error(trans->dev, tb_phys)))431goto out_err;432/*433* No need for _with_wa(), we ensure (via alignment) that the data434* here can never cross or end at a page boundary.435*/436iwl_txq_gen2_set_tb(trans, tfd, tb_phys, tb1_len);437trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd), &dev_cmd->hdr,438IWL_FIRST_TB_SIZE + tb1_len, hdr_len);439440/* set up TFD's third entry to point to remainder of skb's head */441tb2_len = skb_headlen(skb) - hdr_len;442443if (tb2_len > 0) {444int ret;445446tb_phys = dma_map_single(trans->dev, skb->data + hdr_len,447tb2_len, DMA_TO_DEVICE);448ret = iwl_txq_gen2_set_tb_with_wa(trans, skb, tfd, tb_phys,449skb->data + hdr_len, tb2_len,450NULL, true);451if (ret)452goto out_err;453}454455if (iwl_txq_gen2_tx_add_frags(trans, skb, tfd, out_meta))456goto out_err;457458skb_walk_frags(skb, frag) {459int ret;460461tb_phys = dma_map_single(trans->dev, frag->data,462skb_headlen(frag), DMA_TO_DEVICE);463ret = iwl_txq_gen2_set_tb_with_wa(trans, skb, tfd, tb_phys,464frag->data,465skb_headlen(frag), NULL,466true);467if (ret)468goto out_err;469if (iwl_txq_gen2_tx_add_frags(trans, frag, tfd, out_meta))470goto out_err;471}472473return tfd;474475out_err:476iwl_txq_gen2_tfd_unmap(trans, out_meta, tfd);477return NULL;478}479480static481struct iwl_tfh_tfd *iwl_txq_gen2_build_tfd(struct iwl_trans *trans,482struct iwl_txq *txq,483struct iwl_device_tx_cmd *dev_cmd,484struct sk_buff *skb,485struct iwl_cmd_meta *out_meta)486{487struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;488int idx = iwl_txq_get_cmd_index(txq, txq->write_ptr);489struct iwl_tfh_tfd *tfd = iwl_txq_get_tfd(trans, txq, idx);490int len, hdr_len;491bool amsdu;492493/* There must be data left over for TB1 or this code must be changed */494BUILD_BUG_ON(sizeof(struct iwl_tx_cmd_v9) < IWL_FIRST_TB_SIZE);495BUILD_BUG_ON(sizeof(struct iwl_cmd_header) +496offsetofend(struct iwl_tx_cmd_v9, dram_info) >497IWL_FIRST_TB_SIZE);498BUILD_BUG_ON(sizeof(struct iwl_tx_cmd) < IWL_FIRST_TB_SIZE);499BUILD_BUG_ON(sizeof(struct iwl_cmd_header) +500offsetofend(struct iwl_tx_cmd, dram_info) >501IWL_FIRST_TB_SIZE);502503memset(tfd, 0, sizeof(*tfd));504505if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210)506len = sizeof(struct iwl_tx_cmd_v9);507else508len = sizeof(struct iwl_tx_cmd);509510amsdu = ieee80211_is_data_qos(hdr->frame_control) &&511(*ieee80211_get_qos_ctl(hdr) &512IEEE80211_QOS_CTL_A_MSDU_PRESENT);513514hdr_len = ieee80211_hdrlen(hdr->frame_control);515516/*517* Only build A-MSDUs here if doing so by GSO, otherwise it may be518* an A-MSDU for other reasons, e.g. NAN or an A-MSDU having been519* built in the higher layers already.520*/521if (amsdu && skb_shinfo(skb)->gso_size)522return iwl_txq_gen2_build_tx_amsdu(trans, txq, dev_cmd, skb,523out_meta, hdr_len, len);524return iwl_txq_gen2_build_tx(trans, txq, dev_cmd, skb, out_meta,525hdr_len, len, !amsdu);526}527528int iwl_txq_space(struct iwl_trans *trans, const struct iwl_txq *q)529{530unsigned int max;531unsigned int used;532533/*534* To avoid ambiguity between empty and completely full queues, there535* should always be less than max_tfd_queue_size elements in the queue.536* If q->n_window is smaller than max_tfd_queue_size, there is no need537* to reserve any queue entries for this purpose.538*/539if (q->n_window < trans->mac_cfg->base->max_tfd_queue_size)540max = q->n_window;541else542max = trans->mac_cfg->base->max_tfd_queue_size - 1;543544/*545* max_tfd_queue_size is a power of 2, so the following is equivalent to546* modulo by max_tfd_queue_size and is well defined.547*/548used = (q->write_ptr - q->read_ptr) &549(trans->mac_cfg->base->max_tfd_queue_size - 1);550551if (WARN_ON(used > max))552return 0;553554return max - used;555}556557/*558* iwl_pcie_gen2_update_byte_tbl - Set up entry in Tx byte-count array559*/560static void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans *trans,561struct iwl_txq *txq, u16 byte_cnt,562int num_tbs)563{564int idx = iwl_txq_get_cmd_index(txq, txq->write_ptr);565struct iwl_bc_tbl_entry *scd_bc_tbl = txq->bc_tbl.addr;566u8 filled_tfd_size, num_fetch_chunks;567u16 len = byte_cnt;568__le16 bc_ent;569570if (WARN(idx >= txq->n_window, "%d >= %d\n", idx, txq->n_window))571return;572573filled_tfd_size = offsetof(struct iwl_tfh_tfd, tbs) +574num_tbs * sizeof(struct iwl_tfh_tb);575/*576* filled_tfd_size contains the number of filled bytes in the TFD.577* Dividing it by 64 will give the number of chunks to fetch578* to SRAM- 0 for one chunk, 1 for 2 and so on.579* If, for example, TFD contains only 3 TBs then 32 bytes580* of the TFD are used, and only one chunk of 64 bytes should581* be fetched582*/583num_fetch_chunks = DIV_ROUND_UP(filled_tfd_size, 64) - 1;584585if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) {586WARN_ON(len > 0x3FFF);587bc_ent = cpu_to_le16(len | (num_fetch_chunks << 14));588} else {589len = DIV_ROUND_UP(len, 4);590WARN_ON(len > 0xFFF);591bc_ent = cpu_to_le16(len | (num_fetch_chunks << 12));592}593594scd_bc_tbl[idx].tfd_offset = bc_ent;595}596597static u8 iwl_txq_gen2_get_num_tbs(struct iwl_tfh_tfd *tfd)598{599return le16_to_cpu(tfd->num_tbs) & 0x1f;600}601602int iwl_txq_gen2_set_tb(struct iwl_trans *trans, struct iwl_tfh_tfd *tfd,603dma_addr_t addr, u16 len)604{605struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);606int idx = iwl_txq_gen2_get_num_tbs(tfd);607struct iwl_tfh_tb *tb;608609/* Only WARN here so we know about the issue, but we mess up our610* unmap path because not every place currently checks for errors611* returned from this function - it can only return an error if612* there's no more space, and so when we know there is enough we613* don't always check ...614*/615WARN(iwl_txq_crosses_4g_boundary(addr, len),616"possible DMA problem with iova:0x%llx, len:%d\n",617(unsigned long long)addr, len);618619if (WARN_ON(idx >= IWL_TFH_NUM_TBS))620return -EINVAL;621tb = &tfd->tbs[idx];622623/* Each TFD can point to a maximum max_tbs Tx buffers */624if (le16_to_cpu(tfd->num_tbs) >= trans_pcie->txqs.tfd.max_tbs) {625IWL_ERR(trans, "Error can not send more than %d chunks\n",626trans_pcie->txqs.tfd.max_tbs);627return -EINVAL;628}629630put_unaligned_le64(addr, &tb->addr);631tb->tb_len = cpu_to_le16(len);632633tfd->num_tbs = cpu_to_le16(idx + 1);634635return idx;636}637638void iwl_txq_gen2_tfd_unmap(struct iwl_trans *trans,639struct iwl_cmd_meta *meta,640struct iwl_tfh_tfd *tfd)641{642struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);643int i, num_tbs;644645/* Sanity check on number of chunks */646num_tbs = iwl_txq_gen2_get_num_tbs(tfd);647648if (num_tbs > trans_pcie->txqs.tfd.max_tbs) {649IWL_ERR(trans, "Too many chunks: %i\n", num_tbs);650return;651}652653/* TB1 is mapped directly, the rest is the TSO page and SG list. */654if (meta->sg_offset)655num_tbs = 2;656657/* first TB is never freed - it's the bidirectional DMA data */658for (i = 1; i < num_tbs; i++) {659if (meta->tbs & BIT(i))660dma_unmap_page(trans->dev,661le64_to_cpu(tfd->tbs[i].addr),662le16_to_cpu(tfd->tbs[i].tb_len),663DMA_TO_DEVICE);664else665dma_unmap_single(trans->dev,666le64_to_cpu(tfd->tbs[i].addr),667le16_to_cpu(tfd->tbs[i].tb_len),668DMA_TO_DEVICE);669}670671iwl_txq_set_tfd_invalid_gen2(trans, tfd);672}673674static void iwl_txq_gen2_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq)675{676/* rd_ptr is bounded by TFD_QUEUE_SIZE_MAX and677* idx is bounded by n_window678*/679int idx = iwl_txq_get_cmd_index(txq, txq->read_ptr);680struct sk_buff *skb;681682lockdep_assert_held(&txq->lock);683684if (!txq->entries)685return;686687iwl_txq_gen2_tfd_unmap(trans, &txq->entries[idx].meta,688iwl_txq_get_tfd(trans, txq, idx));689690skb = txq->entries[idx].skb;691692/* Can be called from irqs-disabled context693* If skb is not NULL, it means that the whole queue is being694* freed and that the queue is not empty - free the skb695*/696if (skb) {697iwl_op_mode_free_skb(trans->op_mode, skb);698txq->entries[idx].skb = NULL;699}700}701702/*703* iwl_txq_inc_wr_ptr - Send new write index to hardware704*/705static void iwl_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq)706{707lockdep_assert_held(&txq->lock);708709IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq->id, txq->write_ptr);710711/*712* if not in power-save mode, uCode will never sleep when we're713* trying to tx (during RFKILL, we're not trying to tx).714*/715iwl_write32(trans, HBUS_TARG_WRPTR, txq->write_ptr | (txq->id << 16));716}717718int iwl_txq_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb,719struct iwl_device_tx_cmd *dev_cmd, int txq_id)720{721struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);722struct iwl_cmd_meta *out_meta;723struct iwl_txq *txq = trans_pcie->txqs.txq[txq_id];724u16 cmd_len;725int idx;726void *tfd;727728if (WARN_ONCE(txq_id >= IWL_MAX_TVQM_QUEUES,729"queue %d out of range", txq_id))730return -EINVAL;731732if (WARN_ONCE(!test_bit(txq_id, trans_pcie->txqs.queue_used),733"TX on unused queue %d\n", txq_id))734return -EINVAL;735736if (skb_is_nonlinear(skb) &&737skb_shinfo(skb)->nr_frags > IWL_TRANS_PCIE_MAX_FRAGS(trans_pcie) &&738__skb_linearize(skb))739return -ENOMEM;740741spin_lock(&txq->lock);742743if (iwl_txq_space(trans, txq) < txq->high_mark) {744iwl_txq_stop(trans, txq);745746/* don't put the packet on the ring, if there is no room */747if (unlikely(iwl_txq_space(trans, txq) < 3)) {748struct iwl_device_tx_cmd **dev_cmd_ptr;749750dev_cmd_ptr = (void *)((u8 *)skb->cb +751trans->conf.cb_data_offs +752sizeof(void *));753754*dev_cmd_ptr = dev_cmd;755__skb_queue_tail(&txq->overflow_q, skb);756spin_unlock(&txq->lock);757return 0;758}759}760761idx = iwl_txq_get_cmd_index(txq, txq->write_ptr);762763/* Set up driver data for this TFD */764txq->entries[idx].skb = skb;765txq->entries[idx].cmd = dev_cmd;766767dev_cmd->hdr.sequence =768cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |769INDEX_TO_SEQ(idx)));770771/* Set up first empty entry in queue's array of Tx/cmd buffers */772out_meta = &txq->entries[idx].meta;773memset(out_meta, 0, sizeof(*out_meta));774775tfd = iwl_txq_gen2_build_tfd(trans, txq, dev_cmd, skb, out_meta);776if (!tfd) {777spin_unlock(&txq->lock);778return -1;779}780781if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) {782struct iwl_tx_cmd *tx_cmd =783(void *)dev_cmd->payload;784785cmd_len = le16_to_cpu(tx_cmd->len);786} else {787struct iwl_tx_cmd_v9 *tx_cmd_v9 =788(void *)dev_cmd->payload;789790cmd_len = le16_to_cpu(tx_cmd_v9->len);791}792793/* Set up entry for this TFD in Tx byte-count array */794iwl_pcie_gen2_update_byte_tbl(trans, txq, cmd_len,795iwl_txq_gen2_get_num_tbs(tfd));796797/* start timer if queue currently empty */798if (txq->read_ptr == txq->write_ptr && txq->wd_timeout)799mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout);800801/* Tell device the write index *just past* this latest filled TFD */802txq->write_ptr = iwl_txq_inc_wrap(trans, txq->write_ptr);803iwl_txq_inc_wr_ptr(trans, txq);804/*805* At this point the frame is "transmitted" successfully806* and we will get a TX status notification eventually.807*/808spin_unlock(&txq->lock);809return 0;810}811812/*************** HOST COMMAND QUEUE FUNCTIONS *****/813814/*815* iwl_txq_gen2_unmap - Unmap any remaining DMA mappings and free skb's816*/817static void iwl_txq_gen2_unmap(struct iwl_trans *trans, int txq_id)818{819struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);820struct iwl_txq *txq = trans_pcie->txqs.txq[txq_id];821822spin_lock_bh(&txq->reclaim_lock);823spin_lock(&txq->lock);824while (txq->write_ptr != txq->read_ptr) {825IWL_DEBUG_TX_REPLY(trans, "Q %d Free %d\n",826txq_id, txq->read_ptr);827828if (txq_id != trans->conf.cmd_queue) {829int idx = iwl_txq_get_cmd_index(txq, txq->read_ptr);830struct iwl_cmd_meta *cmd_meta = &txq->entries[idx].meta;831struct sk_buff *skb = txq->entries[idx].skb;832833if (!WARN_ON_ONCE(!skb))834iwl_pcie_free_tso_pages(trans, skb, cmd_meta);835}836iwl_txq_gen2_free_tfd(trans, txq);837txq->read_ptr = iwl_txq_inc_wrap(trans, txq->read_ptr);838}839840while (!skb_queue_empty(&txq->overflow_q)) {841struct sk_buff *skb = __skb_dequeue(&txq->overflow_q);842843iwl_op_mode_free_skb(trans->op_mode, skb);844}845846spin_unlock(&txq->lock);847spin_unlock_bh(&txq->reclaim_lock);848849/* just in case - this queue may have been stopped */850iwl_trans_pcie_wake_queue(trans, txq);851}852853static void iwl_txq_gen2_free_memory(struct iwl_trans *trans,854struct iwl_txq *txq)855{856struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);857struct device *dev = trans->dev;858859/* De-alloc circular buffer of TFDs */860if (txq->tfds) {861dma_free_coherent(dev,862trans_pcie->txqs.tfd.size * txq->n_window,863txq->tfds, txq->dma_addr);864dma_free_coherent(dev,865sizeof(*txq->first_tb_bufs) * txq->n_window,866txq->first_tb_bufs, txq->first_tb_dma);867}868869kfree(txq->entries);870if (txq->bc_tbl.addr)871dma_pool_free(trans_pcie->txqs.bc_pool,872txq->bc_tbl.addr, txq->bc_tbl.dma);873kfree(txq);874}875876/*877* iwl_pcie_txq_free - Deallocate DMA queue.878* @txq: Transmit queue to deallocate.879*880* Empty queue by removing and destroying all BD's.881* Free all buffers.882* 0-fill, but do not free "txq" descriptor structure.883*/884static void iwl_txq_gen2_free(struct iwl_trans *trans, int txq_id)885{886struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);887struct iwl_txq *txq;888int i;889890if (WARN_ONCE(txq_id >= IWL_MAX_TVQM_QUEUES,891"queue %d out of range", txq_id))892return;893894txq = trans_pcie->txqs.txq[txq_id];895896if (WARN_ON(!txq))897return;898899iwl_txq_gen2_unmap(trans, txq_id);900901/* De-alloc array of command/tx buffers */902if (txq_id == trans->conf.cmd_queue)903for (i = 0; i < txq->n_window; i++) {904kfree_sensitive(txq->entries[i].cmd);905kfree_sensitive(txq->entries[i].free_buf);906}907timer_delete_sync(&txq->stuck_timer);908909iwl_txq_gen2_free_memory(trans, txq);910911trans_pcie->txqs.txq[txq_id] = NULL;912913clear_bit(txq_id, trans_pcie->txqs.queue_used);914}915916static struct iwl_txq *917iwl_txq_dyn_alloc_dma(struct iwl_trans *trans, int size, unsigned int timeout)918{919struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);920size_t bc_tbl_size, bc_tbl_entries;921struct iwl_txq *txq;922int ret;923924WARN_ON(!trans_pcie->txqs.bc_tbl_size);925926bc_tbl_size = trans_pcie->txqs.bc_tbl_size;927bc_tbl_entries = bc_tbl_size / sizeof(u16);928929if (WARN_ON(size > bc_tbl_entries))930return ERR_PTR(-EINVAL);931932txq = kzalloc(sizeof(*txq), GFP_KERNEL);933if (!txq)934return ERR_PTR(-ENOMEM);935936txq->bc_tbl.addr = dma_pool_alloc(trans_pcie->txqs.bc_pool, GFP_KERNEL,937&txq->bc_tbl.dma);938if (!txq->bc_tbl.addr) {939IWL_ERR(trans, "Scheduler BC Table allocation failed\n");940kfree(txq);941return ERR_PTR(-ENOMEM);942}943944ret = iwl_pcie_txq_alloc(trans, txq, size, false);945if (ret) {946IWL_ERR(trans, "Tx queue alloc failed\n");947goto error;948}949ret = iwl_txq_init(trans, txq, size, false);950if (ret) {951IWL_ERR(trans, "Tx queue init failed\n");952goto error;953}954955txq->wd_timeout = msecs_to_jiffies(timeout);956957return txq;958959error:960iwl_txq_gen2_free_memory(trans, txq);961return ERR_PTR(ret);962}963964static int iwl_pcie_txq_alloc_response(struct iwl_trans *trans,965struct iwl_txq *txq,966struct iwl_host_cmd *hcmd)967{968struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);969struct iwl_tx_queue_cfg_rsp *rsp;970int ret, qid;971u32 wr_ptr;972973if (WARN_ON(iwl_rx_packet_payload_len(hcmd->resp_pkt) !=974sizeof(*rsp))) {975ret = -EINVAL;976goto error_free_resp;977}978979rsp = (void *)hcmd->resp_pkt->data;980qid = le16_to_cpu(rsp->queue_number);981wr_ptr = le16_to_cpu(rsp->write_pointer);982983if (qid >= ARRAY_SIZE(trans_pcie->txqs.txq)) {984WARN_ONCE(1, "queue index %d unsupported", qid);985ret = -EIO;986goto error_free_resp;987}988989if (test_and_set_bit(qid, trans_pcie->txqs.queue_used)) {990WARN_ONCE(1, "queue %d already used", qid);991ret = -EIO;992goto error_free_resp;993}994995if (WARN_ONCE(trans_pcie->txqs.txq[qid],996"queue %d already allocated\n", qid)) {997ret = -EIO;998goto error_free_resp;999}10001001txq->id = qid;1002trans_pcie->txqs.txq[qid] = txq;1003wr_ptr &= (trans->mac_cfg->base->max_tfd_queue_size - 1);10041005/* Place first TFD at index corresponding to start sequence number */1006txq->read_ptr = wr_ptr;1007txq->write_ptr = wr_ptr;10081009IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d\n", qid);10101011iwl_free_resp(hcmd);1012return qid;10131014error_free_resp:1015iwl_free_resp(hcmd);1016iwl_txq_gen2_free_memory(trans, txq);1017return ret;1018}10191020int iwl_txq_dyn_alloc(struct iwl_trans *trans, u32 flags, u32 sta_mask,1021u8 tid, int size, unsigned int timeout)1022{1023struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);1024struct iwl_txq *txq;1025union {1026struct iwl_tx_queue_cfg_cmd old;1027struct iwl_scd_queue_cfg_cmd new;1028} cmd;1029struct iwl_host_cmd hcmd = {1030.flags = CMD_WANT_SKB,1031};1032int ret;10331034/* take the min with bytecount table entries allowed */1035size = min_t(u32, size, trans_pcie->txqs.bc_tbl_size / sizeof(u16));1036/* but must be power of 2 values for calculating read/write pointers */1037size = rounddown_pow_of_two(size);10381039if (trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_BZ &&1040trans->info.hw_rev_step == SILICON_A_STEP) {1041size = 4096;1042txq = iwl_txq_dyn_alloc_dma(trans, size, timeout);1043} else {1044do {1045txq = iwl_txq_dyn_alloc_dma(trans, size, timeout);1046if (!IS_ERR(txq))1047break;10481049IWL_DEBUG_TX_QUEUES(trans,1050"Failed allocating TXQ of size %d for sta mask %x tid %d, ret: %ld\n",1051size, sta_mask, tid,1052PTR_ERR(txq));1053size /= 2;1054} while (size >= 16);1055}10561057if (IS_ERR(txq))1058return PTR_ERR(txq);10591060if (trans->conf.queue_alloc_cmd_ver == 0) {1061memset(&cmd.old, 0, sizeof(cmd.old));1062cmd.old.tfdq_addr = cpu_to_le64(txq->dma_addr);1063cmd.old.byte_cnt_addr = cpu_to_le64(txq->bc_tbl.dma);1064cmd.old.cb_size = cpu_to_le32(TFD_QUEUE_CB_SIZE(size));1065cmd.old.flags = cpu_to_le16(flags | TX_QUEUE_CFG_ENABLE_QUEUE);1066cmd.old.tid = tid;10671068if (hweight32(sta_mask) != 1) {1069ret = -EINVAL;1070goto error;1071}1072cmd.old.sta_id = ffs(sta_mask) - 1;10731074hcmd.id = SCD_QUEUE_CFG;1075hcmd.len[0] = sizeof(cmd.old);1076hcmd.data[0] = &cmd.old;1077} else if (trans->conf.queue_alloc_cmd_ver == 3) {1078memset(&cmd.new, 0, sizeof(cmd.new));1079cmd.new.operation = cpu_to_le32(IWL_SCD_QUEUE_ADD);1080cmd.new.u.add.tfdq_dram_addr = cpu_to_le64(txq->dma_addr);1081cmd.new.u.add.bc_dram_addr = cpu_to_le64(txq->bc_tbl.dma);1082cmd.new.u.add.cb_size = cpu_to_le32(TFD_QUEUE_CB_SIZE(size));1083cmd.new.u.add.flags = cpu_to_le32(flags);1084cmd.new.u.add.sta_mask = cpu_to_le32(sta_mask);1085cmd.new.u.add.tid = tid;10861087hcmd.id = WIDE_ID(DATA_PATH_GROUP, SCD_QUEUE_CONFIG_CMD);1088hcmd.len[0] = sizeof(cmd.new);1089hcmd.data[0] = &cmd.new;1090} else {1091ret = -EOPNOTSUPP;1092goto error;1093}10941095ret = iwl_trans_send_cmd(trans, &hcmd);1096if (ret)1097goto error;10981099return iwl_pcie_txq_alloc_response(trans, txq, &hcmd);11001101error:1102iwl_txq_gen2_free_memory(trans, txq);1103return ret;1104}11051106void iwl_txq_dyn_free(struct iwl_trans *trans, int queue)1107{1108struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);11091110if (WARN(queue >= IWL_MAX_TVQM_QUEUES,1111"queue %d out of range", queue))1112return;11131114/*1115* Upon HW Rfkill - we stop the device, and then stop the queues1116* in the op_mode. Just for the sake of the simplicity of the op_mode,1117* allow the op_mode to call txq_disable after it already called1118* stop_device.1119*/1120if (!test_and_clear_bit(queue, trans_pcie->txqs.queue_used)) {1121WARN_ONCE(test_bit(STATUS_DEVICE_ENABLED, &trans->status),1122"queue %d not used", queue);1123return;1124}11251126iwl_txq_gen2_free(trans, queue);11271128IWL_DEBUG_TX_QUEUES(trans, "Deactivate queue %d\n", queue);1129}11301131void iwl_txq_gen2_tx_free(struct iwl_trans *trans)1132{1133struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);1134int i;11351136memset(trans_pcie->txqs.queue_used, 0,1137sizeof(trans_pcie->txqs.queue_used));11381139/* Free all TX queues */1140for (i = 0; i < ARRAY_SIZE(trans_pcie->txqs.txq); i++) {1141if (!trans_pcie->txqs.txq[i])1142continue;11431144iwl_txq_gen2_free(trans, i);1145}1146}11471148int iwl_txq_gen2_init(struct iwl_trans *trans, int txq_id, int queue_size)1149{1150struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);1151struct iwl_txq *queue;1152int ret;11531154/* alloc and init the tx queue */1155if (!trans_pcie->txqs.txq[txq_id]) {1156queue = kzalloc(sizeof(*queue), GFP_KERNEL);1157if (!queue) {1158IWL_ERR(trans, "Not enough memory for tx queue\n");1159return -ENOMEM;1160}1161trans_pcie->txqs.txq[txq_id] = queue;1162ret = iwl_pcie_txq_alloc(trans, queue, queue_size, true);1163if (ret) {1164IWL_ERR(trans, "Tx %d queue init failed\n", txq_id);1165goto error;1166}1167} else {1168queue = trans_pcie->txqs.txq[txq_id];1169}11701171ret = iwl_txq_init(trans, queue, queue_size,1172(txq_id == trans->conf.cmd_queue));1173if (ret) {1174IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id);1175goto error;1176}1177trans_pcie->txqs.txq[txq_id]->id = txq_id;1178set_bit(txq_id, trans_pcie->txqs.queue_used);11791180return 0;11811182error:1183iwl_txq_gen2_tx_free(trans);1184return ret;1185}11861187/*************** HOST COMMAND QUEUE FUNCTIONS *****/11881189/*1190* iwl_pcie_gen2_enqueue_hcmd - enqueue a uCode command1191* @priv: device private data point1192* @cmd: a pointer to the ucode command structure1193*1194* The function returns < 0 values to indicate the operation1195* failed. On success, it returns the index (>= 0) of command in the1196* command queue.1197*/1198int iwl_pcie_gen2_enqueue_hcmd(struct iwl_trans *trans,1199struct iwl_host_cmd *cmd)1200{1201struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);1202struct iwl_txq *txq = trans_pcie->txqs.txq[trans->conf.cmd_queue];1203struct iwl_device_cmd *out_cmd;1204struct iwl_cmd_meta *out_meta;1205void *dup_buf = NULL;1206dma_addr_t phys_addr;1207int i, cmd_pos, idx;1208u16 copy_size, cmd_size, tb0_size;1209bool had_nocopy = false;1210u8 group_id = iwl_cmd_groupid(cmd->id);1211const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD];1212u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD];1213struct iwl_tfh_tfd *tfd;1214unsigned long flags;12151216if (WARN_ON(cmd->flags & CMD_BLOCK_TXQS))1217return -EINVAL;12181219copy_size = sizeof(struct iwl_cmd_header_wide);1220cmd_size = sizeof(struct iwl_cmd_header_wide);12211222for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) {1223cmddata[i] = cmd->data[i];1224cmdlen[i] = cmd->len[i];12251226if (!cmd->len[i])1227continue;12281229/* need at least IWL_FIRST_TB_SIZE copied */1230if (copy_size < IWL_FIRST_TB_SIZE) {1231int copy = IWL_FIRST_TB_SIZE - copy_size;12321233if (copy > cmdlen[i])1234copy = cmdlen[i];1235cmdlen[i] -= copy;1236cmddata[i] += copy;1237copy_size += copy;1238}12391240if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) {1241had_nocopy = true;1242if (WARN_ON(cmd->dataflags[i] & IWL_HCMD_DFL_DUP)) {1243idx = -EINVAL;1244goto free_dup_buf;1245}1246} else if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP) {1247/*1248* This is also a chunk that isn't copied1249* to the static buffer so set had_nocopy.1250*/1251had_nocopy = true;12521253/* only allowed once */1254if (WARN_ON(dup_buf)) {1255idx = -EINVAL;1256goto free_dup_buf;1257}12581259dup_buf = kmemdup(cmddata[i], cmdlen[i],1260GFP_ATOMIC);1261if (!dup_buf)1262return -ENOMEM;1263} else {1264/* NOCOPY must not be followed by normal! */1265if (WARN_ON(had_nocopy)) {1266idx = -EINVAL;1267goto free_dup_buf;1268}1269copy_size += cmdlen[i];1270}1271cmd_size += cmd->len[i];1272}12731274/*1275* If any of the command structures end up being larger than the1276* TFD_MAX_PAYLOAD_SIZE and they aren't dynamically allocated into1277* separate TFDs, then we will need to increase the size of the buffers1278*/1279if (WARN(copy_size > TFD_MAX_PAYLOAD_SIZE,1280"Command %s (%#x) is too large (%d bytes)\n",1281iwl_get_cmd_string(trans, cmd->id), cmd->id, copy_size)) {1282idx = -EINVAL;1283goto free_dup_buf;1284}12851286spin_lock_irqsave(&txq->lock, flags);12871288idx = iwl_txq_get_cmd_index(txq, txq->write_ptr);1289tfd = iwl_txq_get_tfd(trans, txq, txq->write_ptr);1290memset(tfd, 0, sizeof(*tfd));12911292if (iwl_txq_space(trans, txq) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {1293spin_unlock_irqrestore(&txq->lock, flags);12941295IWL_ERR(trans, "No space in command queue\n");1296iwl_op_mode_nic_error(trans->op_mode,1297IWL_ERR_TYPE_CMD_QUEUE_FULL);1298iwl_trans_schedule_reset(trans, IWL_ERR_TYPE_CMD_QUEUE_FULL);1299idx = -ENOSPC;1300goto free_dup_buf;1301}13021303out_cmd = txq->entries[idx].cmd;1304out_meta = &txq->entries[idx].meta;13051306/* re-initialize, this also marks the SG list as unused */1307memset(out_meta, 0, sizeof(*out_meta));1308if (cmd->flags & CMD_WANT_SKB)1309out_meta->source = cmd;13101311/* set up the header */1312out_cmd->hdr_wide.cmd = iwl_cmd_opcode(cmd->id);1313out_cmd->hdr_wide.group_id = group_id;1314out_cmd->hdr_wide.version = iwl_cmd_version(cmd->id);1315out_cmd->hdr_wide.length =1316cpu_to_le16(cmd_size - sizeof(struct iwl_cmd_header_wide));1317out_cmd->hdr_wide.reserved = 0;1318out_cmd->hdr_wide.sequence =1319cpu_to_le16(QUEUE_TO_SEQ(trans->conf.cmd_queue) |1320INDEX_TO_SEQ(txq->write_ptr));13211322cmd_pos = sizeof(struct iwl_cmd_header_wide);1323copy_size = sizeof(struct iwl_cmd_header_wide);13241325/* and copy the data that needs to be copied */1326for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) {1327int copy;13281329if (!cmd->len[i])1330continue;13311332/* copy everything if not nocopy/dup */1333if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY |1334IWL_HCMD_DFL_DUP))) {1335copy = cmd->len[i];13361337memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], copy);1338cmd_pos += copy;1339copy_size += copy;1340continue;1341}13421343/*1344* Otherwise we need at least IWL_FIRST_TB_SIZE copied1345* in total (for bi-directional DMA), but copy up to what1346* we can fit into the payload for debug dump purposes.1347*/1348copy = min_t(int, TFD_MAX_PAYLOAD_SIZE - cmd_pos, cmd->len[i]);13491350memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], copy);1351cmd_pos += copy;13521353/* However, treat copy_size the proper way, we need it below */1354if (copy_size < IWL_FIRST_TB_SIZE) {1355copy = IWL_FIRST_TB_SIZE - copy_size;13561357if (copy > cmd->len[i])1358copy = cmd->len[i];1359copy_size += copy;1360}1361}13621363IWL_DEBUG_HC(trans,1364"Sending command %s (%.2x.%.2x), seq: 0x%04X, %d bytes at %d[%d]:%d\n",1365iwl_get_cmd_string(trans, cmd->id), group_id,1366out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),1367cmd_size, txq->write_ptr, idx, trans->conf.cmd_queue);13681369/* start the TFD with the minimum copy bytes */1370tb0_size = min_t(int, copy_size, IWL_FIRST_TB_SIZE);1371memcpy(&txq->first_tb_bufs[idx], out_cmd, tb0_size);1372iwl_txq_gen2_set_tb(trans, tfd, iwl_txq_get_first_tb_dma(txq, idx),1373tb0_size);13741375/* map first command fragment, if any remains */1376if (copy_size > tb0_size) {1377phys_addr = dma_map_single(trans->dev,1378(u8 *)out_cmd + tb0_size,1379copy_size - tb0_size,1380DMA_TO_DEVICE);1381if (dma_mapping_error(trans->dev, phys_addr)) {1382idx = -ENOMEM;1383iwl_txq_gen2_tfd_unmap(trans, out_meta, tfd);1384goto out;1385}1386iwl_txq_gen2_set_tb(trans, tfd, phys_addr,1387copy_size - tb0_size);1388}13891390/* map the remaining (adjusted) nocopy/dup fragments */1391for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) {1392void *data = (void *)(uintptr_t)cmddata[i];13931394if (!cmdlen[i])1395continue;1396if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY |1397IWL_HCMD_DFL_DUP)))1398continue;1399if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP)1400data = dup_buf;1401phys_addr = dma_map_single(trans->dev, data,1402cmdlen[i], DMA_TO_DEVICE);1403if (dma_mapping_error(trans->dev, phys_addr)) {1404idx = -ENOMEM;1405iwl_txq_gen2_tfd_unmap(trans, out_meta, tfd);1406goto out;1407}1408iwl_txq_gen2_set_tb(trans, tfd, phys_addr, cmdlen[i]);1409}14101411BUILD_BUG_ON(IWL_TFH_NUM_TBS > sizeof(out_meta->tbs) * BITS_PER_BYTE);1412out_meta->flags = cmd->flags;1413if (WARN_ON_ONCE(txq->entries[idx].free_buf))1414kfree_sensitive(txq->entries[idx].free_buf);1415txq->entries[idx].free_buf = dup_buf;14161417trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr_wide);14181419/* start timer if queue currently empty */1420if (txq->read_ptr == txq->write_ptr && txq->wd_timeout)1421mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout);14221423spin_lock(&trans_pcie->reg_lock);1424/* Increment and update queue's write index */1425txq->write_ptr = iwl_txq_inc_wrap(trans, txq->write_ptr);1426iwl_txq_inc_wr_ptr(trans, txq);1427spin_unlock(&trans_pcie->reg_lock);14281429out:1430spin_unlock_irqrestore(&txq->lock, flags);1431free_dup_buf:1432if (idx < 0)1433kfree(dup_buf);1434return idx;1435}143614371438