1 /* 2 * Copyright (C) 2005 - 2013 Emulex 3 * All rights reserved. 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License version 2 7 * as published by the Free Software Foundation. The full GNU General 8 * Public License is included in this distribution in the file called COPYING. 9 * 10 * Contact Information: 11 * linux-drivers@emulex.com 12 * 13 * Emulex 14 * 3333 Susan Street 15 * Costa Mesa, CA 92626 16 */ 17 18 #include <linux/mutex.h> 19 #include <linux/list.h> 20 #include <linux/netdevice.h> 21 #include <linux/module.h> 22 23 #include "be.h" 24 #include "be_cmds.h" 25 26 static struct ocrdma_driver *ocrdma_drv; 27 static LIST_HEAD(be_adapter_list); 28 static DEFINE_MUTEX(be_adapter_list_lock); 29 30 static void _be_roce_dev_add(struct be_adapter *adapter) 31 { 32 struct be_dev_info dev_info; 33 int i, num_vec; 34 struct pci_dev *pdev = adapter->pdev; 35 36 if (!ocrdma_drv) 37 return; 38 if (pdev->device == OC_DEVICE_ID5) { 39 /* only msix is supported on these devices */ 40 if (!msix_enabled(adapter)) 41 return; 42 /* DPP region address and length */ 43 dev_info.dpp_unmapped_addr = pci_resource_start(pdev, 2); 44 dev_info.dpp_unmapped_len = pci_resource_len(pdev, 2); 45 } else { 46 dev_info.dpp_unmapped_addr = 0; 47 dev_info.dpp_unmapped_len = 0; 48 } 49 dev_info.pdev = adapter->pdev; 50 dev_info.db = adapter->db; 51 dev_info.unmapped_db = adapter->roce_db.io_addr; 52 dev_info.db_page_size = adapter->roce_db.size; 53 dev_info.db_total_size = adapter->roce_db.total_size; 54 dev_info.netdev = adapter->netdev; 55 memcpy(dev_info.mac_addr, adapter->netdev->dev_addr, ETH_ALEN); 56 dev_info.dev_family = adapter->sli_family; 57 if (msix_enabled(adapter)) { 58 /* provide all the vectors, so that EQ creation response 59 * can decide which one to use. 60 */ 61 num_vec = adapter->num_msix_vec + adapter->num_msix_roce_vec; 62 dev_info.intr_mode = BE_INTERRUPT_MODE_MSIX; 63 dev_info.msix.num_vectors = min(num_vec, MAX_MSIX_VECTORS); 64 /* provide start index of the vector, 65 * so in case of linear usage, 66 * it can use the base as starting point. 67 */ 68 dev_info.msix.start_vector = adapter->num_evt_qs; 69 for (i = 0; i < dev_info.msix.num_vectors; i++) { 70 dev_info.msix.vector_list[i] = 71 adapter->msix_entries[i].vector; 72 } 73 } else { 74 dev_info.msix.num_vectors = 0; 75 dev_info.intr_mode = BE_INTERRUPT_MODE_INTX; 76 } 77 adapter->ocrdma_dev = ocrdma_drv->add(&dev_info); 78 } 79 80 void be_roce_dev_add(struct be_adapter *adapter) 81 { 82 if (be_roce_supported(adapter)) { 83 INIT_LIST_HEAD(&adapter->entry); 84 mutex_lock(&be_adapter_list_lock); 85 list_add_tail(&adapter->entry, &be_adapter_list); 86 87 /* invoke add() routine of roce driver only if 88 * valid driver registered with add method and add() is not yet 89 * invoked on a given adapter. 90 */ 91 _be_roce_dev_add(adapter); 92 mutex_unlock(&be_adapter_list_lock); 93 } 94 } 95 96 static void _be_roce_dev_remove(struct be_adapter *adapter) 97 { 98 if (ocrdma_drv && ocrdma_drv->remove && adapter->ocrdma_dev) 99 ocrdma_drv->remove(adapter->ocrdma_dev); 100 adapter->ocrdma_dev = NULL; 101 } 102 103 void be_roce_dev_remove(struct be_adapter *adapter) 104 { 105 if (be_roce_supported(adapter)) { 106 mutex_lock(&be_adapter_list_lock); 107 _be_roce_dev_remove(adapter); 108 list_del(&adapter->entry); 109 mutex_unlock(&be_adapter_list_lock); 110 } 111 } 112 113 static void _be_roce_dev_open(struct be_adapter *adapter) 114 { 115 if (ocrdma_drv && adapter->ocrdma_dev && 116 ocrdma_drv->state_change_handler) 117 ocrdma_drv->state_change_handler(adapter->ocrdma_dev, 0); 118 } 119 120 void be_roce_dev_open(struct be_adapter *adapter) 121 { 122 if (be_roce_supported(adapter)) { 123 mutex_lock(&be_adapter_list_lock); 124 _be_roce_dev_open(adapter); 125 mutex_unlock(&be_adapter_list_lock); 126 } 127 } 128 129 static void _be_roce_dev_close(struct be_adapter *adapter) 130 { 131 if (ocrdma_drv && adapter->ocrdma_dev && 132 ocrdma_drv->state_change_handler) 133 ocrdma_drv->state_change_handler(adapter->ocrdma_dev, 1); 134 } 135 136 void be_roce_dev_close(struct be_adapter *adapter) 137 { 138 if (be_roce_supported(adapter)) { 139 mutex_lock(&be_adapter_list_lock); 140 _be_roce_dev_close(adapter); 141 mutex_unlock(&be_adapter_list_lock); 142 } 143 } 144 145 int be_roce_register_driver(struct ocrdma_driver *drv) 146 { 147 struct be_adapter *dev; 148 149 mutex_lock(&be_adapter_list_lock); 150 if (ocrdma_drv) { 151 mutex_unlock(&be_adapter_list_lock); 152 return -EINVAL; 153 } 154 ocrdma_drv = drv; 155 list_for_each_entry(dev, &be_adapter_list, entry) { 156 struct net_device *netdev; 157 _be_roce_dev_add(dev); 158 netdev = dev->netdev; 159 if (netif_running(netdev) && netif_oper_up(netdev)) 160 _be_roce_dev_open(dev); 161 } 162 mutex_unlock(&be_adapter_list_lock); 163 return 0; 164 } 165 EXPORT_SYMBOL(be_roce_register_driver); 166 167 void be_roce_unregister_driver(struct ocrdma_driver *drv) 168 { 169 struct be_adapter *dev; 170 171 mutex_lock(&be_adapter_list_lock); 172 list_for_each_entry(dev, &be_adapter_list, entry) { 173 if (dev->ocrdma_dev) 174 _be_roce_dev_remove(dev); 175 } 176 ocrdma_drv = NULL; 177 mutex_unlock(&be_adapter_list_lock); 178 } 179 EXPORT_SYMBOL(be_roce_unregister_driver); 180