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