net/bnxt: retry IRQ callback deregistration
[dpdk.git] / drivers / net / bnxt / bnxt_irq.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2014-2018 Broadcom
3  * All rights reserved.
4  */
5
6 #include <inttypes.h>
7
8 #include <rte_cycles.h>
9 #include <rte_malloc.h>
10
11 #include "bnxt.h"
12 #include "bnxt_cpr.h"
13 #include "bnxt_irq.h"
14 #include "bnxt_ring.h"
15 #include "hsi_struct_def_dpdk.h"
16
17 /*
18  * Interrupts
19  */
20
21 static void bnxt_int_handler(void *param)
22 {
23         struct rte_eth_dev *eth_dev = (struct rte_eth_dev *)param;
24         struct bnxt *bp = eth_dev->data->dev_private;
25         struct bnxt_cp_ring_info *cpr = bp->def_cp_ring;
26         struct cmpl_base *cmp;
27         uint32_t raw_cons;
28         uint32_t cons;
29
30         if (cpr == NULL)
31                 return;
32
33         raw_cons = cpr->cp_raw_cons;
34         while (1) {
35                 if (!cpr || !cpr->cp_ring_struct || !cpr->cp_db.doorbell)
36                         return;
37
38                 cons = RING_CMP(cpr->cp_ring_struct, raw_cons);
39                 cmp = &cpr->cp_desc_ring[cons];
40
41                 if (!CMP_VALID(cmp, raw_cons, cpr->cp_ring_struct))
42                         break;
43
44                 bnxt_event_hwrm_resp_handler(bp, cmp);
45                 raw_cons = NEXT_RAW_CMP(raw_cons);
46         };
47
48         cpr->cp_raw_cons = raw_cons;
49         B_CP_DB_REARM(cpr, cpr->cp_raw_cons);
50 }
51
52 int bnxt_free_int(struct bnxt *bp)
53 {
54         struct rte_intr_handle *intr_handle = &bp->pdev->intr_handle;
55         struct bnxt_irq *irq = bp->irq_tbl;
56         int rc = 0;
57
58         if (!irq)
59                 return 0;
60
61         if (irq->requested) {
62                 int count = 0;
63
64                 /*
65                  * Callback deregistration will fail with rc -EAGAIN if the
66                  * callback is currently active. Retry every 50 ms until
67                  * successful or 500 ms has elapsed.
68                  */
69                 do {
70                         rc = rte_intr_callback_unregister(intr_handle,
71                                                           irq->handler,
72                                                           bp->eth_dev);
73                         if (rc >= 0) {
74                                 irq->requested = 0;
75                                 break;
76                         }
77                         rte_delay_ms(50);
78                 } while (count++ < 10);
79
80                 if (rc < 0) {
81                         PMD_DRV_LOG(ERR, "irq cb unregister failed rc: %d\n",
82                                     rc);
83                         return rc;
84                 }
85         }
86
87         rte_free(bp->irq_tbl);
88         bp->irq_tbl = NULL;
89
90         return 0;
91 }
92
93 void bnxt_disable_int(struct bnxt *bp)
94 {
95         struct bnxt_cp_ring_info *cpr = bp->def_cp_ring;
96
97         /* Only the default completion ring */
98         if (cpr != NULL && cpr->cp_db.doorbell != NULL)
99                 B_CP_DB_DISARM(cpr);
100 }
101
102 void bnxt_enable_int(struct bnxt *bp)
103 {
104         struct bnxt_cp_ring_info *cpr = bp->def_cp_ring;
105
106         /* Only the default completion ring */
107         if (cpr != NULL && cpr->cp_db.doorbell != NULL)
108                 B_CP_DB_ARM(cpr);
109 }
110
111 int bnxt_setup_int(struct bnxt *bp)
112 {
113         uint16_t total_vecs;
114         const int len = sizeof(bp->irq_tbl[0].name);
115         int i, rc = 0;
116
117         /* DPDK host only supports 1 MSI-X vector */
118         total_vecs = 1;
119         bp->irq_tbl = rte_calloc("bnxt_irq_tbl", total_vecs,
120                                  sizeof(struct bnxt_irq), 0);
121         if (bp->irq_tbl) {
122                 for (i = 0; i < total_vecs; i++) {
123                         bp->irq_tbl[i].vector = i;
124                         snprintf(bp->irq_tbl[i].name, len,
125                                  "%s-%d", bp->eth_dev->device->name, i);
126                         bp->irq_tbl[i].handler = bnxt_int_handler;
127                 }
128         } else {
129                 rc = -ENOMEM;
130                 goto setup_exit;
131         }
132         return 0;
133
134 setup_exit:
135         PMD_DRV_LOG(ERR, "bnxt_irq_tbl setup failed\n");
136         return rc;
137 }
138
139 int bnxt_request_int(struct bnxt *bp)
140 {
141         struct rte_intr_handle *intr_handle = &bp->pdev->intr_handle;
142         struct bnxt_irq *irq = bp->irq_tbl;
143         int rc = 0;
144
145         if (!irq)
146                 return 0;
147
148         if (!irq->requested) {
149                 rc = rte_intr_callback_register(intr_handle,
150                                                 irq->handler,
151                                                 bp->eth_dev);
152                 if (!rc)
153                         irq->requested = 1;
154         }
155
156         return rc;
157 }