Commit 6ca6a665 authored by Vinicius Costa Gomes's avatar Vinicius Costa Gomes Committed by David S. Miller

taprio: Add support for setting the cycle-time manually

IEEE 802.1Q-2018 defines that a the cycle-time of a schedule may be
overridden, so the schedule is truncated to a determined "width".
Signed-off-by: default avatarVinicius Costa Gomes <vinicius.gomes@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a3d43c0d
...@@ -1167,6 +1167,7 @@ enum { ...@@ -1167,6 +1167,7 @@ enum {
TCA_TAPRIO_ATTR_SCHED_CLOCKID, /* s32 */ TCA_TAPRIO_ATTR_SCHED_CLOCKID, /* s32 */
TCA_TAPRIO_PAD, TCA_TAPRIO_PAD,
TCA_TAPRIO_ATTR_ADMIN_SCHED, /* The admin sched, only used in dump */ TCA_TAPRIO_ATTR_ADMIN_SCHED, /* The admin sched, only used in dump */
TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME, /* s64 */
__TCA_TAPRIO_ATTR_MAX, __TCA_TAPRIO_ATTR_MAX,
}; };
......
...@@ -46,6 +46,8 @@ struct sched_gate_list { ...@@ -46,6 +46,8 @@ struct sched_gate_list {
struct rcu_head rcu; struct rcu_head rcu;
struct list_head entries; struct list_head entries;
size_t num_entries; size_t num_entries;
ktime_t cycle_close_time;
s64 cycle_time;
s64 base_time; s64 base_time;
}; };
...@@ -105,6 +107,22 @@ static void switch_schedules(struct taprio_sched *q, ...@@ -105,6 +107,22 @@ static void switch_schedules(struct taprio_sched *q,
*admin = NULL; *admin = NULL;
} }
static ktime_t get_cycle_time(struct sched_gate_list *sched)
{
struct sched_entry *entry;
ktime_t cycle = 0;
if (sched->cycle_time != 0)
return sched->cycle_time;
list_for_each_entry(entry, &sched->entries, list)
cycle = ktime_add_ns(cycle, entry->interval);
sched->cycle_time = cycle;
return cycle;
}
static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch,
struct sk_buff **to_free) struct sk_buff **to_free)
{ {
...@@ -256,6 +274,18 @@ static struct sk_buff *taprio_dequeue(struct Qdisc *sch) ...@@ -256,6 +274,18 @@ static struct sk_buff *taprio_dequeue(struct Qdisc *sch)
return skb; return skb;
} }
static bool should_restart_cycle(const struct sched_gate_list *oper,
const struct sched_entry *entry)
{
if (list_is_last(&entry->list, &oper->entries))
return true;
if (ktime_compare(entry->close_time, oper->cycle_close_time) == 0)
return true;
return false;
}
static bool should_change_schedules(const struct sched_gate_list *admin, static bool should_change_schedules(const struct sched_gate_list *admin,
const struct sched_gate_list *oper, const struct sched_gate_list *oper,
ktime_t close_time) ktime_t close_time)
...@@ -309,13 +339,17 @@ static enum hrtimer_restart advance_sched(struct hrtimer *timer) ...@@ -309,13 +339,17 @@ static enum hrtimer_restart advance_sched(struct hrtimer *timer)
goto first_run; goto first_run;
} }
if (list_is_last(&entry->list, &oper->entries)) if (should_restart_cycle(oper, entry)) {
next = list_first_entry(&oper->entries, struct sched_entry, next = list_first_entry(&oper->entries, struct sched_entry,
list); list);
else oper->cycle_close_time = ktime_add_ns(oper->cycle_close_time,
oper->cycle_time);
} else {
next = list_next_entry(entry, list); next = list_next_entry(entry, list);
}
close_time = ktime_add_ns(entry->close_time, next->interval); close_time = ktime_add_ns(entry->close_time, next->interval);
close_time = min_t(ktime_t, close_time, oper->cycle_close_time);
if (should_change_schedules(admin, oper, close_time)) { if (should_change_schedules(admin, oper, close_time)) {
/* Set things so the next time this runs, the new /* Set things so the next time this runs, the new
...@@ -360,6 +394,7 @@ static const struct nla_policy taprio_policy[TCA_TAPRIO_ATTR_MAX + 1] = { ...@@ -360,6 +394,7 @@ static const struct nla_policy taprio_policy[TCA_TAPRIO_ATTR_MAX + 1] = {
[TCA_TAPRIO_ATTR_SCHED_BASE_TIME] = { .type = NLA_S64 }, [TCA_TAPRIO_ATTR_SCHED_BASE_TIME] = { .type = NLA_S64 },
[TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY] = { .type = NLA_NESTED }, [TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY] = { .type = NLA_NESTED },
[TCA_TAPRIO_ATTR_SCHED_CLOCKID] = { .type = NLA_S32 }, [TCA_TAPRIO_ATTR_SCHED_CLOCKID] = { .type = NLA_S32 },
[TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME] = { .type = NLA_S64 },
}; };
static int fill_sched_entry(struct nlattr **tb, struct sched_entry *entry, static int fill_sched_entry(struct nlattr **tb, struct sched_entry *entry,
...@@ -461,6 +496,9 @@ static int parse_taprio_schedule(struct nlattr **tb, ...@@ -461,6 +496,9 @@ static int parse_taprio_schedule(struct nlattr **tb,
if (tb[TCA_TAPRIO_ATTR_SCHED_BASE_TIME]) if (tb[TCA_TAPRIO_ATTR_SCHED_BASE_TIME])
new->base_time = nla_get_s64(tb[TCA_TAPRIO_ATTR_SCHED_BASE_TIME]); new->base_time = nla_get_s64(tb[TCA_TAPRIO_ATTR_SCHED_BASE_TIME]);
if (tb[TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME])
new->cycle_time = nla_get_s64(tb[TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME]);
if (tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST]) if (tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST])
err = parse_sched_list( err = parse_sched_list(
tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST], new, extack); tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST], new, extack);
...@@ -537,7 +575,6 @@ static int taprio_get_start_time(struct Qdisc *sch, ...@@ -537,7 +575,6 @@ static int taprio_get_start_time(struct Qdisc *sch,
ktime_t *start) ktime_t *start)
{ {
struct taprio_sched *q = qdisc_priv(sch); struct taprio_sched *q = qdisc_priv(sch);
struct sched_entry *entry;
ktime_t now, base, cycle; ktime_t now, base, cycle;
s64 n; s64 n;
...@@ -549,11 +586,7 @@ static int taprio_get_start_time(struct Qdisc *sch, ...@@ -549,11 +586,7 @@ static int taprio_get_start_time(struct Qdisc *sch,
return 0; return 0;
} }
/* Calculate the cycle_time, by summing all the intervals. cycle = get_cycle_time(sched);
*/
cycle = 0;
list_for_each_entry(entry, &sched->entries, list)
cycle = ktime_add_ns(cycle, entry->interval);
/* The qdisc is expected to have at least one sched_entry. Moreover, /* The qdisc is expected to have at least one sched_entry. Moreover,
* any entry must have 'interval' > 0. Thus if the cycle time is zero, * any entry must have 'interval' > 0. Thus if the cycle time is zero,
...@@ -575,10 +608,16 @@ static void setup_first_close_time(struct taprio_sched *q, ...@@ -575,10 +608,16 @@ static void setup_first_close_time(struct taprio_sched *q,
struct sched_gate_list *sched, ktime_t base) struct sched_gate_list *sched, ktime_t base)
{ {
struct sched_entry *first; struct sched_entry *first;
ktime_t cycle;
first = list_first_entry(&sched->entries, first = list_first_entry(&sched->entries,
struct sched_entry, list); struct sched_entry, list);
cycle = get_cycle_time(sched);
/* FIXME: find a better place to do this */
sched->cycle_close_time = ktime_add_ns(base, cycle);
first->close_time = ktime_add_ns(base, first->interval); first->close_time = ktime_add_ns(base, first->interval);
taprio_set_budget(q, first); taprio_set_budget(q, first);
rcu_assign_pointer(q->current_entry, NULL); rcu_assign_pointer(q->current_entry, NULL);
...@@ -965,6 +1004,10 @@ static int dump_schedule(struct sk_buff *msg, ...@@ -965,6 +1004,10 @@ static int dump_schedule(struct sk_buff *msg,
root->base_time, TCA_TAPRIO_PAD)) root->base_time, TCA_TAPRIO_PAD))
return -1; return -1;
if (nla_put_s64(msg, TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME,
root->cycle_time, TCA_TAPRIO_PAD))
return -1;
entry_list = nla_nest_start_noflag(msg, entry_list = nla_nest_start_noflag(msg,
TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST); TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST);
if (!entry_list) if (!entry_list)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment