Commit 8a48b711 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] drivers/atm/horizon.c delousing

Same as with ambassador.c - same authors, same braindamage.
parent 5917ab47
...@@ -597,126 +597,112 @@ static inline u16 rx_q_entry_to_rx_channel (u32 x) { ...@@ -597,126 +597,112 @@ static inline u16 rx_q_entry_to_rx_channel (u32 x) {
// p ranges from 1 to a power of 2 // p ranges from 1 to a power of 2
#define CR_MAXPEXP 4 #define CR_MAXPEXP 4
static int make_rate (const hrz_dev * dev, u32 c, rounding r, static int make_rate (const hrz_dev * dev, u32 c, rounding r,
u16 * bits, unsigned int * actual) { u16 * bits, unsigned int * actual)
{
// note: rounding the rate down means rounding 'p' up // note: rounding the rate down means rounding 'p' up
const unsigned long br = test_bit(ultra, &dev->flags) ? BR_ULT : BR_HRZ;
const unsigned long br = test_bit(ultra, &dev->flags) ? BR_ULT : BR_HRZ;
u32 div = CR_MIND;
u32 pre;
// local fn to build the timer bits u32 div = CR_MIND;
int set_cr (void) { u32 pre;
// 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;
}
}
// br_exp and br_man are used to avoid overflowing (c*maxp*2^d) in // br_exp and br_man are used to avoid overflowing (c*maxp*2^d) in
// the tests below. We could think harder about exact possibilities // the tests below. We could think harder about exact possibilities
// of failure... // of failure...
unsigned long br_man = br; unsigned long br_man = br;
unsigned int br_exp = 0; unsigned int br_exp = 0;
PRINTD (DBG_QOS|DBG_FLOW, "make_rate b=%lu, c=%u, %s", br, c, PRINTD (DBG_QOS|DBG_FLOW, "make_rate b=%lu, c=%u, %s", br, c,
(r == round_up) ? "up" : (r == round_down) ? "down" : "nearest"); r == round_up ? "up" : r == round_down ? "down" : "nearest");
// avoid div by zero // avoid div by zero
if (!c) { if (!c) {
PRINTD (DBG_QOS|DBG_ERR, "zero rate is not allowed!"); PRINTD (DBG_QOS|DBG_ERR, "zero rate is not allowed!");
return -EINVAL; return -EINVAL;
} }
while (br_exp < CR_MAXPEXP + CR_MIND && (br_man % 2 == 0)) { while (br_exp < CR_MAXPEXP + CR_MIND && (br_man % 2 == 0)) {
br_man = br_man >> 1; br_man = br_man >> 1;
++br_exp; ++br_exp;
} }
// (br >>br_exp) <<br_exp == br and // (br >>br_exp) <<br_exp == br and
// br_exp <= CR_MAXPEXP+CR_MIND // br_exp <= CR_MAXPEXP+CR_MIND
if (br_man <= (c << (CR_MAXPEXP+CR_MIND-br_exp))) {
// Equivalent to: B <= (c << (MAXPEXP+MIND))
// take care of rounding
switch (r) {
case round_down:
pre = (br+(c<<div)-1)/(c<<div);
// but p must be non-zero
if (!pre)
pre = 1;
break;
case round_nearest:
pre = (br+(c<<div)/2)/(c<<div);
// but p must be non-zero
if (!pre)
pre = 1;
break;
default: /* round_up */
pre = br/(c<<div);
// but p must be non-zero
if (!pre)
return -EINVAL;
}
PRINTD (DBG_QOS, "A: p=%u, d=%u", pre, div);
goto got_it;
}
if (br_man <= (c << (CR_MAXPEXP+CR_MIND-br_exp))) { // at this point we have
// Equivalent to: B <= (c << (MAXPEXP+MIND)) // d == MIND and (c << (MAXPEXP+MIND)) < B
// take care of rounding while (div < CR_MAXD) {
switch (r) { div++;
case round_down: if (br_man <= (c << (CR_MAXPEXP+div-br_exp))) {
pre = (br+(c<<div)-1)/(c<<div); // Equivalent to: B <= (c << (MAXPEXP+d))
// but p must be non-zero // c << (MAXPEXP+d-1) < B <= c << (MAXPEXP+d)
if (!pre) // 1 << (MAXPEXP-1) < B/2^d/c <= 1 << MAXPEXP
pre = 1; // MAXP/2 < B/c2^d <= MAXP
break; // take care of rounding
case round_nearest: switch (r) {
pre = (br+(c<<div)/2)/(c<<div); case round_down:
// but p must be non-zero pre = (br+(c<<div)-1)/(c<<div);
if (!pre) break;
pre = 1; case round_nearest:
break; pre = (br+(c<<div)/2)/(c<<div);
case round_up: break;
pre = br/(c<<div); default: /* round_up */
// but p must be non-zero pre = br/(c<<div);
if (!pre) }
return -EINVAL; PRINTD (DBG_QOS, "B: p=%u, d=%u", pre, div);
break; goto got_it;
} }
PRINTD (DBG_QOS, "A: 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
// at this point we have // take care of rounding
// d == MIND and (c << (MAXPEXP+MIND)) < B if (r == round_down)
while (div < CR_MAXD) { return -EINVAL;
div++; pre = 1 << CR_MAXPEXP;
if (br_man <= (c << (CR_MAXPEXP+div-br_exp))) { PRINTD (DBG_QOS, "C: p=%u, d=%u", pre, div);
// Equivalent to: B <= (c << (MAXPEXP+d)) got_it:
// c << (MAXPEXP+d-1) < B <= c << (MAXPEXP+d) // paranoia
// 1 << (MAXPEXP-1) < B/2^d/c <= 1 << MAXPEXP if (div > CR_MAXD || (!pre) || pre > 1<<CR_MAXPEXP) {
// MAXP/2 < B/c2^d <= MAXP PRINTD (DBG_QOS, "set_cr internal failure: d=%u p=%u",
// take care of rounding div, pre);
switch (r) { return -EINVAL;
case round_down: } else {
pre = (br+(c<<div)-1)/(c<<div); if (bits)
break; *bits = (div<<CLOCK_SELECT_SHIFT) | (pre-1);
case round_nearest: if (actual) {
pre = (br+(c<<div)/2)/(c<<div); *actual = (br + (pre<<div) - 1) / (pre<<div);
break; PRINTD (DBG_QOS, "actual rate: %u", *actual);
case round_up: }
pre = br/(c<<div); return 0;
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 ();
} }
static int make_rate_with_tolerance (const hrz_dev * dev, u32 c, rounding r, unsigned int tol, static int make_rate_with_tolerance (const hrz_dev * dev, u32 c, rounding r, unsigned int tol,
...@@ -1823,23 +1809,23 @@ static void hrz_reset (const hrz_dev * dev) { ...@@ -1823,23 +1809,23 @@ static void hrz_reset (const hrz_dev * dev) {
/********** read the burnt in address **********/ /********** read the burnt in address **********/
static u16 __init read_bia (const hrz_dev * dev, u16 addr) { static inline void WRITE_IT_WAIT (const hrz_dev *dev, u32 ctrl)
{
wr_regl (dev, CONTROL_0_REG, ctrl);
udelay (5);
}
static inline void CLOCK_IT (const hrz_dev *dev, u32 ctrl)
{
// DI must be valid around rising SK edge
WRITE_IT_WAIT(dev, ctrl & ~SEEPROM_SK);
WRITE_IT_WAIT(dev, ctrl | SEEPROM_SK);
}
static u16 __init read_bia (const hrz_dev * dev, u16 addr)
{
u32 ctrl = rd_regl (dev, CONTROL_0_REG); u32 ctrl = rd_regl (dev, CONTROL_0_REG);
void WRITE_IT_WAIT (void) {
wr_regl (dev, CONTROL_0_REG, ctrl);
udelay (5);
}
void CLOCK_IT (void) {
// DI must be valid around rising SK edge
ctrl &= ~SEEPROM_SK;
WRITE_IT_WAIT();
ctrl |= SEEPROM_SK;
WRITE_IT_WAIT();
}
const unsigned int addr_bits = 6; const unsigned int addr_bits = 6;
const unsigned int data_bits = 16; const unsigned int data_bits = 16;
...@@ -1848,17 +1834,17 @@ static u16 __init read_bia (const hrz_dev * dev, u16 addr) { ...@@ -1848,17 +1834,17 @@ static u16 __init read_bia (const hrz_dev * dev, u16 addr) {
u16 res; u16 res;
ctrl &= ~(SEEPROM_CS | SEEPROM_SK | SEEPROM_DI); ctrl &= ~(SEEPROM_CS | SEEPROM_SK | SEEPROM_DI);
WRITE_IT_WAIT(); WRITE_IT_WAIT(dev, ctrl);
// wake Serial EEPROM and send 110 (READ) command // wake Serial EEPROM and send 110 (READ) command
ctrl |= (SEEPROM_CS | SEEPROM_DI); ctrl |= (SEEPROM_CS | SEEPROM_DI);
CLOCK_IT(); CLOCK_IT(dev, ctrl);
ctrl |= SEEPROM_DI; ctrl |= SEEPROM_DI;
CLOCK_IT(); CLOCK_IT(dev, ctrl);
ctrl &= ~SEEPROM_DI; ctrl &= ~SEEPROM_DI;
CLOCK_IT(); CLOCK_IT(dev, ctrl);
for (i=0; i<addr_bits; i++) { for (i=0; i<addr_bits; i++) {
if (addr & (1 << (addr_bits-1))) if (addr & (1 << (addr_bits-1)))
...@@ -1866,7 +1852,7 @@ static u16 __init read_bia (const hrz_dev * dev, u16 addr) { ...@@ -1866,7 +1852,7 @@ static u16 __init read_bia (const hrz_dev * dev, u16 addr) {
else else
ctrl &= ~SEEPROM_DI; ctrl &= ~SEEPROM_DI;
CLOCK_IT(); CLOCK_IT(dev, ctrl);
addr = addr << 1; addr = addr << 1;
} }
...@@ -1878,14 +1864,14 @@ static u16 __init read_bia (const hrz_dev * dev, u16 addr) { ...@@ -1878,14 +1864,14 @@ static u16 __init read_bia (const hrz_dev * dev, u16 addr) {
for (i=0;i<data_bits;i++) { for (i=0;i<data_bits;i++) {
res = res >> 1; res = res >> 1;
CLOCK_IT(); CLOCK_IT(dev, ctrl);
if (rd_regl (dev, CONTROL_0_REG) & SEEPROM_DO) if (rd_regl (dev, CONTROL_0_REG) & SEEPROM_DO)
res |= (1 << (data_bits-1)); res |= (1 << (data_bits-1));
} }
ctrl &= ~(SEEPROM_SK | SEEPROM_CS); ctrl &= ~(SEEPROM_SK | SEEPROM_CS);
WRITE_IT_WAIT(); WRITE_IT_WAIT(dev, ctrl);
return res; return res;
} }
......
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