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
iwl_txq_get_first_tb_dma(struct iwl_txq * txq,int idx)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 
iwl_txq_get_cmd_index(const struct iwl_txq * q,u32 index)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 
iwl_wake_queue(struct iwl_trans * trans,struct iwl_txq * txq)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 
iwl_txq_get_tfd(struct iwl_trans * trans,struct iwl_txq * txq,int idx)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  */
iwl_txq_crosses_4g_boundary(u64 phys,u16 len)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 
iwl_txq_stop(struct iwl_trans * trans,struct iwl_txq * txq)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  */
iwl_txq_inc_wrap(struct iwl_trans * trans,int index)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  */
iwl_txq_dec_wrap(struct iwl_trans * trans,int index)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 
iwl_txq_used(const struct iwl_txq * q,int i)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
iwl_txq_gen1_tfd_get_num_tbs(struct iwl_trans * trans,struct iwl_tfd * tfd)1330179bfffSMordechay Goodstein static inline u8 iwl_txq_gen1_tfd_get_num_tbs(struct iwl_trans *trans,
134a0632004SJohannes Berg 					      struct iwl_tfd *tfd)
1350179bfffSMordechay Goodstein {
1360179bfffSMordechay Goodstein 	return tfd->num_tbs & 0x1f;
1370179bfffSMordechay Goodstein }
1380179bfffSMordechay Goodstein 
iwl_txq_gen1_tfd_tb_get_len(struct iwl_trans * trans,void * _tfd,u8 idx)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 
iwl_pcie_gen1_tfd_set_tb(struct iwl_trans * trans,struct iwl_tfd * tfd,u8 idx,dma_addr_t addr,u16 len)158c522948aSJohannes Berg static inline void iwl_pcie_gen1_tfd_set_tb(struct iwl_trans *trans,
159c522948aSJohannes Berg 					    struct iwl_tfd *tfd,
160c522948aSJohannes Berg 					    u8 idx, dma_addr_t addr, u16 len)
161c522948aSJohannes Berg {
162c522948aSJohannes Berg 	struct iwl_tfd_tb *tb = &tfd->tbs[idx];
163c522948aSJohannes Berg 	u16 hi_n_len = len << 4;
164c522948aSJohannes Berg 
165c522948aSJohannes Berg 	put_unaligned_le32(addr, &tb->lo);
166c522948aSJohannes Berg 	hi_n_len |= iwl_get_dma_hi_addr(addr);
167c522948aSJohannes Berg 
168c522948aSJohannes Berg 	tb->hi_n_len = cpu_to_le16(hi_n_len);
169c522948aSJohannes Berg 
170c522948aSJohannes Berg 	tfd->num_tbs = idx + 1;
171c522948aSJohannes Berg }
172c522948aSJohannes Berg 
1730179bfffSMordechay Goodstein void iwl_txq_gen1_tfd_unmap(struct iwl_trans *trans,
1740179bfffSMordechay Goodstein 			    struct iwl_cmd_meta *meta,
1750179bfffSMordechay Goodstein 			    struct iwl_txq *txq, int index);
1760179bfffSMordechay Goodstein void iwl_txq_gen1_inval_byte_cnt_tbl(struct iwl_trans *trans,
1770179bfffSMordechay Goodstein 				     struct iwl_txq *txq);
1780179bfffSMordechay Goodstein void iwl_txq_gen1_update_byte_cnt_tbl(struct iwl_trans *trans,
1790179bfffSMordechay Goodstein 				      struct iwl_txq *txq, u16 byte_cnt,
1800179bfffSMordechay Goodstein 				      int num_tbs);
181a4450980SMordechay Goodstein void iwl_txq_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
182*fc163831SMiri Korenblit 		     struct sk_buff_head *skbs, bool is_flush);
183a4450980SMordechay Goodstein void iwl_txq_set_q_ptrs(struct iwl_trans *trans, int txq_id, int ptr);
184a4450980SMordechay Goodstein void iwl_trans_txq_freeze_timer(struct iwl_trans *trans, unsigned long txqs,
185a4450980SMordechay Goodstein 				bool freeze);
186a4450980SMordechay Goodstein void iwl_txq_progress(struct iwl_txq *txq);
187a4450980SMordechay Goodstein void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq);
18813f028b4SMordechay Goodstein int iwl_trans_txq_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
1890cd1ad2dSMordechay Goodstein #endif /* __iwl_trans_queue_tx_h__ */
190