18e99ea8dSJohannes Berg /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ 28e99ea8dSJohannes Berg /* 312a89f01SJohannes Berg * Copyright (C) 2020-2023 Intel Corporation 48e99ea8dSJohannes Berg */ 50cd1ad2dSMordechay Goodstein #ifndef __iwl_trans_queue_tx_h__ 60cd1ad2dSMordechay Goodstein #define __iwl_trans_queue_tx_h__ 70cd1ad2dSMordechay Goodstein #include "iwl-fh.h" 80cd1ad2dSMordechay Goodstein #include "fw/api/tx.h" 90cd1ad2dSMordechay Goodstein 100cd1ad2dSMordechay Goodstein struct iwl_tso_hdr_page { 110cd1ad2dSMordechay Goodstein struct page *page; 120cd1ad2dSMordechay Goodstein u8 *pos; 130cd1ad2dSMordechay Goodstein }; 140cd1ad2dSMordechay Goodstein 150cd1ad2dSMordechay Goodstein static inline dma_addr_t 160cd1ad2dSMordechay Goodstein iwl_txq_get_first_tb_dma(struct iwl_txq *txq, int idx) 170cd1ad2dSMordechay Goodstein { 180cd1ad2dSMordechay Goodstein return txq->first_tb_dma + 190cd1ad2dSMordechay Goodstein sizeof(struct iwl_pcie_first_tb_buf) * idx; 200cd1ad2dSMordechay Goodstein } 210cd1ad2dSMordechay Goodstein 220cd1ad2dSMordechay Goodstein static inline u16 iwl_txq_get_cmd_index(const struct iwl_txq *q, u32 index) 230cd1ad2dSMordechay Goodstein { 240cd1ad2dSMordechay Goodstein return index & (q->n_window - 1); 250cd1ad2dSMordechay Goodstein } 260cd1ad2dSMordechay Goodstein 270cd1ad2dSMordechay Goodstein void iwl_txq_gen2_unmap(struct iwl_trans *trans, int txq_id); 280cd1ad2dSMordechay Goodstein 290cd1ad2dSMordechay Goodstein static inline void iwl_wake_queue(struct iwl_trans *trans, 300cd1ad2dSMordechay Goodstein struct iwl_txq *txq) 310cd1ad2dSMordechay Goodstein { 320cd1ad2dSMordechay Goodstein if (test_and_clear_bit(txq->id, trans->txqs.queue_stopped)) { 330cd1ad2dSMordechay Goodstein IWL_DEBUG_TX_QUEUES(trans, "Wake hwq %d\n", txq->id); 340cd1ad2dSMordechay Goodstein iwl_op_mode_queue_not_full(trans->op_mode, txq->id); 350cd1ad2dSMordechay Goodstein } 360cd1ad2dSMordechay Goodstein } 370cd1ad2dSMordechay Goodstein 380cd1ad2dSMordechay Goodstein static inline void *iwl_txq_get_tfd(struct iwl_trans *trans, 390cd1ad2dSMordechay Goodstein struct iwl_txq *txq, int idx) 400cd1ad2dSMordechay Goodstein { 4112a89f01SJohannes Berg if (trans->trans_cfg->gen2) 420cd1ad2dSMordechay Goodstein idx = iwl_txq_get_cmd_index(txq, idx); 430cd1ad2dSMordechay Goodstein 443827cb59SJohannes Berg return (u8 *)txq->tfds + trans->txqs.tfd.size * idx; 450cd1ad2dSMordechay Goodstein } 460cd1ad2dSMordechay Goodstein 470cd1ad2dSMordechay Goodstein int iwl_txq_alloc(struct iwl_trans *trans, struct iwl_txq *txq, int slots_num, 480cd1ad2dSMordechay Goodstein bool cmd_queue); 490cd1ad2dSMordechay Goodstein /* 500cd1ad2dSMordechay Goodstein * We need this inline in case dma_addr_t is only 32-bits - since the 510cd1ad2dSMordechay Goodstein * hardware is always 64-bit, the issue can still occur in that case, 520cd1ad2dSMordechay Goodstein * so use u64 for 'phys' here to force the addition in 64-bit. 530cd1ad2dSMordechay Goodstein */ 540cd1ad2dSMordechay Goodstein static inline bool iwl_txq_crosses_4g_boundary(u64 phys, u16 len) 550cd1ad2dSMordechay Goodstein { 560cd1ad2dSMordechay Goodstein return upper_32_bits(phys) != upper_32_bits(phys + len); 570cd1ad2dSMordechay Goodstein } 580cd1ad2dSMordechay Goodstein 590cd1ad2dSMordechay Goodstein int iwl_txq_space(struct iwl_trans *trans, const struct iwl_txq *q); 600cd1ad2dSMordechay Goodstein 610cd1ad2dSMordechay Goodstein static inline void iwl_txq_stop(struct iwl_trans *trans, struct iwl_txq *txq) 620cd1ad2dSMordechay Goodstein { 630cd1ad2dSMordechay Goodstein if (!test_and_set_bit(txq->id, trans->txqs.queue_stopped)) { 640cd1ad2dSMordechay Goodstein iwl_op_mode_queue_full(trans->op_mode, txq->id); 650cd1ad2dSMordechay Goodstein IWL_DEBUG_TX_QUEUES(trans, "Stop hwq %d\n", txq->id); 660cd1ad2dSMordechay Goodstein } else { 670cd1ad2dSMordechay Goodstein IWL_DEBUG_TX_QUEUES(trans, "hwq %d already stopped\n", 680cd1ad2dSMordechay Goodstein txq->id); 690cd1ad2dSMordechay Goodstein } 700cd1ad2dSMordechay Goodstein } 710cd1ad2dSMordechay Goodstein 720cd1ad2dSMordechay Goodstein /** 730cd1ad2dSMordechay Goodstein * iwl_txq_inc_wrap - increment queue index, wrap back to beginning 740cd1ad2dSMordechay Goodstein * @index -- current index 750cd1ad2dSMordechay Goodstein */ 760cd1ad2dSMordechay Goodstein static inline int iwl_txq_inc_wrap(struct iwl_trans *trans, int index) 770cd1ad2dSMordechay Goodstein { 780cd1ad2dSMordechay Goodstein return ++index & 790cd1ad2dSMordechay Goodstein (trans->trans_cfg->base_params->max_tfd_queue_size - 1); 800cd1ad2dSMordechay Goodstein } 810cd1ad2dSMordechay Goodstein 820cd1ad2dSMordechay Goodstein /** 830cd1ad2dSMordechay Goodstein * iwl_txq_dec_wrap - decrement queue index, wrap back to end 840cd1ad2dSMordechay Goodstein * @index -- current index 850cd1ad2dSMordechay Goodstein */ 860cd1ad2dSMordechay Goodstein static inline int iwl_txq_dec_wrap(struct iwl_trans *trans, int index) 870cd1ad2dSMordechay Goodstein { 880cd1ad2dSMordechay Goodstein return --index & 890cd1ad2dSMordechay Goodstein (trans->trans_cfg->base_params->max_tfd_queue_size - 1); 900cd1ad2dSMordechay Goodstein } 910cd1ad2dSMordechay Goodstein 920cd1ad2dSMordechay Goodstein static inline bool iwl_txq_used(const struct iwl_txq *q, int i) 930cd1ad2dSMordechay Goodstein { 940cd1ad2dSMordechay Goodstein int index = iwl_txq_get_cmd_index(q, i); 950cd1ad2dSMordechay Goodstein int r = iwl_txq_get_cmd_index(q, q->read_ptr); 960cd1ad2dSMordechay Goodstein int w = iwl_txq_get_cmd_index(q, q->write_ptr); 970cd1ad2dSMordechay Goodstein 980cd1ad2dSMordechay Goodstein return w >= r ? 990cd1ad2dSMordechay Goodstein (index >= r && index < w) : 1000cd1ad2dSMordechay Goodstein !(index < r && index >= w); 1010cd1ad2dSMordechay Goodstein } 1020cd1ad2dSMordechay Goodstein 1030cd1ad2dSMordechay Goodstein void iwl_txq_free_tso_page(struct iwl_trans *trans, struct sk_buff *skb); 1040cd1ad2dSMordechay Goodstein 1050cd1ad2dSMordechay Goodstein void iwl_txq_log_scd_error(struct iwl_trans *trans, struct iwl_txq *txq); 1060cd1ad2dSMordechay Goodstein 1070cd1ad2dSMordechay Goodstein int iwl_txq_gen2_set_tb(struct iwl_trans *trans, 1080cd1ad2dSMordechay Goodstein struct iwl_tfh_tfd *tfd, dma_addr_t addr, 1090cd1ad2dSMordechay Goodstein u16 len); 1100cd1ad2dSMordechay Goodstein 1110cd1ad2dSMordechay Goodstein void iwl_txq_gen2_tfd_unmap(struct iwl_trans *trans, 1120cd1ad2dSMordechay Goodstein struct iwl_cmd_meta *meta, 1130cd1ad2dSMordechay Goodstein struct iwl_tfh_tfd *tfd); 1140cd1ad2dSMordechay Goodstein 115227f2597SJohannes Berg int iwl_txq_dyn_alloc(struct iwl_trans *trans, u32 flags, 116227f2597SJohannes Berg u32 sta_mask, u8 tid, 11785b17a33SJohannes Berg int size, unsigned int timeout); 1180cd1ad2dSMordechay Goodstein 1190cd1ad2dSMordechay Goodstein int iwl_txq_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, 1200cd1ad2dSMordechay Goodstein struct iwl_device_tx_cmd *dev_cmd, int txq_id); 1210cd1ad2dSMordechay Goodstein 1220cd1ad2dSMordechay Goodstein void iwl_txq_dyn_free(struct iwl_trans *trans, int queue); 1230cd1ad2dSMordechay Goodstein void iwl_txq_gen2_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq); 1240cd1ad2dSMordechay Goodstein void iwl_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq); 1250cd1ad2dSMordechay Goodstein void iwl_txq_gen2_tx_free(struct iwl_trans *trans); 1260cd1ad2dSMordechay Goodstein int iwl_txq_init(struct iwl_trans *trans, struct iwl_txq *txq, int slots_num, 1270cd1ad2dSMordechay Goodstein bool cmd_queue); 1280cd1ad2dSMordechay Goodstein int iwl_txq_gen2_init(struct iwl_trans *trans, int txq_id, int queue_size); 1290cd1ad2dSMordechay Goodstein #ifdef CONFIG_INET 1300cd1ad2dSMordechay Goodstein struct iwl_tso_hdr_page *get_page_hdr(struct iwl_trans *trans, size_t len, 1310cd1ad2dSMordechay Goodstein struct sk_buff *skb); 1320cd1ad2dSMordechay Goodstein #endif 1330179bfffSMordechay Goodstein static inline u8 iwl_txq_gen1_tfd_get_num_tbs(struct iwl_trans *trans, 134*a0632004SJohannes Berg struct iwl_tfd *tfd) 1350179bfffSMordechay Goodstein { 1360179bfffSMordechay Goodstein return tfd->num_tbs & 0x1f; 1370179bfffSMordechay Goodstein } 1380179bfffSMordechay Goodstein 1390179bfffSMordechay Goodstein static inline u16 iwl_txq_gen1_tfd_tb_get_len(struct iwl_trans *trans, 1400179bfffSMordechay Goodstein void *_tfd, u8 idx) 1410179bfffSMordechay Goodstein { 1420179bfffSMordechay Goodstein struct iwl_tfd *tfd; 1430179bfffSMordechay Goodstein struct iwl_tfd_tb *tb; 1440179bfffSMordechay Goodstein 14512a89f01SJohannes Berg if (trans->trans_cfg->gen2) { 146d4530f63SJohannes Berg struct iwl_tfh_tfd *tfh_tfd = _tfd; 147d4530f63SJohannes Berg struct iwl_tfh_tb *tfh_tb = &tfh_tfd->tbs[idx]; 1480179bfffSMordechay Goodstein 149d4530f63SJohannes Berg return le16_to_cpu(tfh_tb->tb_len); 1500179bfffSMordechay Goodstein } 1510179bfffSMordechay Goodstein 1520179bfffSMordechay Goodstein tfd = (struct iwl_tfd *)_tfd; 1530179bfffSMordechay Goodstein tb = &tfd->tbs[idx]; 1540179bfffSMordechay Goodstein 1550179bfffSMordechay Goodstein return le16_to_cpu(tb->hi_n_len) >> 4; 1560179bfffSMordechay Goodstein } 1570179bfffSMordechay Goodstein 1580179bfffSMordechay Goodstein void iwl_txq_gen1_tfd_unmap(struct iwl_trans *trans, 1590179bfffSMordechay Goodstein struct iwl_cmd_meta *meta, 1600179bfffSMordechay Goodstein struct iwl_txq *txq, int index); 1610179bfffSMordechay Goodstein void iwl_txq_gen1_inval_byte_cnt_tbl(struct iwl_trans *trans, 1620179bfffSMordechay Goodstein struct iwl_txq *txq); 1630179bfffSMordechay Goodstein void iwl_txq_gen1_update_byte_cnt_tbl(struct iwl_trans *trans, 1640179bfffSMordechay Goodstein struct iwl_txq *txq, u16 byte_cnt, 1650179bfffSMordechay Goodstein int num_tbs); 166a4450980SMordechay Goodstein void iwl_txq_reclaim(struct iwl_trans *trans, int txq_id, int ssn, 167a4450980SMordechay Goodstein struct sk_buff_head *skbs); 168a4450980SMordechay Goodstein void iwl_txq_set_q_ptrs(struct iwl_trans *trans, int txq_id, int ptr); 169a4450980SMordechay Goodstein void iwl_trans_txq_freeze_timer(struct iwl_trans *trans, unsigned long txqs, 170a4450980SMordechay Goodstein bool freeze); 171a4450980SMordechay Goodstein void iwl_txq_progress(struct iwl_txq *txq); 172a4450980SMordechay Goodstein void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq); 17313f028b4SMordechay Goodstein int iwl_trans_txq_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd); 1740cd1ad2dSMordechay Goodstein #endif /* __iwl_trans_queue_tx_h__ */ 175