[media] dib8000: improve block statistics
authorMauro Carvalho Chehab <m.chehab@samsung.com>
Tue, 17 Dec 2013 14:34:22 +0000 (11:34 -0300)
committerMauro Carvalho Chehab <m.chehab@samsung.com>
Thu, 19 Dec 2013 10:17:47 +0000 (08:17 -0200)
PER/UCB statistics are collected once on each 1 second.
However, it doesn't provide the total number of packets
needed to calculate PER.

Yet, as we know the bit rate, it is possible to estimate
such number. So, do it.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Acked-by: Patrick Boettcher <pboettcher@kernellabs.com>
drivers/media/dvb-frontends/dib8000.c

index c67a3dba116c035d641f513fba4a44e2f60cb95c..7539d7af2cf78c2cc6d5fa199243b9123f905ba2 100644 (file)
@@ -121,8 +121,9 @@ struct dib8000_state {
 
        /* for DVBv5 stats */
        s64 init_ucb;
-       unsigned long jiffies_stats;
-       unsigned long jiffies_stats_layer[3];
+       unsigned long per_jiffies_stats;
+       unsigned long ber_jiffies_stats;
+       unsigned long ber_jiffies_stats_layer[3];
 
 #ifdef DIB8000_AGC_FREEZE
        u16 agc1_max;
@@ -1006,6 +1007,7 @@ static void dib8000_reset_stats(struct dvb_frontend *fe)
        c->strength.len = 1;
        c->cnr.len = 1;
        c->block_error.len = 1;
+       c->block_count.len = 1;
        c->post_bit_error.len = 1;
        c->post_bit_count.len = 1;
 
@@ -1014,15 +1016,17 @@ static void dib8000_reset_stats(struct dvb_frontend *fe)
 
        c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
        c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       c->block_count.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;
 
        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));
+       state->ber_jiffies_stats = 0;
+       state->per_jiffies_stats = 0;
+       memset(&state->ber_jiffies_stats_layer, 0,
+              sizeof(state->ber_jiffies_stats_layer));
 }
 
 static int dib8000_reset(struct dvb_frontend *fe)
@@ -4059,7 +4063,9 @@ 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;
-       u32 time_us, snr, val;
+       int show_per_stats = 0;
+       u32 time_us = 0, snr, val;
+       u64 blocks;
        s32 db;
        u16 strength;
 
@@ -4074,6 +4080,7 @@ static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
        /* UCB/BER/CNR measures require lock */
        if (!(stat & FE_HAS_LOCK)) {
                c->cnr.len = 1;
+               c->block_count.len = 1;
                c->block_error.len = 1;
                c->post_bit_error.len = 1;
                c->post_bit_count.len = 1;
@@ -4081,15 +4088,13 @@ static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
                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;
+               c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
                return 0;
        }
 
        /* 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);
+       if (time_after(jiffies, state->per_jiffies_stats)) {
+               state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
 
                /* Get SNR */
                snr = dib8000_get_snr(fe);
@@ -4108,7 +4113,34 @@ 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;
 
-               /* Get UCB and post-BER measures */
+               /* Get UCB measures */
+               dib8000_read_unc_blocks(fe, &val);
+               if (val < state->init_ucb)
+                       state->init_ucb += 0x100000000L;
+
+               c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+               c->block_error.stat[0].uvalue = val + state->init_ucb;
+
+               /* Estimate the number of packets based on bitrate */
+               if (!time_us)
+                       time_us = dib8000_get_time_us(fe, -1);
+
+               if (time_us) {
+                       blocks = 1250000UL * 1000000UL;
+                       do_div(blocks, time_us * 8 * 204);
+                       c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+                       c->block_count.stat[0].uvalue += blocks;
+               }
+
+               show_per_stats = 1;
+       }
+
+       /* Get post-BER measures */
+       if (time_after(jiffies, state->ber_jiffies_stats)) {
+               time_us = dib8000_get_time_us(fe, -1);
+               state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
+
+               dprintk("Next all layers stats available in %u us.", time_us);
 
                dib8000_read_ber(fe, &val);
                c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
@@ -4116,13 +4148,6 @@ static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
 
                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)
@@ -4133,27 +4158,43 @@ 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++) {
-               if (!time_after(jiffies, state->jiffies_stats_layer[i]))
-                       continue;
-               time_us = dib8000_get_time_us(fe, i);
-               if (!time_us)
+               unsigned nsegs = c->layer[i].segment_count;
+
+               if (nsegs == 0 || nsegs > 13)
                        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);
+               time_us = 0;
+
+               if (time_after(jiffies, state->ber_jiffies_stats_layer[i])) {
+                       time_us = dib8000_get_time_us(fe, i);
+
+                       state->ber_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;
+                       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;
+                       c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
+                       c->post_bit_count.stat[1 + i].uvalue += 100000000;
+               }
+
+               if (show_per_stats) {
+                       val = dib8000_read_word(state, per_layer_regs[i].per);
 
-               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;
 
-               c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER;
-               c->block_error.stat[1 + i].uvalue += val;
+                       if (!time_us)
+                               time_us = dib8000_get_time_us(fe, i);
+                       if (time_us) {
+                               blocks = 1250000UL * 1000000UL;
+                               do_div(blocks, time_us * 8 * 204);
+                               c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+                               c->block_count.stat[0].uvalue += blocks;
+                       }
+               }
        }
        return 0;
 }