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