X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;ds=sidebyside;f=kernel%2Flinux%2Fkni%2Fkni_misc.c;h=ec7019004296c2836d6a3ba6a493a6cd055d23af;hb=f1b2991c3c0f480fe8e9f6c5c640a1d913b76bed;hp=04c78eb8745c64d0137598863b5a1ca503613500;hpb=ff1e35fb5f8330f89d13f58c9fb767b5bd188940;p=dpdk.git diff --git a/kernel/linux/kni/kni_misc.c b/kernel/linux/kni/kni_misc.c index 04c78eb874..ec70190042 100644 --- a/kernel/linux/kni/kni_misc.c +++ b/kernel/linux/kni/kni_misc.c @@ -16,11 +16,12 @@ #include #include -#include +#include #include "compat.h" #include "kni_dev.h" +MODULE_VERSION(KNI_VERSION); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Intel Corporation"); MODULE_DESCRIPTION("Kernel Module for managing kni devices"); @@ -29,9 +30,6 @@ MODULE_DESCRIPTION("Kernel Module for managing kni devices"); #define KNI_MAX_DEVICES 32 -extern const struct pci_device_id ixgbe_pci_tbl[]; -extern const struct pci_device_id igb_pci_tbl[]; - /* loopback mode */ static char *lo_mode; @@ -41,7 +39,15 @@ static uint32_t multiple_kthread_on; /* Default carrier state for created KNI network interfaces */ static char *carrier; -uint32_t dflt_carrier; +uint32_t kni_dflt_carrier; + +/* Request processing support for bifurcated drivers. */ +static char *enable_bifurcated; +uint32_t bifurcated_support; + +/* KNI thread scheduling interval */ +static long min_scheduling_interval = 100; /* us */ +static long max_scheduling_interval = 200; /* us */ #define KNI_DEV_IN_USE_BIT_NUM 0 /* Bit number for device in use */ @@ -130,11 +136,8 @@ kni_thread_single(void *data) } } up_read(&knet->kni_list_lock); -#ifdef RTE_KNI_PREEMPT_DEFAULT /* reschedule out for a while */ - schedule_timeout_interruptible( - usecs_to_jiffies(KNI_KTHREAD_RESCHEDULE_INTERVAL)); -#endif + usleep_range(min_scheduling_interval, max_scheduling_interval); } return 0; @@ -151,10 +154,7 @@ kni_thread_multiple(void *param) kni_net_rx(dev); kni_net_poll_resp(dev); } -#ifdef RTE_KNI_PREEMPT_DEFAULT - schedule_timeout_interruptible( - usecs_to_jiffies(KNI_KTHREAD_RESCHEDULE_INTERVAL)); -#endif + usleep_range(min_scheduling_interval, max_scheduling_interval); } return 0; @@ -182,15 +182,6 @@ kni_dev_remove(struct kni_dev *dev) if (!dev) return -ENODEV; -#ifdef RTE_KNI_KMOD_ETHTOOL - if (dev->pci_dev) { - if (pci_match_id(ixgbe_pci_tbl, dev->pci_dev)) - ixgbe_kni_remove(dev->pci_dev); - else if (pci_match_id(igb_pci_tbl, dev->pci_dev)) - igb_kni_remove(dev->pci_dev); - } -#endif - if (dev->net_dev) { unregister_netdev(dev->net_dev); free_netdev(dev->net_dev); @@ -306,11 +297,6 @@ kni_ioctl_create(struct net *net, uint32_t ioctl_num, struct rte_kni_device_info dev_info; struct net_device *net_dev = NULL; struct kni_dev *kni, *dev, *n; -#ifdef RTE_KNI_KMOD_ETHTOOL - struct pci_dev *found_pci = NULL; - struct net_device *lad_dev = NULL; - struct pci_dev *pci = NULL; -#endif pr_info("Creating kni...\n"); /* Check the buffer size, to avoid warning */ @@ -318,11 +304,8 @@ kni_ioctl_create(struct net *net, uint32_t ioctl_num, return -EINVAL; /* Copy kni info from user space */ - ret = copy_from_user(&dev_info, (void *)ioctl_param, sizeof(dev_info)); - if (ret) { - pr_err("copy_from_user in kni_ioctl_create"); - return -EIO; - } + if (copy_from_user(&dev_info, (void *)ioctl_param, sizeof(dev_info))) + return -EFAULT; /* Check if name is zero-ended */ if (strnlen(dev_info.name, sizeof(dev_info.name)) == sizeof(dev_info.name)) { @@ -363,20 +346,40 @@ kni_ioctl_create(struct net *net, uint32_t ioctl_num, kni = netdev_priv(net_dev); 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 */ - kni->tx_q = phys_to_virt(dev_info.tx_phys); - kni->rx_q = phys_to_virt(dev_info.rx_phys); - kni->alloc_q = phys_to_virt(dev_info.alloc_phys); - kni->free_q = phys_to_virt(dev_info.free_phys); + if (dev_info.iova_mode) { +#ifdef HAVE_IOVA_TO_KVA_MAPPING_SUPPORT + kni->tx_q = iova_to_kva(current, dev_info.tx_phys); + kni->rx_q = iova_to_kva(current, dev_info.rx_phys); + kni->alloc_q = iova_to_kva(current, dev_info.alloc_phys); + kni->free_q = iova_to_kva(current, dev_info.free_phys); + + kni->req_q = iova_to_kva(current, dev_info.req_phys); + kni->resp_q = iova_to_kva(current, dev_info.resp_phys); + kni->sync_va = dev_info.sync_va; + kni->sync_kva = iova_to_kva(current, dev_info.sync_phys); + kni->usr_tsk = current; + kni->iova_mode = 1; +#else + pr_err("KNI module does not support IOVA to VA translation\n"); + return -EINVAL; +#endif + } else { - kni->req_q = phys_to_virt(dev_info.req_phys); - kni->resp_q = phys_to_virt(dev_info.resp_phys); - kni->sync_va = dev_info.sync_va; - kni->sync_kva = phys_to_virt(dev_info.sync_phys); + kni->tx_q = phys_to_virt(dev_info.tx_phys); + kni->rx_q = phys_to_virt(dev_info.rx_phys); + kni->alloc_q = phys_to_virt(dev_info.alloc_phys); + kni->free_q = phys_to_virt(dev_info.free_phys); + + kni->req_q = phys_to_virt(dev_info.req_phys); + kni->resp_q = phys_to_virt(dev_info.resp_phys); + kni->sync_va = dev_info.sync_va; + kni->sync_kva = phys_to_virt(dev_info.sync_phys); + kni->iova_mode = 0; + } kni->mbuf_size = dev_info.mbuf_size; @@ -394,73 +397,23 @@ kni_ioctl_create(struct net *net, uint32_t ioctl_num, (unsigned long long) dev_info.resp_phys, kni->resp_q); pr_debug("mbuf_size: %u\n", kni->mbuf_size); - pr_debug("PCI: %02x:%02x.%02x %04x:%04x\n", - dev_info.bus, - dev_info.devid, - dev_info.function, - dev_info.vendor_id, - dev_info.device_id); -#ifdef RTE_KNI_KMOD_ETHTOOL - pci = pci_get_device(dev_info.vendor_id, dev_info.device_id, NULL); - - /* Support Ethtool */ - while (pci) { - pr_debug("pci_bus: %02x:%02x:%02x\n", - pci->bus->number, - PCI_SLOT(pci->devfn), - PCI_FUNC(pci->devfn)); - - if ((pci->bus->number == dev_info.bus) && - (PCI_SLOT(pci->devfn) == dev_info.devid) && - (PCI_FUNC(pci->devfn) == dev_info.function)) { - found_pci = pci; - - if (pci_match_id(ixgbe_pci_tbl, found_pci)) - ret = ixgbe_kni_probe(found_pci, &lad_dev); - else if (pci_match_id(igb_pci_tbl, found_pci)) - ret = igb_kni_probe(found_pci, &lad_dev); - else - ret = -1; - - pr_debug("PCI found: pci=0x%p, lad_dev=0x%p\n", - pci, lad_dev); - if (ret == 0) { - kni->lad_dev = lad_dev; - kni_set_ethtool_ops(kni->net_dev); - } else { - pr_err("Device not supported by ethtool"); - kni->lad_dev = NULL; - } - - kni->pci_dev = found_pci; - kni->device_id = dev_info.device_id; - break; - } - pci = pci_get_device(dev_info.vendor_id, - dev_info.device_id, pci); - } - if (pci) - pci_dev_put(pci); -#endif - - if (kni->lad_dev) - ether_addr_copy(net_dev->dev_addr, kni->lad_dev->dev_addr); - else { - /* if user has provided a valid mac address */ - if (is_valid_ether_addr((unsigned char *)(dev_info.mac_addr))) - memcpy(net_dev->dev_addr, dev_info.mac_addr, ETH_ALEN); - else - /* - * Generate random mac address. eth_random_addr() is the - * newer version of generating mac address in kernel. - */ - random_ether_addr(net_dev->dev_addr); - } + /* if user has provided a valid mac address */ + if (is_valid_ether_addr(dev_info.mac_addr)) + memcpy(net_dev->dev_addr, dev_info.mac_addr, ETH_ALEN); + else + /* Generate random MAC address. */ + eth_random_addr(net_dev->dev_addr); if (dev_info.mtu) net_dev->mtu = dev_info.mtu; #ifdef HAVE_MAX_MTU_PARAM net_dev->max_mtu = net_dev->mtu; + + if (dev_info.min_mtu) + net_dev->min_mtu = dev_info.min_mtu; + + if (dev_info.max_mtu) + net_dev->max_mtu = dev_info.max_mtu; #endif ret = register_netdev(net_dev); @@ -498,15 +451,12 @@ kni_ioctl_release(struct net *net, uint32_t ioctl_num, if (_IOC_SIZE(ioctl_num) > sizeof(dev_info)) return -EINVAL; - ret = copy_from_user(&dev_info, (void *)ioctl_param, sizeof(dev_info)); - if (ret) { - pr_err("copy_from_user in kni_ioctl_release"); - return -EIO; - } + if (copy_from_user(&dev_info, (void *)ioctl_param, sizeof(dev_info))) + return -EFAULT; /* Release the network device according to its name */ if (strlen(dev_info.name) == 0) - return ret; + return -EINVAL; down_write(&knet->kni_list_lock); list_for_each_entry_safe(dev, n, &knet->kni_list_head, list) { @@ -530,10 +480,10 @@ kni_ioctl_release(struct net *net, uint32_t ioctl_num, return ret; } -static int -kni_ioctl(struct inode *inode, uint32_t ioctl_num, unsigned long ioctl_param) +static long +kni_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param) { - int ret = -EINVAL; + long ret = -EINVAL; struct net *net = current->nsproxy->net_ns; pr_debug("IOCTL num=0x%0x param=0x%0lx\n", ioctl_num, ioctl_param); @@ -559,8 +509,8 @@ kni_ioctl(struct inode *inode, uint32_t ioctl_num, unsigned long ioctl_param) return ret; } -static int -kni_compat_ioctl(struct inode *inode, uint32_t ioctl_num, +static long +kni_compat_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param) { /* 32 bits app on 64 bits OS to be supported later */ @@ -573,8 +523,8 @@ static const struct file_operations kni_fops = { .owner = THIS_MODULE, .open = kni_open, .release = kni_release, - .unlocked_ioctl = (void *)kni_ioctl, - .compat_ioctl = (void *)kni_compat_ioctl, + .unlocked_ioctl = kni_ioctl, + .compat_ioctl = kni_compat_ioctl, }; static struct miscdevice kni_misc = { @@ -603,14 +553,30 @@ static int __init kni_parse_carrier_state(void) { if (!carrier) { - dflt_carrier = 0; + kni_dflt_carrier = 0; return 0; } if (strcmp(carrier, "off") == 0) - dflt_carrier = 0; + kni_dflt_carrier = 0; else if (strcmp(carrier, "on") == 0) - dflt_carrier = 1; + kni_dflt_carrier = 1; + else + return -1; + + return 0; +} + +static int __init +kni_parse_bifurcated_support(void) +{ + if (!enable_bifurcated) { + bifurcated_support = 0; + return 0; + } + + if (strcmp(enable_bifurcated, "on") == 0) + bifurcated_support = 1; else return -1; @@ -637,11 +603,26 @@ kni_init(void) return -EINVAL; } - if (dflt_carrier == 0) + if (kni_dflt_carrier == 0) pr_debug("Default carrier state set to off.\n"); else pr_debug("Default carrier state set to on.\n"); + if (kni_parse_bifurcated_support() < 0) { + pr_err("Invalid parameter for bifurcated support\n"); + return -EINVAL; + } + if (bifurcated_support == 1) + pr_debug("bifurcated support is enabled.\n"); + + if (min_scheduling_interval < 0 || max_scheduling_interval < 0 || + min_scheduling_interval > KNI_KTHREAD_MAX_RESCHEDULE_INTERVAL || + max_scheduling_interval > KNI_KTHREAD_MAX_RESCHEDULE_INTERVAL || + min_scheduling_interval >= max_scheduling_interval) { + pr_err("Invalid parameters for scheduling interval\n"); + return -EINVAL; + } + #ifdef HAVE_SIMPLIFIED_PERNET_OPERATIONS rc = register_pernet_subsys(&kni_net_ops); #else @@ -708,3 +689,22 @@ MODULE_PARM_DESC(carrier, "\t\ton Interfaces will be created with carrier state set to on.\n" "\t\t" ); + +module_param(enable_bifurcated, charp, 0644); +MODULE_PARM_DESC(enable_bifurcated, +"Enable request processing support for bifurcated drivers, " +"which means releasing rtnl_lock before calling userspace callback and " +"supporting async requests (default=off):\n" +"\t\ton Enable request processing support for bifurcated drivers.\n" +"\t\t" +); + +module_param(min_scheduling_interval, long, 0644); +MODULE_PARM_DESC(min_scheduling_interval, +"KNI thread min scheduling interval (default=100 microseconds)" +); + +module_param(max_scheduling_interval, long, 0644); +MODULE_PARM_DESC(max_scheduling_interval, +"KNI thread max scheduling interval (default=200 microseconds)" +);