xref: /openbmc/linux/drivers/infiniband/hw/hfi1/iowait.c (revision 34025fb0c4c9d6b2e294f8f8f0a82491a13c83a2)
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 
9*34025fb0SKaike Wan /* 1 priority == 16 starve_cnt */
10*34025fb0SKaike Wan #define IOWAIT_PRIORITY_STARVE_SHIFT 4
11*34025fb0SKaike Wan 
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 
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 
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 
295da0fc9dSDennis Dalessandro /**
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  */
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),
50*34025fb0SKaike Wan 		 void (*sdma_drained)(struct iowait *wait),
51*34025fb0SKaike 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;
65*34025fb0SKaike 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  */
815da0fc9dSDennis Dalessandro void iowait_cancel_work(struct iowait *w)
825da0fc9dSDennis Dalessandro {
835da0fc9dSDennis Dalessandro 	cancel_work_sync(&iowait_get_ib_work(w)->iowork);
845da0fc9dSDennis Dalessandro 	cancel_work_sync(&iowait_get_tid_work(w)->iowork);
855da0fc9dSDennis Dalessandro }
865da0fc9dSDennis Dalessandro 
875da0fc9dSDennis Dalessandro /**
885da0fc9dSDennis Dalessandro  * iowait_set_work_flag - set work flag based on leg
895da0fc9dSDennis Dalessandro  * @w - the iowait work struct
905da0fc9dSDennis Dalessandro  */
915da0fc9dSDennis Dalessandro int iowait_set_work_flag(struct iowait_work *w)
925da0fc9dSDennis Dalessandro {
935da0fc9dSDennis Dalessandro 	if (w == &w->iow->wait[IOWAIT_IB_SE]) {
945da0fc9dSDennis Dalessandro 		iowait_set_flag(w->iow, IOWAIT_PENDING_IB);
955da0fc9dSDennis Dalessandro 		return IOWAIT_IB_SE;
965da0fc9dSDennis Dalessandro 	}
975da0fc9dSDennis Dalessandro 	iowait_set_flag(w->iow, IOWAIT_PENDING_TID);
985da0fc9dSDennis Dalessandro 	return IOWAIT_TID_SE;
995da0fc9dSDennis Dalessandro }
100*34025fb0SKaike Wan 
101*34025fb0SKaike Wan /**
102*34025fb0SKaike Wan  * iowait_priority_update_top - update the top priority entry
103*34025fb0SKaike Wan  * @w: the iowait struct
104*34025fb0SKaike Wan  * @top: a pointer to the top priority entry
105*34025fb0SKaike Wan  * @idx: the index of the current iowait in an array
106*34025fb0SKaike Wan  * @top_idx: the array index for the iowait entry that has the top priority
107*34025fb0SKaike Wan  *
108*34025fb0SKaike Wan  * This function is called to compare the priority of a given
109*34025fb0SKaike Wan  * iowait with the given top priority entry. The top index will
110*34025fb0SKaike Wan  * be returned.
111*34025fb0SKaike Wan  */
112*34025fb0SKaike Wan uint iowait_priority_update_top(struct iowait *w,
113*34025fb0SKaike Wan 				struct iowait *top,
114*34025fb0SKaike Wan 				uint idx, uint top_idx)
115*34025fb0SKaike Wan {
116*34025fb0SKaike Wan 	u8 cnt, tcnt;
117*34025fb0SKaike Wan 
118*34025fb0SKaike Wan 	/* Convert priority into starve_cnt and compare the total.*/
119*34025fb0SKaike Wan 	cnt = (w->priority << IOWAIT_PRIORITY_STARVE_SHIFT) + w->starved_cnt;
120*34025fb0SKaike Wan 	tcnt = (top->priority << IOWAIT_PRIORITY_STARVE_SHIFT) +
121*34025fb0SKaike Wan 		top->starved_cnt;
122*34025fb0SKaike Wan 	if (cnt > tcnt)
123*34025fb0SKaike Wan 		return idx;
124*34025fb0SKaike Wan 	else
125*34025fb0SKaike Wan 		return top_idx;
126*34025fb0SKaike Wan }
127