/******************************************************************************* NAME $RCSfile: nicX550Diag.c,v $ SUMMARY Intel Ethernet Controller (X550) diagnostics VERSION $Revision: 1.0 $ UPDATE DATE $Date: 2014/07/30 04:16:50 $ PROGRAMMER $Author: TCS $ COPYRIGHT: DESCRIPTION: REFERENCE: *******************************************************************************/ //#ifndef NIC_KERNEL_MODULE_C #define NIC_KERNEL_MODULE_C #include #include #include #include #include #include #include #include #include "nicX550IOCTL.h" #include #undef TRUE #undef FALSE #include "commRpt.h" #include "commMEC.h" #define _GPL_ #define stringify(s) tostring(s) #define tostring(s) #s static int nicX550_major; static struct class *nicX550_module_class; #define IS_VALID_NAME_ON_PP(name) \ do { \ if (strcmp(name, "em1") && strcmp(name, "em2")) { \ printk("Invalid eth interface (%s) for nic X550 \n", name); \ return (-EINVAL); \ } \ } while(0) extern int ixgbeLoopbackTest(const char *name, LOOPBACK_TYPE type, struct block_cus blocks); extern int ixgbeLinkTest(const char *name); extern int ixgbeEepromTest(const char *name); extern int ixgbeIntrTest(const char *name); extern int ixgbeMDIORead(const char *name, int page, int reg, u16 *PHY_data); extern int ixgbeMDIOWrite(const char *name, int page, int reg, u16 PHY_data); int nicX550MdiTest(const char *name) { int ret; //IS_VALID_NAME_ON_PP(name); ret = ixgbeLinkTest(name); return (ret); } int nicX550EepromTest(const char *name) { int ret; //IS_VALID_NAME_ON_PP(name); ret = ixgbeEepromTest(name); return (ret); } int nicX550IntrTest(const char *name) { int ret; //IS_VALID_NAME_ON_PP(name); ret = ixgbeIntrTest(name); return (ret); } int nicX550LoopbackTest(const char *name, LOOPBACK_TYPE type, struct block_cus blocks) { int ret; //IS_VALID_NAME_ON_PP(name); ret = ixgbeLoopbackTest(name, type, blocks); return (ret); } int nicX550MDIORead(const char *name, int page, int reg, int *PHY_data) { int ret; ret = ixgbeMDIORead(name, page, reg, (u16 *)PHY_data); return (ret); } int nicX550MDIOWrite(const char *name, int page, int reg, int PHY_data) { int ret; ret = ixgbeMDIOWrite(name, page, reg, (u16 )PHY_data); return (ret); } int nicX550_open(struct inode *inod, struct file *filp) { int major, minor; major = imajor(inod); minor = iminor(inod); try_module_get(THIS_MODULE); return 0; } int nicX550_release(struct inode *inod, struct file *filp) { module_put(THIS_MODULE); return 0; } //int nicX550_ioctl(struct file *filp, unsigned int cmd, void *arg) long nicX550_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int err = 0; int ret = 0; argu *ag; argu ker_ag; struct phy_register_info *phy = NULL; struct phy_register_info ker_phy; printk("[## eth ##] ioctl door\n"); if (_IOC_TYPE(cmd) != NICX550_MODULE_IOC_MAGIC) { return -ENOTTY; } if (_IOC_NR(cmd) > NICX550_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; } if ((cmd == IOCTL_NICX550_IXGBEMDIORead) || (cmd == IOCTL_NICX550_IXGBEMDIOWrite)) { phy =(struct phy_register_info *) arg; ret = copy_from_user(&ker_phy, phy, sizeof(struct phy_register_info)); } else { ag = (argu *) arg; ret = copy_from_user(&ker_ag, ag, sizeof(argu)); } if (ret) { printk("nicX550_ioctl : Copy from user space error!\n"); return -EFAULT; } switch (cmd) { case IOCTL_NICX550_LOOPBACK: ret = nicX550LoopbackTest(ker_ag.ethname, ker_ag.type, ker_ag.blocks); printk("[## eth ##] LoopbackTesfinishret:(%d)\n", ret); break; case IOCTL_NICX550_IXGBEEEPROMTEST: ret = nicX550EepromTest(ker_ag.ethname); printk("[## eth ##] EepromTestfinishret:(%d)\n", ret); break; case IOCTL_NICX550_IXGBEINTRTEST: ret = nicX550IntrTest(ker_ag.ethname); printk("[## eth ##] IntrTesfinishret:(%d)\n", ret); break; case IOCTL_NICX550_IXGBEMDITEST: ret = nicX550MdiTest(ker_ag.ethname); printk("[## eth ##] MdiTesfinishret:(%d)\n", ret); break; case IOCTL_NICX550_IXGBEIEEETEST: printk("[## eth ##] IEEETest not supported\n"); return -ENOTTY; case IOCTL_NICX550_IXGBEMDIORead: ret = nicX550MDIORead(ker_phy.ethname, ker_phy.phyPage, ker_phy.phyRegister, &ker_phy.phyData); printk("[## eth ##] MDIOReadfinishret:(%d)\n", ret); //printk("PHY register: Page:%x Register_address:%x PHY_data:%x\n", ker_phy.phyPage, ker_phy.phyRegister, ker_phy.phyData); ret = copy_to_user(phy, &ker_phy, sizeof(struct phy_register_info)); break; case IOCTL_NICX550_IXGBEMDIOWrite: ret = nicX550MDIOWrite(ker_phy.ethname, ker_phy.phyPage, ker_phy.phyRegister, ker_phy.phyData); printk("[## eth ##] MDIOWritefinishret:(%d)\n", ret); printk("PHY register: Page:%x Register_address:%x PHY_data:%x\n", ker_phy.phyPage, ker_phy.phyRegister, ker_phy.phyData); break; default: printk("[## eth ##] Not a valid IOCTL \n"); return -ENOTTY; } return ret; } long nicX550_unlocked_ioctl(struct file *File, unsigned int Cmd, unsigned long Arg) { //return nicX550_ioctl(File, Cmd, (void *)Arg); return nicX550_ioctl(File, Cmd, Arg); } struct file_operations nicX550_fops = { .owner = THIS_MODULE, .open = nicX550_open, .unlocked_ioctl = nicX550_ioctl, .release = nicX550_release, }; int nicX550_init_module(void) { int ret_num = 0; nicX550_major = 0; ret_num = register_chrdev(NICX550_DYNAMIC_MAJOR, NICX550_DEVICE_NAME, &nicX550_fops); nicX550_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) { nicX550_module_class = class_create(THIS_MODULE, NICX550_DEVICE_NAME); device_create(nicX550_module_class, NULL, MKDEV(nicX550_major, 0), NULL, "%s", NICX550_DEVICE_NAME); printk(KERN_INFO "NIC X550 kernel module have been loaded successfully (MAJOR_NUM=%d)!\n", ret_num); } return 0; } void nicX550_cleanup_module(void) { unregister_chrdev(nicX550_major, NICX550_DEVICE_NAME); device_destroy(nicX550_module_class, MKDEV(nicX550_major, 0)); class_destroy(nicX550_module_class); } module_init(nicX550_init_module); module_exit(nicX550_cleanup_module); MODULE_AUTHOR("rain_wang@jabil.com"); MODULE_DESCRIPTION("NetApp NIC X550 Diag Code"); MODULE_LICENSE("GPL"); MODULE_VERSION("0.1");