As reported at:
https://tvheadend.org/issues/5625
Retrieving certain status can cause discontinuity issues.
Prevent that by adding a timeout to each status logic.
Currently, the timeout is estimated based at the channel
bandwidth. There are other parameters that may also affect
the timeout, but that would require a per-delivery system
calculus and probably more information about how cxd2481er
works, with we don't have.
So, do a poor man's best guess.
Cc: [email protected]
Signed-off-by: Mauro Carvalho Chehab <[email protected]>
---
drivers/media/dvb-frontends/cxd2841er.c | 68 +++++++++++++++++++++++++
1 file changed, 68 insertions(+)
diff --git a/drivers/media/dvb-frontends/cxd2841er.c
b/drivers/media/dvb-frontends/cxd2841er.c
index 1b30cf570803..218da631df19 100644
--- a/drivers/media/dvb-frontends/cxd2841er.c
+++ b/drivers/media/dvb-frontends/cxd2841er.c
@@ -60,6 +60,13 @@ struct cxd2841er_priv {
enum cxd2841er_xtal xtal;
enum fe_caps caps;
u32 flags;
+
+ unsigned long ber_interval;
+ unsigned long ucb_interval;
+
+ unsigned long ber_time;
+ unsigned long ucb_time;
+ unsigned long snr_time;
};
static const struct cxd2841er_cnr_data s_cn_data[] = {
@@ -1941,6 +1948,10 @@ static void cxd2841er_read_ber(struct dvb_frontend *fe)
struct cxd2841er_priv *priv = fe->demodulator_priv;
u32 ret, bit_error = 0, bit_count = 0;
+ if (priv->ber_time &&
+ (!time_after(jiffies, priv->ber_time)))
+ return;
+
dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
switch (p->delivery_system) {
case SYS_DVBC_ANNEX_A:
@@ -1953,9 +1964,15 @@ static void cxd2841er_read_ber(struct dvb_frontend *fe)
break;
case SYS_DVBS:
ret = cxd2841er_mon_read_ber_s(priv, &bit_error, &bit_count);
+
+ if (!priv->ber_interval && p->symbol_rate)
+ priv->ber_interval = (10000000) / (p->symbol_rate /
1000);
break;
case SYS_DVBS2:
ret = cxd2841er_mon_read_ber_s2(priv, &bit_error, &bit_count);
+
+ if (!priv->ber_interval && p->symbol_rate)
+ priv->ber_interval = (10000000) / (p->symbol_rate /
1000);
break;
case SYS_DVBT:
ret = cxd2841er_read_ber_t(priv, &bit_error, &bit_count);
@@ -1978,6 +1995,21 @@ static void cxd2841er_read_ber(struct dvb_frontend *fe)
p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
}
+
+ /*
+ * If the per-delivery system doesn't specify, set a default timeout
+ * that will wait for ~12.5 seconds for 8MHz channels
+ */
+ if (!priv->ber_interval && p->bandwidth_hz)
+ priv->ber_interval = (100000000) / (p->bandwidth_hz / 1000);
+
+ if (priv->ber_interval < 1000)
+ priv->ber_interval = 1000;
+
+// HACK:
+dev_info(&priv->i2c->dev, "BER interval: %d ms", priv->ber_interval);
+
+ priv->ber_time = jiffies + msecs_to_jiffies(priv->ber_interval);
}
static void cxd2841er_read_signal_strength(struct dvb_frontend *fe)
@@ -2037,6 +2069,16 @@ static void cxd2841er_read_snr(struct dvb_frontend *fe)
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct cxd2841er_priv *priv = fe->demodulator_priv;
+ if (priv->snr_time &&
+ (!time_after(jiffies, priv->snr_time)))
+ return;
+
+ /* Preventing asking SNR more than once per second */
+ priv->snr_time = jiffies + msecs_to_jiffies(1000);
+
+// HACK
+dev_info(&priv->i2c->dev, "SNR interval: %d ms", 1000);
+
dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
switch (p->delivery_system) {
case SYS_DVBC_ANNEX_A:
@@ -2081,6 +2123,10 @@ static void cxd2841er_read_ucblocks(struct dvb_frontend
*fe)
struct cxd2841er_priv *priv = fe->demodulator_priv;
u32 ucblocks = 0;
+ if (priv->ucb_time &&
+ (!time_after(jiffies, priv->ucb_time)))
+ return;
+
dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
switch (p->delivery_system) {
case SYS_DVBC_ANNEX_A:
@@ -2105,6 +2151,21 @@ static void cxd2841er_read_ucblocks(struct dvb_frontend
*fe)
p->block_error.stat[0].scale = FE_SCALE_COUNTER;
p->block_error.stat[0].uvalue = ucblocks;
+
+ /*
+ * If the per-delivery system doesn't specify, set a default timeout
+ * that will wait 20-30 seconds
+ */
+ if (!priv->ucb_interval && p->bandwidth_hz)
+ priv->ucb_interval = (100 * 204 * 1000 * 8) / p->bandwidth_hz;
+
+ if (priv->ucb_interval < 1000)
+ priv->ucb_interval = 1000;
+
+// HACK:
+dev_info(&priv->i2c->dev, "UCB interval: %d ms", priv->ucb_interval);
+
+ priv->ucb_time = jiffies + msecs_to_jiffies(priv->ucb_interval);
}
static int cxd2841er_dvbt2_set_profile(
@@ -3360,6 +3421,13 @@ static int cxd2841er_set_frontend_s(struct dvb_frontend
*fe)
p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ /* Reset the wait for jiffies logic */
+ priv->ber_interval = 0;
+ priv->ucb_interval = 0;
+ priv->ber_time = 0;
+ priv->ucb_time = 0;
+ priv->snr_time = 0;
+
return ret;
}
--
2.21.0