From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
To: "Jasmin J." <jasmin@anw.at>
Cc: linux-media@vger.kernel.org, rjkm@metzlerbros.de, d.scheller@gmx.net
Subject: Re: [PATCH 2/2] Added timers for dvb_ca_en50221_write_data
Date: Thu, 14 Dec 2017 10:03:16 -0200 [thread overview]
Message-ID: <20171214100316.2549ec2e@vento.lan> (raw)
In-Reply-To: <1505611642-6552-3-git-send-email-jasmin@anw.at>
Em Sun, 17 Sep 2017 03:27:22 +0200
"Jasmin J." <jasmin@anw.at> escreveu:
> From: Jasmin Jessich <jasmin@anw.at>
>
> Some (older) CAMs are really slow in accepting data. The CI interface
> specification doesn't define a handshake for accepted data. Thus, the
> en50221 protocol driver can't control if a data byte has been correctly
> written to the CAM.
>
> The current implementation writes the length and the data quick after
> each other. Thus, the slow CAMs may generate a WR error, which leads to
> the known error logging
> "CAM tried to send a buffer larger than the ecount size".
>
> To solve this issue the en50221 protocol driver needs to wait some CAM
> depending time between the different bytes to be written. Because the
> time is CAM dependent, an individual value per CAM needs to be set. For
> that SysFS is used in favor of ioctl's to allow the control of the timer
> values independent from any user space application.
>
> This patch adds the timers and the SysFS nodes to set/get the timeout
> values and the timer waiting between the different steps of the CAM write
> access. A timer value of 0 (default) means "no timeout".
The patch series looks OK. However, I'm not seeing any documentation
patches explaining the new sysfs interface. I would be expecting an
update at linux DVB uAPI. Also, for all sysfs stuff, you need to add
it to Documentation/ABI/ using the format explained at its README.
Once you add it, I'll gladly apply it. Please add Ralph's ack on the
existing patches on your next submission.
Just a minor nitpick: on all patches, please prepend with "media: "
and the name of the part of the media subsystem that you're patching.
In this case, a good subject would be:
media: dvb-core: add timers for dvb_ca_en50221_write_data
Regards,
Mauro
>
> Signed-off-by: Jasmin Jessich <jasmin@anw.at>
> ---
> drivers/media/dvb-core/dvb_ca_en50221.c | 132 +++++++++++++++++++++++++++++++-
> 1 file changed, 131 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c
> index 95b3723..50c4e45 100644
> --- a/drivers/media/dvb-core/dvb_ca_en50221.c
> +++ b/drivers/media/dvb-core/dvb_ca_en50221.c
> @@ -86,6 +86,13 @@ MODULE_PARM_DESC(cam_debug, "enable verbose debug messages");
> #define DVB_CA_SLOTSTATE_WAITFR 6
> #define DVB_CA_SLOTSTATE_LINKINIT 7
>
> +enum dvb_ca_timers {
> + DVB_CA_TIM_WR_HIGH /* wait after writing length high */
> +, DVB_CA_TIM_WR_LOW /* wait after writing length low */
> +, DVB_CA_TIM_WR_DATA /* wait between data bytes */
> +, DVB_CA_TIM_MAX
> +};
> +
> /* Information on a CA slot */
> struct dvb_ca_slot {
> /* current state of the CAM */
> @@ -119,6 +126,11 @@ struct dvb_ca_slot {
> unsigned long timeout;
> };
>
> +struct dvb_ca_timer {
> + unsigned long min;
> + unsigned long max;
> +};
> +
> /* Private CA-interface information */
> struct dvb_ca_private {
> struct kref refcount;
> @@ -161,6 +173,14 @@ struct dvb_ca_private {
>
> /* mutex serializing ioctls */
> struct mutex ioctl_mutex;
> +
> + struct dvb_ca_timer timers[DVB_CA_TIM_MAX];
> +};
> +
> +static const char dvb_ca_tim_names[DVB_CA_TIM_MAX][15] = {
> + "tim_wr_high"
> +, "tim_wr_low"
> +, "tim_wr_data"
> };
>
> static void dvb_ca_private_free(struct dvb_ca_private *ca)
> @@ -223,6 +243,14 @@ static char *findstr(char *haystack, int hlen, char *needle, int nlen)
> return NULL;
> }
>
> +static void dvb_ca_sleep(struct dvb_ca_private *ca, enum dvb_ca_timers tim)
> +{
> + unsigned long min = ca->timers[tim].min;
> +
> + if (min)
> + usleep_range(min, ca->timers[tim].max);
> +}
> +
> /* ************************************************************************** */
> /* EN50221 physical interface functions */
>
> @@ -868,10 +896,13 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
> bytes_write >> 8);
> if (status)
> goto exit;
> + dvb_ca_sleep(ca, DVB_CA_TIM_WR_HIGH);
> +
> status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW,
> bytes_write & 0xff);
> if (status)
> goto exit;
> + dvb_ca_sleep(ca, DVB_CA_TIM_WR_LOW);
>
> /* send the buffer */
> for (i = 0; i < bytes_write; i++) {
> @@ -879,6 +910,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
> buf[i]);
> if (status)
> goto exit;
> + dvb_ca_sleep(ca, DVB_CA_TIM_WR_DATA);
> }
>
> /* check for write error (WE should now be 0) */
> @@ -1832,6 +1864,97 @@ static const struct dvb_device dvbdev_ca = {
> };
>
> /* ************************************************************************** */
> +/* EN50221 device attributes (SysFS) */
> +
> +static int dvb_ca_tim_idx(struct dvb_ca_private *ca, const char *name)
> +{
> + int tim_idx;
> +
> + for (tim_idx = 0; tim_idx < DVB_CA_TIM_MAX; tim_idx++) {
> + if (!strcmp(dvb_ca_tim_names[tim_idx], name))
> + return tim_idx;
> + }
> + return -1;
> +}
> +
> +static ssize_t dvb_ca_tim_show(struct device *device,
> + struct device_attribute *attr, char *buf)
> +{
> + struct dvb_device *dvbdev = dev_get_drvdata(device);
> + struct dvb_ca_private *ca = dvbdev->priv;
> + int tim_idx = dvb_ca_tim_idx(ca, attr->attr.name);
> +
> + if (tim_idx < 0)
> + return -ENXIO;
> +
> + return sprintf(buf, "%ld\n", ca->timers[tim_idx].min);
> +}
> +
> +static ssize_t dvb_ca_tim_store(struct device *device,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct dvb_device *dvbdev = dev_get_drvdata(device);
> + struct dvb_ca_private *ca = dvbdev->priv;
> + int tim_idx = dvb_ca_tim_idx(ca, attr->attr.name);
> + unsigned long min, max;
> +
> + if (tim_idx < 0)
> + return -ENXIO;
> +
> + if (sscanf(buf, "%lu\n", &min) != 1)
> + return -EINVAL;
> +
> + /* value is in us; 100ms is a good maximum */
> + if (min > (100 * USEC_PER_MSEC))
> + return -EINVAL;
> +
> + /* +10% (rounded up) */
> + max = (min * 11 + 5) / 10;
> + ca->timers[tim_idx].min = min;
> + ca->timers[tim_idx].max = max;
> +
> + return count;
> +}
> +
> +/* attribute definition with string pointer (see include/linux/sysfs.h) */
> +#define DVB_CA_ATTR(_name, _mode, _show, _store) { \
> + .attr = {.name = _name, .mode = _mode }, \
> + .show = _show, \
> + .store = _store, \
> +}
> +
> +#define DVB_CA_ATTR_TIM(_tim_idx) \
> + DVB_CA_ATTR(dvb_ca_tim_names[_tim_idx], 0664, dvb_ca_tim_show, \
> + dvb_ca_tim_store)
> +
> +static const struct device_attribute dvb_ca_attrs[DVB_CA_TIM_MAX] = {
> + DVB_CA_ATTR_TIM(DVB_CA_TIM_WR_HIGH)
> +, DVB_CA_ATTR_TIM(DVB_CA_TIM_WR_LOW)
> +, DVB_CA_ATTR_TIM(DVB_CA_TIM_WR_DATA)
> +};
> +
> +static int dvb_ca_device_attrs_add(struct dvb_ca_private *ca)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(dvb_ca_attrs); i++)
> + if (device_create_file(ca->dvbdev->dev, &dvb_ca_attrs[i]))
> + goto fail;
> + return 0;
> +fail:
> + return -1;
> +}
> +
> +static void ddb_device_attrs_del(struct dvb_ca_private *ca)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(dvb_ca_attrs); i++)
> + device_remove_file(ca->dvbdev->dev, &dvb_ca_attrs[i]);
> +}
> +
> +/* ************************************************************************** */
> /* Initialisation/shutdown functions */
>
> /**
> @@ -1901,6 +2024,10 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
> ret = -EINTR;
> goto unregister_device;
> }
> +
> + if (dvb_ca_device_attrs_add(ca))
> + goto unregister_device;
> +
> mb();
>
> /* create a kthread for monitoring this CA device */
> @@ -1910,10 +2037,12 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
> ret = PTR_ERR(ca->thread);
> pr_err("dvb_ca_init: failed to start kernel_thread (%d)\n",
> ret);
> - goto unregister_device;
> + goto delete_attrs;
> }
> return 0;
>
> +delete_attrs:
> + ddb_device_attrs_del(ca);
> unregister_device:
> dvb_unregister_device(ca->dvbdev);
> free_slot_info:
> @@ -1945,6 +2074,7 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
> for (i = 0; i < ca->slot_count; i++)
> dvb_ca_en50221_slot_shutdown(ca, i);
>
> + ddb_device_attrs_del(ca);
> dvb_remove_device(ca->dvbdev);
> dvb_ca_private_put(ca);
> pubca->private = NULL;
Thanks,
Mauro
next prev parent reply other threads:[~2017-12-14 12:03 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-09-17 1:27 [PATCH 0/2] Add timers to en50221 protocol driver Jasmin J.
2017-09-17 1:27 ` [PATCH 1/2] Store device structure in dvb_register_device Jasmin J.
2017-09-17 1:27 ` [PATCH 2/2] Added timers for dvb_ca_en50221_write_data Jasmin J.
2017-12-14 12:03 ` Mauro Carvalho Chehab [this message]
2017-10-15 13:59 ` [PATCH 0/2] Add timers to en50221 protocol driver Jasmin J.
2017-12-11 21:33 ` Jasmin J.
2017-12-11 21:59 ` Ralph Metzler
2017-12-11 23:17 ` Jasmin J.
2017-12-12 9:00 ` Ralph Metzler
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20171214100316.2549ec2e@vento.lan \
--to=mchehab@s-opensource.com \
--cc=d.scheller@gmx.net \
--cc=jasmin@anw.at \
--cc=linux-media@vger.kernel.org \
--cc=rjkm@metzlerbros.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).