1fb9e53ccSThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */ 2557fc4a0SMichal Kazior /* 3557fc4a0SMichal Kazior * Copyright (c) 2016 Qualcomm Atheros, Inc 4557fc4a0SMichal Kazior * 5557fc4a0SMichal Kazior * Based on net/sched/sch_fq_codel.c 6557fc4a0SMichal Kazior */ 7557fc4a0SMichal Kazior #ifndef __NET_SCHED_FQ_IMPL_H 8557fc4a0SMichal Kazior #define __NET_SCHED_FQ_IMPL_H 9557fc4a0SMichal Kazior 10557fc4a0SMichal Kazior #include <net/fq.h> 11557fc4a0SMichal Kazior 12557fc4a0SMichal Kazior /* functions that are embedded into includer */ 13557fc4a0SMichal Kazior 148c418b5bSJohannes Berg static void fq_adjust_removal(struct fq *fq, 158c418b5bSJohannes Berg struct fq_flow *flow, 168c418b5bSJohannes Berg struct sk_buff *skb) 17557fc4a0SMichal Kazior { 18557fc4a0SMichal Kazior struct fq_tin *tin = flow->tin; 19557fc4a0SMichal Kazior 20557fc4a0SMichal Kazior tin->backlog_bytes -= skb->len; 21557fc4a0SMichal Kazior tin->backlog_packets--; 22557fc4a0SMichal Kazior flow->backlog -= skb->len; 23557fc4a0SMichal Kazior fq->backlog--; 24097b065bSToke Høiland-Jørgensen fq->memory_usage -= skb->truesize; 258c418b5bSJohannes Berg } 268c418b5bSJohannes Berg 278c418b5bSJohannes Berg static void fq_rejigger_backlog(struct fq *fq, struct fq_flow *flow) 288c418b5bSJohannes Berg { 298c418b5bSJohannes Berg struct fq_flow *i; 30557fc4a0SMichal Kazior 31557fc4a0SMichal Kazior if (flow->backlog == 0) { 32557fc4a0SMichal Kazior list_del_init(&flow->backlogchain); 33557fc4a0SMichal Kazior } else { 34557fc4a0SMichal Kazior i = flow; 35557fc4a0SMichal Kazior 36557fc4a0SMichal Kazior list_for_each_entry_continue(i, &fq->backlogs, backlogchain) 37557fc4a0SMichal Kazior if (i->backlog < flow->backlog) 38557fc4a0SMichal Kazior break; 39557fc4a0SMichal Kazior 40557fc4a0SMichal Kazior list_move_tail(&flow->backlogchain, 41557fc4a0SMichal Kazior &i->backlogchain); 42557fc4a0SMichal Kazior } 438c418b5bSJohannes Berg } 448c418b5bSJohannes Berg 458c418b5bSJohannes Berg static struct sk_buff *fq_flow_dequeue(struct fq *fq, 468c418b5bSJohannes Berg struct fq_flow *flow) 478c418b5bSJohannes Berg { 488c418b5bSJohannes Berg struct sk_buff *skb; 498c418b5bSJohannes Berg 508c418b5bSJohannes Berg lockdep_assert_held(&fq->lock); 518c418b5bSJohannes Berg 528c418b5bSJohannes Berg skb = __skb_dequeue(&flow->queue); 538c418b5bSJohannes Berg if (!skb) 548c418b5bSJohannes Berg return NULL; 558c418b5bSJohannes Berg 568c418b5bSJohannes Berg fq_adjust_removal(fq, flow, skb); 578c418b5bSJohannes Berg fq_rejigger_backlog(fq, flow); 58557fc4a0SMichal Kazior 59557fc4a0SMichal Kazior return skb; 60557fc4a0SMichal Kazior } 61557fc4a0SMichal Kazior 62557fc4a0SMichal Kazior static struct sk_buff *fq_tin_dequeue(struct fq *fq, 63557fc4a0SMichal Kazior struct fq_tin *tin, 64557fc4a0SMichal Kazior fq_tin_dequeue_t dequeue_func) 65557fc4a0SMichal Kazior { 66557fc4a0SMichal Kazior struct fq_flow *flow; 67557fc4a0SMichal Kazior struct list_head *head; 68557fc4a0SMichal Kazior struct sk_buff *skb; 69557fc4a0SMichal Kazior 70557fc4a0SMichal Kazior lockdep_assert_held(&fq->lock); 71557fc4a0SMichal Kazior 72557fc4a0SMichal Kazior begin: 73557fc4a0SMichal Kazior head = &tin->new_flows; 74557fc4a0SMichal Kazior if (list_empty(head)) { 75557fc4a0SMichal Kazior head = &tin->old_flows; 76557fc4a0SMichal Kazior if (list_empty(head)) 77557fc4a0SMichal Kazior return NULL; 78557fc4a0SMichal Kazior } 79557fc4a0SMichal Kazior 80557fc4a0SMichal Kazior flow = list_first_entry(head, struct fq_flow, flowchain); 81557fc4a0SMichal Kazior 82557fc4a0SMichal Kazior if (flow->deficit <= 0) { 83557fc4a0SMichal Kazior flow->deficit += fq->quantum; 84557fc4a0SMichal Kazior list_move_tail(&flow->flowchain, 85557fc4a0SMichal Kazior &tin->old_flows); 86557fc4a0SMichal Kazior goto begin; 87557fc4a0SMichal Kazior } 88557fc4a0SMichal Kazior 89557fc4a0SMichal Kazior skb = dequeue_func(fq, tin, flow); 90557fc4a0SMichal Kazior if (!skb) { 91557fc4a0SMichal Kazior /* force a pass through old_flows to prevent starvation */ 92557fc4a0SMichal Kazior if ((head == &tin->new_flows) && 93557fc4a0SMichal Kazior !list_empty(&tin->old_flows)) { 94557fc4a0SMichal Kazior list_move_tail(&flow->flowchain, &tin->old_flows); 95557fc4a0SMichal Kazior } else { 96557fc4a0SMichal Kazior list_del_init(&flow->flowchain); 97557fc4a0SMichal Kazior flow->tin = NULL; 98557fc4a0SMichal Kazior } 99557fc4a0SMichal Kazior goto begin; 100557fc4a0SMichal Kazior } 101557fc4a0SMichal Kazior 102557fc4a0SMichal Kazior flow->deficit -= skb->len; 103557fc4a0SMichal Kazior tin->tx_bytes += skb->len; 104557fc4a0SMichal Kazior tin->tx_packets++; 105557fc4a0SMichal Kazior 106557fc4a0SMichal Kazior return skb; 107557fc4a0SMichal Kazior } 108557fc4a0SMichal Kazior 109f2af2df8SFelix Fietkau static u32 fq_flow_idx(struct fq *fq, struct sk_buff *skb) 110f2af2df8SFelix Fietkau { 111*48a54f6bSFelix Fietkau u32 hash = skb_get_hash(skb); 112f2af2df8SFelix Fietkau 113f2af2df8SFelix Fietkau return reciprocal_scale(hash, fq->flows_cnt); 114f2af2df8SFelix Fietkau } 115f2af2df8SFelix Fietkau 116557fc4a0SMichal Kazior static struct fq_flow *fq_flow_classify(struct fq *fq, 117f2af2df8SFelix Fietkau struct fq_tin *tin, u32 idx, 118557fc4a0SMichal Kazior struct sk_buff *skb, 119557fc4a0SMichal Kazior fq_flow_get_default_t get_default_func) 120557fc4a0SMichal Kazior { 121557fc4a0SMichal Kazior struct fq_flow *flow; 122557fc4a0SMichal Kazior 123557fc4a0SMichal Kazior lockdep_assert_held(&fq->lock); 124557fc4a0SMichal Kazior 125557fc4a0SMichal Kazior flow = &fq->flows[idx]; 126557fc4a0SMichal Kazior if (flow->tin && flow->tin != tin) { 127557fc4a0SMichal Kazior flow = get_default_func(fq, tin, idx, skb); 128557fc4a0SMichal Kazior tin->collisions++; 129557fc4a0SMichal Kazior fq->collisions++; 130557fc4a0SMichal Kazior } 131557fc4a0SMichal Kazior 132557fc4a0SMichal Kazior if (!flow->tin) 133557fc4a0SMichal Kazior tin->flows++; 134557fc4a0SMichal Kazior 135557fc4a0SMichal Kazior return flow; 136557fc4a0SMichal Kazior } 137557fc4a0SMichal Kazior 138b43e7199SMichal Kazior static void fq_recalc_backlog(struct fq *fq, 139557fc4a0SMichal Kazior struct fq_tin *tin, 140b43e7199SMichal Kazior struct fq_flow *flow) 141557fc4a0SMichal Kazior { 142557fc4a0SMichal Kazior struct fq_flow *i; 143557fc4a0SMichal Kazior 144557fc4a0SMichal Kazior if (list_empty(&flow->backlogchain)) 145557fc4a0SMichal Kazior list_add_tail(&flow->backlogchain, &fq->backlogs); 146557fc4a0SMichal Kazior 147557fc4a0SMichal Kazior i = flow; 148557fc4a0SMichal Kazior list_for_each_entry_continue_reverse(i, &fq->backlogs, 149557fc4a0SMichal Kazior backlogchain) 150557fc4a0SMichal Kazior if (i->backlog > flow->backlog) 151557fc4a0SMichal Kazior break; 152557fc4a0SMichal Kazior 153557fc4a0SMichal Kazior list_move(&flow->backlogchain, &i->backlogchain); 154b43e7199SMichal Kazior } 155b43e7199SMichal Kazior 156b43e7199SMichal Kazior static void fq_tin_enqueue(struct fq *fq, 157f2af2df8SFelix Fietkau struct fq_tin *tin, u32 idx, 158b43e7199SMichal Kazior struct sk_buff *skb, 159b43e7199SMichal Kazior fq_skb_free_t free_func, 160b43e7199SMichal Kazior fq_flow_get_default_t get_default_func) 161b43e7199SMichal Kazior { 162b43e7199SMichal Kazior struct fq_flow *flow; 1630bfe649fSToke Høiland-Jørgensen bool oom; 164b43e7199SMichal Kazior 165b43e7199SMichal Kazior lockdep_assert_held(&fq->lock); 166b43e7199SMichal Kazior 167f2af2df8SFelix Fietkau flow = fq_flow_classify(fq, tin, idx, skb, get_default_func); 168b43e7199SMichal Kazior 169b43e7199SMichal Kazior flow->tin = tin; 170b43e7199SMichal Kazior flow->backlog += skb->len; 171b43e7199SMichal Kazior tin->backlog_bytes += skb->len; 172b43e7199SMichal Kazior tin->backlog_packets++; 173097b065bSToke Høiland-Jørgensen fq->memory_usage += skb->truesize; 174b43e7199SMichal Kazior fq->backlog++; 175b43e7199SMichal Kazior 176b43e7199SMichal Kazior fq_recalc_backlog(fq, tin, flow); 177557fc4a0SMichal Kazior 178557fc4a0SMichal Kazior if (list_empty(&flow->flowchain)) { 179557fc4a0SMichal Kazior flow->deficit = fq->quantum; 180557fc4a0SMichal Kazior list_add_tail(&flow->flowchain, 181557fc4a0SMichal Kazior &tin->new_flows); 182557fc4a0SMichal Kazior } 183557fc4a0SMichal Kazior 184557fc4a0SMichal Kazior __skb_queue_tail(&flow->queue, skb); 1850bfe649fSToke Høiland-Jørgensen oom = (fq->memory_usage > fq->memory_limit); 1860bfe649fSToke Høiland-Jørgensen while (fq->backlog > fq->limit || oom) { 187557fc4a0SMichal Kazior flow = list_first_entry_or_null(&fq->backlogs, 188557fc4a0SMichal Kazior struct fq_flow, 189557fc4a0SMichal Kazior backlogchain); 190557fc4a0SMichal Kazior if (!flow) 191557fc4a0SMichal Kazior return; 192557fc4a0SMichal Kazior 193557fc4a0SMichal Kazior skb = fq_flow_dequeue(fq, flow); 194557fc4a0SMichal Kazior if (!skb) 195557fc4a0SMichal Kazior return; 196557fc4a0SMichal Kazior 197557fc4a0SMichal Kazior free_func(fq, flow->tin, flow, skb); 198557fc4a0SMichal Kazior 199557fc4a0SMichal Kazior flow->tin->overlimit++; 200557fc4a0SMichal Kazior fq->overlimit++; 2010bfe649fSToke Høiland-Jørgensen if (oom) { 202097b065bSToke Høiland-Jørgensen fq->overmemory++; 2030bfe649fSToke Høiland-Jørgensen oom = (fq->memory_usage > fq->memory_limit); 2040bfe649fSToke Høiland-Jørgensen } 205557fc4a0SMichal Kazior } 206557fc4a0SMichal Kazior } 207557fc4a0SMichal Kazior 2088c418b5bSJohannes Berg static void fq_flow_filter(struct fq *fq, 2098c418b5bSJohannes Berg struct fq_flow *flow, 2108c418b5bSJohannes Berg fq_skb_filter_t filter_func, 2118c418b5bSJohannes Berg void *filter_data, 2128c418b5bSJohannes Berg fq_skb_free_t free_func) 2138c418b5bSJohannes Berg { 2148c418b5bSJohannes Berg struct fq_tin *tin = flow->tin; 2158c418b5bSJohannes Berg struct sk_buff *skb, *tmp; 2168c418b5bSJohannes Berg 2178c418b5bSJohannes Berg lockdep_assert_held(&fq->lock); 2188c418b5bSJohannes Berg 2198c418b5bSJohannes Berg skb_queue_walk_safe(&flow->queue, skb, tmp) { 2208c418b5bSJohannes Berg if (!filter_func(fq, tin, flow, skb, filter_data)) 2218c418b5bSJohannes Berg continue; 2228c418b5bSJohannes Berg 2238c418b5bSJohannes Berg __skb_unlink(skb, &flow->queue); 2248c418b5bSJohannes Berg fq_adjust_removal(fq, flow, skb); 2258c418b5bSJohannes Berg free_func(fq, tin, flow, skb); 2268c418b5bSJohannes Berg } 2278c418b5bSJohannes Berg 2288c418b5bSJohannes Berg fq_rejigger_backlog(fq, flow); 2298c418b5bSJohannes Berg } 2308c418b5bSJohannes Berg 2318c418b5bSJohannes Berg static void fq_tin_filter(struct fq *fq, 2328c418b5bSJohannes Berg struct fq_tin *tin, 2338c418b5bSJohannes Berg fq_skb_filter_t filter_func, 2348c418b5bSJohannes Berg void *filter_data, 2358c418b5bSJohannes Berg fq_skb_free_t free_func) 2368c418b5bSJohannes Berg { 2378c418b5bSJohannes Berg struct fq_flow *flow; 2388c418b5bSJohannes Berg 2398c418b5bSJohannes Berg lockdep_assert_held(&fq->lock); 2408c418b5bSJohannes Berg 2418c418b5bSJohannes Berg list_for_each_entry(flow, &tin->new_flows, flowchain) 2428c418b5bSJohannes Berg fq_flow_filter(fq, flow, filter_func, filter_data, free_func); 2438c418b5bSJohannes Berg list_for_each_entry(flow, &tin->old_flows, flowchain) 2448c418b5bSJohannes Berg fq_flow_filter(fq, flow, filter_func, filter_data, free_func); 2458c418b5bSJohannes Berg } 2468c418b5bSJohannes Berg 247557fc4a0SMichal Kazior static void fq_flow_reset(struct fq *fq, 248557fc4a0SMichal Kazior struct fq_flow *flow, 249557fc4a0SMichal Kazior fq_skb_free_t free_func) 250557fc4a0SMichal Kazior { 251557fc4a0SMichal Kazior struct sk_buff *skb; 252557fc4a0SMichal Kazior 253557fc4a0SMichal Kazior while ((skb = fq_flow_dequeue(fq, flow))) 254557fc4a0SMichal Kazior free_func(fq, flow->tin, flow, skb); 255557fc4a0SMichal Kazior 256557fc4a0SMichal Kazior if (!list_empty(&flow->flowchain)) 257557fc4a0SMichal Kazior list_del_init(&flow->flowchain); 258557fc4a0SMichal Kazior 259557fc4a0SMichal Kazior if (!list_empty(&flow->backlogchain)) 260557fc4a0SMichal Kazior list_del_init(&flow->backlogchain); 261557fc4a0SMichal Kazior 262557fc4a0SMichal Kazior flow->tin = NULL; 263557fc4a0SMichal Kazior 264557fc4a0SMichal Kazior WARN_ON_ONCE(flow->backlog); 265557fc4a0SMichal Kazior } 266557fc4a0SMichal Kazior 267557fc4a0SMichal Kazior static void fq_tin_reset(struct fq *fq, 268557fc4a0SMichal Kazior struct fq_tin *tin, 269557fc4a0SMichal Kazior fq_skb_free_t free_func) 270557fc4a0SMichal Kazior { 271557fc4a0SMichal Kazior struct list_head *head; 272557fc4a0SMichal Kazior struct fq_flow *flow; 273557fc4a0SMichal Kazior 274557fc4a0SMichal Kazior for (;;) { 275557fc4a0SMichal Kazior head = &tin->new_flows; 276557fc4a0SMichal Kazior if (list_empty(head)) { 277557fc4a0SMichal Kazior head = &tin->old_flows; 278557fc4a0SMichal Kazior if (list_empty(head)) 279557fc4a0SMichal Kazior break; 280557fc4a0SMichal Kazior } 281557fc4a0SMichal Kazior 282557fc4a0SMichal Kazior flow = list_first_entry(head, struct fq_flow, flowchain); 283557fc4a0SMichal Kazior fq_flow_reset(fq, flow, free_func); 284557fc4a0SMichal Kazior } 285557fc4a0SMichal Kazior 286557fc4a0SMichal Kazior WARN_ON_ONCE(tin->backlog_bytes); 287557fc4a0SMichal Kazior WARN_ON_ONCE(tin->backlog_packets); 288557fc4a0SMichal Kazior } 289557fc4a0SMichal Kazior 290557fc4a0SMichal Kazior static void fq_flow_init(struct fq_flow *flow) 291557fc4a0SMichal Kazior { 292557fc4a0SMichal Kazior INIT_LIST_HEAD(&flow->flowchain); 293557fc4a0SMichal Kazior INIT_LIST_HEAD(&flow->backlogchain); 294557fc4a0SMichal Kazior __skb_queue_head_init(&flow->queue); 295557fc4a0SMichal Kazior } 296557fc4a0SMichal Kazior 297557fc4a0SMichal Kazior static void fq_tin_init(struct fq_tin *tin) 298557fc4a0SMichal Kazior { 299557fc4a0SMichal Kazior INIT_LIST_HEAD(&tin->new_flows); 300557fc4a0SMichal Kazior INIT_LIST_HEAD(&tin->old_flows); 301557fc4a0SMichal Kazior } 302557fc4a0SMichal Kazior 303557fc4a0SMichal Kazior static int fq_init(struct fq *fq, int flows_cnt) 304557fc4a0SMichal Kazior { 305557fc4a0SMichal Kazior int i; 306557fc4a0SMichal Kazior 307557fc4a0SMichal Kazior memset(fq, 0, sizeof(fq[0])); 308557fc4a0SMichal Kazior INIT_LIST_HEAD(&fq->backlogs); 309557fc4a0SMichal Kazior spin_lock_init(&fq->lock); 310557fc4a0SMichal Kazior fq->flows_cnt = max_t(u32, flows_cnt, 1); 311557fc4a0SMichal Kazior fq->quantum = 300; 312557fc4a0SMichal Kazior fq->limit = 8192; 313097b065bSToke Høiland-Jørgensen fq->memory_limit = 16 << 20; /* 16 MBytes */ 314557fc4a0SMichal Kazior 31571e67c3bSToke Høiland-Jørgensen fq->flows = kvcalloc(fq->flows_cnt, sizeof(fq->flows[0]), GFP_KERNEL); 316557fc4a0SMichal Kazior if (!fq->flows) 317557fc4a0SMichal Kazior return -ENOMEM; 318557fc4a0SMichal Kazior 319557fc4a0SMichal Kazior for (i = 0; i < fq->flows_cnt; i++) 320557fc4a0SMichal Kazior fq_flow_init(&fq->flows[i]); 321557fc4a0SMichal Kazior 322557fc4a0SMichal Kazior return 0; 323557fc4a0SMichal Kazior } 324557fc4a0SMichal Kazior 325557fc4a0SMichal Kazior static void fq_reset(struct fq *fq, 326557fc4a0SMichal Kazior fq_skb_free_t free_func) 327557fc4a0SMichal Kazior { 328557fc4a0SMichal Kazior int i; 329557fc4a0SMichal Kazior 330557fc4a0SMichal Kazior for (i = 0; i < fq->flows_cnt; i++) 331557fc4a0SMichal Kazior fq_flow_reset(fq, &fq->flows[i], free_func); 332557fc4a0SMichal Kazior 33371e67c3bSToke Høiland-Jørgensen kvfree(fq->flows); 334557fc4a0SMichal Kazior fq->flows = NULL; 335557fc4a0SMichal Kazior } 336557fc4a0SMichal Kazior 337557fc4a0SMichal Kazior #endif 338