lkml.org 
[lkml]   [2019]   [Apr]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH V2 10/12] 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 | 123 +++++++++++++++++++++++++++++++++++++++
    include/uapi/misc/xilinx_sdfec.h | 75 ++++++++++++++++++++++++
    2 files changed, 198 insertions(+)

    diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
    index 32b2e2d..317c5c4 100644
    --- a/drivers/misc/xilinx_sdfec.c
    +++ b/drivers/misc/xilinx_sdfec.c
    @@ -203,6 +203,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
    @@ -222,6 +223,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;
    @@ -320,6 +322,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_irq(&xsdfec->irq_lock);
    + status.state = xsdfec->state;
    + xsdfec->state_updated = false;
    + spin_unlock_irq(&xsdfec->irq_lock);
    + 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;
    @@ -896,6 +918,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_err(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_err(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);
    +
    + return 0;
    +}
    +
    +static int xsdfec_get_stats(struct xsdfec_dev *xsdfec, void __user *arg)
    +{
    + int err;
    + struct xsdfec_stats user_stats;
    +
    + spin_lock_irq(&xsdfec->irq_lock);
    + 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_irq(&xsdfec->irq_lock);
    +
    + 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)
    {
    @@ -907,6 +1003,15 @@ static long xsdfec_dev_ioctl(struct file *fptr, unsigned int cmd,
    if (!xsdfec)
    return rval;

    + /* 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)) {
    + dev_err(xsdfec->dev, "SDFEC%d in failed state. Reset Required",
    + xsdfec->config.fec_id);
    + return -EPERM;
    + }
    +
    if (_IOC_TYPE(cmd) != XSDFEC_MAGIC)
    return -ENOTTY;

    @@ -926,9 +1031,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 7dd9495..7f7e229 100644
    --- a/include/uapi/misc/xilinx_sdfec.h
    +++ b/include/uapi/misc/xilinx_sdfec.h
    @@ -240,6 +240,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.
    @@ -279,6 +294,32 @@ xsdfec_calculate_shared_ldpc_table_entry_size(struct xsdfec_ldpc_params *ldpc,
    */
    #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
    *
    @@ -397,4 +438,38 @@ xsdfec_calculate_shared_ldpc_table_entry_size(struct xsdfec_ldpc_params *ldpc,
    * 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-04-09 12:07    [W:2.956 / U:0.024 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site