|
@@ -119,15 +119,17 @@ struct dib8000_state {
|
|
u8 longest_intlv_layer;
|
|
u8 longest_intlv_layer;
|
|
u16 output_mode;
|
|
u16 output_mode;
|
|
|
|
|
|
|
|
+ /* for DVBv5 stats */
|
|
s64 init_ucb;
|
|
s64 init_ucb;
|
|
|
|
+ unsigned long jiffies_stats;
|
|
|
|
+ unsigned long jiffies_stats_layer[3];
|
|
|
|
+
|
|
#ifdef DIB8000_AGC_FREEZE
|
|
#ifdef DIB8000_AGC_FREEZE
|
|
u16 agc1_max;
|
|
u16 agc1_max;
|
|
u16 agc1_min;
|
|
u16 agc1_min;
|
|
u16 agc2_max;
|
|
u16 agc2_max;
|
|
u16 agc2_min;
|
|
u16 agc2_min;
|
|
#endif
|
|
#endif
|
|
-
|
|
|
|
- unsigned long get_stats_time;
|
|
|
|
};
|
|
};
|
|
|
|
|
|
enum dib8000_power_mode {
|
|
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;
|
|
c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
|
|
|
|
|
|
dib8000_read_unc_blocks(fe, &ucb);
|
|
dib8000_read_unc_blocks(fe, &ucb);
|
|
|
|
+
|
|
state->init_ucb = -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)
|
|
static int dib8000_reset(struct dvb_frontend *fe)
|
|
@@ -3936,12 +3942,124 @@ static u32 interpolate_value(u32 value, struct linear_segments *segments,
|
|
return ret;
|
|
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)
|
|
static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
|
|
{
|
|
{
|
|
struct dib8000_state *state = fe->demodulator_priv;
|
|
struct dib8000_state *state = fe->demodulator_priv;
|
|
struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
|
|
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;
|
|
s32 db;
|
|
u16 strength;
|
|
u16 strength;
|
|
|
|
|
|
@@ -3953,55 +4071,59 @@ static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
|
|
ARRAY_SIZE(strength_to_db_table)) - 131000;
|
|
ARRAY_SIZE(strength_to_db_table)) - 131000;
|
|
c->strength.stat[0].svalue = db;
|
|
c->strength.stat[0].svalue = db;
|
|
|
|
|
|
- /* Check if 1 second was elapsed */
|
|
|
|
- if (!time_after(jiffies, state->get_stats_time))
|
|
|
|
- return 0;
|
|
|
|
- state->get_stats_time = jiffies + msecs_to_jiffies(1000);
|
|
|
|
-
|
|
|
|
- /* Get SNR */
|
|
|
|
- snr = dib8000_get_snr(fe);
|
|
|
|
- for (i = 1; i < MAX_NUMBER_OF_FRONTENDS; i++) {
|
|
|
|
- if (state->fe[i])
|
|
|
|
- snr += dib8000_get_snr(state->fe[i]);
|
|
|
|
- }
|
|
|
|
- snr = snr >> 16;
|
|
|
|
-
|
|
|
|
- if (snr) {
|
|
|
|
- snr = 10 * intlog10(snr);
|
|
|
|
- snr = (1000L * snr) >> 24;
|
|
|
|
- } else {
|
|
|
|
- snr = 0;
|
|
|
|
- }
|
|
|
|
- c->cnr.stat[0].svalue = snr;
|
|
|
|
- c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
|
|
|
|
-
|
|
|
|
- /* UCB/BER measures require lock */
|
|
|
|
|
|
+ /* UCB/BER/CNR measures require lock */
|
|
if (!(stat & FE_HAS_LOCK)) {
|
|
if (!(stat & FE_HAS_LOCK)) {
|
|
|
|
+ c->cnr.len = 1;
|
|
c->block_error.len = 1;
|
|
c->block_error.len = 1;
|
|
c->post_bit_error.len = 1;
|
|
c->post_bit_error.len = 1;
|
|
c->post_bit_count.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_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
|
|
c->post_bit_count.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;
|
|
c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
- /* Get UCB and post-BER measures */
|
|
|
|
|
|
+ /* 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);
|
|
|
|
+ for (i = 1; i < MAX_NUMBER_OF_FRONTENDS; i++) {
|
|
|
|
+ if (state->fe[i])
|
|
|
|
+ snr += dib8000_get_snr(state->fe[i]);
|
|
|
|
+ }
|
|
|
|
+ snr = snr >> 16;
|
|
|
|
|
|
- /* 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;
|
|
|
|
|
|
+ if (snr) {
|
|
|
|
+ snr = 10 * intlog10(snr);
|
|
|
|
+ snr = (1000L * snr) >> 24;
|
|
|
|
+ } else {
|
|
|
|
+ snr = 0;
|
|
|
|
+ }
|
|
|
|
+ c->cnr.stat[0].svalue = snr;
|
|
|
|
+ c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
|
|
|
|
|
|
- c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
|
|
|
|
- c->post_bit_count.stat[0].uvalue += 100000000;
|
|
|
|
|
|
+ /* Get UCB and post-BER measures */
|
|
|
|
|
|
- dib8000_read_unc_blocks(fe, &val);
|
|
|
|
- if (val < state->init_ucb)
|
|
|
|
- state->init_ucb += 1L << 32;
|
|
|
|
|
|
+ dib8000_read_ber(fe, &val);
|
|
|
|
+ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
|
|
|
|
+ c->post_bit_error.stat[0].uvalue += val;
|
|
|
|
|
|
- c->block_error.stat[0].scale = FE_SCALE_COUNTER;
|
|
|
|
- c->block_error.stat[0].uvalue = val + state->init_ucb;
|
|
|
|
|
|
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
|
|
|
|
+ c->post_bit_count.stat[0].uvalue += 100000000;
|
|
|
|
+
|
|
|
|
+ dib8000_read_unc_blocks(fe, &val);
|
|
|
|
+ if (val < state->init_ucb)
|
|
|
|
+ state->init_ucb += 1L << 32;
|
|
|
|
+
|
|
|
|
+ c->block_error.stat[0].scale = FE_SCALE_COUNTER;
|
|
|
|
+ c->block_error.stat[0].uvalue = val + state->init_ucb;
|
|
|
|
+ }
|
|
|
|
|
|
if (state->revision < 0x8002)
|
|
if (state->revision < 0x8002)
|
|
return 0;
|
|
return 0;
|
|
@@ -4011,25 +4133,27 @@ static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
|
|
c->post_bit_count.len = 4;
|
|
c->post_bit_count.len = 4;
|
|
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
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 */
|
|
|
|
- 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;
|
|
|
|
-
|
|
|
|
- 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;
|
|
|
|
- }
|
|
|
|
|
|
+ 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;
|
|
|
|
+
|
|
|
|
+ c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
|
|
|
|
+ c->post_bit_count.stat[1 + i].uvalue += 100000000;
|
|
|
|
+
|
|
|
|
+ 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;
|
|
return 0;
|
|
}
|
|
}
|