Commit 704f01bb authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab

[media] dib8000: be sure that stats are available before reading them

On dib8000, the BER statistics are updated on every 1.25e6 bits.
Adjust the code to only update the statistics after having it
done.
Signed-off-by: default avatarMauro Carvalho Chehab <m.chehab@samsung.com>
Acked-by: default avatarPatrick Boettcher <pboettcher@kernellabs.com>
parent 7a9d85d5
......@@ -119,15 +119,17 @@ struct dib8000_state {
u8 longest_intlv_layer;
u16 output_mode;
/* for DVBv5 stats */
s64 init_ucb;
unsigned long jiffies_stats;
unsigned long jiffies_stats_layer[3];
#ifdef DIB8000_AGC_FREEZE
u16 agc1_max;
u16 agc1_min;
u16 agc2_max;
u16 agc2_min;
#endif
unsigned long get_stats_time;
};
enum dib8000_power_mode {
......@@ -1016,7 +1018,11 @@ static void dib8000_reset_stats(struct dvb_frontend *fe)
c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
dib8000_read_unc_blocks(fe, &ucb);
state->init_ucb = -ucb;
state->jiffies_stats = 0;
memset(&state->jiffies_stats_layer, 0,
sizeof(state->jiffies_stats_layer));
}
static int dib8000_reset(struct dvb_frontend *fe)
......@@ -3936,12 +3942,124 @@ static u32 interpolate_value(u32 value, struct linear_segments *segments,
return ret;
}
static u32 dib8000_get_time_us(struct dvb_frontend *fe, int layer)
{
struct dib8000_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
int ini_layer, end_layer, i;
u64 time_us;
u32 tmp, denom;
int guard, rate_num, rate_denum, bits_per_symbol, nsegs;
int interleaving, fft_div;
if (layer >= 0) {
ini_layer = layer;
end_layer = layer + 1;
} else {
ini_layer = 0;
end_layer = 3;
}
switch (c->guard_interval) {
case GUARD_INTERVAL_1_4:
guard = 4;
break;
case GUARD_INTERVAL_1_8:
guard = 8;
break;
case GUARD_INTERVAL_1_16:
guard = 16;
break;
default:
case GUARD_INTERVAL_1_32:
guard = 32;
break;
}
switch (c->transmission_mode) {
case TRANSMISSION_MODE_2K:
fft_div = 4;
break;
case TRANSMISSION_MODE_4K:
fft_div = 2;
break;
default:
case TRANSMISSION_MODE_8K:
fft_div = 1;
break;
}
denom = 0;
for (i = ini_layer; i < end_layer; i++) {
nsegs = c->layer[i].segment_count;
if (nsegs == 0 || nsegs > 13)
continue;
switch (c->layer[i].modulation) {
case DQPSK:
case QPSK:
bits_per_symbol = 2;
break;
case QAM_16:
bits_per_symbol = 4;
break;
default:
case QAM_64:
bits_per_symbol = 6;
break;
}
switch (c->layer[i].fec) {
case FEC_1_2:
rate_num = 1;
rate_denum = 2;
break;
case FEC_2_3:
rate_num = 2;
rate_denum = 3;
break;
case FEC_3_4:
rate_num = 3;
rate_denum = 4;
break;
case FEC_5_6:
rate_num = 5;
rate_denum = 6;
break;
default:
case FEC_7_8:
rate_num = 7;
rate_denum = 8;
break;
}
interleaving = c->layer[i].interleaving;
denom += bits_per_symbol * rate_num * fft_div * nsegs * 384;
}
/* If all goes wrong, wait for 1s for the next stats */
if (!denom)
return 0;
/* Estimate the period for the total bit rate */
time_us = rate_denum * (1008 * 1562500L);
time_us = time_us + time_us / guard;
time_us += denom / 2;
do_div(time_us, denom);
tmp = 1008 * 96 * interleaving;
time_us += tmp + tmp / guard;
return time_us;
}
static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
{
struct dib8000_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
int i, lock;
u32 snr, val;
int i;
u32 time_us, snr, val;
s32 db;
u16 strength;
......@@ -3953,10 +4071,25 @@ static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
ARRAY_SIZE(strength_to_db_table)) - 131000;
c->strength.stat[0].svalue = db;
/* Check if 1 second was elapsed */
if (!time_after(jiffies, state->get_stats_time))
/* UCB/BER/CNR measures require lock */
if (!(stat & FE_HAS_LOCK)) {
c->cnr.len = 1;
c->block_error.len = 1;
c->post_bit_error.len = 1;
c->post_bit_count.len = 1;
c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
return 0;
state->get_stats_time = jiffies + msecs_to_jiffies(1000);
}
/* Check if time for stats was elapsed */
if (time_after(jiffies, state->jiffies_stats)) {
time_us = dib8000_get_time_us(fe, -1);
state->jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
dprintk("Next all layers stats available in %u us.\n", time_us);
/* Get SNR */
snr = dib8000_get_snr(fe);
......@@ -3975,20 +4108,8 @@ static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
c->cnr.stat[0].svalue = snr;
c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
/* UCB/BER measures require lock */
if (!(stat & FE_HAS_LOCK)) {
c->block_error.len = 1;
c->post_bit_error.len = 1;
c->post_bit_count.len = 1;
c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
return 0;
}
/* Get UCB and post-BER measures */
/* FIXME: need to check if 1.25e6 bits already passed */
dib8000_read_ber(fe, &val);
c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
c->post_bit_error.stat[0].uvalue += val;
......@@ -4002,6 +4123,7 @@ static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
c->block_error.stat[0].scale = FE_SCALE_COUNTER;
c->block_error.stat[0].uvalue = val + state->init_ucb;
}
if (state->revision < 0x8002)
return 0;
......@@ -4011,9 +4133,16 @@ static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
c->post_bit_count.len = 4;
for (i = 0; i < 3; i++) {
lock = dib8000_read_word(state, per_layer_regs[i].lock);
if (lock & 0x01) {
/* FIXME: need to check if 1.25e6 bits already passed */
if (!time_after(jiffies, state->jiffies_stats_layer[i]))
continue;
time_us = dib8000_get_time_us(fe, i);
if (!time_us)
continue;
state->jiffies_stats_layer[i] = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
dprintk("Next layer %c stats will be available in %u us\n",
'A' + i, time_us);
val = dib8000_read_word(state, per_layer_regs[i].ber);
c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
c->post_bit_error.stat[1 + i].uvalue += val;
......@@ -4021,16 +4150,11 @@ static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
c->post_bit_count.stat[1 + i].uvalue += 100000000;
/*
* FIXME: this is refreshed on every second, but a time
* drift between dib8000 and PC clock may cause troubles
*/
val = dib8000_read_word(state, per_layer_regs[i].per);
c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER;
c->block_error.stat[1 + i].uvalue += val;
}
}
return 0;
}
......
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