18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2005 - 2016 Broadcom 48c2ecf20Sopenharmony_ci * All rights reserved. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Contact Information: 78c2ecf20Sopenharmony_ci * linux-drivers@emulex.com 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Emulex 108c2ecf20Sopenharmony_ci * 3333 Susan Street 118c2ecf20Sopenharmony_ci * Costa Mesa, CA 92626 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/mutex.h> 158c2ecf20Sopenharmony_ci#include <linux/list.h> 168c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "be.h" 208c2ecf20Sopenharmony_ci#include "be_cmds.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic struct ocrdma_driver *ocrdma_drv; 238c2ecf20Sopenharmony_cistatic LIST_HEAD(be_adapter_list); 248c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(be_adapter_list_lock); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic void _be_roce_dev_add(struct be_adapter *adapter) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci struct be_dev_info dev_info; 298c2ecf20Sopenharmony_ci int i, num_vec; 308c2ecf20Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci if (!ocrdma_drv) 338c2ecf20Sopenharmony_ci return; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci if (ocrdma_drv->be_abi_version != BE_ROCE_ABI_VERSION) { 368c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "Cannot initialize RoCE due to ocrdma ABI mismatch\n"); 378c2ecf20Sopenharmony_ci return; 388c2ecf20Sopenharmony_ci } 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci if (pdev->device == OC_DEVICE_ID5) { 418c2ecf20Sopenharmony_ci /* only msix is supported on these devices */ 428c2ecf20Sopenharmony_ci if (!msix_enabled(adapter)) 438c2ecf20Sopenharmony_ci return; 448c2ecf20Sopenharmony_ci /* DPP region address and length */ 458c2ecf20Sopenharmony_ci dev_info.dpp_unmapped_addr = pci_resource_start(pdev, 2); 468c2ecf20Sopenharmony_ci dev_info.dpp_unmapped_len = pci_resource_len(pdev, 2); 478c2ecf20Sopenharmony_ci } else { 488c2ecf20Sopenharmony_ci dev_info.dpp_unmapped_addr = 0; 498c2ecf20Sopenharmony_ci dev_info.dpp_unmapped_len = 0; 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci dev_info.pdev = adapter->pdev; 528c2ecf20Sopenharmony_ci dev_info.db = adapter->db; 538c2ecf20Sopenharmony_ci dev_info.unmapped_db = adapter->roce_db.io_addr; 548c2ecf20Sopenharmony_ci dev_info.db_page_size = adapter->roce_db.size; 558c2ecf20Sopenharmony_ci dev_info.db_total_size = adapter->roce_db.total_size; 568c2ecf20Sopenharmony_ci dev_info.netdev = adapter->netdev; 578c2ecf20Sopenharmony_ci memcpy(dev_info.mac_addr, adapter->netdev->dev_addr, ETH_ALEN); 588c2ecf20Sopenharmony_ci dev_info.dev_family = adapter->sli_family; 598c2ecf20Sopenharmony_ci if (msix_enabled(adapter)) { 608c2ecf20Sopenharmony_ci /* provide all the vectors, so that EQ creation response 618c2ecf20Sopenharmony_ci * can decide which one to use. 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_ci num_vec = adapter->num_msix_vec + adapter->num_msix_roce_vec; 648c2ecf20Sopenharmony_ci dev_info.intr_mode = BE_INTERRUPT_MODE_MSIX; 658c2ecf20Sopenharmony_ci dev_info.msix.num_vectors = min(num_vec, MAX_MSIX_VECTORS); 668c2ecf20Sopenharmony_ci /* provide start index of the vector, 678c2ecf20Sopenharmony_ci * so in case of linear usage, 688c2ecf20Sopenharmony_ci * it can use the base as starting point. 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_ci dev_info.msix.start_vector = adapter->num_evt_qs; 718c2ecf20Sopenharmony_ci for (i = 0; i < dev_info.msix.num_vectors; i++) { 728c2ecf20Sopenharmony_ci dev_info.msix.vector_list[i] = 738c2ecf20Sopenharmony_ci adapter->msix_entries[i].vector; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci } else { 768c2ecf20Sopenharmony_ci dev_info.msix.num_vectors = 0; 778c2ecf20Sopenharmony_ci dev_info.intr_mode = BE_INTERRUPT_MODE_INTX; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci adapter->ocrdma_dev = ocrdma_drv->add(&dev_info); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_civoid be_roce_dev_add(struct be_adapter *adapter) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci if (be_roce_supported(adapter)) { 858c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adapter->entry); 868c2ecf20Sopenharmony_ci mutex_lock(&be_adapter_list_lock); 878c2ecf20Sopenharmony_ci list_add_tail(&adapter->entry, &be_adapter_list); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /* invoke add() routine of roce driver only if 908c2ecf20Sopenharmony_ci * valid driver registered with add method and add() is not yet 918c2ecf20Sopenharmony_ci * invoked on a given adapter. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_ci _be_roce_dev_add(adapter); 948c2ecf20Sopenharmony_ci mutex_unlock(&be_adapter_list_lock); 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic void _be_roce_dev_remove(struct be_adapter *adapter) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci if (ocrdma_drv && ocrdma_drv->remove && adapter->ocrdma_dev) 1018c2ecf20Sopenharmony_ci ocrdma_drv->remove(adapter->ocrdma_dev); 1028c2ecf20Sopenharmony_ci adapter->ocrdma_dev = NULL; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_civoid be_roce_dev_remove(struct be_adapter *adapter) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci if (be_roce_supported(adapter)) { 1088c2ecf20Sopenharmony_ci mutex_lock(&be_adapter_list_lock); 1098c2ecf20Sopenharmony_ci _be_roce_dev_remove(adapter); 1108c2ecf20Sopenharmony_ci list_del(&adapter->entry); 1118c2ecf20Sopenharmony_ci mutex_unlock(&be_adapter_list_lock); 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_civoid be_roce_dev_shutdown(struct be_adapter *adapter) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci if (be_roce_supported(adapter)) { 1188c2ecf20Sopenharmony_ci mutex_lock(&be_adapter_list_lock); 1198c2ecf20Sopenharmony_ci if (ocrdma_drv && adapter->ocrdma_dev && 1208c2ecf20Sopenharmony_ci ocrdma_drv->state_change_handler) 1218c2ecf20Sopenharmony_ci ocrdma_drv->state_change_handler(adapter->ocrdma_dev, 1228c2ecf20Sopenharmony_ci BE_DEV_SHUTDOWN); 1238c2ecf20Sopenharmony_ci mutex_unlock(&be_adapter_list_lock); 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ciint be_roce_register_driver(struct ocrdma_driver *drv) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci struct be_adapter *dev; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci mutex_lock(&be_adapter_list_lock); 1328c2ecf20Sopenharmony_ci if (ocrdma_drv) { 1338c2ecf20Sopenharmony_ci mutex_unlock(&be_adapter_list_lock); 1348c2ecf20Sopenharmony_ci return -EINVAL; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci ocrdma_drv = drv; 1378c2ecf20Sopenharmony_ci list_for_each_entry(dev, &be_adapter_list, entry) { 1388c2ecf20Sopenharmony_ci _be_roce_dev_add(dev); 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci mutex_unlock(&be_adapter_list_lock); 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(be_roce_register_driver); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_civoid be_roce_unregister_driver(struct ocrdma_driver *drv) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct be_adapter *dev; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci mutex_lock(&be_adapter_list_lock); 1508c2ecf20Sopenharmony_ci list_for_each_entry(dev, &be_adapter_list, entry) { 1518c2ecf20Sopenharmony_ci if (dev->ocrdma_dev) 1528c2ecf20Sopenharmony_ci _be_roce_dev_remove(dev); 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci ocrdma_drv = NULL; 1558c2ecf20Sopenharmony_ci mutex_unlock(&be_adapter_list_lock); 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(be_roce_unregister_driver); 158