RE: [PATCH V4 10/12] misc: xilinx_sdfec: Add stats & status ioctls
From: Dragan Cvetic
Date: Thu Jun 06 2019 - 14:31:38 EST
> -----Original Message-----
> From: Greg KH [mailto:gregkh@xxxxxxxxxxxxxxxxxxx]
> Sent: Thursday 6 June 2019 15:12
> To: Dragan Cvetic <draganc@xxxxxxxxxx>
> Cc: arnd@xxxxxxxx; Michal Simek <michals@xxxxxxxxxx>; linux-arm-kernel@xxxxxxxxxxxxxxxxxxx; robh+dt@xxxxxxxxxx;
> mark.rutland@xxxxxxx; devicetree@xxxxxxxxxxxxxxx; linux-kernel@xxxxxxxxxxxxxxx; Derek Kiernan <dkiernan@xxxxxxxxxx>
> Subject: Re: [PATCH V4 10/12] misc: xilinx_sdfec: Add stats & status ioctls
>
> On Sat, May 25, 2019 at 12:37:23PM +0100, Dragan Cvetic wrote:
> > SD-FEC statistic data are:
> > - count of data interface errors (isr_err_count)
> > - count of Correctable ECC errors (cecc_count)
> > - count of Uncorrectable ECC errors (uecc_count)
> >
> > Add support:
> > 1. clear stats ioctl callback which clears collected
> > statistic data,
> > 2. get stats ioctl callback which reads a collected
> > statistic data,
> > 3. set default configuration ioctl callback,
> > 4. start ioctl callback enables SD-FEC HW,
> > 5. stop ioctl callback disables SD-FEC HW.
> >
> > In a failed state driver enables the following ioctls:
> > - get status
> > - get statistics
> > - clear stats
> > - set default SD-FEC device configuration
> >
> > Tested-by: Santhosh Dyavanapally <SDYAVANA@xxxxxxxxxx>
> > Tested by: Punnaiah Choudary Kalluri <punnaia@xxxxxxxxxx>
> > Tested-by: Derek Kiernan <derek.kiernan@xxxxxxxxxx>
> > Tested-by: Dragan Cvetic <dragan.cvetic@xxxxxxxxxx>
> > Signed-off-by: Derek Kiernan <derek.kiernan@xxxxxxxxxx>
> > Signed-off-by: Dragan Cvetic <dragan.cvetic@xxxxxxxxxx>
> > ---
> > drivers/misc/xilinx_sdfec.c | 121 +++++++++++++++++++++++++++++++++++++++
> > include/uapi/misc/xilinx_sdfec.h | 75 ++++++++++++++++++++++++
> > 2 files changed, 196 insertions(+)
> >
> > diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
> > index 544e746..6e04492 100644
> > --- a/drivers/misc/xilinx_sdfec.c
> > +++ b/drivers/misc/xilinx_sdfec.c
> > @@ -189,6 +189,7 @@ struct xsdfec_clks {
> > * @dev: pointer to device struct
> > * @state: State of the SDFEC device
> > * @config: Configuration of the SDFEC device
> > + * @intr_enabled: indicates IRQ enabled
> > * @state_updated: indicates State updated by interrupt handler
> > * @stats_updated: indicates Stats updated by interrupt handler
> > * @isr_err_count: Count of ISR errors
> > @@ -207,6 +208,7 @@ struct xsdfec_dev {
> > struct device *dev;
> > enum xsdfec_state state;
> > struct xsdfec_config config;
> > + bool intr_enabled;
> > bool state_updated;
> > bool stats_updated;
> > atomic_t isr_err_count;
> > @@ -290,6 +292,26 @@ static int xsdfec_dev_release(struct inode *iptr, struct file *fptr)
> > return 0;
> > }
> >
> > +static int xsdfec_get_status(struct xsdfec_dev *xsdfec, void __user *arg)
> > +{
> > + struct xsdfec_status status;
> > + int err;
> > +
> > + status.fec_id = xsdfec->config.fec_id;
> > + spin_lock_irqsave(&xsdfec->irq_lock, xsdfec->flags);
> > + status.state = xsdfec->state;
> > + xsdfec->state_updated = false;
> > + spin_unlock_irqrestore(&xsdfec->irq_lock, xsdfec->flags);
> > + status.activity = (xsdfec_regread(xsdfec, XSDFEC_ACTIVE_ADDR) &
> > + XSDFEC_IS_ACTIVITY_SET);
> > +
> > + err = copy_to_user(arg, &status, sizeof(status));
> > + if (err)
> > + err = -EFAULT;
> > +
> > + return err;
> > +}
> > +
> > static int xsdfec_get_config(struct xsdfec_dev *xsdfec, void __user *arg)
> > {
> > int err;
> > @@ -850,6 +872,80 @@ static int xsdfec_cfg_axi_streams(struct xsdfec_dev *xsdfec)
> > return 0;
> > }
> >
> > +static int xsdfec_start(struct xsdfec_dev *xsdfec)
> > +{
> > + u32 regread;
> > +
> > + regread = xsdfec_regread(xsdfec, XSDFEC_FEC_CODE_ADDR);
> > + regread &= 0x1;
> > + if (regread != xsdfec->config.code) {
> > + dev_dbg(xsdfec->dev,
> > + "%s SDFEC HW code does not match driver code, reg %d, code %d",
> > + __func__, regread, xsdfec->config.code);
> > + return -EINVAL;
> > + }
> > +
> > + /* Set AXIS enable */
> > + xsdfec_regwrite(xsdfec, XSDFEC_AXIS_ENABLE_ADDR,
> > + XSDFEC_AXIS_ENABLE_MASK);
> > + /* Done */
> > + xsdfec->state = XSDFEC_STARTED;
> > + return 0;
> > +}
> > +
> > +static int xsdfec_stop(struct xsdfec_dev *xsdfec)
> > +{
> > + u32 regread;
> > +
> > + if (xsdfec->state != XSDFEC_STARTED)
> > + dev_dbg(xsdfec->dev, "Device not started correctly");
> > + /* Disable AXIS_ENABLE Input interfaces only */
> > + regread = xsdfec_regread(xsdfec, XSDFEC_AXIS_ENABLE_ADDR);
> > + regread &= (~XSDFEC_AXIS_IN_ENABLE_MASK);
> > + xsdfec_regwrite(xsdfec, XSDFEC_AXIS_ENABLE_ADDR, regread);
> > + /* Stop */
> > + xsdfec->state = XSDFEC_STOPPED;
> > + return 0;
> > +}
> > +
> > +static int xsdfec_clear_stats(struct xsdfec_dev *xsdfec)
> > +{
> > + atomic_set(&xsdfec->isr_err_count, 0);
> > + atomic_set(&xsdfec->uecc_count, 0);
> > + atomic_set(&xsdfec->cecc_count, 0);
>
> Atomics for counters? Are you sure? Don't we have some sort of sane
> counter api these days for stuff like this instead of abusing atomic
> variables? What does the networking people use? How often/fast do
> these change that you need to synchronize things?
Accepted.
No need to have them atomic. They are lock protected already.
>
> > +
> > + return 0;
> > +}
> > +
> > +static int xsdfec_get_stats(struct xsdfec_dev *xsdfec, void __user *arg)
> > +{
> > + int err;
> > + struct xsdfec_stats user_stats;
> > +
> > + spin_lock_irqsave(&xsdfec->irq_lock, xsdfec->flags);
> > + user_stats.isr_err_count = atomic_read(&xsdfec->isr_err_count);
> > + user_stats.cecc_count = atomic_read(&xsdfec->cecc_count);
> > + user_stats.uecc_count = atomic_read(&xsdfec->uecc_count);
> > + xsdfec->stats_updated = false;
> > + spin_unlock_irqrestore(&xsdfec->irq_lock, xsdfec->flags);
>
> Wait, you just grabbed a lock, and then read atomic variables, why? Why
> do these need to be atomic variables if you are already locking around
> them? Unless you want to be "extra sure" they are safe? :)
Accepted.
Absolutely no need for atomic variables.
>
> Please fix up.
>
> thanks,
>
> greg k-h