729d68d704124379f2401e1c6be4d760f90fde1e
[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 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->async_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         if (BNXT_HAS_NQ(bp))
50                 bnxt_db_nq_arm(cpr);
51         else
52                 B_CP_DB_REARM(cpr, cpr->cp_raw_cons);
53 }
54
55 int bnxt_free_int(struct bnxt *bp)
56 {
57         struct rte_intr_handle *intr_handle = &bp->pdev->intr_handle;
58         struct bnxt_irq *irq = bp->irq_tbl;
59         int rc = 0;
60
61         if (!irq)
62                 return 0;
63
64         if (irq->requested) {
65                 int count = 0;
66
67                 /*
68                  * Callback deregistration will fail with rc -EAGAIN if the
69                  * callback is currently active. Retry every 50 ms until
70                  * successful or 500 ms has elapsed.
71                  */
72                 do {
73                         rc = rte_intr_callback_unregister(intr_handle,
74                                                           irq->handler,
75                                                           bp->eth_dev);
76                         if (rc >= 0) {
77                                 irq->requested = 0;
78                                 break;
79                         }
80                         rte_delay_ms(50);
81                 } while (count++ < 10);
82
83                 if (rc < 0) {
84                         PMD_DRV_LOG(ERR, "irq cb unregister failed rc: %d\n",
85                                     rc);
86                         return rc;
87                 }
88         }
89
90         rte_free(bp->irq_tbl);
91         bp->irq_tbl = NULL;
92
93         return 0;
94 }
95
96 void bnxt_disable_int(struct bnxt *bp)
97 {
98         struct bnxt_cp_ring_info *cpr = bp->async_cp_ring;
99
100         if (BNXT_NUM_ASYNC_CPR(bp) == 0)
101                 return;
102
103         if (!cpr || !cpr->cp_db.doorbell)
104                 return;
105
106         /* Only the default completion ring */
107         if (BNXT_HAS_NQ(bp))
108                 bnxt_db_nq(cpr);
109         else
110                 B_CP_DB_DISARM(cpr);
111 }
112
113 void bnxt_enable_int(struct bnxt *bp)
114 {
115         struct bnxt_cp_ring_info *cpr = bp->async_cp_ring;
116
117         if (BNXT_NUM_ASYNC_CPR(bp) == 0)
118                 return;
119
120         if (!cpr || !cpr->cp_db.doorbell)
121                 return;
122
123         /* Only the default completion ring */
124         if (BNXT_HAS_NQ(bp))
125                 bnxt_db_nq_arm(cpr);
126         else
127                 B_CP_DB_ARM(cpr);
128 }
129
130 int bnxt_setup_int(struct bnxt *bp)
131 {
132         uint16_t total_vecs;
133         const int len = sizeof(bp->irq_tbl[0].name);
134         int i;
135
136         /* DPDK host only supports 1 MSI-X vector */
137         total_vecs = 1;
138         bp->irq_tbl = rte_calloc("bnxt_irq_tbl", total_vecs,
139                                  sizeof(struct bnxt_irq), 0);
140         if (bp->irq_tbl) {
141                 for (i = 0; i < total_vecs; i++) {
142                         bp->irq_tbl[i].vector = i;
143                         snprintf(bp->irq_tbl[i].name, len,
144                                  "%s-%d", bp->eth_dev->device->name, i);
145                         bp->irq_tbl[i].handler = bnxt_int_handler;
146                 }
147         } else {
148                 PMD_DRV_LOG(ERR, "bnxt_irq_tbl setup failed\n");
149                 return -ENOMEM;
150         }
151
152         return 0;
153 }
154
155 int bnxt_request_int(struct bnxt *bp)
156 {
157         struct rte_intr_handle *intr_handle = &bp->pdev->intr_handle;
158         struct bnxt_irq *irq = bp->irq_tbl;
159         int rc = 0;
160
161         if (!irq)
162                 return 0;
163
164         if (!irq->requested) {
165                 rc = rte_intr_callback_register(intr_handle,
166                                                 irq->handler,
167                                                 bp->eth_dev);
168                 if (!rc)
169                         irq->requested = 1;
170         }
171
172         return rc;
173 }