fd8b8fac989aeff726eb0c803d4e5bdd9353fc25
[dpdk.git] / drivers / net / bnxt / bnxt_irq.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2014-2021 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_irq.h"
13 #include "bnxt_ring.h"
14 #include "hsi_struct_def_dpdk.h"
15
16 /*
17  * Interrupts
18  */
19
20 void bnxt_int_handler(void *param)
21 {
22         struct rte_eth_dev *eth_dev = (struct rte_eth_dev *)param;
23         struct bnxt *bp = eth_dev->data->dev_private;
24         struct bnxt_cp_ring_info *cpr;
25         struct cmpl_base *cmp;
26         uint32_t raw_cons;
27         uint32_t cons;
28
29         if (bp == NULL)
30                 return;
31         cpr = bp->async_cp_ring;
32         if (cpr == NULL)
33                 return;
34
35         raw_cons = cpr->cp_raw_cons;
36         pthread_mutex_lock(&bp->def_cp_lock);
37         while (1) {
38                 if (!cpr || !cpr->cp_ring_struct || !cpr->cp_db.doorbell) {
39                         pthread_mutex_unlock(&bp->def_cp_lock);
40                         return;
41                 }
42
43                 if (is_bnxt_in_error(bp)) {
44                         pthread_mutex_unlock(&bp->def_cp_lock);
45                         return;
46                 }
47
48                 cons = RING_CMP(cpr->cp_ring_struct, raw_cons);
49                 cmp = &cpr->cp_desc_ring[cons];
50
51                 if (!CMP_VALID(cmp, raw_cons, cpr->cp_ring_struct))
52                         break;
53
54                 bnxt_event_hwrm_resp_handler(bp, cmp);
55                 raw_cons = NEXT_RAW_CMP(raw_cons);
56         }
57
58         cpr->cp_raw_cons = raw_cons;
59         if (BNXT_HAS_NQ(bp))
60                 bnxt_db_nq_arm(cpr);
61         else
62                 B_CP_DB_REARM(cpr, cpr->cp_raw_cons);
63
64         pthread_mutex_unlock(&bp->def_cp_lock);
65 }
66
67 int bnxt_free_int(struct bnxt *bp)
68 {
69         struct rte_intr_handle *intr_handle = &bp->pdev->intr_handle;
70         struct bnxt_irq *irq = bp->irq_tbl;
71         int rc = 0;
72
73         if (!irq)
74                 return 0;
75
76         if (irq->requested) {
77                 int count = 0;
78
79                 /*
80                  * Callback deregistration will fail with rc -EAGAIN if the
81                  * callback is currently active. Retry every 50 ms until
82                  * successful or 500 ms has elapsed.
83                  */
84                 do {
85                         rc = rte_intr_callback_unregister(intr_handle,
86                                                           irq->handler,
87                                                           bp->eth_dev);
88                         if (rc >= 0) {
89                                 irq->requested = 0;
90                                 break;
91                         }
92                         rte_delay_ms(50);
93                 } while (count++ < 10);
94
95                 if (rc < 0) {
96                         PMD_DRV_LOG(ERR, "irq cb unregister failed rc: %d\n",
97                                     rc);
98                         return rc;
99                 }
100         }
101
102         rte_free(bp->irq_tbl);
103         bp->irq_tbl = NULL;
104
105         return 0;
106 }
107
108 void bnxt_disable_int(struct bnxt *bp)
109 {
110         struct bnxt_cp_ring_info *cpr = bp->async_cp_ring;
111
112         if (BNXT_NUM_ASYNC_CPR(bp) == 0)
113                 return;
114
115         if (is_bnxt_in_error(bp))
116                 return;
117
118         if (!cpr || !cpr->cp_db.doorbell)
119                 return;
120
121         /* Only the default completion ring */
122         if (BNXT_HAS_NQ(bp))
123                 bnxt_db_nq(cpr);
124         else
125                 B_CP_DB_DISARM(cpr);
126 }
127
128 void bnxt_enable_int(struct bnxt *bp)
129 {
130         struct bnxt_cp_ring_info *cpr = bp->async_cp_ring;
131
132         if (BNXT_NUM_ASYNC_CPR(bp) == 0)
133                 return;
134
135         if (!cpr || !cpr->cp_db.doorbell)
136                 return;
137
138         /* Only the default completion ring */
139         if (BNXT_HAS_NQ(bp))
140                 bnxt_db_nq_arm(cpr);
141         else
142                 B_CP_DB_ARM(cpr);
143 }
144
145 int bnxt_setup_int(struct bnxt *bp)
146 {
147         uint16_t total_vecs;
148         const int len = sizeof(bp->irq_tbl[0].name);
149         int i;
150
151         /* DPDK host only supports 1 MSI-X vector */
152         total_vecs = 1;
153         bp->irq_tbl = rte_calloc("bnxt_irq_tbl", total_vecs,
154                                  sizeof(struct bnxt_irq), 0);
155         if (bp->irq_tbl) {
156                 for (i = 0; i < total_vecs; i++) {
157                         bp->irq_tbl[i].vector_idx = i;
158                         snprintf(bp->irq_tbl[i].name, len,
159                                  "%s-%d", bp->eth_dev->device->name, i);
160                         bp->irq_tbl[i].handler = bnxt_int_handler;
161                 }
162         } else {
163                 PMD_DRV_LOG(ERR, "bnxt_irq_tbl setup failed\n");
164                 return -ENOMEM;
165         }
166
167         return 0;
168 }
169
170 int bnxt_request_int(struct bnxt *bp)
171 {
172         struct rte_intr_handle *intr_handle = &bp->pdev->intr_handle;
173         struct bnxt_irq *irq = bp->irq_tbl;
174         int rc = 0;
175
176         if (!irq)
177                 return 0;
178
179         if (!irq->requested) {
180                 rc = rte_intr_callback_register(intr_handle,
181                                                 irq->handler,
182                                                 bp->eth_dev);
183                 if (!rc)
184                         irq->requested = 1;
185         }
186
187 #ifdef RTE_EXEC_ENV_FREEBSD
188         /**
189          * In FreeBSD OS, nic_uio does not support interrupts and
190          * interrupt register callback will fail.
191          */
192         rc = 0;
193 #endif
194
195         return rc;
196 }