18e99ea8dSJohannes Berg /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
28e99ea8dSJohannes Berg /*
34cf2f590SMordechay Goodstein  * Copyright (C) 2020-2021 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 {
410cd1ad2dSMordechay Goodstein 	if (trans->trans_cfg->use_tfh)
420cd1ad2dSMordechay Goodstein 		idx = iwl_txq_get_cmd_index(txq, idx);
430cd1ad2dSMordechay Goodstein 
44*3827cb59SJohannes 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 
1150cd1ad2dSMordechay Goodstein int iwl_txq_dyn_alloc(struct iwl_trans *trans,
1160cd1ad2dSMordechay Goodstein 		      __le16 flags, u8 sta_id, u8 tid,
1170cd1ad2dSMordechay Goodstein 		      int cmd_id, int size,
1180cd1ad2dSMordechay Goodstein 		      unsigned int timeout);
1190cd1ad2dSMordechay Goodstein 
1200cd1ad2dSMordechay Goodstein int iwl_txq_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb,
1210cd1ad2dSMordechay Goodstein 		    struct iwl_device_tx_cmd *dev_cmd, int txq_id);
1220cd1ad2dSMordechay Goodstein 
1230cd1ad2dSMordechay Goodstein void iwl_txq_dyn_free(struct iwl_trans *trans, int queue);
1240cd1ad2dSMordechay Goodstein void iwl_txq_gen2_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq);
1250cd1ad2dSMordechay Goodstein void iwl_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq);
1260cd1ad2dSMordechay Goodstein void iwl_txq_gen2_tx_free(struct iwl_trans *trans);
1270cd1ad2dSMordechay Goodstein int iwl_txq_init(struct iwl_trans *trans, struct iwl_txq *txq, int slots_num,
1280cd1ad2dSMordechay Goodstein 		 bool cmd_queue);
1290cd1ad2dSMordechay Goodstein int iwl_txq_gen2_init(struct iwl_trans *trans, int txq_id, int queue_size);
1300cd1ad2dSMordechay Goodstein #ifdef CONFIG_INET
1310cd1ad2dSMordechay Goodstein struct iwl_tso_hdr_page *get_page_hdr(struct iwl_trans *trans, size_t len,
1320cd1ad2dSMordechay Goodstein 				      struct sk_buff *skb);
1330cd1ad2dSMordechay Goodstein #endif
1340179bfffSMordechay Goodstein static inline u8 iwl_txq_gen1_tfd_get_num_tbs(struct iwl_trans *trans,
1350179bfffSMordechay Goodstein 					      void *_tfd)
1360179bfffSMordechay Goodstein {
1370179bfffSMordechay Goodstein 	struct iwl_tfd *tfd;
1380179bfffSMordechay Goodstein 
1390179bfffSMordechay Goodstein 	if (trans->trans_cfg->use_tfh) {
1400179bfffSMordechay Goodstein 		struct iwl_tfh_tfd *tfd = _tfd;
1410179bfffSMordechay Goodstein 
1420179bfffSMordechay Goodstein 		return le16_to_cpu(tfd->num_tbs) & 0x1f;
1430179bfffSMordechay Goodstein 	}
1440179bfffSMordechay Goodstein 
1450179bfffSMordechay Goodstein 	tfd = (struct iwl_tfd *)_tfd;
1460179bfffSMordechay Goodstein 	return tfd->num_tbs & 0x1f;
1470179bfffSMordechay Goodstein }
1480179bfffSMordechay Goodstein 
1490179bfffSMordechay Goodstein static inline u16 iwl_txq_gen1_tfd_tb_get_len(struct iwl_trans *trans,
1500179bfffSMordechay Goodstein 					      void *_tfd, u8 idx)
1510179bfffSMordechay Goodstein {
1520179bfffSMordechay Goodstein 	struct iwl_tfd *tfd;
1530179bfffSMordechay Goodstein 	struct iwl_tfd_tb *tb;
1540179bfffSMordechay Goodstein 
1550179bfffSMordechay Goodstein 	if (trans->trans_cfg->use_tfh) {
1560179bfffSMordechay Goodstein 		struct iwl_tfh_tfd *tfd = _tfd;
1570179bfffSMordechay Goodstein 		struct iwl_tfh_tb *tb = &tfd->tbs[idx];
1580179bfffSMordechay Goodstein 
1590179bfffSMordechay Goodstein 		return le16_to_cpu(tb->tb_len);
1600179bfffSMordechay Goodstein 	}
1610179bfffSMordechay Goodstein 
1620179bfffSMordechay Goodstein 	tfd = (struct iwl_tfd *)_tfd;
1630179bfffSMordechay Goodstein 	tb = &tfd->tbs[idx];
1640179bfffSMordechay Goodstein 
1650179bfffSMordechay Goodstein 	return le16_to_cpu(tb->hi_n_len) >> 4;
1660179bfffSMordechay Goodstein }
1670179bfffSMordechay Goodstein 
1680179bfffSMordechay Goodstein void iwl_txq_gen1_tfd_unmap(struct iwl_trans *trans,
1690179bfffSMordechay Goodstein 			    struct iwl_cmd_meta *meta,
1700179bfffSMordechay Goodstein 			    struct iwl_txq *txq, int index);
1710179bfffSMordechay Goodstein void iwl_txq_gen1_inval_byte_cnt_tbl(struct iwl_trans *trans,
1720179bfffSMordechay Goodstein 				     struct iwl_txq *txq);
1730179bfffSMordechay Goodstein void iwl_txq_gen1_update_byte_cnt_tbl(struct iwl_trans *trans,
1740179bfffSMordechay Goodstein 				      struct iwl_txq *txq, u16 byte_cnt,
1750179bfffSMordechay Goodstein 				      int num_tbs);
176a4450980SMordechay Goodstein void iwl_txq_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
177a4450980SMordechay Goodstein 		     struct sk_buff_head *skbs);
178a4450980SMordechay Goodstein void iwl_txq_set_q_ptrs(struct iwl_trans *trans, int txq_id, int ptr);
179a4450980SMordechay Goodstein void iwl_trans_txq_freeze_timer(struct iwl_trans *trans, unsigned long txqs,
180a4450980SMordechay Goodstein 				bool freeze);
181a4450980SMordechay Goodstein void iwl_txq_progress(struct iwl_txq *txq);
182a4450980SMordechay Goodstein void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq);
18313f028b4SMordechay Goodstein int iwl_trans_txq_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
1840cd1ad2dSMordechay Goodstein #endif /* __iwl_trans_queue_tx_h__ */
185