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