Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / net / ethernet / emulex / benet / be_roce.c
diff --git a/kernel/drivers/net/ethernet/emulex/benet/be_roce.c b/kernel/drivers/net/ethernet/emulex/benet/be_roce.c
new file mode 100644 (file)
index 0000000..1328664
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2005 - 2014 Emulex
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+ * linux-drivers@emulex.com
+ *
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
+ */
+
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/module.h>
+
+#include "be.h"
+#include "be_cmds.h"
+
+static struct ocrdma_driver *ocrdma_drv;
+static LIST_HEAD(be_adapter_list);
+static DEFINE_MUTEX(be_adapter_list_lock);
+
+static void _be_roce_dev_add(struct be_adapter *adapter)
+{
+       struct be_dev_info dev_info;
+       int i, num_vec;
+       struct pci_dev *pdev = adapter->pdev;
+
+       if (!ocrdma_drv)
+               return;
+
+       if (ocrdma_drv->be_abi_version != BE_ROCE_ABI_VERSION) {
+               dev_warn(&pdev->dev, "Cannot initialize RoCE due to ocrdma ABI mismatch\n");
+               return;
+       }
+
+       if (pdev->device == OC_DEVICE_ID5) {
+               /* only msix is supported on these devices */
+               if (!msix_enabled(adapter))
+                       return;
+               /* DPP region address and length */
+               dev_info.dpp_unmapped_addr = pci_resource_start(pdev, 2);
+               dev_info.dpp_unmapped_len = pci_resource_len(pdev, 2);
+       } else {
+               dev_info.dpp_unmapped_addr = 0;
+               dev_info.dpp_unmapped_len = 0;
+       }
+       dev_info.pdev = adapter->pdev;
+       dev_info.db = adapter->db;
+       dev_info.unmapped_db = adapter->roce_db.io_addr;
+       dev_info.db_page_size = adapter->roce_db.size;
+       dev_info.db_total_size = adapter->roce_db.total_size;
+       dev_info.netdev = adapter->netdev;
+       memcpy(dev_info.mac_addr, adapter->netdev->dev_addr, ETH_ALEN);
+       dev_info.dev_family = adapter->sli_family;
+       if (msix_enabled(adapter)) {
+               /* provide all the vectors, so that EQ creation response
+                * can decide which one to use.
+                */
+               num_vec = adapter->num_msix_vec + adapter->num_msix_roce_vec;
+               dev_info.intr_mode = BE_INTERRUPT_MODE_MSIX;
+               dev_info.msix.num_vectors = min(num_vec, MAX_MSIX_VECTORS);
+               /* provide start index of the vector,
+                * so in case of linear usage,
+                * it can use the base as starting point.
+                */
+               dev_info.msix.start_vector = adapter->num_evt_qs;
+               for (i = 0; i < dev_info.msix.num_vectors; i++) {
+                       dev_info.msix.vector_list[i] =
+                           adapter->msix_entries[i].vector;
+               }
+       } else {
+               dev_info.msix.num_vectors = 0;
+               dev_info.intr_mode = BE_INTERRUPT_MODE_INTX;
+       }
+       adapter->ocrdma_dev = ocrdma_drv->add(&dev_info);
+}
+
+void be_roce_dev_add(struct be_adapter *adapter)
+{
+       if (be_roce_supported(adapter)) {
+               INIT_LIST_HEAD(&adapter->entry);
+               mutex_lock(&be_adapter_list_lock);
+               list_add_tail(&adapter->entry, &be_adapter_list);
+
+               /* invoke add() routine of roce driver only if
+                * valid driver registered with add method and add() is not yet
+                * invoked on a given adapter.
+                */
+               _be_roce_dev_add(adapter);
+               mutex_unlock(&be_adapter_list_lock);
+       }
+}
+
+static void _be_roce_dev_remove(struct be_adapter *adapter)
+{
+       if (ocrdma_drv && ocrdma_drv->remove && adapter->ocrdma_dev)
+               ocrdma_drv->remove(adapter->ocrdma_dev);
+       adapter->ocrdma_dev = NULL;
+}
+
+void be_roce_dev_remove(struct be_adapter *adapter)
+{
+       if (be_roce_supported(adapter)) {
+               mutex_lock(&be_adapter_list_lock);
+               _be_roce_dev_remove(adapter);
+               list_del(&adapter->entry);
+               mutex_unlock(&be_adapter_list_lock);
+       }
+}
+
+static void _be_roce_dev_open(struct be_adapter *adapter)
+{
+       if (ocrdma_drv && adapter->ocrdma_dev &&
+           ocrdma_drv->state_change_handler)
+               ocrdma_drv->state_change_handler(adapter->ocrdma_dev,
+                                                BE_DEV_UP);
+}
+
+void be_roce_dev_open(struct be_adapter *adapter)
+{
+       if (be_roce_supported(adapter)) {
+               mutex_lock(&be_adapter_list_lock);
+               _be_roce_dev_open(adapter);
+               mutex_unlock(&be_adapter_list_lock);
+       }
+}
+
+static void _be_roce_dev_close(struct be_adapter *adapter)
+{
+       if (ocrdma_drv && adapter->ocrdma_dev &&
+           ocrdma_drv->state_change_handler)
+               ocrdma_drv->state_change_handler(adapter->ocrdma_dev,
+                                                BE_DEV_DOWN);
+}
+
+void be_roce_dev_close(struct be_adapter *adapter)
+{
+       if (be_roce_supported(adapter)) {
+               mutex_lock(&be_adapter_list_lock);
+               _be_roce_dev_close(adapter);
+               mutex_unlock(&be_adapter_list_lock);
+       }
+}
+
+void be_roce_dev_shutdown(struct be_adapter *adapter)
+{
+       if (be_roce_supported(adapter)) {
+               mutex_lock(&be_adapter_list_lock);
+               if (ocrdma_drv && adapter->ocrdma_dev &&
+                   ocrdma_drv->state_change_handler)
+                       ocrdma_drv->state_change_handler(adapter->ocrdma_dev,
+                                                        BE_DEV_SHUTDOWN);
+               mutex_unlock(&be_adapter_list_lock);
+       }
+}
+
+int be_roce_register_driver(struct ocrdma_driver *drv)
+{
+       struct be_adapter *dev;
+
+       mutex_lock(&be_adapter_list_lock);
+       if (ocrdma_drv) {
+               mutex_unlock(&be_adapter_list_lock);
+               return -EINVAL;
+       }
+       ocrdma_drv = drv;
+       list_for_each_entry(dev, &be_adapter_list, entry) {
+               struct net_device *netdev;
+
+               _be_roce_dev_add(dev);
+               netdev = dev->netdev;
+               if (netif_running(netdev) && netif_oper_up(netdev))
+                       _be_roce_dev_open(dev);
+       }
+       mutex_unlock(&be_adapter_list_lock);
+       return 0;
+}
+EXPORT_SYMBOL(be_roce_register_driver);
+
+void be_roce_unregister_driver(struct ocrdma_driver *drv)
+{
+       struct be_adapter *dev;
+
+       mutex_lock(&be_adapter_list_lock);
+       list_for_each_entry(dev, &be_adapter_list, entry) {
+               if (dev->ocrdma_dev)
+                       _be_roce_dev_remove(dev);
+       }
+       ocrdma_drv = NULL;
+       mutex_unlock(&be_adapter_list_lock);
+}
+EXPORT_SYMBOL(be_roce_unregister_driver);