Dennis Dalessandro | 5da0fc9 | 2018-09-28 07:17:09 -0700 | [diff] [blame] | 1 | // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) |
| 2 | /* |
| 3 | * Copyright(c) 2018 Intel Corporation. |
| 4 | * |
| 5 | */ |
| 6 | #include "iowait.h" |
Kaike Wan | 15b796b | 2018-09-26 10:27:03 -0700 | [diff] [blame] | 7 | #include "trace_iowait.h" |
Dennis Dalessandro | 5da0fc9 | 2018-09-28 07:17:09 -0700 | [diff] [blame] | 8 | |
Kaike Wan | 34025fb | 2019-01-23 21:52:19 -0800 | [diff] [blame^] | 9 | /* 1 priority == 16 starve_cnt */ |
| 10 | #define IOWAIT_PRIORITY_STARVE_SHIFT 4 |
| 11 | |
Dennis Dalessandro | 5da0fc9 | 2018-09-28 07:17:09 -0700 | [diff] [blame] | 12 | void iowait_set_flag(struct iowait *wait, u32 flag) |
| 13 | { |
Kaike Wan | 15b796b | 2018-09-26 10:27:03 -0700 | [diff] [blame] | 14 | trace_hfi1_iowait_set(wait, flag); |
Dennis Dalessandro | 5da0fc9 | 2018-09-28 07:17:09 -0700 | [diff] [blame] | 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 | { |
Kaike Wan | 15b796b | 2018-09-26 10:27:03 -0700 | [diff] [blame] | 25 | trace_hfi1_iowait_clear(wait, flag); |
Dennis Dalessandro | 5da0fc9 | 2018-09-28 07:17:09 -0700 | [diff] [blame] | 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), |
Kaike Wan | 34025fb | 2019-01-23 21:52:19 -0800 | [diff] [blame^] | 50 | void (*sdma_drained)(struct iowait *wait), |
| 51 | void (*init_priority)(struct iowait *wait)) |
Dennis Dalessandro | 5da0fc9 | 2018-09-28 07:17:09 -0700 | [diff] [blame] | 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; |
Kaike Wan | 34025fb | 2019-01-23 21:52:19 -0800 | [diff] [blame^] | 65 | wait->init_priority = init_priority; |
Dennis Dalessandro | 5da0fc9 | 2018-09-28 07:17:09 -0700 | [diff] [blame] | 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 | } |
Kaike Wan | 34025fb | 2019-01-23 21:52:19 -0800 | [diff] [blame^] | 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 | } |