X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Flibrte_eal%2Flinuxapp%2Fkni%2Fkni_misc.c;h=1c085d93cb5bd931833918ee820565caaee849bb;hb=3031749c2df04a63cdcef186dcce3781e61436e8;hp=9adf697144ba57ad0865aeb4254202dd69ad9634;hpb=fbf895d44cfebf7bd92bb4edf3f7ff15365e57a5;p=dpdk.git diff --git a/lib/librte_eal/linuxapp/kni/kni_misc.c b/lib/librte_eal/linuxapp/kni/kni_misc.c index 9adf697144..1c085d93cb 100644 --- a/lib/librte_eal/linuxapp/kni/kni_misc.c +++ b/lib/librte_eal/linuxapp/kni/kni_misc.c @@ -1,23 +1,23 @@ /*- * 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 * published by the Free Software Foundation. - * + * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * The full GNU General Public License is included in this distribution * in the file called LICENSE.GPL. - * + * * Contact Information: * Intel Corporation */ @@ -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,55 @@ 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) { @@ -237,6 +324,16 @@ 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) { @@ -258,6 +355,7 @@ kni_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param) kni->net_dev = net_dev; 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 */ @@ -274,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", @@ -352,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); @@ -388,20 +511,15 @@ kni_ioctl_release(unsigned int ioctl_num, unsigned long ioctl_param) 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; @@ -466,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" +); +