common/cnxk: fix log level during MCAM allocation
[dpdk.git] / drivers / common / cnxk / roc_irq.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2021 Marvell.
3  */
4
5 #include "roc_api.h"
6 #include "roc_priv.h"
7
8 #if defined(__linux__)
9
10 #include <inttypes.h>
11 #include <linux/vfio.h>
12 #include <sys/eventfd.h>
13 #include <sys/ioctl.h>
14 #include <unistd.h>
15
16 #define MSIX_IRQ_SET_BUF_LEN                                                   \
17         (sizeof(struct vfio_irq_set) + sizeof(int) *                           \
18                         (plt_intr_max_intr_get(intr_handle)))
19
20 static int
21 irq_get_info(struct plt_intr_handle *intr_handle)
22 {
23         struct vfio_irq_info irq = {.argsz = sizeof(irq)};
24         int rc, vfio_dev_fd;
25
26         irq.index = VFIO_PCI_MSIX_IRQ_INDEX;
27
28         vfio_dev_fd = plt_intr_dev_fd_get(intr_handle);
29         rc = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_IRQ_INFO, &irq);
30         if (rc < 0) {
31                 plt_err("Failed to get IRQ info rc=%d errno=%d", rc, errno);
32                 return rc;
33         }
34
35         plt_base_dbg("Flags=0x%x index=0x%x count=0x%x max_intr_vec_id=0x%x",
36                      irq.flags, irq.index, irq.count, PLT_MAX_RXTX_INTR_VEC_ID);
37
38         if (irq.count == 0) {
39                 plt_err("HW max=%d > PLT_MAX_RXTX_INTR_VEC_ID: %d", irq.count,
40                         PLT_MAX_RXTX_INTR_VEC_ID);
41                 plt_intr_max_intr_set(intr_handle, PLT_MAX_RXTX_INTR_VEC_ID);
42         } else {
43                 if (plt_intr_max_intr_set(intr_handle, irq.count))
44                         return -1;
45         }
46
47         return 0;
48 }
49
50 static int
51 irq_config(struct plt_intr_handle *intr_handle, unsigned int vec)
52 {
53         char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
54         struct vfio_irq_set *irq_set;
55         int len, rc, vfio_dev_fd;
56         int32_t *fd_ptr;
57
58         if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) {
59                 plt_err("vector=%d greater than max_intr=%d", vec,
60                         plt_intr_max_intr_get(intr_handle));
61                 return -EINVAL;
62         }
63
64         len = sizeof(struct vfio_irq_set) + sizeof(int32_t);
65
66         irq_set = (struct vfio_irq_set *)irq_set_buf;
67         irq_set->argsz = len;
68
69         irq_set->start = vec;
70         irq_set->count = 1;
71         irq_set->flags =
72                 VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
73         irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
74
75         /* Use vec fd to set interrupt vectors */
76         fd_ptr = (int32_t *)&irq_set->data[0];
77         fd_ptr[0] = plt_intr_efds_index_get(intr_handle, vec);
78
79         vfio_dev_fd = plt_intr_dev_fd_get(intr_handle);
80         rc = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
81         if (rc)
82                 plt_err("Failed to set_irqs vector=0x%x rc=%d", vec, rc);
83
84         return rc;
85 }
86
87 static int
88 irq_init(struct plt_intr_handle *intr_handle)
89 {
90         char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
91         struct vfio_irq_set *irq_set;
92         int len, rc, vfio_dev_fd;
93         int32_t *fd_ptr;
94         uint32_t i;
95
96         len = sizeof(struct vfio_irq_set) +
97               sizeof(int32_t) * plt_intr_max_intr_get(intr_handle);
98
99         irq_set = (struct vfio_irq_set *)irq_set_buf;
100         irq_set->argsz = len;
101         irq_set->start = 0;
102         irq_set->count = plt_intr_max_intr_get(intr_handle);
103         irq_set->flags =
104                 VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
105         irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
106
107         fd_ptr = (int32_t *)&irq_set->data[0];
108         for (i = 0; i < irq_set->count; i++)
109                 fd_ptr[i] = -1;
110
111         vfio_dev_fd = plt_intr_dev_fd_get(intr_handle);
112         rc = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
113         if (rc)
114                 plt_err("Failed to set irqs vector rc=%d", rc);
115
116         return rc;
117 }
118
119 int
120 dev_irqs_disable(struct plt_intr_handle *intr_handle)
121 {
122         /* Clear max_intr to indicate re-init next time */
123         plt_intr_max_intr_set(intr_handle, 0);
124         return plt_intr_disable(intr_handle);
125 }
126
127 int
128 dev_irq_register(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
129                  void *data, unsigned int vec)
130 {
131         struct plt_intr_handle *tmp_handle;
132         uint32_t nb_efd, tmp_nb_efd;
133         int rc, fd;
134
135         /* If no max_intr read from VFIO */
136         if (plt_intr_max_intr_get(intr_handle) == 0) {
137                 irq_get_info(intr_handle);
138                 irq_init(intr_handle);
139         }
140
141         if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) {
142                 plt_err("Vector=%d greater than max_intr=%d or ",
143                         vec, plt_intr_max_intr_get(intr_handle));
144                 return -EINVAL;
145         }
146
147         tmp_handle = intr_handle;
148         /* Create new eventfd for interrupt vector */
149         fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
150         if (fd == -1)
151                 return -ENODEV;
152
153         if (plt_intr_fd_set(tmp_handle, fd))
154                 return -errno;
155
156         /* Register vector interrupt callback */
157         rc = plt_intr_callback_register(tmp_handle, cb, data);
158         if (rc) {
159                 plt_err("Failed to register vector:0x%x irq callback.", vec);
160                 return rc;
161         }
162
163         plt_intr_efds_index_set(intr_handle, vec, fd);
164         nb_efd = (vec > (uint32_t)plt_intr_nb_efd_get(intr_handle)) ?
165                 vec : (uint32_t)plt_intr_nb_efd_get(intr_handle);
166         plt_intr_nb_efd_set(intr_handle, nb_efd);
167
168         tmp_nb_efd = plt_intr_nb_efd_get(intr_handle) + 1;
169         if (tmp_nb_efd > (uint32_t)plt_intr_max_intr_get(intr_handle))
170                 plt_intr_max_intr_set(intr_handle, tmp_nb_efd);
171         plt_base_dbg("Enable vector:0x%x for vfio (efds: %d, max:%d)", vec,
172                      plt_intr_nb_efd_get(intr_handle),
173                      plt_intr_max_intr_get(intr_handle));
174
175         /* Enable MSIX vectors to VFIO */
176         return irq_config(intr_handle, vec);
177 }
178
179 void
180 dev_irq_unregister(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
181                    void *data, unsigned int vec)
182 {
183         struct plt_intr_handle *tmp_handle;
184         uint8_t retries = 5; /* 5 ms */
185         int rc, fd;
186
187         if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) {
188                 plt_err("Error unregistering MSI-X interrupts vec:%d > %d", vec,
189                         plt_intr_max_intr_get(intr_handle));
190                 return;
191         }
192
193         tmp_handle = intr_handle;
194         fd = plt_intr_efds_index_get(intr_handle, vec);
195         if (fd == -1)
196                 return;
197
198         if (plt_intr_fd_set(tmp_handle, fd))
199                 return;
200
201         do {
202                 /* Un-register callback func from platform lib */
203                 rc = plt_intr_callback_unregister(tmp_handle, cb, data);
204                 /* Retry only if -EAGAIN */
205                 if (rc != -EAGAIN)
206                         break;
207                 plt_delay_ms(1);
208                 retries--;
209         } while (retries);
210
211         if (rc < 0) {
212                 plt_err("Error unregistering MSI-X vec %d cb, rc=%d", vec, rc);
213                 return;
214         }
215
216         plt_base_dbg("Disable vector:0x%x for vfio (efds: %d, max:%d)", vec,
217                      plt_intr_nb_efd_get(intr_handle),
218                      plt_intr_max_intr_get(intr_handle));
219
220         if (plt_intr_efds_index_get(intr_handle, vec) != -1)
221                 close(plt_intr_efds_index_get(intr_handle, vec));
222         /* Disable MSIX vectors from VFIO */
223         plt_intr_efds_index_set(intr_handle, vec, -1);
224
225         irq_config(intr_handle, vec);
226 }
227
228 #else
229
230 int
231 dev_irq_register(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
232                  void *data, unsigned int vec)
233 {
234         PLT_SET_USED(intr_handle);
235         PLT_SET_USED(cb);
236         PLT_SET_USED(data);
237         PLT_SET_USED(vec);
238
239         return -ENOTSUP;
240 }
241
242 void
243 dev_irq_unregister(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
244                    void *data, unsigned int vec)
245 {
246         PLT_SET_USED(intr_handle);
247         PLT_SET_USED(cb);
248         PLT_SET_USED(data);
249         PLT_SET_USED(vec);
250 }
251
252 int
253 dev_irqs_disable(struct plt_intr_handle *intr_handle)
254 {
255         PLT_SET_USED(intr_handle);
256
257         return -ENOTSUP;
258 }
259
260 #endif /* __linux__ */