/******************************************************************************* NAME $RCSfile: nic82574Diag.c,v $ SUMMARY Intel Ibex-Peak Ethernet Controller (82574) diagnostics VERSION $Revision: 1.5 $ UPDATE DATE $Date: 2010/02/23 04:16:50 $ PROGRAMMER $Author: jim $ Copyright 2009 LSI Corporation. All Rights Reserved. DESCRIPTION: REFERENCE: *******************************************************************************/ #ifndef NIC82574_KERNEL_MODULE_C #define NIC82574_KERNEL_MODULE_C #include #include #include #include #include #include #include #include #include "nic82574IOCTL.h" #include //#include #undef TRUE #undef FALSE #include "commPciChip.h" #include #include #define _GPL_ #define stringify(s) tostring(s) #define tostring(s) #s static int nic82574_major; static struct class *nic82574_module_class; extern int e1000MdiTest(const char *name); extern int e1000IeeeTest(const char *name,LOOPBACK_TYPE type,int testPat); extern int e1000LinkTest(const char *name); extern int e1000RegTest(const char *name); extern int e1000EepromTest(const char *name); extern int e1000IntrTest(const char *name); extern int e1000DMAPCITest(const char *name, LOOPBACK_TYPE type,struct block_cus blocks); extern int e1000LoopbackTest(const char *name, LOOPBACK_TYPE type,struct block_cus blocks); extern int e1000CrossLoopbackTest(const char *name1, const char *name2, LOOPBACK_TYPE type); extern int e1000GetStatistics(const char *name, struct e1000_hw_stats *buffer); #define IS_VALID_NAME_ON_PP(name) \ do { \ if (strcmp(name, "eth1") && strcmp(name, "eth0")) { \ printk("Invalid eth interface (%s) for nic 82576\n", name); \ return (-EINVAL); \ } \ } while(0) /* int nic82574PciReadTest(void) { return (pciRegTest(NIC_INTEL_82574, pciReadTest)); } int nic82574PciAddrLineTest(void) { return (pciRegTest(NIC_INTEL_82574, pciAddressLineTest)); } int nic82574PciDataLineTest(void) { return (pciRegTest(NIC_INTEL_82574, pciDataLineTest)); } */ int nic82574MdiTest(const char *name) { int ret; IS_VALID_NAME_ON_PP(name); //ret = e1000MdiTest(name); ret = e1000LinkTest(name); //if (ret) // commReportError(MEC_NIC82574, NIC82574_ITEM_MDI, // NIC82574_CODE_MDI, NIC82574_MSG_EMDI, // 0, 0, 0, DG_FORMAT_NONE); return (ret); } int nic82574IeeeTest(const char *name,LOOPBACK_TYPE type,int testPat) { int ret; //IS_VALID_NAME_ON_PP(name); ret = e1000IeeeTest(name,type,testPat); //if (ret) // commReportError(MEC_NIC82574, NIC82574_ITEM_MDI, // NIC82574_CODE_MDI, NIC82574_MSG_EMDI, // 0, 0, 0, DG_FORMAT_NONE); return (ret); } int nic82574LinkTest(const char *name) { int ret; IS_VALID_NAME_ON_PP(name); ret = e1000LinkTest(name); //if (ret) // commReportError(MEC_NIC82574, NIC82574_ITEM_LINK, // NIC82574_CODE_LINK, NIC82574_MSG_ELINK, // 0, 0, 0, DG_FORMAT_NONE); return (ret); } int nic82574RegTest(const char *name) { int ret; IS_VALID_NAME_ON_PP(name); ret = e1000RegTest(name); //if (ret) // commReportError(MEC_NIC82574, NIC82574_ITEM_REG, // NIC82574_CODE_REG, NIC82574_MSG_EREG, // 0, 0, 0, DG_FORMAT_NONE); return (ret); } int nic82574EepromTest(const char *name) { int ret; IS_VALID_NAME_ON_PP(name); ret = e1000EepromTest(name); //if (ret) // commReportError(MEC_NIC82574, NIC82574_ITEM_EEPROM, // NIC82574_CODE_EEPROM, NIC82574_MSG_EEEPROM, // 0, 0, 0, DG_FORMAT_NONE); return (ret); } int nic82574IntrTest(const char *name) { int ret; IS_VALID_NAME_ON_PP(name); ret = e1000IntrTest(name); //if (ret) // commReportError(MEC_NIC82574, NIC82574_ITEM_INTR, // NIC82574_CODE_INTR, NIC82574_MSG_EINTR, // 0, 0, 0, DG_FORMAT_NONE); return (ret); } int nic82574LoopbackTest(const char *name, LOOPBACK_TYPE type,struct block_cus blocks) { int ret; IS_VALID_NAME_ON_PP(name); ret = e1000LoopbackTest(name, type, blocks); //if (ret) // commReportError(MEC_NIC82574, NIC82574_ITEM_LOOPBACK, // NIC82574_CODE_LOOPBACK, NIC82574_MSG_ELP_PHY1000, // 0, 0, 0, DG_FORMAT_NONE); return (ret); } int nic82574DmapciTest(const char *name, LOOPBACK_TYPE type,struct block_cus blocks) { int ret; IS_VALID_NAME_ON_PP(name); ret = e1000DMAPCITest(name, type, blocks); //if (ret) // commReportError(MEC_NIC82574, NIC82574_ITEM_LOOPBACK, // NIC82574_CODE_LOOPBACK, NIC82574_MSG_ELP_PHY1000, // 0, 0, 0, DG_FORMAT_NONE); return (ret); } int nic82574GetStatistics(const char *name) { struct e1000_hw_stats stats; int ret; int result = 0; IS_VALID_NAME_ON_PP(name); ret = e1000GetStatistics(name, &stats); if (ret) { printk("%s failed to get statistics\n", name); return (ret); } printk("<%s> Tx bytes: %llu\n", name, stats.gotc); printk("<%s> Rx bytes: %llu\n", name, stats.gorc); printk("--------------------------------------------\n\n"); printk("<%s> CRC error count: %llu\n", name, stats.crcerrs); printk("<%s> Alignment error count: %llu\n", name, stats.algnerrc); printk("<%s> Symbol error count: %llu\n", name, stats.symerrs); printk("<%s> Rx error count: %llu\n", name, stats.rxerrc); printk("<%s> Missed packets count: %llu\n", name, stats.mpc); printk("<%s> Collision count: %llu\n", name, stats.colc); printk("<%s> Defer count: %llu\n", name, stats.dc); printk("<%s> Tx - No CRS: %llu\n", name, stats.tncrs); printk("<%s> Sequence error count: %llu\n", name, stats.sec); printk("<%s> Carrier ext error count: %llu\n", name, stats.cexterr); printk("<%s> Rx length error count: %llu\n", name, stats.rlec); if(stats.crcerrs > 0) { result++; } if(stats.algnerrc > 0) { result++; } if(stats.symerrs > 0) { result++; } if(stats.rxerrc > 0) { result++; } if(stats.mpc > 0) { result++; } if(stats.colc > 0) { result++; } if(stats.dc > 0) { result++; } if(stats.tncrs > 0) { result++; } if(stats.sec > 0) { result++; } if(stats.cexterr > 0) { result++; } if(stats.rlec > 0) { result++; } if(result > 0) { printk(" \n"); printk("## ## ## ##### ## ## #### ## ## ##### \n"); printk("## ## ## ## ## ### ## ## ### ## ## ## \n"); printk("## ## ## ####### ## # ## ## ## # ## ## \n"); printk("## ## ## ## ## ## ### ## ## ### ## ### \n"); printk(" ## ## ## ## ## ## #### ## ## #### # \n"); printk(" \n"); printk("[NIC_BS] NIC82574 has error count \n"); printk(" \n"); /* commReportError(MEC_NIC82574, NIC82574_ITEM_STRESS, NIC82574_CODE_STRESS, NIC82574_MSG_STRESS, 0, 0, 0, DG_FORMAT_NONE); */ } return (0); } int nic82574_open (struct inode *inod, struct file *filp) { //int major, minor; //major = imajor(inod); //minor = iminor(inod); printk("[## eth ##] tcc_eth_dev_open\n"); try_module_get(THIS_MODULE); return 0; } int nic82574_release(struct inode *inod, struct file *filp) { module_put(THIS_MODULE); return 0; } int nic82574_ioctl(struct file *filp, unsigned int cmd, void *arg) { int err = 0; int ret = 0; struct argu* ag; ag =( struct argu *)arg; printk("[## eth ##] ioctl door\n"); if (_IOC_TYPE(cmd) != NIC82574_MODULE_IOC_MAGIC){ return -ENOTTY;} if (_IOC_NR(cmd) > NIC82574_MODULE_IOC_MAXNUM){ return -ENOTTY;} /* ** The direction is a bitmask, and VERIFY_WRITE catches R/W transfers. ** 'Type' is user-oriented, while access_ok is kernel-oriented, so the ** concept of "read" and "write" is reversed */ if (_IOC_DIR(cmd) & _IOC_READ) { err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); } else if (_IOC_DIR(cmd) & _IOC_WRITE) { err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); } if (err){ printk("[## eth ##] > IODIRM\n"); return -EFAULT; } switch (cmd) { case IOCTL_NIC82574_LOOPBACK: ret = nic82574LoopbackTest(ag->name, ag->type,ag->blocks); //ret = nic82574LoopbackTest(ag->name, ag->type); printk("[## eth ##] LoopbackTesfinishret:(%d)\n",ret); break; case IOCTL_NIC82574_IGBLINKTEST: ret = nic82574LinkTest(ag->name); printk("[## eth ##] LinkTestfinishret:(%d)\n",ret); break; case IOCTL_NIC82574_IGBREGTEST: ret = nic82574RegTest(ag->name); printk("[## eth ##] RegTestfinishret:(%d)\n",ret); break; case IOCTL_NIC82574_IGBEEPROMTEST: ret = nic82574EepromTest(ag->name); printk("[## eth ##] EepromTestfinishret:(%d)\n",ret); break; case IOCTL_NIC82574_IGBINTRTEST: ret = nic82574IntrTest(ag->name); printk("[## eth ##] IntrTesfinishret:(%d)\n",ret); break; case IOCTL_NIC82574_IGBMDITEST: ret = nic82574MdiTest(ag->name); printk("[## eth ##] MdiTesfinishret:(%d)\n",ret); break; case IOCTL_NIC82574_IGBGETSTATTEST: ret = nic82574GetStatistics(ag->name); printk("[## eth ##] GetStatistics:(%d)\n",ret); break; case IOCTL_NIC82574_IGBIEEETEST : ret = nic82574IeeeTest(ag->name, ag->type,ag->blocks.numOfBlocks); printk("[## eth ##] IEEETesfinishret:(%d)\n",ret); break; case IOCTL_NIC82574_DMAPCITEST: ret = nic82574DmapciTest(ag->name, ag->type,ag->blocks); printk("[## eth ##] DmapciTesfinishret:(%d)\n",ret); break; default: printk("[## eth ##] 333333333335555555555555\n"); return -ENOTTY; } return ret; } long nic82574_unlocked_ioctl(struct file* File, unsigned int Cmd, unsigned long Arg) { return nic82574_ioctl(File, Cmd, (void *)Arg); } struct file_operations nic82574_fops = { .owner = THIS_MODULE, .open = nic82574_open, #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) .ioctl = nic82574_ioctl, #else .unlocked_ioctl = nic82574_unlocked_ioctl, #endif .release = nic82574_release, }; int nic82574_init_module(void) { int ret_num = 0; nic82574_major = 0; ret_num = register_chrdev(NIC82574_DYNAMIC_MAJOR, DEVICE_NAME, &nic82574_fops); nic82574_major = ret_num; if (ret_num < 0) { printk(KERN_ERR "TPPC476 MODULE: Can't get major device Number !\n"); return ret_num; } if (ret_num >= 0) { nic82574_module_class = class_create(THIS_MODULE, DEVICE_NAME); device_create(nic82574_module_class, NULL, MKDEV(nic82574_major, 0), NULL, "%s", DEVICE_NAME); printk(KERN_INFO "NIC82574 kernel module have been loaded successfully (MAJOR_NUM=%d)!\n", ret_num); } return 0; } void nic82574_cleanup_module(void) { unregister_chrdev(nic82574_major, DEVICE_NAME); device_destroy(nic82574_module_class, MKDEV(nic82574_major, 0)); class_destroy(nic82574_module_class); } module_init(nic82574_init_module); module_exit(nic82574_cleanup_module); #ifdef _GPL_ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ocean H.Y Lee"); #else MODULE_LICENSE("Copyright 2012-2020, Foxconn"); MODULE_AUTHOR("LHY"); #endif #endif /* TPPC476_KERNEL_MODULE_C */ MODULE_AUTHOR( "merck.hung@netapp.com" ); MODULE_DESCRIPTION( "NetApp NIC 82574 Diag Code" ); MODULE_LICENSE( "GPL" ); MODULE_VERSION( "0.1" );