Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

misc: xilinx_sdfec: Add stats & status ioctls

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>
Link: https://lore.kernel.org/r/1564216438-322406-7-git-send-email-dragan.cvetic@xilinx.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Dragan Cvetic and committed by
Greg Kroah-Hartman
6bd6a690 cc538f60

+200
+125
drivers/misc/xilinx_sdfec.c
··· 206 206 * @irq: IRQ number 207 207 * @state_updated: indicates State updated by interrupt handler 208 208 * @stats_updated: indicates Stats updated by interrupt handler 209 + * @intr_enabled: indicates IRQ enabled 209 210 * 210 211 * This structure contains necessary state for SDFEC driver to operate 211 212 */ ··· 229 228 int irq; 230 229 bool state_updated; 231 230 bool stats_updated; 231 + bool intr_enabled; 232 232 }; 233 233 234 234 static inline void xsdfec_regwrite(struct xsdfec_dev *xsdfec, u32 addr, ··· 289 287 xsdfec->state = XSDFEC_STARTED; 290 288 else 291 289 xsdfec->state = XSDFEC_STOPPED; 290 + } 291 + 292 + static int xsdfec_get_status(struct xsdfec_dev *xsdfec, void __user *arg) 293 + { 294 + struct xsdfec_status status; 295 + int err; 296 + 297 + spin_lock_irqsave(&xsdfec->error_data_lock, xsdfec->flags); 298 + status.state = xsdfec->state; 299 + xsdfec->state_updated = false; 300 + spin_unlock_irqrestore(&xsdfec->error_data_lock, xsdfec->flags); 301 + status.activity = (xsdfec_regread(xsdfec, XSDFEC_ACTIVE_ADDR) & 302 + XSDFEC_IS_ACTIVITY_SET); 303 + 304 + err = copy_to_user(arg, &status, sizeof(status)); 305 + if (err) 306 + err = -EFAULT; 307 + 308 + return err; 292 309 } 293 310 294 311 static int xsdfec_get_config(struct xsdfec_dev *xsdfec, void __user *arg) ··· 861 840 return 0; 862 841 } 863 842 843 + static int xsdfec_start(struct xsdfec_dev *xsdfec) 844 + { 845 + u32 regread; 846 + 847 + regread = xsdfec_regread(xsdfec, XSDFEC_FEC_CODE_ADDR); 848 + regread &= 0x1; 849 + if (regread != xsdfec->config.code) { 850 + dev_dbg(xsdfec->dev, 851 + "%s SDFEC HW code does not match driver code, reg %d, code %d", 852 + __func__, regread, xsdfec->config.code); 853 + return -EINVAL; 854 + } 855 + 856 + /* Set AXIS enable */ 857 + xsdfec_regwrite(xsdfec, XSDFEC_AXIS_ENABLE_ADDR, 858 + XSDFEC_AXIS_ENABLE_MASK); 859 + /* Done */ 860 + xsdfec->state = XSDFEC_STARTED; 861 + return 0; 862 + } 863 + 864 + static int xsdfec_stop(struct xsdfec_dev *xsdfec) 865 + { 866 + u32 regread; 867 + 868 + if (xsdfec->state != XSDFEC_STARTED) 869 + dev_dbg(xsdfec->dev, "Device not started correctly"); 870 + /* Disable AXIS_ENABLE Input interfaces only */ 871 + regread = xsdfec_regread(xsdfec, XSDFEC_AXIS_ENABLE_ADDR); 872 + regread &= (~XSDFEC_AXIS_IN_ENABLE_MASK); 873 + xsdfec_regwrite(xsdfec, XSDFEC_AXIS_ENABLE_ADDR, regread); 874 + /* Stop */ 875 + xsdfec->state = XSDFEC_STOPPED; 876 + return 0; 877 + } 878 + 879 + static int xsdfec_clear_stats(struct xsdfec_dev *xsdfec) 880 + { 881 + spin_lock_irqsave(&xsdfec->error_data_lock, xsdfec->flags); 882 + xsdfec->isr_err_count = 0; 883 + xsdfec->uecc_count = 0; 884 + xsdfec->cecc_count = 0; 885 + spin_unlock_irqrestore(&xsdfec->error_data_lock, xsdfec->flags); 886 + 887 + return 0; 888 + } 889 + 890 + static int xsdfec_get_stats(struct xsdfec_dev *xsdfec, void __user *arg) 891 + { 892 + int err; 893 + struct xsdfec_stats user_stats; 894 + 895 + spin_lock_irqsave(&xsdfec->error_data_lock, xsdfec->flags); 896 + user_stats.isr_err_count = xsdfec->isr_err_count; 897 + user_stats.cecc_count = xsdfec->cecc_count; 898 + user_stats.uecc_count = xsdfec->uecc_count; 899 + xsdfec->stats_updated = false; 900 + spin_unlock_irqrestore(&xsdfec->error_data_lock, xsdfec->flags); 901 + 902 + err = copy_to_user(arg, &user_stats, sizeof(user_stats)); 903 + if (err) 904 + err = -EFAULT; 905 + 906 + return err; 907 + } 908 + 909 + static int xsdfec_set_default_config(struct xsdfec_dev *xsdfec) 910 + { 911 + /* Ensure registers are aligned with core configuration */ 912 + xsdfec_regwrite(xsdfec, XSDFEC_FEC_CODE_ADDR, xsdfec->config.code); 913 + xsdfec_cfg_axi_streams(xsdfec); 914 + update_config_from_hw(xsdfec); 915 + 916 + return 0; 917 + } 918 + 864 919 static long xsdfec_dev_ioctl(struct file *fptr, unsigned int cmd, 865 920 unsigned long data) 866 921 { ··· 946 849 947 850 xsdfec = container_of(fptr->private_data, struct xsdfec_dev, miscdev); 948 851 852 + /* In failed state allow only reset and get status IOCTLs */ 853 + if (xsdfec->state == XSDFEC_NEEDS_RESET && 854 + (cmd != XSDFEC_SET_DEFAULT_CONFIG && cmd != XSDFEC_GET_STATUS && 855 + cmd != XSDFEC_GET_STATS && cmd != XSDFEC_CLEAR_STATS)) { 856 + return -EPERM; 857 + } 858 + 859 + if (_IOC_TYPE(cmd) != XSDFEC_MAGIC) 860 + return -ENOTTY; 861 + 949 862 /* check if ioctl argument is present and valid */ 950 863 if (_IOC_DIR(cmd) != _IOC_NONE) { 951 864 arg = (void __user *)data; ··· 964 857 } 965 858 966 859 switch (cmd) { 860 + case XSDFEC_START_DEV: 861 + rval = xsdfec_start(xsdfec); 862 + break; 863 + case XSDFEC_STOP_DEV: 864 + rval = xsdfec_stop(xsdfec); 865 + break; 866 + case XSDFEC_CLEAR_STATS: 867 + rval = xsdfec_clear_stats(xsdfec); 868 + break; 869 + case XSDFEC_GET_STATS: 870 + rval = xsdfec_get_stats(xsdfec, arg); 871 + break; 872 + case XSDFEC_GET_STATUS: 873 + rval = xsdfec_get_status(xsdfec, arg); 874 + break; 967 875 case XSDFEC_GET_CONFIG: 968 876 rval = xsdfec_get_config(xsdfec, arg); 877 + break; 878 + case XSDFEC_SET_DEFAULT_CONFIG: 879 + rval = xsdfec_set_default_config(xsdfec); 969 880 break; 970 881 case XSDFEC_SET_IRQ: 971 882 rval = xsdfec_set_irq(xsdfec, arg);
+75
include/uapi/misc/xilinx_sdfec.h
··· 234 234 }; 235 235 236 236 /** 237 + * struct xsdfec_stats - Stats retrived by ioctl XSDFEC_GET_STATS. Used 238 + * to buffer atomic_t variables from struct 239 + * xsdfec_dev. Counts are accumulated until 240 + * the user clears them. 241 + * @isr_err_count: Count of ISR errors 242 + * @cecc_count: Count of Correctable ECC errors (SBE) 243 + * @uecc_count: Count of Uncorrectable ECC errors (MBE) 244 + */ 245 + struct xsdfec_stats { 246 + __u32 isr_err_count; 247 + __u32 cecc_count; 248 + __u32 uecc_count; 249 + }; 250 + 251 + /** 237 252 * struct xsdfec_ldpc_param_table_sizes - Used to store sizes of SD-FEC table 238 253 * entries for an individual LPDC code 239 254 * parameter. ··· 266 251 * XSDFEC IOCTL List 267 252 */ 268 253 #define XSDFEC_MAGIC 'f' 254 + /** 255 + * DOC: XSDFEC_START_DEV 256 + * 257 + * @Description 258 + * 259 + * ioctl to start SD-FEC core 260 + * 261 + * This fails if the XSDFEC_SET_ORDER ioctl has not been previously called 262 + */ 263 + #define XSDFEC_START_DEV _IO(XSDFEC_MAGIC, 0) 264 + /** 265 + * DOC: XSDFEC_STOP_DEV 266 + * 267 + * @Description 268 + * 269 + * ioctl to stop the SD-FEC core 270 + */ 271 + #define XSDFEC_STOP_DEV _IO(XSDFEC_MAGIC, 1) 272 + /** 273 + * DOC: XSDFEC_GET_STATUS 274 + * 275 + * @Description 276 + * 277 + * ioctl that returns status of SD-FEC core 278 + */ 279 + #define XSDFEC_GET_STATUS _IOR(XSDFEC_MAGIC, 2, struct xsdfec_status) 269 280 /** 270 281 * DOC: XSDFEC_SET_IRQ 271 282 * @Parameters ··· 411 370 * ioctl that determines if SD-FEC is processing data 412 371 */ 413 372 #define XSDFEC_IS_ACTIVE _IOR(XSDFEC_MAGIC, 10, bool) 373 + /** 374 + * DOC: XSDFEC_CLEAR_STATS 375 + * 376 + * @Description 377 + * 378 + * ioctl that clears error stats collected during interrupts 379 + */ 380 + #define XSDFEC_CLEAR_STATS _IO(XSDFEC_MAGIC, 11) 381 + /** 382 + * DOC: XSDFEC_GET_STATS 383 + * @Parameters 384 + * 385 + * @struct xsdfec_stats * 386 + * Pointer to the &struct xsdfec_stats that will contain the updated stats 387 + * values 388 + * 389 + * @Description 390 + * 391 + * ioctl that returns SD-FEC core stats 392 + * 393 + * This can only be used when the driver is in the XSDFEC_STOPPED state 394 + */ 395 + #define XSDFEC_GET_STATS _IOR(XSDFEC_MAGIC, 12, struct xsdfec_stats) 396 + /** 397 + * DOC: XSDFEC_SET_DEFAULT_CONFIG 398 + * 399 + * @Description 400 + * 401 + * ioctl that returns SD-FEC core to default config, use after a reset 402 + * 403 + * This can only be used when the driver is in the XSDFEC_STOPPED state 404 + */ 405 + #define XSDFEC_SET_DEFAULT_CONFIG _IO(XSDFEC_MAGIC, 13) 406 + 414 407 #endif /* __XILINX_SDFEC_H__ */