diff options
author | Mauro Carvalho Chehab <mchehab@s-opensource.com> | 2016-07-01 10:03:15 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@s-opensource.com> | 2016-07-16 05:53:46 -0400 |
commit | 4216be14be19ef3ca0c0afdb2f5c1a352e688a61 (patch) | |
tree | 9acb20dd1d69395b566e21f66ea376905ef68c35 | |
parent | eca2d34b9d2ce70165a50510659838e28ca22742 (diff) |
[media] cxd2841er: fix BER report via DVBv5 stats API
What userspace expects is to receive both bit_error and bit_count
counters. So, instead of doing the division at the Kernel,
return the counters for userspace to handle it the way it
wants.
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
-rw-r--r-- | drivers/media/dvb-frontends/cxd2841er.c | 137 |
1 files changed, 66 insertions, 71 deletions
diff --git a/drivers/media/dvb-frontends/cxd2841er.c b/drivers/media/dvb-frontends/cxd2841er.c index 721fb074da7c..94de6ba3d0e2 100644 --- a/drivers/media/dvb-frontends/cxd2841er.c +++ b/drivers/media/dvb-frontends/cxd2841er.c | |||
@@ -1330,11 +1330,10 @@ static int cxd2841er_read_packet_errors_i( | |||
1330 | return 0; | 1330 | return 0; |
1331 | } | 1331 | } |
1332 | 1332 | ||
1333 | static int cxd2841er_mon_read_ber_s(struct cxd2841er_priv *priv, u32 *ber) | 1333 | static int cxd2841er_mon_read_ber_s(struct cxd2841er_priv *priv, |
1334 | u32 *bit_error, u32 *bit_count) | ||
1334 | { | 1335 | { |
1335 | u8 data[11]; | 1336 | u8 data[11]; |
1336 | u32 bit_error, bit_count; | ||
1337 | u32 temp_q, temp_r; | ||
1338 | 1337 | ||
1339 | /* Set SLV-T Bank : 0xA0 */ | 1338 | /* Set SLV-T Bank : 0xA0 */ |
1340 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0); | 1339 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0); |
@@ -1350,28 +1349,18 @@ static int cxd2841er_mon_read_ber_s(struct cxd2841er_priv *priv, u32 *ber) | |||
1350 | */ | 1349 | */ |
1351 | cxd2841er_read_regs(priv, I2C_SLVT, 0x35, data, 11); | 1350 | cxd2841er_read_regs(priv, I2C_SLVT, 0x35, data, 11); |
1352 | if (data[0] & 0x01) { | 1351 | if (data[0] & 0x01) { |
1353 | bit_error = ((u32)(data[1] & 0x3F) << 16) | | 1352 | *bit_error = ((u32)(data[1] & 0x3F) << 16) | |
1354 | ((u32)(data[2] & 0xFF) << 8) | | 1353 | ((u32)(data[2] & 0xFF) << 8) | |
1355 | (u32)(data[3] & 0xFF); | 1354 | (u32)(data[3] & 0xFF); |
1356 | bit_count = ((u32)(data[8] & 0x3F) << 16) | | 1355 | *bit_count = ((u32)(data[8] & 0x3F) << 16) | |
1357 | ((u32)(data[9] & 0xFF) << 8) | | 1356 | ((u32)(data[9] & 0xFF) << 8) | |
1358 | (u32)(data[10] & 0xFF); | 1357 | (u32)(data[10] & 0xFF); |
1359 | /* | 1358 | if ((*bit_count == 0) || (*bit_error > *bit_count)) { |
1360 | * BER = bitError / bitCount | ||
1361 | * = (bitError * 10^7) / bitCount | ||
1362 | * = ((bitError * 625 * 125 * 128) / bitCount | ||
1363 | */ | ||
1364 | if ((bit_count == 0) || (bit_error > bit_count)) { | ||
1365 | dev_dbg(&priv->i2c->dev, | 1359 | dev_dbg(&priv->i2c->dev, |
1366 | "%s(): invalid bit_error %d, bit_count %d\n", | 1360 | "%s(): invalid bit_error %d, bit_count %d\n", |
1367 | __func__, bit_error, bit_count); | 1361 | __func__, *bit_error, *bit_count); |
1368 | return -EINVAL; | 1362 | return -EINVAL; |
1369 | } | 1363 | } |
1370 | temp_q = div_u64_rem(10000000ULL * bit_error, | ||
1371 | bit_count, &temp_r); | ||
1372 | if (bit_count != 1 && temp_r >= bit_count / 2) | ||
1373 | temp_q++; | ||
1374 | *ber = temp_q; | ||
1375 | return 0; | 1364 | return 0; |
1376 | } | 1365 | } |
1377 | dev_dbg(&priv->i2c->dev, "%s(): no data available\n", __func__); | 1366 | dev_dbg(&priv->i2c->dev, "%s(): no data available\n", __func__); |
@@ -1379,11 +1368,11 @@ static int cxd2841er_mon_read_ber_s(struct cxd2841er_priv *priv, u32 *ber) | |||
1379 | } | 1368 | } |
1380 | 1369 | ||
1381 | 1370 | ||
1382 | static int cxd2841er_mon_read_ber_s2(struct cxd2841er_priv *priv, u32 *ber) | 1371 | static int cxd2841er_mon_read_ber_s2(struct cxd2841er_priv *priv, |
1372 | u32 *bit_error, u32 *bit_count) | ||
1383 | { | 1373 | { |
1384 | u8 data[5]; | 1374 | u8 data[5]; |
1385 | u32 bit_error, period; | 1375 | u32 period; |
1386 | u32 temp_q, temp_r; | ||
1387 | 1376 | ||
1388 | /* Set SLV-T Bank : 0xB2 */ | 1377 | /* Set SLV-T Bank : 0xB2 */ |
1389 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xb2); | 1378 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xb2); |
@@ -1398,10 +1387,10 @@ static int cxd2841er_mon_read_ber_s2(struct cxd2841er_priv *priv, u32 *ber) | |||
1398 | cxd2841er_read_regs(priv, I2C_SLVT, 0x30, data, 5); | 1387 | cxd2841er_read_regs(priv, I2C_SLVT, 0x30, data, 5); |
1399 | if (data[0] & 0x01) { | 1388 | if (data[0] & 0x01) { |
1400 | /* Bit error count */ | 1389 | /* Bit error count */ |
1401 | bit_error = ((u32)(data[1] & 0x0F) << 24) | | 1390 | *bit_error = ((u32)(data[1] & 0x0F) << 24) | |
1402 | ((u32)(data[2] & 0xFF) << 16) | | 1391 | ((u32)(data[2] & 0xFF) << 16) | |
1403 | ((u32)(data[3] & 0xFF) << 8) | | 1392 | ((u32)(data[3] & 0xFF) << 8) | |
1404 | (u32)(data[4] & 0xFF); | 1393 | (u32)(data[4] & 0xFF); |
1405 | 1394 | ||
1406 | /* Set SLV-T Bank : 0xA0 */ | 1395 | /* Set SLV-T Bank : 0xA0 */ |
1407 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0); | 1396 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0); |
@@ -1413,24 +1402,14 @@ static int cxd2841er_mon_read_ber_s2(struct cxd2841er_priv *priv, u32 *ber) | |||
1413 | "%s(): period is 0\n", __func__); | 1402 | "%s(): period is 0\n", __func__); |
1414 | return -EINVAL; | 1403 | return -EINVAL; |
1415 | } | 1404 | } |
1416 | if (bit_error > (period * 64800)) { | 1405 | if (*bit_error > (period * 64800)) { |
1417 | dev_dbg(&priv->i2c->dev, | 1406 | dev_dbg(&priv->i2c->dev, |
1418 | "%s(): invalid bit_err 0x%x period 0x%x\n", | 1407 | "%s(): invalid bit_err 0x%x period 0x%x\n", |
1419 | __func__, bit_error, period); | 1408 | __func__, *bit_error, period); |
1420 | return -EINVAL; | 1409 | return -EINVAL; |
1421 | } | 1410 | } |
1422 | /* | 1411 | *bit_count = period * 64800; |
1423 | * BER = bitError / (period * 64800) | 1412 | |
1424 | * = (bitError * 10^7) / (period * 64800) | ||
1425 | * = (bitError * 10^5) / (period * 648) | ||
1426 | * = (bitError * 12500) / (period * 81) | ||
1427 | * = (bitError * 10) * 1250 / (period * 81) | ||
1428 | */ | ||
1429 | temp_q = div_u64_rem(12500ULL * bit_error, | ||
1430 | period * 81, &temp_r); | ||
1431 | if (temp_r >= period * 40) | ||
1432 | temp_q++; | ||
1433 | *ber = temp_q; | ||
1434 | return 0; | 1413 | return 0; |
1435 | } else { | 1414 | } else { |
1436 | dev_dbg(&priv->i2c->dev, | 1415 | dev_dbg(&priv->i2c->dev, |
@@ -1439,13 +1418,12 @@ static int cxd2841er_mon_read_ber_s2(struct cxd2841er_priv *priv, u32 *ber) | |||
1439 | return -EINVAL; | 1418 | return -EINVAL; |
1440 | } | 1419 | } |
1441 | 1420 | ||
1442 | static int cxd2841er_read_ber_t2(struct cxd2841er_priv *priv, u32 *ber) | 1421 | static int cxd2841er_read_ber_t2(struct cxd2841er_priv *priv, |
1422 | u32 *bit_error, u32 *bit_count) | ||
1443 | { | 1423 | { |
1444 | u8 data[4]; | 1424 | u8 data[4]; |
1445 | u32 div, q, r; | 1425 | u32 period_exp, n_ldpc; |
1446 | u32 bit_err, period_exp, n_ldpc; | ||
1447 | 1426 | ||
1448 | *ber = 0; | ||
1449 | if (priv->state != STATE_ACTIVE_TC) { | 1427 | if (priv->state != STATE_ACTIVE_TC) { |
1450 | dev_dbg(&priv->i2c->dev, | 1428 | dev_dbg(&priv->i2c->dev, |
1451 | "%s(): invalid state %d\n", __func__, priv->state); | 1429 | "%s(): invalid state %d\n", __func__, priv->state); |
@@ -1456,40 +1434,44 @@ static int cxd2841er_read_ber_t2(struct cxd2841er_priv *priv, u32 *ber) | |||
1456 | if (!(data[0] & 0x10)) { | 1434 | if (!(data[0] & 0x10)) { |
1457 | dev_dbg(&priv->i2c->dev, | 1435 | dev_dbg(&priv->i2c->dev, |
1458 | "%s(): no valid BER data\n", __func__); | 1436 | "%s(): no valid BER data\n", __func__); |
1459 | return 0; | 1437 | return -EINVAL; |
1460 | } | 1438 | } |
1461 | bit_err = ((u32)(data[0] & 0x0f) << 24) | | 1439 | *bit_error = ((u32)(data[0] & 0x0f) << 24) | |
1462 | ((u32)data[1] << 16) | | 1440 | ((u32)data[1] << 16) | |
1463 | ((u32)data[2] << 8) | | 1441 | ((u32)data[2] << 8) | |
1464 | (u32)data[3]; | 1442 | (u32)data[3]; |
1465 | cxd2841er_read_reg(priv, I2C_SLVT, 0x6f, data); | 1443 | cxd2841er_read_reg(priv, I2C_SLVT, 0x6f, data); |
1466 | period_exp = data[0] & 0x0f; | 1444 | period_exp = data[0] & 0x0f; |
1467 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x22); | 1445 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x22); |
1468 | cxd2841er_read_reg(priv, I2C_SLVT, 0x5e, data); | 1446 | cxd2841er_read_reg(priv, I2C_SLVT, 0x5e, data); |
1469 | n_ldpc = ((data[0] & 0x03) == 0 ? 16200 : 64800); | 1447 | n_ldpc = ((data[0] & 0x03) == 0 ? 16200 : 64800); |
1470 | if (bit_err > ((1U << period_exp) * n_ldpc)) { | 1448 | if (*bit_error > ((1U << period_exp) * n_ldpc)) { |
1471 | dev_dbg(&priv->i2c->dev, | 1449 | dev_dbg(&priv->i2c->dev, |
1472 | "%s(): invalid BER value\n", __func__); | 1450 | "%s(): invalid BER value\n", __func__); |
1473 | return -EINVAL; | 1451 | return -EINVAL; |
1474 | } | 1452 | } |
1453 | |||
1454 | /* | ||
1455 | * FIXME: the right thing would be to return bit_error untouched, | ||
1456 | * but, as we don't know the scale returned by the counters, let's | ||
1457 | * at least preserver BER = bit_error/bit_count. | ||
1458 | */ | ||
1475 | if (period_exp >= 4) { | 1459 | if (period_exp >= 4) { |
1476 | div = (1U << (period_exp - 4)) * (n_ldpc / 200); | 1460 | *bit_count = (1U << (period_exp - 4)) * (n_ldpc / 200); |
1477 | q = div_u64_rem(3125ULL * bit_err, div, &r); | 1461 | *bit_error *= 3125ULL; |
1478 | } else { | 1462 | } else { |
1479 | div = (1U << period_exp) * (n_ldpc / 200); | 1463 | *bit_count = (1U << period_exp) * (n_ldpc / 200); |
1480 | q = div_u64_rem(50000ULL * bit_err, div, &r); | 1464 | *bit_error *= 50000ULL;; |
1481 | } | 1465 | } |
1482 | *ber = (r >= div / 2) ? q + 1 : q; | ||
1483 | return 0; | 1466 | return 0; |
1484 | } | 1467 | } |
1485 | 1468 | ||
1486 | static int cxd2841er_read_ber_t(struct cxd2841er_priv *priv, u32 *ber) | 1469 | static int cxd2841er_read_ber_t(struct cxd2841er_priv *priv, |
1470 | u32 *bit_error, u32 *bit_count) | ||
1487 | { | 1471 | { |
1488 | u8 data[2]; | 1472 | u8 data[2]; |
1489 | u32 div, q, r; | 1473 | u32 period; |
1490 | u32 bit_err, period; | ||
1491 | 1474 | ||
1492 | *ber = 0; | ||
1493 | if (priv->state != STATE_ACTIVE_TC) { | 1475 | if (priv->state != STATE_ACTIVE_TC) { |
1494 | dev_dbg(&priv->i2c->dev, | 1476 | dev_dbg(&priv->i2c->dev, |
1495 | "%s(): invalid state %d\n", __func__, priv->state); | 1477 | "%s(): invalid state %d\n", __func__, priv->state); |
@@ -1503,12 +1485,17 @@ static int cxd2841er_read_ber_t(struct cxd2841er_priv *priv, u32 *ber) | |||
1503 | return 0; | 1485 | return 0; |
1504 | } | 1486 | } |
1505 | cxd2841er_read_regs(priv, I2C_SLVT, 0x22, data, sizeof(data)); | 1487 | cxd2841er_read_regs(priv, I2C_SLVT, 0x22, data, sizeof(data)); |
1506 | bit_err = ((u32)data[0] << 8) | (u32)data[1]; | 1488 | *bit_error = ((u32)data[0] << 8) | (u32)data[1]; |
1507 | cxd2841er_read_reg(priv, I2C_SLVT, 0x6f, data); | 1489 | cxd2841er_read_reg(priv, I2C_SLVT, 0x6f, data); |
1508 | period = ((data[0] & 0x07) == 0) ? 256 : (4096 << (data[0] & 0x07)); | 1490 | period = ((data[0] & 0x07) == 0) ? 256 : (4096 << (data[0] & 0x07)); |
1509 | div = period / 128; | 1491 | |
1510 | q = div_u64_rem(78125ULL * bit_err, div, &r); | 1492 | /* |
1511 | *ber = (r >= div / 2) ? q + 1 : q; | 1493 | * FIXME: the right thing would be to return bit_error untouched, |
1494 | * but, as we don't know the scale returned by the counters, let's | ||
1495 | * at least preserver BER = bit_error/bit_count. | ||
1496 | */ | ||
1497 | *bit_count = period / 128; | ||
1498 | *bit_error *= 78125ULL; | ||
1512 | return 0; | 1499 | return 0; |
1513 | } | 1500 | } |
1514 | 1501 | ||
@@ -1722,32 +1709,36 @@ static void cxd2841er_read_ber(struct dvb_frontend *fe) | |||
1722 | { | 1709 | { |
1723 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | 1710 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
1724 | struct cxd2841er_priv *priv = fe->demodulator_priv; | 1711 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
1725 | u32 ber = 0, ret; | 1712 | u32 ret, bit_error = 0, bit_count = 0; |
1726 | 1713 | ||
1727 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 1714 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
1728 | switch (p->delivery_system) { | 1715 | switch (p->delivery_system) { |
1729 | case SYS_DVBS: | 1716 | case SYS_DVBS: |
1730 | ret = cxd2841er_mon_read_ber_s(priv, &ber); | 1717 | ret = cxd2841er_mon_read_ber_s(priv, &bit_error, &bit_count); |
1731 | break; | 1718 | break; |
1732 | case SYS_DVBS2: | 1719 | case SYS_DVBS2: |
1733 | ret = cxd2841er_mon_read_ber_s2(priv, &ber); | 1720 | ret = cxd2841er_mon_read_ber_s2(priv, &bit_error, &bit_count); |
1734 | break; | 1721 | break; |
1735 | case SYS_DVBT: | 1722 | case SYS_DVBT: |
1736 | ret = cxd2841er_read_ber_t(priv, &ber); | 1723 | ret = cxd2841er_read_ber_t(priv, &bit_error, &bit_count); |
1737 | break; | 1724 | break; |
1738 | case SYS_DVBT2: | 1725 | case SYS_DVBT2: |
1739 | ret = cxd2841er_read_ber_t2(priv, &ber); | 1726 | ret = cxd2841er_read_ber_t2(priv, &bit_error, &bit_count); |
1740 | break; | 1727 | break; |
1741 | default: | 1728 | default: |
1742 | p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | 1729 | p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1730 | p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
1743 | return; | 1731 | return; |
1744 | } | 1732 | } |
1745 | 1733 | ||
1746 | if (!ret) { | 1734 | if (!ret) { |
1747 | p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; | 1735 | p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; |
1748 | p->post_bit_error.stat[0].uvalue = ber; | 1736 | p->post_bit_error.stat[0].uvalue = bit_error; |
1737 | p->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; | ||
1738 | p->post_bit_count.stat[0].uvalue = bit_count; | ||
1749 | } else { | 1739 | } else { |
1750 | p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | 1740 | p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1741 | p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
1751 | } | 1742 | } |
1752 | } | 1743 | } |
1753 | 1744 | ||
@@ -2988,6 +2979,7 @@ static int cxd2841er_get_frontend(struct dvb_frontend *fe, | |||
2988 | p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | 2979 | p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
2989 | p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | 2980 | p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
2990 | p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | 2981 | p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
2982 | p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
2991 | } | 2983 | } |
2992 | return 0; | 2984 | return 0; |
2993 | } | 2985 | } |
@@ -3052,6 +3044,7 @@ done: | |||
3052 | p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | 3044 | p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
3053 | p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | 3045 | p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
3054 | p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | 3046 | p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
3047 | p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
3055 | 3048 | ||
3056 | return ret; | 3049 | return ret; |
3057 | } | 3050 | } |
@@ -3426,6 +3419,8 @@ static void cxd2841er_init_stats(struct dvb_frontend *fe) | |||
3426 | p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | 3419 | p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
3427 | p->post_bit_error.len = 1; | 3420 | p->post_bit_error.len = 1; |
3428 | p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | 3421 | p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
3422 | p->post_bit_count.len = 1; | ||
3423 | p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
3429 | } | 3424 | } |
3430 | 3425 | ||
3431 | 3426 | ||