1*4882a593Smuzhiyun // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright(c) 2018 Intel Corporation.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun #include "iowait.h"
7*4882a593Smuzhiyun #include "trace_iowait.h"
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun /* 1 priority == 16 starve_cnt */
10*4882a593Smuzhiyun #define IOWAIT_PRIORITY_STARVE_SHIFT 4
11*4882a593Smuzhiyun
iowait_set_flag(struct iowait * wait,u32 flag)12*4882a593Smuzhiyun void iowait_set_flag(struct iowait *wait, u32 flag)
13*4882a593Smuzhiyun {
14*4882a593Smuzhiyun trace_hfi1_iowait_set(wait, flag);
15*4882a593Smuzhiyun set_bit(flag, &wait->flags);
16*4882a593Smuzhiyun }
17*4882a593Smuzhiyun
iowait_flag_set(struct iowait * wait,u32 flag)18*4882a593Smuzhiyun bool iowait_flag_set(struct iowait *wait, u32 flag)
19*4882a593Smuzhiyun {
20*4882a593Smuzhiyun return test_bit(flag, &wait->flags);
21*4882a593Smuzhiyun }
22*4882a593Smuzhiyun
iowait_clear_flag(struct iowait * wait,u32 flag)23*4882a593Smuzhiyun inline void iowait_clear_flag(struct iowait *wait, u32 flag)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun trace_hfi1_iowait_clear(wait, flag);
26*4882a593Smuzhiyun clear_bit(flag, &wait->flags);
27*4882a593Smuzhiyun }
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun /**
30*4882a593Smuzhiyun * iowait_init() - initialize wait structure
31*4882a593Smuzhiyun * @wait: wait struct to initialize
32*4882a593Smuzhiyun * @tx_limit: limit for overflow queuing
33*4882a593Smuzhiyun * @func: restart function for workqueue
34*4882a593Smuzhiyun * @sleep: sleep function for no space
35*4882a593Smuzhiyun * @resume: wakeup function for no space
36*4882a593Smuzhiyun *
37*4882a593Smuzhiyun * This function initializes the iowait
38*4882a593Smuzhiyun * structure embedded in the QP or PQ.
39*4882a593Smuzhiyun *
40*4882a593Smuzhiyun */
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))41*4882a593Smuzhiyun void iowait_init(struct iowait *wait, u32 tx_limit,
42*4882a593Smuzhiyun void (*func)(struct work_struct *work),
43*4882a593Smuzhiyun void (*tidfunc)(struct work_struct *work),
44*4882a593Smuzhiyun int (*sleep)(struct sdma_engine *sde,
45*4882a593Smuzhiyun struct iowait_work *wait,
46*4882a593Smuzhiyun struct sdma_txreq *tx,
47*4882a593Smuzhiyun uint seq,
48*4882a593Smuzhiyun bool pkts_sent),
49*4882a593Smuzhiyun void (*wakeup)(struct iowait *wait, int reason),
50*4882a593Smuzhiyun void (*sdma_drained)(struct iowait *wait),
51*4882a593Smuzhiyun void (*init_priority)(struct iowait *wait))
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun int i;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun wait->count = 0;
56*4882a593Smuzhiyun INIT_LIST_HEAD(&wait->list);
57*4882a593Smuzhiyun init_waitqueue_head(&wait->wait_dma);
58*4882a593Smuzhiyun init_waitqueue_head(&wait->wait_pio);
59*4882a593Smuzhiyun atomic_set(&wait->sdma_busy, 0);
60*4882a593Smuzhiyun atomic_set(&wait->pio_busy, 0);
61*4882a593Smuzhiyun wait->tx_limit = tx_limit;
62*4882a593Smuzhiyun wait->sleep = sleep;
63*4882a593Smuzhiyun wait->wakeup = wakeup;
64*4882a593Smuzhiyun wait->sdma_drained = sdma_drained;
65*4882a593Smuzhiyun wait->init_priority = init_priority;
66*4882a593Smuzhiyun wait->flags = 0;
67*4882a593Smuzhiyun for (i = 0; i < IOWAIT_SES; i++) {
68*4882a593Smuzhiyun wait->wait[i].iow = wait;
69*4882a593Smuzhiyun INIT_LIST_HEAD(&wait->wait[i].tx_head);
70*4882a593Smuzhiyun if (i == IOWAIT_IB_SE)
71*4882a593Smuzhiyun INIT_WORK(&wait->wait[i].iowork, func);
72*4882a593Smuzhiyun else
73*4882a593Smuzhiyun INIT_WORK(&wait->wait[i].iowork, tidfunc);
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun /**
78*4882a593Smuzhiyun * iowait_cancel_work - cancel all work in iowait
79*4882a593Smuzhiyun * @w: the iowait struct
80*4882a593Smuzhiyun */
iowait_cancel_work(struct iowait * w)81*4882a593Smuzhiyun void iowait_cancel_work(struct iowait *w)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun cancel_work_sync(&iowait_get_ib_work(w)->iowork);
84*4882a593Smuzhiyun /* Make sure that the iowork for TID RDMA is used */
85*4882a593Smuzhiyun if (iowait_get_tid_work(w)->iowork.func)
86*4882a593Smuzhiyun cancel_work_sync(&iowait_get_tid_work(w)->iowork);
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun /**
90*4882a593Smuzhiyun * iowait_set_work_flag - set work flag based on leg
91*4882a593Smuzhiyun * @w - the iowait work struct
92*4882a593Smuzhiyun */
iowait_set_work_flag(struct iowait_work * w)93*4882a593Smuzhiyun int iowait_set_work_flag(struct iowait_work *w)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun if (w == &w->iow->wait[IOWAIT_IB_SE]) {
96*4882a593Smuzhiyun iowait_set_flag(w->iow, IOWAIT_PENDING_IB);
97*4882a593Smuzhiyun return IOWAIT_IB_SE;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun iowait_set_flag(w->iow, IOWAIT_PENDING_TID);
100*4882a593Smuzhiyun return IOWAIT_TID_SE;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun /**
104*4882a593Smuzhiyun * iowait_priority_update_top - update the top priority entry
105*4882a593Smuzhiyun * @w: the iowait struct
106*4882a593Smuzhiyun * @top: a pointer to the top priority entry
107*4882a593Smuzhiyun * @idx: the index of the current iowait in an array
108*4882a593Smuzhiyun * @top_idx: the array index for the iowait entry that has the top priority
109*4882a593Smuzhiyun *
110*4882a593Smuzhiyun * This function is called to compare the priority of a given
111*4882a593Smuzhiyun * iowait with the given top priority entry. The top index will
112*4882a593Smuzhiyun * be returned.
113*4882a593Smuzhiyun */
iowait_priority_update_top(struct iowait * w,struct iowait * top,uint idx,uint top_idx)114*4882a593Smuzhiyun uint iowait_priority_update_top(struct iowait *w,
115*4882a593Smuzhiyun struct iowait *top,
116*4882a593Smuzhiyun uint idx, uint top_idx)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun u8 cnt, tcnt;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun /* Convert priority into starve_cnt and compare the total.*/
121*4882a593Smuzhiyun cnt = (w->priority << IOWAIT_PRIORITY_STARVE_SHIFT) + w->starved_cnt;
122*4882a593Smuzhiyun tcnt = (top->priority << IOWAIT_PRIORITY_STARVE_SHIFT) +
123*4882a593Smuzhiyun top->starved_cnt;
124*4882a593Smuzhiyun if (cnt > tcnt)
125*4882a593Smuzhiyun return idx;
126*4882a593Smuzhiyun else
127*4882a593Smuzhiyun return top_idx;
128*4882a593Smuzhiyun }
129