xref: /openbmc/linux/drivers/infiniband/hw/hfi1/iowait.c (revision d0034a7a4ac7fae708146ac0059b9c47a1543f0d)
15da0fc9dSDennis Dalessandro // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
25da0fc9dSDennis Dalessandro /*
35da0fc9dSDennis Dalessandro  * Copyright(c) 2018 Intel Corporation.
45da0fc9dSDennis Dalessandro  *
55da0fc9dSDennis Dalessandro  */
65da0fc9dSDennis Dalessandro #include "iowait.h"
715b796bcSKaike Wan #include "trace_iowait.h"
85da0fc9dSDennis Dalessandro 
934025fb0SKaike Wan /* 1 priority == 16 starve_cnt */
1034025fb0SKaike Wan #define IOWAIT_PRIORITY_STARVE_SHIFT 4
1134025fb0SKaike Wan 
iowait_set_flag(struct iowait * wait,u32 flag)125da0fc9dSDennis Dalessandro void iowait_set_flag(struct iowait *wait, u32 flag)
135da0fc9dSDennis Dalessandro {
1415b796bcSKaike Wan 	trace_hfi1_iowait_set(wait, flag);
155da0fc9dSDennis Dalessandro 	set_bit(flag, &wait->flags);
165da0fc9dSDennis Dalessandro }
175da0fc9dSDennis Dalessandro 
iowait_flag_set(struct iowait * wait,u32 flag)185da0fc9dSDennis Dalessandro bool iowait_flag_set(struct iowait *wait, u32 flag)
195da0fc9dSDennis Dalessandro {
205da0fc9dSDennis Dalessandro 	return test_bit(flag, &wait->flags);
215da0fc9dSDennis Dalessandro }
225da0fc9dSDennis Dalessandro 
iowait_clear_flag(struct iowait * wait,u32 flag)235da0fc9dSDennis Dalessandro inline void iowait_clear_flag(struct iowait *wait, u32 flag)
245da0fc9dSDennis Dalessandro {
2515b796bcSKaike Wan 	trace_hfi1_iowait_clear(wait, flag);
265da0fc9dSDennis Dalessandro 	clear_bit(flag, &wait->flags);
275da0fc9dSDennis Dalessandro }
285da0fc9dSDennis Dalessandro 
29*36da5370SLee Jones /*
305da0fc9dSDennis Dalessandro  * iowait_init() - initialize wait structure
315da0fc9dSDennis Dalessandro  * @wait: wait struct to initialize
325da0fc9dSDennis Dalessandro  * @tx_limit: limit for overflow queuing
335da0fc9dSDennis Dalessandro  * @func: restart function for workqueue
345da0fc9dSDennis Dalessandro  * @sleep: sleep function for no space
355da0fc9dSDennis Dalessandro  * @resume: wakeup function for no space
365da0fc9dSDennis Dalessandro  *
375da0fc9dSDennis Dalessandro  * This function initializes the iowait
385da0fc9dSDennis Dalessandro  * structure embedded in the QP or PQ.
395da0fc9dSDennis Dalessandro  *
405da0fc9dSDennis Dalessandro  */
iowait_init(struct iowait * wait,u32 tx_limit,void (* func)(struct work_struct * work),void (* tidfunc)(struct work_struct * work),int (* sleep)(struct sdma_engine * sde,struct iowait_work * wait,struct sdma_txreq * tx,uint seq,bool pkts_sent),void (* wakeup)(struct iowait * wait,int reason),void (* sdma_drained)(struct iowait * wait),void (* init_priority)(struct iowait * wait))415da0fc9dSDennis Dalessandro void iowait_init(struct iowait *wait, u32 tx_limit,
425da0fc9dSDennis Dalessandro 		 void (*func)(struct work_struct *work),
435da0fc9dSDennis Dalessandro 		 void (*tidfunc)(struct work_struct *work),
445da0fc9dSDennis Dalessandro 		 int (*sleep)(struct sdma_engine *sde,
455da0fc9dSDennis Dalessandro 			      struct iowait_work *wait,
465da0fc9dSDennis Dalessandro 			      struct sdma_txreq *tx,
475da0fc9dSDennis Dalessandro 			      uint seq,
485da0fc9dSDennis Dalessandro 			      bool pkts_sent),
495da0fc9dSDennis Dalessandro 		 void (*wakeup)(struct iowait *wait, int reason),
5034025fb0SKaike Wan 		 void (*sdma_drained)(struct iowait *wait),
5134025fb0SKaike Wan 		 void (*init_priority)(struct iowait *wait))
525da0fc9dSDennis Dalessandro {
535da0fc9dSDennis Dalessandro 	int i;
545da0fc9dSDennis Dalessandro 
555da0fc9dSDennis Dalessandro 	wait->count = 0;
565da0fc9dSDennis Dalessandro 	INIT_LIST_HEAD(&wait->list);
575da0fc9dSDennis Dalessandro 	init_waitqueue_head(&wait->wait_dma);
585da0fc9dSDennis Dalessandro 	init_waitqueue_head(&wait->wait_pio);
595da0fc9dSDennis Dalessandro 	atomic_set(&wait->sdma_busy, 0);
605da0fc9dSDennis Dalessandro 	atomic_set(&wait->pio_busy, 0);
615da0fc9dSDennis Dalessandro 	wait->tx_limit = tx_limit;
625da0fc9dSDennis Dalessandro 	wait->sleep = sleep;
635da0fc9dSDennis Dalessandro 	wait->wakeup = wakeup;
645da0fc9dSDennis Dalessandro 	wait->sdma_drained = sdma_drained;
6534025fb0SKaike Wan 	wait->init_priority = init_priority;
665da0fc9dSDennis Dalessandro 	wait->flags = 0;
675da0fc9dSDennis Dalessandro 	for (i = 0; i < IOWAIT_SES; i++) {
685da0fc9dSDennis Dalessandro 		wait->wait[i].iow = wait;
695da0fc9dSDennis Dalessandro 		INIT_LIST_HEAD(&wait->wait[i].tx_head);
705da0fc9dSDennis Dalessandro 		if (i == IOWAIT_IB_SE)
715da0fc9dSDennis Dalessandro 			INIT_WORK(&wait->wait[i].iowork, func);
725da0fc9dSDennis Dalessandro 		else
735da0fc9dSDennis Dalessandro 			INIT_WORK(&wait->wait[i].iowork, tidfunc);
745da0fc9dSDennis Dalessandro 	}
755da0fc9dSDennis Dalessandro }
765da0fc9dSDennis Dalessandro 
775da0fc9dSDennis Dalessandro /**
785da0fc9dSDennis Dalessandro  * iowait_cancel_work - cancel all work in iowait
795da0fc9dSDennis Dalessandro  * @w: the iowait struct
805da0fc9dSDennis Dalessandro  */
iowait_cancel_work(struct iowait * w)815da0fc9dSDennis Dalessandro void iowait_cancel_work(struct iowait *w)
825da0fc9dSDennis Dalessandro {
835da0fc9dSDennis Dalessandro 	cancel_work_sync(&iowait_get_ib_work(w)->iowork);
84ca9033baSKaike Wan 	/* Make sure that the iowork for TID RDMA is used */
85ca9033baSKaike Wan 	if (iowait_get_tid_work(w)->iowork.func)
865da0fc9dSDennis Dalessandro 		cancel_work_sync(&iowait_get_tid_work(w)->iowork);
875da0fc9dSDennis Dalessandro }
885da0fc9dSDennis Dalessandro 
895da0fc9dSDennis Dalessandro /**
905da0fc9dSDennis Dalessandro  * iowait_set_work_flag - set work flag based on leg
91*36da5370SLee Jones  * @w: the iowait work struct
925da0fc9dSDennis Dalessandro  */
iowait_set_work_flag(struct iowait_work * w)935da0fc9dSDennis Dalessandro int iowait_set_work_flag(struct iowait_work *w)
945da0fc9dSDennis Dalessandro {
955da0fc9dSDennis Dalessandro 	if (w == &w->iow->wait[IOWAIT_IB_SE]) {
965da0fc9dSDennis Dalessandro 		iowait_set_flag(w->iow, IOWAIT_PENDING_IB);
975da0fc9dSDennis Dalessandro 		return IOWAIT_IB_SE;
985da0fc9dSDennis Dalessandro 	}
995da0fc9dSDennis Dalessandro 	iowait_set_flag(w->iow, IOWAIT_PENDING_TID);
1005da0fc9dSDennis Dalessandro 	return IOWAIT_TID_SE;
1015da0fc9dSDennis Dalessandro }
10234025fb0SKaike Wan 
10334025fb0SKaike Wan /**
10434025fb0SKaike Wan  * iowait_priority_update_top - update the top priority entry
10534025fb0SKaike Wan  * @w: the iowait struct
10634025fb0SKaike Wan  * @top: a pointer to the top priority entry
10734025fb0SKaike Wan  * @idx: the index of the current iowait in an array
10834025fb0SKaike Wan  * @top_idx: the array index for the iowait entry that has the top priority
10934025fb0SKaike Wan  *
11034025fb0SKaike Wan  * This function is called to compare the priority of a given
11134025fb0SKaike Wan  * iowait with the given top priority entry. The top index will
11234025fb0SKaike Wan  * be returned.
11334025fb0SKaike Wan  */
iowait_priority_update_top(struct iowait * w,struct iowait * top,uint idx,uint top_idx)11434025fb0SKaike Wan uint iowait_priority_update_top(struct iowait *w,
11534025fb0SKaike Wan 				struct iowait *top,
11634025fb0SKaike Wan 				uint idx, uint top_idx)
11734025fb0SKaike Wan {
11834025fb0SKaike Wan 	u8 cnt, tcnt;
11934025fb0SKaike Wan 
12034025fb0SKaike Wan 	/* Convert priority into starve_cnt and compare the total.*/
12134025fb0SKaike Wan 	cnt = (w->priority << IOWAIT_PRIORITY_STARVE_SHIFT) + w->starved_cnt;
12234025fb0SKaike Wan 	tcnt = (top->priority << IOWAIT_PRIORITY_STARVE_SHIFT) +
12334025fb0SKaike Wan 		top->starved_cnt;
12434025fb0SKaike Wan 	if (cnt > tcnt)
12534025fb0SKaike Wan 		return idx;
12634025fb0SKaike Wan 	else
12734025fb0SKaike Wan 		return top_idx;
12834025fb0SKaike Wan }
129