lkml.org 
[lkml]   [2019]   [Jun]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH V6 09/11] misc: xilinx_sdfec: Add stats & status ioctls
    Date
    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@xilinx.com>
    Tested by: Punnaiah Choudary Kalluri <punnaia@xilinx.com>
    Tested-by: Derek Kiernan <derek.kiernan@xilinx.com>
    Tested-by: Dragan Cvetic <dragan.cvetic@xilinx.com>
    Signed-off-by: Derek Kiernan <derek.kiernan@xilinx.com>
    Signed-off-by: Dragan Cvetic <dragan.cvetic@xilinx.com>
    ---
    drivers/misc/xilinx_sdfec.c | 125 +++++++++++++++++++++++++++++++++++++++
    include/uapi/misc/xilinx_sdfec.h | 75 +++++++++++++++++++++++
    2 files changed, 200 insertions(+)

    diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
    index 040dc59..881f464 100644
    --- a/drivers/misc/xilinx_sdfec.c
    +++ b/drivers/misc/xilinx_sdfec.c
    @@ -193,6 +193,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
    @@ -213,6 +214,7 @@ struct xsdfec_dev {
    struct device *dev;
    enum xsdfec_state state;
    struct xsdfec_config config;
    + bool intr_enabled;
    bool state_updated;
    bool stats_updated;
    u32 isr_err_count;
    @@ -288,6 +290,25 @@ static void update_config_from_hw(struct xsdfec_dev *xsdfec)
    xsdfec->state = XSDFEC_STOPPED;
    }

    +static int xsdfec_get_status(struct xsdfec_dev *xsdfec, void __user *arg)
    +{
    + struct xsdfec_status status;
    + int err;
    +
    + spin_lock_irqsave(&xsdfec->error_data_lock, xsdfec->flags);
    + status.state = xsdfec->state;
    + xsdfec->state_updated = false;
    + spin_unlock_irqrestore(&xsdfec->error_data_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;
    @@ -839,6 +860,82 @@ static int xsdfec_dev_release(struct inode *iptr, struct file *fptr)
    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)
    +{
    + spin_lock_irqsave(&xsdfec->error_data_lock, xsdfec->flags);
    + xsdfec->isr_err_count = 0;
    + xsdfec->uecc_count = 0;
    + xsdfec->cecc_count = 0;
    + spin_unlock_irqrestore(&xsdfec->error_data_lock, xsdfec->flags);
    +
    + 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->error_data_lock, xsdfec->flags);
    + user_stats.isr_err_count = xsdfec->isr_err_count;
    + user_stats.cecc_count = xsdfec->cecc_count;
    + user_stats.uecc_count = xsdfec->uecc_count;
    + xsdfec->stats_updated = false;
    + spin_unlock_irqrestore(&xsdfec->error_data_lock, xsdfec->flags);
    +
    + err = copy_to_user(arg, &user_stats, sizeof(user_stats));
    + if (err)
    + err = -EFAULT;
    +
    + return err;
    +}
    +
    +static int xsdfec_set_default_config(struct xsdfec_dev *xsdfec)
    +{
    + /* Ensure registers are aligned with core configuration */
    + xsdfec_regwrite(xsdfec, XSDFEC_FEC_CODE_ADDR, xsdfec->config.code);
    + xsdfec_cfg_axi_streams(xsdfec);
    + update_config_from_hw(xsdfec);
    +
    + return 0;
    +}
    +
    static long xsdfec_dev_ioctl(struct file *fptr, unsigned int cmd,
    unsigned long data)
    {
    @@ -848,6 +945,16 @@ static long xsdfec_dev_ioctl(struct file *fptr, unsigned int cmd,

    xsdfec = container_of(fptr->private_data, struct xsdfec_dev, miscdev);

    + /* In failed state allow only reset and get status IOCTLs */
    + if (xsdfec->state == XSDFEC_NEEDS_RESET &&
    + (cmd != XSDFEC_SET_DEFAULT_CONFIG && cmd != XSDFEC_GET_STATUS &&
    + cmd != XSDFEC_GET_STATS && cmd != XSDFEC_CLEAR_STATS)) {
    + return -EPERM;
    + }
    +
    + if (_IOC_TYPE(cmd) != XSDFEC_MAGIC)
    + return -ENOTTY;
    +
    /* check if ioctl argument is present and valid */
    if (_IOC_DIR(cmd) != _IOC_NONE) {
    arg = (void __user *)data;
    @@ -856,9 +963,27 @@ static long xsdfec_dev_ioctl(struct file *fptr, unsigned int cmd,
    }

    switch (cmd) {
    + case XSDFEC_START_DEV:
    + rval = xsdfec_start(xsdfec);
    + break;
    + case XSDFEC_STOP_DEV:
    + rval = xsdfec_stop(xsdfec);
    + break;
    + case XSDFEC_CLEAR_STATS:
    + rval = xsdfec_clear_stats(xsdfec);
    + break;
    + case XSDFEC_GET_STATS:
    + rval = xsdfec_get_stats(xsdfec, arg);
    + break;
    + case XSDFEC_GET_STATUS:
    + rval = xsdfec_get_status(xsdfec, arg);
    + break;
    case XSDFEC_GET_CONFIG:
    rval = xsdfec_get_config(xsdfec, arg);
    break;
    + case XSDFEC_SET_DEFAULT_CONFIG:
    + rval = xsdfec_set_default_config(xsdfec);
    + break;
    case XSDFEC_SET_IRQ:
    rval = xsdfec_set_irq(xsdfec, arg);
    break;
    diff --git a/include/uapi/misc/xilinx_sdfec.h b/include/uapi/misc/xilinx_sdfec.h
    index 59ee10c..31a9110 100644
    --- a/include/uapi/misc/xilinx_sdfec.h
    +++ b/include/uapi/misc/xilinx_sdfec.h
    @@ -234,6 +234,21 @@ struct xsdfec_config {
    };

    /**
    + * struct xsdfec_stats - Stats retrived by ioctl XSDFEC_GET_STATS. Used
    + * to buffer atomic_t variables from struct
    + * xsdfec_dev. Counts are accumulated until
    + * the user clears them.
    + * @isr_err_count: Count of ISR errors
    + * @cecc_count: Count of Correctable ECC errors (SBE)
    + * @uecc_count: Count of Uncorrectable ECC errors (MBE)
    + */
    +struct xsdfec_stats {
    + __u32 isr_err_count;
    + __u32 cecc_count;
    + __u32 uecc_count;
    +};
    +
    +/**
    * struct xsdfec_ldpc_param_table_sizes - Used to store sizes of SD-FEC table
    * entries for an individual LPDC code
    * parameter.
    @@ -252,6 +267,32 @@ struct xsdfec_ldpc_param_table_sizes {
    */
    #define XSDFEC_MAGIC 'f'
    /**
    + * DOC: XSDFEC_START_DEV
    + *
    + * @Description
    + *
    + * ioctl to start SD-FEC core
    + *
    + * This fails if the XSDFEC_SET_ORDER ioctl has not been previously called
    + */
    +#define XSDFEC_START_DEV _IO(XSDFEC_MAGIC, 0)
    +/**
    + * DOC: XSDFEC_STOP_DEV
    + *
    + * @Description
    + *
    + * ioctl to stop the SD-FEC core
    + */
    +#define XSDFEC_STOP_DEV _IO(XSDFEC_MAGIC, 1)
    +/**
    + * DOC: XSDFEC_GET_STATUS
    + *
    + * @Description
    + *
    + * ioctl that returns status of SD-FEC core
    + */
    +#define XSDFEC_GET_STATUS _IOR(XSDFEC_MAGIC, 2, struct xsdfec_status)
    +/**
    * DOC: XSDFEC_SET_IRQ
    * @Parameters
    *
    @@ -370,4 +411,38 @@ struct xsdfec_ldpc_param_table_sizes {
    * ioctl that determines if SD-FEC is processing data
    */
    #define XSDFEC_IS_ACTIVE _IOR(XSDFEC_MAGIC, 10, bool)
    +/**
    + * DOC: XSDFEC_CLEAR_STATS
    + *
    + * @Description
    + *
    + * ioctl that clears error stats collected during interrupts
    + */
    +#define XSDFEC_CLEAR_STATS _IO(XSDFEC_MAGIC, 11)
    +/**
    + * DOC: XSDFEC_GET_STATS
    + * @Parameters
    + *
    + * @struct xsdfec_stats *
    + * Pointer to the &struct xsdfec_stats that will contain the updated stats
    + * values
    + *
    + * @Description
    + *
    + * ioctl that returns SD-FEC core stats
    + *
    + * This can only be used when the driver is in the XSDFEC_STOPPED state
    + */
    +#define XSDFEC_GET_STATS _IOR(XSDFEC_MAGIC, 12, struct xsdfec_stats)
    +/**
    + * DOC: XSDFEC_SET_DEFAULT_CONFIG
    + *
    + * @Description
    + *
    + * ioctl that returns SD-FEC core to default config, use after a reset
    + *
    + * This can only be used when the driver is in the XSDFEC_STOPPED state
    + */
    +#define XSDFEC_SET_DEFAULT_CONFIG _IO(XSDFEC_MAGIC, 13)
    +
    #endif /* __XILINX_SDFEC_H__ */
    --
    2.7.4
    \
     
     \ /
      Last update: 2019-06-10 15:46    [W:2.825 / U:0.336 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site