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