| /* | |
| * Copyright (C) 2005 - 2016 Broadcom | |
| * 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); | |
| } | |
| } | |
| 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) { | |
| _be_roce_dev_add(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); |