diff options
-rw-r--r-- | net/sched/sch_generic.c | 70 |
1 files changed, 48 insertions, 22 deletions
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 693df7ae33d8..6f7aebd14072 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -406,18 +406,38 @@ static const u8 prio2band[TC_PRIO_MAX+1] = | |||
406 | 406 | ||
407 | #define PFIFO_FAST_BANDS 3 | 407 | #define PFIFO_FAST_BANDS 3 |
408 | 408 | ||
409 | static inline struct sk_buff_head *prio2list(struct sk_buff *skb, | 409 | /* |
410 | struct Qdisc *qdisc) | 410 | * Private data for a pfifo_fast scheduler containing: |
411 | * - queues for the three band | ||
412 | * - bitmap indicating which of the bands contain skbs | ||
413 | */ | ||
414 | struct pfifo_fast_priv { | ||
415 | u32 bitmap; | ||
416 | struct sk_buff_head q[PFIFO_FAST_BANDS]; | ||
417 | }; | ||
418 | |||
419 | /* | ||
420 | * Convert a bitmap to the first band number where an skb is queued, where: | ||
421 | * bitmap=0 means there are no skbs on any band. | ||
422 | * bitmap=1 means there is an skb on band 0. | ||
423 | * bitmap=7 means there are skbs on all 3 bands, etc. | ||
424 | */ | ||
425 | static const int bitmap2band[] = {-1, 0, 1, 0, 2, 0, 1, 0}; | ||
426 | |||
427 | static inline struct sk_buff_head *band2list(struct pfifo_fast_priv *priv, | ||
428 | int band) | ||
411 | { | 429 | { |
412 | struct sk_buff_head *list = qdisc_priv(qdisc); | 430 | return priv->q + band; |
413 | return list + prio2band[skb->priority & TC_PRIO_MAX]; | ||
414 | } | 431 | } |
415 | 432 | ||
416 | static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc* qdisc) | 433 | static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc* qdisc) |
417 | { | 434 | { |
418 | struct sk_buff_head *list = prio2list(skb, qdisc); | 435 | int band = prio2band[skb->priority & TC_PRIO_MAX]; |
436 | struct pfifo_fast_priv *priv = qdisc_priv(qdisc); | ||
437 | struct sk_buff_head *list = band2list(priv, band); | ||
419 | 438 | ||
420 | if (skb_queue_len(list) < qdisc_dev(qdisc)->tx_queue_len) { | 439 | if (skb_queue_len(list) < qdisc_dev(qdisc)->tx_queue_len) { |
440 | priv->bitmap |= (1 << band); | ||
421 | qdisc->q.qlen++; | 441 | qdisc->q.qlen++; |
422 | return __qdisc_enqueue_tail(skb, qdisc, list); | 442 | return __qdisc_enqueue_tail(skb, qdisc, list); |
423 | } | 443 | } |
@@ -427,14 +447,18 @@ static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc* qdisc) | |||
427 | 447 | ||
428 | static struct sk_buff *pfifo_fast_dequeue(struct Qdisc* qdisc) | 448 | static struct sk_buff *pfifo_fast_dequeue(struct Qdisc* qdisc) |
429 | { | 449 | { |
430 | int prio; | 450 | struct pfifo_fast_priv *priv = qdisc_priv(qdisc); |
431 | struct sk_buff_head *list = qdisc_priv(qdisc); | 451 | int band = bitmap2band[priv->bitmap]; |
432 | 452 | ||
433 | for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) { | 453 | if (likely(band >= 0)) { |
434 | if (!skb_queue_empty(list + prio)) { | 454 | struct sk_buff_head *list = band2list(priv, band); |
435 | qdisc->q.qlen--; | 455 | struct sk_buff *skb = __qdisc_dequeue_head(qdisc, list); |
436 | return __qdisc_dequeue_head(qdisc, list + prio); | 456 | |
437 | } | 457 | qdisc->q.qlen--; |
458 | if (skb_queue_empty(list)) | ||
459 | priv->bitmap &= ~(1 << band); | ||
460 | |||
461 | return skb; | ||
438 | } | 462 | } |
439 | 463 | ||
440 | return NULL; | 464 | return NULL; |
@@ -442,12 +466,13 @@ static struct sk_buff *pfifo_fast_dequeue(struct Qdisc* qdisc) | |||
442 | 466 | ||
443 | static struct sk_buff *pfifo_fast_peek(struct Qdisc* qdisc) | 467 | static struct sk_buff *pfifo_fast_peek(struct Qdisc* qdisc) |
444 | { | 468 | { |
445 | int prio; | 469 | struct pfifo_fast_priv *priv = qdisc_priv(qdisc); |
446 | struct sk_buff_head *list = qdisc_priv(qdisc); | 470 | int band = bitmap2band[priv->bitmap]; |
471 | |||
472 | if (band >= 0) { | ||
473 | struct sk_buff_head *list = band2list(priv, band); | ||
447 | 474 | ||
448 | for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) { | 475 | return skb_peek(list); |
449 | if (!skb_queue_empty(list + prio)) | ||
450 | return skb_peek(list + prio); | ||
451 | } | 476 | } |
452 | 477 | ||
453 | return NULL; | 478 | return NULL; |
@@ -456,11 +481,12 @@ static struct sk_buff *pfifo_fast_peek(struct Qdisc* qdisc) | |||
456 | static void pfifo_fast_reset(struct Qdisc* qdisc) | 481 | static void pfifo_fast_reset(struct Qdisc* qdisc) |
457 | { | 482 | { |
458 | int prio; | 483 | int prio; |
459 | struct sk_buff_head *list = qdisc_priv(qdisc); | 484 | struct pfifo_fast_priv *priv = qdisc_priv(qdisc); |
460 | 485 | ||
461 | for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) | 486 | for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) |
462 | __qdisc_reset_queue(qdisc, list + prio); | 487 | __qdisc_reset_queue(qdisc, band2list(priv, prio)); |
463 | 488 | ||
489 | priv->bitmap = 0; | ||
464 | qdisc->qstats.backlog = 0; | 490 | qdisc->qstats.backlog = 0; |
465 | qdisc->q.qlen = 0; | 491 | qdisc->q.qlen = 0; |
466 | } | 492 | } |
@@ -480,17 +506,17 @@ nla_put_failure: | |||
480 | static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt) | 506 | static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt) |
481 | { | 507 | { |
482 | int prio; | 508 | int prio; |
483 | struct sk_buff_head *list = qdisc_priv(qdisc); | 509 | struct pfifo_fast_priv *priv = qdisc_priv(qdisc); |
484 | 510 | ||
485 | for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) | 511 | for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) |
486 | skb_queue_head_init(list + prio); | 512 | skb_queue_head_init(band2list(priv, prio)); |
487 | 513 | ||
488 | return 0; | 514 | return 0; |
489 | } | 515 | } |
490 | 516 | ||
491 | static struct Qdisc_ops pfifo_fast_ops __read_mostly = { | 517 | static struct Qdisc_ops pfifo_fast_ops __read_mostly = { |
492 | .id = "pfifo_fast", | 518 | .id = "pfifo_fast", |
493 | .priv_size = PFIFO_FAST_BANDS * sizeof(struct sk_buff_head), | 519 | .priv_size = sizeof(struct pfifo_fast_priv), |
494 | .enqueue = pfifo_fast_enqueue, | 520 | .enqueue = pfifo_fast_enqueue, |
495 | .dequeue = pfifo_fast_dequeue, | 521 | .dequeue = pfifo_fast_dequeue, |
496 | .peek = pfifo_fast_peek, | 522 | .peek = pfifo_fast_peek, |