0001
0002
0003
0004
0005
0006
0007 #include <linux/types.h>
0008 #include <linux/kernel.h>
0009 #include <linux/jiffies.h>
0010 #include <linux/dynamic_queue_limits.h>
0011 #include <linux/compiler.h>
0012 #include <linux/export.h>
0013
0014 #define POSDIFF(A, B) ((int)((A) - (B)) > 0 ? (A) - (B) : 0)
0015 #define AFTER_EQ(A, B) ((int)((A) - (B)) >= 0)
0016
0017
0018 void dql_completed(struct dql *dql, unsigned int count)
0019 {
0020 unsigned int inprogress, prev_inprogress, limit;
0021 unsigned int ovlimit, completed, num_queued;
0022 bool all_prev_completed;
0023
0024 num_queued = READ_ONCE(dql->num_queued);
0025
0026
0027 BUG_ON(count > num_queued - dql->num_completed);
0028
0029 completed = dql->num_completed + count;
0030 limit = dql->limit;
0031 ovlimit = POSDIFF(num_queued - dql->num_completed, limit);
0032 inprogress = num_queued - completed;
0033 prev_inprogress = dql->prev_num_queued - dql->num_completed;
0034 all_prev_completed = AFTER_EQ(completed, dql->prev_num_queued);
0035
0036 if ((ovlimit && !inprogress) ||
0037 (dql->prev_ovlimit && all_prev_completed)) {
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053 limit += POSDIFF(completed, dql->prev_num_queued) +
0054 dql->prev_ovlimit;
0055 dql->slack_start_time = jiffies;
0056 dql->lowest_slack = UINT_MAX;
0057 } else if (inprogress && prev_inprogress && !all_prev_completed) {
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069 unsigned int slack, slack_last_objs;
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082 slack = POSDIFF(limit + dql->prev_ovlimit,
0083 2 * (completed - dql->num_completed));
0084 slack_last_objs = dql->prev_ovlimit ?
0085 POSDIFF(dql->prev_last_obj_cnt, dql->prev_ovlimit) : 0;
0086
0087 slack = max(slack, slack_last_objs);
0088
0089 if (slack < dql->lowest_slack)
0090 dql->lowest_slack = slack;
0091
0092 if (time_after(jiffies,
0093 dql->slack_start_time + dql->slack_hold_time)) {
0094 limit = POSDIFF(limit, dql->lowest_slack);
0095 dql->slack_start_time = jiffies;
0096 dql->lowest_slack = UINT_MAX;
0097 }
0098 }
0099
0100
0101 limit = clamp(limit, dql->min_limit, dql->max_limit);
0102
0103 if (limit != dql->limit) {
0104 dql->limit = limit;
0105 ovlimit = 0;
0106 }
0107
0108 dql->adj_limit = limit + completed;
0109 dql->prev_ovlimit = ovlimit;
0110 dql->prev_last_obj_cnt = dql->last_obj_cnt;
0111 dql->num_completed = completed;
0112 dql->prev_num_queued = num_queued;
0113 }
0114 EXPORT_SYMBOL(dql_completed);
0115
0116 void dql_reset(struct dql *dql)
0117 {
0118
0119 dql->limit = 0;
0120 dql->num_queued = 0;
0121 dql->num_completed = 0;
0122 dql->last_obj_cnt = 0;
0123 dql->prev_num_queued = 0;
0124 dql->prev_last_obj_cnt = 0;
0125 dql->prev_ovlimit = 0;
0126 dql->lowest_slack = UINT_MAX;
0127 dql->slack_start_time = jiffies;
0128 }
0129 EXPORT_SYMBOL(dql_reset);
0130
0131 void dql_init(struct dql *dql, unsigned int hold_time)
0132 {
0133 dql->max_limit = DQL_MAX_LIMIT;
0134 dql->min_limit = 0;
0135 dql->slack_hold_time = hold_time;
0136 dql_reset(dql);
0137 }
0138 EXPORT_SYMBOL(dql_init);