X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Flibrte_eal%2Flinuxapp%2Fkni%2Fkni_misc.c;h=a69477c7163435764dc835e5b260d836f2ab755b;hb=e9d48c0072d36eb6423b45fba4ec49d0def6c36f;hp=4ef210ddb574fb6a8a548c7d0cc43067e6e86e80;hpb=47cda8c47001bc8aa8c7b807a0f4bd3cfdf16983;p=dpdk.git diff --git a/lib/librte_eal/linuxapp/kni/kni_misc.c b/lib/librte_eal/linuxapp/kni/kni_misc.c index 4ef210ddb5..a69477c716 100644 --- a/lib/librte_eal/linuxapp/kni/kni_misc.c +++ b/lib/librte_eal/linuxapp/kni/kni_misc.c @@ -1,7 +1,7 @@ /*- * GPL LICENSE SUMMARY * - * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -58,9 +58,14 @@ static int kni_ioctl(struct inode *inode, unsigned int ioctl_num, unsigned long ioctl_param); static int kni_compat_ioctl(struct inode *inode, unsigned int ioctl_num, unsigned long ioctl_param); +static int kni_dev_remove(struct kni_dev *dev); -/* kni kernel thread for rx */ -static int kni_thread(void *unused); +static int __init kni_parse_kthread_mode(void); + +/* KNI processing for single kernel thread mode */ +static int kni_thread_single(void *unused); +/* KNI processing for multiple kernel thread mode */ +static int kni_thread_multiple(void *param); static struct file_operations kni_fops = { .owner = THIS_MODULE, @@ -79,6 +84,10 @@ static struct miscdevice kni_misc = { /* loopback mode */ static char *lo_mode = NULL; +/* Kernel thread mode */ +static char *kthread_mode = NULL; +static unsigned multiple_kthread_on = 0; + #define KNI_DEV_IN_USE_BIT_NUM 0 /* Bit number for device in use */ static volatile unsigned long device_in_use; /* device in use flag */ @@ -95,9 +104,14 @@ kni_init(void) { KNI_PRINT("######## DPDK kni module loading ########\n"); + if (kni_parse_kthread_mode() < 0) { + KNI_ERR("Invalid parameter for kthread_mode\n"); + return -EINVAL; + } + if (misc_register(&kni_misc) != 0) { KNI_ERR("Misc registration failed\n"); - return 1; + return -EPERM; } /* Clear the bit of device in use */ @@ -118,6 +132,22 @@ kni_exit(void) KNI_PRINT("####### DPDK kni module unloaded #######\n"); } +static int __init +kni_parse_kthread_mode(void) +{ + if (!kthread_mode) + return 0; + + if (strcmp(kthread_mode, "single") == 0) + return 0; + else if (strcmp(kthread_mode, "multiple") == 0) + multiple_kthread_on = 1; + else + return -1; + + return 0; +} + static int kni_open(struct inode *inode, struct file *file) { @@ -125,12 +155,18 @@ kni_open(struct inode *inode, struct file *file) if (test_and_set_bit(KNI_DEV_IN_USE_BIT_NUM, &device_in_use)) return -EBUSY; - /* Create kernel thread for RX */ - kni_kthread = kthread_run(kni_thread, NULL, "kni_thread"); - if (IS_ERR(kni_kthread)) { - KNI_ERR("Unable to create kernel threaed\n"); - return PTR_ERR(kni_kthread); - } + /* Create kernel thread for single mode */ + if (multiple_kthread_on == 0) { + KNI_PRINT("Single kernel thread for all KNI devices\n"); + /* Create kernel thread for RX */ + kni_kthread = kthread_run(kni_thread_single, NULL, + "kni_single"); + if (IS_ERR(kni_kthread)) { + KNI_ERR("Unable to create kernel threaed\n"); + return PTR_ERR(kni_kthread); + } + } else + KNI_PRINT("Multiple kernel thread mode enabled\n"); KNI_PRINT("/dev/kni opened\n"); @@ -142,27 +178,25 @@ kni_release(struct inode *inode, struct file *file) { struct kni_dev *dev, *n; - /* Stop kernel thread */ - kthread_stop(kni_kthread); - kni_kthread = NULL; + /* Stop kernel thread for single mode */ + if (multiple_kthread_on == 0) { + /* Stop kernel thread */ + kthread_stop(kni_kthread); + kni_kthread = NULL; + } down_write(&kni_list_lock); list_for_each_entry_safe(dev, n, &kni_list_head, list) { - /* Call the remove part to restore pci dev */ - switch (dev->device_id) { - #define RTE_PCI_DEV_ID_DECL_IGB(vend, dev) case (dev): - #include - igb_kni_remove(dev->pci_dev); - break; - #define RTE_PCI_DEV_ID_DECL_IXGBE(vend, dev) case (dev): - #include - ixgbe_kni_remove(dev->pci_dev); - break; - default: - break; + /* Stop kernel thread for multiple mode */ + if (multiple_kthread_on && dev->pthread != NULL) { + kthread_stop(dev->pthread); + dev->pthread = NULL; } - unregister_netdev(dev->net_dev); - free_netdev(dev->net_dev); + +#ifdef RTE_KNI_VHOST + kni_vhost_backend_release(dev); +#endif + kni_dev_remove(dev); list_del(&dev->list); } up_write(&kni_list_lock); @@ -176,7 +210,7 @@ kni_release(struct inode *inode, struct file *file) } static int -kni_thread(void *unused) +kni_thread_single(void *unused) { int j; struct kni_dev *dev, *n; @@ -186,7 +220,11 @@ kni_thread(void *unused) for (j = 0; j < KNI_RX_LOOP_NUM; j++) { list_for_each_entry_safe(dev, n, &kni_list_head, list) { +#ifdef RTE_KNI_VHOST + kni_chk_vhost_rx(dev); +#else kni_net_rx(dev); +#endif kni_net_poll_resp(dev); } } @@ -199,6 +237,70 @@ kni_thread(void *unused) return 0; } +static int +kni_thread_multiple(void *param) +{ + int j; + struct kni_dev *dev = (struct kni_dev *)param; + + while (!kthread_should_stop()) { + for (j = 0; j < KNI_RX_LOOP_NUM; j++) { +#ifdef RTE_KNI_VHOST + kni_chk_vhost_rx(dev); +#else + kni_net_rx(dev); +#endif + kni_net_poll_resp(dev); + } + schedule_timeout_interruptible(usecs_to_jiffies( \ + KNI_KTHREAD_RESCHEDULE_INTERVAL)); + } + + return 0; +} + +static int +kni_dev_remove(struct kni_dev *dev) +{ + if (!dev) + return -ENODEV; + + switch (dev->device_id) { + #define RTE_PCI_DEV_ID_DECL_IGB(vend, dev) case (dev): + #include + igb_kni_remove(dev->pci_dev); + break; + #define RTE_PCI_DEV_ID_DECL_IXGBE(vend, dev) case (dev): + #include + ixgbe_kni_remove(dev->pci_dev); + break; + default: + break; + } + + if (dev->net_dev) { + unregister_netdev(dev->net_dev); + free_netdev(dev->net_dev); + } + + return 0; +} + +static int +kni_check_param(struct kni_dev *kni, struct rte_kni_device_info *dev) +{ + if (!kni || !dev) + return -1; + + /* Check if network name has been used */ + if (!strncmp(kni->name, dev->name, RTE_KNI_NAMESIZE)) { + KNI_ERR("KNI name %s duplicated\n", dev->name); + return -1; + } + + return 0; +} + static int kni_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param) { @@ -222,13 +324,21 @@ kni_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param) return -EIO; } + /** + * Check if the cpu core id is valid for binding, + * for multiple kernel thread mode. + */ + if (multiple_kthread_on && dev_info.force_bind && + !cpu_online(dev_info.core_id)) { + KNI_ERR("cpu %u is not online\n", dev_info.core_id); + return -EINVAL; + } + /* Check if it has been created */ down_read(&kni_list_lock); list_for_each_entry_safe(dev, n, &kni_list_head, list) { - if (dev->port_id == dev_info.port_id) { + if (kni_check_param(dev, &dev_info) < 0) { up_read(&kni_list_lock); - KNI_ERR("Port %d has already been created\n", - dev_info.port_id); return -EINVAL; } } @@ -244,7 +354,9 @@ kni_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param) kni = netdev_priv(net_dev); kni->net_dev = net_dev; - kni->port_id = dev_info.port_id; + kni->group_id = dev_info.group_id; + kni->core_id = dev_info.core_id; + strncpy(kni->name, dev_info.name, RTE_KNI_NAMESIZE); /* Translate user space info into kernel space info */ kni->tx_q = phys_to_virt(dev_info.tx_phys); @@ -260,6 +372,10 @@ kni_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param) kni->mbuf_kva = phys_to_virt(dev_info.mbuf_phys); kni->mbuf_va = dev_info.mbuf_va; +#ifdef RTE_KNI_VHOST + kni->vhost_queue = NULL; + kni->vq_status = BE_STOP; +#endif kni->mbuf_size = dev_info.mbuf_size; KNI_PRINT("tx_phys: 0x%016llx, tx_q addr: 0x%p\n", @@ -338,10 +454,31 @@ kni_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param) if (ret) { KNI_ERR("error %i registering device \"%s\"\n", ret, dev_info.name); - free_netdev(net_dev); + kni_dev_remove(kni); return -ENODEV; } +#ifdef RTE_KNI_VHOST + kni_vhost_init(kni); +#endif + + /** + * Create a new kernel thread for multiple mode, set its core affinity, + * and finally wake it up. + */ + if (multiple_kthread_on) { + kni->pthread = kthread_create(kni_thread_multiple, + (void *)kni, + "kni_%s", kni->name); + if (IS_ERR(kni->pthread)) { + kni_dev_remove(kni); + return -ECANCELED; + } + if (dev_info.force_bind) + kthread_bind(kni->pthread, kni->core_id); + wake_up_process(kni->pthread); + } + down_write(&kni_list_lock); list_add(&kni->list, &kni_list_head); up_write(&kni_list_lock); @@ -353,44 +490,43 @@ static int kni_ioctl_release(unsigned int ioctl_num, unsigned long ioctl_param) { int ret = -EINVAL; - uint8_t port_id; struct kni_dev *dev, *n; + struct rte_kni_device_info dev_info; - if (_IOC_SIZE(ioctl_num) > sizeof(port_id)) + if (_IOC_SIZE(ioctl_num) > sizeof(dev_info)) return -EINVAL; - ret = copy_from_user(&port_id, (void *)ioctl_param, sizeof(port_id)); + ret = copy_from_user(&dev_info, (void *)ioctl_param, sizeof(dev_info)); if (ret) { KNI_ERR("copy_from_user in kni_ioctl_release"); return -EIO; } + /* Release the network device according to its name */ + if (strlen(dev_info.name) == 0) + return ret; + down_write(&kni_list_lock); list_for_each_entry_safe(dev, n, &kni_list_head, list) { - if (dev->port_id != port_id) + if (strncmp(dev->name, dev_info.name, RTE_KNI_NAMESIZE) != 0) continue; - switch (dev->device_id) { - #define RTE_PCI_DEV_ID_DECL_IGB(vend, dev) case (dev): - #include - igb_kni_remove(dev->pci_dev); - break; - #define RTE_PCI_DEV_ID_DECL_IXGBE(vend, dev) case (dev): - #include - ixgbe_kni_remove(dev->pci_dev); - break; - default: - break; + if (multiple_kthread_on && dev->pthread != NULL) { + kthread_stop(dev->pthread); + dev->pthread = NULL; } - unregister_netdev(dev->net_dev); - free_netdev(dev->net_dev); + +#ifdef RTE_KNI_VHOST + kni_vhost_backend_release(dev); +#endif + kni_dev_remove(dev); list_del(&dev->list); ret = 0; break; } up_write(&kni_list_lock); - printk(KERN_INFO "KNI: %s release kni for port %d\n", - (ret == 0 ? "Successfully" : "Unsuccessfully"), port_id); + printk(KERN_INFO "KNI: %s release kni named %s\n", + (ret == 0 ? "Successfully" : "Unsuccessfully"), dev_info.name); return ret; } @@ -448,3 +584,11 @@ MODULE_PARM_DESC(lo_mode, "\n" ); +module_param(kthread_mode, charp, S_IRUGO); +MODULE_PARM_DESC(kthread_mode, +"Kernel thread mode (default=single):\n" +" single Single kernel thread mode enabled.\n" +" multiple Multiple kernel thread mode enabled.\n" +"\n" +); +