xref: /linux/drivers/net/ethernet/broadcom/bnge/bnge_auxr.c (revision 55aa394a5ed871208eac11c5f4677cafd258c4dd)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2025 Broadcom.
3 
4 #include <linux/module.h>
5 
6 #include <linux/kernel.h>
7 #include <linux/errno.h>
8 #include <linux/interrupt.h>
9 #include <linux/pci.h>
10 #include <linux/netdevice.h>
11 #include <linux/rtnetlink.h>
12 #include <linux/bitops.h>
13 #include <linux/irq.h>
14 #include <asm/byteorder.h>
15 #include <linux/bitmap.h>
16 #include <linux/auxiliary_bus.h>
17 #include <linux/bnxt/hsi.h>
18 
19 #include "bnge.h"
20 #include "bnge_hwrm.h"
21 #include "bnge_auxr.h"
22 
23 static DEFINE_IDA(bnge_aux_dev_ids);
24 
bnge_fill_msix_vecs(struct bnge_dev * bd,struct bnge_msix_info * info)25 static void bnge_fill_msix_vecs(struct bnge_dev *bd,
26 				struct bnge_msix_info *info)
27 {
28 	struct bnge_auxr_dev *auxr_dev = bd->auxr_dev;
29 	int num_msix, i;
30 
31 	if (!auxr_dev->auxr_info->msix_requested) {
32 		dev_warn(bd->dev, "Requested MSI-X vectors not allocated\n");
33 		return;
34 	}
35 	num_msix = auxr_dev->auxr_info->msix_requested;
36 	for (i = 0; i < num_msix; i++) {
37 		info[i].vector = bd->irq_tbl[i].vector;
38 		info[i].db_offset = bd->db_offset;
39 		info[i].ring_idx = i;
40 	}
41 }
42 
bnge_register_dev(struct bnge_auxr_dev * auxr_dev,void * handle)43 int bnge_register_dev(struct bnge_auxr_dev *auxr_dev,
44 		      void *handle)
45 {
46 	struct bnge_dev *bd = pci_get_drvdata(auxr_dev->pdev);
47 	struct bnge_auxr_info *auxr_info;
48 	int rc = 0;
49 
50 	netdev_lock(bd->netdev);
51 	mutex_lock(&auxr_dev->auxr_dev_lock);
52 	if (!bd->irq_tbl) {
53 		rc = -ENODEV;
54 		goto exit;
55 	}
56 
57 	if (!bnge_aux_has_enough_resources(bd)) {
58 		rc = -ENOMEM;
59 		goto exit;
60 	}
61 
62 	auxr_info = auxr_dev->auxr_info;
63 	auxr_info->handle = handle;
64 
65 	auxr_info->msix_requested = bd->aux_num_msix;
66 
67 	bnge_fill_msix_vecs(bd, bd->auxr_dev->msix_info);
68 	auxr_dev->flags |= BNGE_ARDEV_MSIX_ALLOC;
69 
70 exit:
71 	mutex_unlock(&auxr_dev->auxr_dev_lock);
72 	netdev_unlock(bd->netdev);
73 	return rc;
74 }
75 EXPORT_SYMBOL(bnge_register_dev);
76 
bnge_unregister_dev(struct bnge_auxr_dev * auxr_dev)77 void bnge_unregister_dev(struct bnge_auxr_dev *auxr_dev)
78 {
79 	struct bnge_dev *bd = pci_get_drvdata(auxr_dev->pdev);
80 	struct bnge_auxr_info *auxr_info;
81 
82 	auxr_info = auxr_dev->auxr_info;
83 	netdev_lock(bd->netdev);
84 	mutex_lock(&auxr_dev->auxr_dev_lock);
85 	if (auxr_info->msix_requested)
86 		auxr_dev->flags &= ~BNGE_ARDEV_MSIX_ALLOC;
87 	auxr_info->msix_requested = 0;
88 
89 	mutex_unlock(&auxr_dev->auxr_dev_lock);
90 	netdev_unlock(bd->netdev);
91 }
92 EXPORT_SYMBOL(bnge_unregister_dev);
93 
bnge_send_msg(struct bnge_auxr_dev * auxr_dev,struct bnge_fw_msg * fw_msg)94 int bnge_send_msg(struct bnge_auxr_dev *auxr_dev, struct bnge_fw_msg *fw_msg)
95 {
96 	struct bnge_dev *bd = pci_get_drvdata(auxr_dev->pdev);
97 	struct output *resp;
98 	struct input *req;
99 	u32 resp_len;
100 	int rc;
101 
102 	rc = bnge_hwrm_req_init(bd, req, 0 /* don't care */);
103 	if (rc)
104 		return rc;
105 
106 	rc = bnge_hwrm_req_replace(bd, req, fw_msg->msg, fw_msg->msg_len);
107 	if (rc)
108 		goto drop_req;
109 
110 	bnge_hwrm_req_timeout(bd, req, fw_msg->timeout);
111 	resp = bnge_hwrm_req_hold(bd, req);
112 	rc = bnge_hwrm_req_send(bd, req);
113 	resp_len = le16_to_cpu(resp->resp_len);
114 	if (resp_len) {
115 		if (fw_msg->resp_max_len < resp_len)
116 			resp_len = fw_msg->resp_max_len;
117 
118 		memcpy(fw_msg->resp, resp, resp_len);
119 	}
120 drop_req:
121 	bnge_hwrm_req_drop(bd, req);
122 	return rc;
123 }
124 EXPORT_SYMBOL(bnge_send_msg);
125 
bnge_rdma_aux_device_uninit(struct bnge_dev * bd)126 void bnge_rdma_aux_device_uninit(struct bnge_dev *bd)
127 {
128 	struct bnge_auxr_priv *aux_priv;
129 	struct auxiliary_device *adev;
130 
131 	/* Skip if no auxiliary device init was done. */
132 	if (!bd->aux_priv)
133 		return;
134 
135 	aux_priv = bd->aux_priv;
136 	adev = &aux_priv->aux_dev;
137 	auxiliary_device_uninit(adev);
138 }
139 
bnge_aux_dev_release(struct device * dev)140 static void bnge_aux_dev_release(struct device *dev)
141 {
142 	struct bnge_auxr_priv *aux_priv =
143 			container_of(dev, struct bnge_auxr_priv, aux_dev.dev);
144 	struct bnge_dev *bd = pci_get_drvdata(aux_priv->auxr_dev->pdev);
145 
146 	ida_free(&bnge_aux_dev_ids, aux_priv->id);
147 	kfree(aux_priv->auxr_dev->auxr_info);
148 	bd->auxr_dev = NULL;
149 	kfree(aux_priv->auxr_dev);
150 	kfree(aux_priv);
151 	bd->aux_priv = NULL;
152 }
153 
bnge_rdma_aux_device_del(struct bnge_dev * bd)154 void bnge_rdma_aux_device_del(struct bnge_dev *bd)
155 {
156 	if (!bd->auxr_dev)
157 		return;
158 
159 	auxiliary_device_delete(&bd->aux_priv->aux_dev);
160 }
161 
bnge_set_auxr_dev_info(struct bnge_auxr_dev * auxr_dev,struct bnge_dev * bd)162 static void bnge_set_auxr_dev_info(struct bnge_auxr_dev *auxr_dev,
163 				   struct bnge_dev *bd)
164 {
165 	auxr_dev->pdev = bd->pdev;
166 	auxr_dev->l2_db_size = bd->db_size;
167 	auxr_dev->l2_db_size_nc = bd->db_size;
168 	auxr_dev->l2_db_offset = bd->db_offset;
169 	mutex_init(&auxr_dev->auxr_dev_lock);
170 
171 	if (bd->flags & BNGE_EN_ROCE_V1)
172 		auxr_dev->flags |= BNGE_ARDEV_ROCEV1_SUPP;
173 	if (bd->flags & BNGE_EN_ROCE_V2)
174 		auxr_dev->flags |= BNGE_ARDEV_ROCEV2_SUPP;
175 
176 	auxr_dev->chip_num = bd->chip_num;
177 	auxr_dev->hw_ring_stats_size = bd->hw_ring_stats_size;
178 	auxr_dev->pf_port_id = bd->pf.port_id;
179 	auxr_dev->en_state = bd->state;
180 	auxr_dev->bar0 = bd->bar0;
181 }
182 
bnge_rdma_aux_device_add(struct bnge_dev * bd)183 void bnge_rdma_aux_device_add(struct bnge_dev *bd)
184 {
185 	struct auxiliary_device *aux_dev;
186 	int rc;
187 
188 	if (!bd->auxr_dev)
189 		return;
190 
191 	aux_dev = &bd->aux_priv->aux_dev;
192 	rc = auxiliary_device_add(aux_dev);
193 	if (rc) {
194 		dev_warn(bd->dev, "Failed to add auxiliary device for ROCE\n");
195 		auxiliary_device_uninit(aux_dev);
196 		bd->flags &= ~BNGE_EN_ROCE;
197 	}
198 
199 	bd->auxr_dev->net = bd->netdev;
200 }
201 
bnge_rdma_aux_device_init(struct bnge_dev * bd)202 void bnge_rdma_aux_device_init(struct bnge_dev *bd)
203 {
204 	struct auxiliary_device *aux_dev;
205 	struct bnge_auxr_info *auxr_info;
206 	struct bnge_auxr_priv *aux_priv;
207 	struct bnge_auxr_dev *auxr_dev;
208 	int rc;
209 
210 	if (!bnge_is_roce_en(bd))
211 		return;
212 
213 	aux_priv = kzalloc(sizeof(*aux_priv), GFP_KERNEL);
214 	if (!aux_priv)
215 		goto exit;
216 
217 	aux_priv->id = ida_alloc(&bnge_aux_dev_ids, GFP_KERNEL);
218 	if (aux_priv->id < 0) {
219 		dev_warn(bd->dev, "ida alloc failed for aux device\n");
220 		kfree(aux_priv);
221 		goto exit;
222 	}
223 
224 	aux_dev = &aux_priv->aux_dev;
225 	aux_dev->id = aux_priv->id;
226 	aux_dev->name = "rdma";
227 	aux_dev->dev.parent = &bd->pdev->dev;
228 	aux_dev->dev.release = bnge_aux_dev_release;
229 
230 	rc = auxiliary_device_init(aux_dev);
231 	if (rc) {
232 		ida_free(&bnge_aux_dev_ids, aux_priv->id);
233 		kfree(aux_priv);
234 		goto exit;
235 	}
236 	bd->aux_priv = aux_priv;
237 
238 	auxr_dev = kzalloc(sizeof(*auxr_dev), GFP_KERNEL);
239 	if (!auxr_dev)
240 		goto aux_dev_uninit;
241 
242 	aux_priv->auxr_dev = auxr_dev;
243 
244 	auxr_info = kzalloc(sizeof(*auxr_info), GFP_KERNEL);
245 	if (!auxr_info)
246 		goto aux_dev_uninit;
247 
248 	auxr_dev->auxr_info = auxr_info;
249 	bd->auxr_dev = auxr_dev;
250 	bnge_set_auxr_dev_info(auxr_dev, bd);
251 
252 	return;
253 
254 aux_dev_uninit:
255 	auxiliary_device_uninit(aux_dev);
256 exit:
257 	bd->flags &= ~BNGE_EN_ROCE;
258 }
259