- // at this point we have
- // d == MIND and (c << (MAXPEXP+MIND)) < B
- while (div < CR_MAXD) {
- div++;
- if (br_man <= (c << (CR_MAXPEXP+div-br_exp))) {
- // Equivalent to: B <= (c << (MAXPEXP+d))
- // c << (MAXPEXP+d-1) < B <= c << (MAXPEXP+d)
- // 1 << (MAXPEXP-1) < B/2^d/c <= 1 << MAXPEXP
- // MAXP/2 < B/c2^d <= MAXP
- // take care of rounding
- switch (r) {
- case round_down:
- pre = (br+(c<<div)-1)/(c<<div);
- break;
- case round_nearest:
- pre = (br+(c<<div)/2)/(c<<div);
- break;
- case round_up:
- pre = br/(c<<div);
- break;
- }
- PRINTD (DBG_QOS, "B: p=%u, d=%u", pre, div);
- return set_cr ();
- }
- }
- // at this point we have
- // d == MAXD and (c << (MAXPEXP+MAXD)) < B
- // but we cannot go any higher
- // take care of rounding
- switch (r) {
- case round_down:
- return -EINVAL;
- break;
- case round_nearest:
- break;
- case round_up:
- break;
- }
- pre = 1 << CR_MAXPEXP;
- PRINTD (DBG_QOS, "C: p=%u, d=%u", pre, div);
- return set_cr ();
+ // at this point we have
+ // d == MIND and (c << (MAXPEXP+MIND)) < B
+ while (div < CR_MAXD) {
+ div++;
+ if (br_man <= (c << (CR_MAXPEXP+div-br_exp))) {
+ // Equivalent to: B <= (c << (MAXPEXP+d))
+ // c << (MAXPEXP+d-1) < B <= c << (MAXPEXP+d)
+ // 1 << (MAXPEXP-1) < B/2^d/c <= 1 << MAXPEXP
+ // MAXP/2 < B/c2^d <= MAXP
+ // take care of rounding
+ switch (r) {
+ case round_down:
+ pre = (br+(c<<div)-1)/(c<<div);
+ break;
+ case round_nearest:
+ pre = (br+(c<<div)/2)/(c<<div);
+ break;
+ default: /* round_up */
+ pre = br/(c<<div);
+ }
+ PRINTD (DBG_QOS, "B: p=%u, d=%u", pre, div);
+ goto got_it;
+ }
+ }
+ // at this point we have
+ // d == MAXD and (c << (MAXPEXP+MAXD)) < B
+ // but we cannot go any higher
+ // take care of rounding
+ if (r == round_down)
+ return -EINVAL;
+ pre = 1 << CR_MAXPEXP;
+ PRINTD (DBG_QOS, "C: p=%u, d=%u", pre, div);
+got_it:
+ // paranoia
+ if (div > CR_MAXD || (!pre) || pre > 1<<CR_MAXPEXP) {
+ PRINTD (DBG_QOS, "set_cr internal failure: d=%u p=%u",
+ div, pre);
+ return -EINVAL;
+ } else {
+ if (bits)
+ *bits = (div<<CLOCK_SELECT_SHIFT) | (pre-1);
+ if (actual) {
+ *actual = (br + (pre<<div) - 1) / (pre<<div);
+ PRINTD (DBG_QOS, "actual rate: %u", *actual);
+ }
+ return 0;
+ }