]> git.proxmox.com Git - mirror_ubuntu-disco-kernel.git/blame - drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
bnxt_en: Fix possible BUG() condition when calling pci_disable_msix().
[mirror_ubuntu-disco-kernel.git] / drivers / net / ethernet / broadcom / bnxt / bnxt_ulp.c
CommitLineData
a588e458
MC
1/* Broadcom NetXtreme-C/E network driver.
2 *
ec86f14e 3 * Copyright (c) 2016-2018 Broadcom Limited
a588e458
MC
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation.
8 */
9
10#include <linux/module.h>
11
12#include <linux/kernel.h>
13#include <linux/errno.h>
14#include <linux/interrupt.h>
15#include <linux/pci.h>
16#include <linux/netdevice.h>
17#include <linux/rtnetlink.h>
18#include <linux/bitops.h>
19#include <linux/irq.h>
20#include <asm/byteorder.h>
21#include <linux/bitmap.h>
22
23#include "bnxt_hsi.h"
24#include "bnxt.h"
25#include "bnxt_ulp.h"
26
27static int bnxt_register_dev(struct bnxt_en_dev *edev, int ulp_id,
28 struct bnxt_ulp_ops *ulp_ops, void *handle)
29{
30 struct net_device *dev = edev->net;
31 struct bnxt *bp = netdev_priv(dev);
32 struct bnxt_ulp *ulp;
33
34 ASSERT_RTNL();
35 if (ulp_id >= BNXT_MAX_ULP)
36 return -EINVAL;
37
38 ulp = &edev->ulp_tbl[ulp_id];
39 if (rcu_access_pointer(ulp->ulp_ops)) {
40 netdev_err(bp->dev, "ulp id %d already registered\n", ulp_id);
41 return -EBUSY;
42 }
43 if (ulp_id == BNXT_ROCE_ULP) {
44 unsigned int max_stat_ctxs;
45
addd4df6
MC
46 if (bp->flags & BNXT_FLAG_CHIP_P5)
47 return -EOPNOTSUPP;
48
a588e458
MC
49 max_stat_ctxs = bnxt_get_max_func_stat_ctxs(bp);
50 if (max_stat_ctxs <= BNXT_MIN_ROCE_STAT_CTXS ||
c027c6b4 51 bp->cp_nr_rings == max_stat_ctxs)
a588e458 52 return -ENOMEM;
a588e458
MC
53 }
54
55 atomic_set(&ulp->ref_count, 0);
56 ulp->handle = handle;
57 rcu_assign_pointer(ulp->ulp_ops, ulp_ops);
58
59 if (ulp_id == BNXT_ROCE_ULP) {
60 if (test_bit(BNXT_STATE_OPEN, &bp->state))
61 bnxt_hwrm_vnic_cfg(bp, 0);
62 }
63
64 return 0;
65}
66
67static int bnxt_unregister_dev(struct bnxt_en_dev *edev, int ulp_id)
68{
69 struct net_device *dev = edev->net;
70 struct bnxt *bp = netdev_priv(dev);
71 struct bnxt_ulp *ulp;
72 int i = 0;
73
74 ASSERT_RTNL();
75 if (ulp_id >= BNXT_MAX_ULP)
76 return -EINVAL;
77
78 ulp = &edev->ulp_tbl[ulp_id];
79 if (!rcu_access_pointer(ulp->ulp_ops)) {
80 netdev_err(bp->dev, "ulp id %d not registered\n", ulp_id);
81 return -EINVAL;
82 }
f4e89614
VV
83 if (ulp_id == BNXT_ROCE_ULP && ulp->msix_requested)
84 edev->en_ops->bnxt_free_msix(edev, ulp_id);
a588e458 85
a588e458
MC
86 if (ulp->max_async_event_id)
87 bnxt_hwrm_func_rgtr_async_events(bp, NULL, 0);
88
89 RCU_INIT_POINTER(ulp->ulp_ops, NULL);
90 synchronize_rcu();
91 ulp->max_async_event_id = 0;
92 ulp->async_events_bmap = NULL;
93 while (atomic_read(&ulp->ref_count) != 0 && i < 10) {
94 msleep(100);
95 i++;
96 }
97 return 0;
98}
99
ec86f14e
MC
100static void bnxt_fill_msix_vecs(struct bnxt *bp, struct bnxt_msix_entry *ent)
101{
102 struct bnxt_en_dev *edev = bp->edev;
103 int num_msix, idx, i;
104
105 num_msix = edev->ulp_tbl[BNXT_ROCE_ULP].msix_requested;
106 idx = edev->ulp_tbl[BNXT_ROCE_ULP].msix_base;
107 for (i = 0; i < num_msix; i++) {
108 ent[i].vector = bp->irq_tbl[idx + i].vector;
109 ent[i].ring_idx = idx + i;
110 ent[i].db_offset = (idx + i) * 0x80;
111 }
112}
113
a588e458
MC
114static int bnxt_req_msix_vecs(struct bnxt_en_dev *edev, int ulp_id,
115 struct bnxt_msix_entry *ent, int num_msix)
116{
117 struct net_device *dev = edev->net;
118 struct bnxt *bp = netdev_priv(dev);
119 int max_idx, max_cp_rings;
ec86f14e 120 int avail_msix, idx;
fbcfc8e4 121 int rc = 0;
a588e458
MC
122
123 ASSERT_RTNL();
124 if (ulp_id != BNXT_ROCE_ULP)
125 return -EINVAL;
126
127 if (!(bp->flags & BNXT_FLAG_USING_MSIX))
128 return -ENODEV;
129
08654eb2
MC
130 if (edev->ulp_tbl[ulp_id].msix_requested)
131 return -EAGAIN;
132
a588e458 133 max_cp_rings = bnxt_get_max_func_cp_rings(bp);
fbcfc8e4 134 avail_msix = bnxt_get_avail_msix(bp, num_msix);
a588e458
MC
135 if (!avail_msix)
136 return -ENOMEM;
137 if (avail_msix > num_msix)
138 avail_msix = num_msix;
139
f1ca94de 140 if (BNXT_NEW_RM(bp)) {
08654eb2 141 idx = bp->cp_nr_rings;
fbcfc8e4
MC
142 } else {
143 max_idx = min_t(int, bp->total_irqs, max_cp_rings);
08654eb2 144 idx = max_idx - avail_msix;
fbcfc8e4 145 }
08654eb2 146 edev->ulp_tbl[ulp_id].msix_base = idx;
fbcfc8e4
MC
147 edev->ulp_tbl[ulp_id].msix_requested = avail_msix;
148 if (bp->total_irqs < (idx + avail_msix)) {
149 if (netif_running(dev)) {
150 bnxt_close_nic(bp, true, false);
151 rc = bnxt_open_nic(bp, true, false);
152 } else {
46d06c7c 153 rc = bnxt_reserve_rings(bp, true);
fbcfc8e4
MC
154 }
155 }
156 if (rc) {
157 edev->ulp_tbl[ulp_id].msix_requested = 0;
158 return -EAGAIN;
159 }
160
f1ca94de 161 if (BNXT_NEW_RM(bp)) {
fbcfc8e4
MC
162 struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
163
75720e63 164 avail_msix = hw_resc->resv_irqs - bp->cp_nr_rings;
fbcfc8e4
MC
165 edev->ulp_tbl[ulp_id].msix_requested = avail_msix;
166 }
ec86f14e 167 bnxt_fill_msix_vecs(bp, ent);
ec86f14e 168 edev->flags |= BNXT_EN_FLAG_MSIX_REQUESTED;
a588e458
MC
169 return avail_msix;
170}
171
172static int bnxt_free_msix_vecs(struct bnxt_en_dev *edev, int ulp_id)
173{
174 struct net_device *dev = edev->net;
175 struct bnxt *bp = netdev_priv(dev);
a588e458
MC
176
177 ASSERT_RTNL();
178 if (ulp_id != BNXT_ROCE_ULP)
179 return -EINVAL;
180
ec86f14e
MC
181 if (!(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED))
182 return 0;
183
a588e458 184 edev->ulp_tbl[ulp_id].msix_requested = 0;
ec86f14e 185 edev->flags &= ~BNXT_EN_FLAG_MSIX_REQUESTED;
fbcfc8e4
MC
186 if (netif_running(dev)) {
187 bnxt_close_nic(bp, true, false);
188 bnxt_open_nic(bp, true, false);
189 }
a588e458
MC
190 return 0;
191}
192
08654eb2
MC
193int bnxt_get_ulp_msix_num(struct bnxt *bp)
194{
195 if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
196 struct bnxt_en_dev *edev = bp->edev;
197
198 return edev->ulp_tbl[BNXT_ROCE_ULP].msix_requested;
199 }
200 return 0;
201}
202
203int bnxt_get_ulp_msix_base(struct bnxt *bp)
204{
205 if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
206 struct bnxt_en_dev *edev = bp->edev;
207
208 if (edev->ulp_tbl[BNXT_ROCE_ULP].msix_requested)
209 return edev->ulp_tbl[BNXT_ROCE_ULP].msix_base;
210 }
211 return 0;
212}
213
c027c6b4
VV
214int bnxt_get_ulp_stat_ctxs(struct bnxt *bp)
215{
216 if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP))
217 return BNXT_MIN_ROCE_STAT_CTXS;
218
219 return 0;
220}
221
a588e458
MC
222static int bnxt_send_msg(struct bnxt_en_dev *edev, int ulp_id,
223 struct bnxt_fw_msg *fw_msg)
224{
225 struct net_device *dev = edev->net;
226 struct bnxt *bp = netdev_priv(dev);
227 struct input *req;
228 int rc;
229
230 mutex_lock(&bp->hwrm_cmd_lock);
231 req = fw_msg->msg;
232 req->resp_addr = cpu_to_le64(bp->hwrm_cmd_resp_dma_addr);
233 rc = _hwrm_send_message(bp, fw_msg->msg, fw_msg->msg_len,
234 fw_msg->timeout);
235 if (!rc) {
236 struct output *resp = bp->hwrm_cmd_resp_addr;
237 u32 len = le16_to_cpu(resp->resp_len);
238
239 if (fw_msg->resp_max_len < len)
240 len = fw_msg->resp_max_len;
241
242 memcpy(fw_msg->resp, resp, len);
243 }
244 mutex_unlock(&bp->hwrm_cmd_lock);
245 return rc;
246}
247
248static void bnxt_ulp_get(struct bnxt_ulp *ulp)
249{
250 atomic_inc(&ulp->ref_count);
251}
252
253static void bnxt_ulp_put(struct bnxt_ulp *ulp)
254{
255 atomic_dec(&ulp->ref_count);
256}
257
258void bnxt_ulp_stop(struct bnxt *bp)
259{
260 struct bnxt_en_dev *edev = bp->edev;
261 struct bnxt_ulp_ops *ops;
262 int i;
263
264 if (!edev)
265 return;
266
267 for (i = 0; i < BNXT_MAX_ULP; i++) {
268 struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
269
270 ops = rtnl_dereference(ulp->ulp_ops);
271 if (!ops || !ops->ulp_stop)
272 continue;
273 ops->ulp_stop(ulp->handle);
274 }
275}
276
277void bnxt_ulp_start(struct bnxt *bp)
278{
279 struct bnxt_en_dev *edev = bp->edev;
280 struct bnxt_ulp_ops *ops;
281 int i;
282
283 if (!edev)
284 return;
285
286 for (i = 0; i < BNXT_MAX_ULP; i++) {
287 struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
288
289 ops = rtnl_dereference(ulp->ulp_ops);
290 if (!ops || !ops->ulp_start)
291 continue;
292 ops->ulp_start(ulp->handle);
293 }
294}
295
296void bnxt_ulp_sriov_cfg(struct bnxt *bp, int num_vfs)
297{
298 struct bnxt_en_dev *edev = bp->edev;
299 struct bnxt_ulp_ops *ops;
300 int i;
301
302 if (!edev)
303 return;
304
305 for (i = 0; i < BNXT_MAX_ULP; i++) {
306 struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
307
308 rcu_read_lock();
309 ops = rcu_dereference(ulp->ulp_ops);
310 if (!ops || !ops->ulp_sriov_config) {
311 rcu_read_unlock();
312 continue;
313 }
314 bnxt_ulp_get(ulp);
315 rcu_read_unlock();
316 ops->ulp_sriov_config(ulp->handle, num_vfs);
317 bnxt_ulp_put(ulp);
318 }
319}
320
0efd2fc6
MC
321void bnxt_ulp_shutdown(struct bnxt *bp)
322{
323 struct bnxt_en_dev *edev = bp->edev;
324 struct bnxt_ulp_ops *ops;
325 int i;
326
327 if (!edev)
328 return;
329
330 for (i = 0; i < BNXT_MAX_ULP; i++) {
331 struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
332
333 ops = rtnl_dereference(ulp->ulp_ops);
334 if (!ops || !ops->ulp_shutdown)
335 continue;
336 ops->ulp_shutdown(ulp->handle);
337 }
338}
339
ec86f14e
MC
340void bnxt_ulp_irq_stop(struct bnxt *bp)
341{
342 struct bnxt_en_dev *edev = bp->edev;
343 struct bnxt_ulp_ops *ops;
344
345 if (!edev || !(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED))
346 return;
347
348 if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
349 struct bnxt_ulp *ulp = &edev->ulp_tbl[BNXT_ROCE_ULP];
350
351 if (!ulp->msix_requested)
352 return;
353
354 ops = rtnl_dereference(ulp->ulp_ops);
355 if (!ops || !ops->ulp_irq_stop)
356 return;
357 ops->ulp_irq_stop(ulp->handle);
358 }
359}
360
361void bnxt_ulp_irq_restart(struct bnxt *bp, int err)
362{
363 struct bnxt_en_dev *edev = bp->edev;
364 struct bnxt_ulp_ops *ops;
365
366 if (!edev || !(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED))
367 return;
368
369 if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
370 struct bnxt_ulp *ulp = &edev->ulp_tbl[BNXT_ROCE_ULP];
371 struct bnxt_msix_entry *ent = NULL;
372
373 if (!ulp->msix_requested)
374 return;
375
376 ops = rtnl_dereference(ulp->ulp_ops);
377 if (!ops || !ops->ulp_irq_restart)
378 return;
379
380 if (!err) {
381 ent = kcalloc(ulp->msix_requested, sizeof(*ent),
382 GFP_KERNEL);
383 if (!ent)
384 return;
385 bnxt_fill_msix_vecs(bp, ent);
386 }
387 ops->ulp_irq_restart(ulp->handle, ent);
388 kfree(ent);
389 }
390}
391
a588e458
MC
392void bnxt_ulp_async_events(struct bnxt *bp, struct hwrm_async_event_cmpl *cmpl)
393{
394 u16 event_id = le16_to_cpu(cmpl->event_id);
395 struct bnxt_en_dev *edev = bp->edev;
396 struct bnxt_ulp_ops *ops;
397 int i;
398
399 if (!edev)
400 return;
401
402 rcu_read_lock();
403 for (i = 0; i < BNXT_MAX_ULP; i++) {
404 struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
405
406 ops = rcu_dereference(ulp->ulp_ops);
407 if (!ops || !ops->ulp_async_notifier)
408 continue;
409 if (!ulp->async_events_bmap ||
410 event_id > ulp->max_async_event_id)
411 continue;
412
413 /* Read max_async_event_id first before testing the bitmap. */
414 smp_rmb();
415 if (test_bit(event_id, ulp->async_events_bmap))
416 ops->ulp_async_notifier(ulp->handle, cmpl);
417 }
418 rcu_read_unlock();
419}
420
421static int bnxt_register_async_events(struct bnxt_en_dev *edev, int ulp_id,
422 unsigned long *events_bmap, u16 max_id)
423{
424 struct net_device *dev = edev->net;
425 struct bnxt *bp = netdev_priv(dev);
426 struct bnxt_ulp *ulp;
427
428 if (ulp_id >= BNXT_MAX_ULP)
429 return -EINVAL;
430
431 ulp = &edev->ulp_tbl[ulp_id];
432 ulp->async_events_bmap = events_bmap;
433 /* Make sure bnxt_ulp_async_events() sees this order */
434 smp_wmb();
435 ulp->max_async_event_id = max_id;
436 bnxt_hwrm_func_rgtr_async_events(bp, events_bmap, max_id + 1);
437 return 0;
438}
439
440static const struct bnxt_en_ops bnxt_en_ops_tbl = {
441 .bnxt_register_device = bnxt_register_dev,
442 .bnxt_unregister_device = bnxt_unregister_dev,
443 .bnxt_request_msix = bnxt_req_msix_vecs,
444 .bnxt_free_msix = bnxt_free_msix_vecs,
445 .bnxt_send_fw_msg = bnxt_send_msg,
446 .bnxt_register_fw_async_events = bnxt_register_async_events,
447};
448
449struct bnxt_en_dev *bnxt_ulp_probe(struct net_device *dev)
450{
451 struct bnxt *bp = netdev_priv(dev);
452 struct bnxt_en_dev *edev;
453
454 edev = bp->edev;
455 if (!edev) {
456 edev = kzalloc(sizeof(*edev), GFP_KERNEL);
457 if (!edev)
458 return ERR_PTR(-ENOMEM);
459 edev->en_ops = &bnxt_en_ops_tbl;
460 if (bp->flags & BNXT_FLAG_ROCEV1_CAP)
461 edev->flags |= BNXT_EN_FLAG_ROCEV1_CAP;
462 if (bp->flags & BNXT_FLAG_ROCEV2_CAP)
463 edev->flags |= BNXT_EN_FLAG_ROCEV2_CAP;
464 edev->net = dev;
465 edev->pdev = bp->pdev;
466 bp->edev = edev;
467 }
468 return bp->edev;
469}