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