common/cnxk: use wider mask to extract RPM ID
[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         rc = plt_intr_efds_index_set(intr_handle, vec, fd);
164         if (rc)
165                 return rc;
166
167         nb_efd = (vec > (uint32_t)plt_intr_nb_efd_get(intr_handle)) ?
168                 vec : (uint32_t)plt_intr_nb_efd_get(intr_handle);
169         plt_intr_nb_efd_set(intr_handle, nb_efd);
170
171         tmp_nb_efd = plt_intr_nb_efd_get(intr_handle) + 1;
172         if (tmp_nb_efd > (uint32_t)plt_intr_max_intr_get(intr_handle))
173                 plt_intr_max_intr_set(intr_handle, tmp_nb_efd);
174         plt_base_dbg("Enable vector:0x%x for vfio (efds: %d, max:%d)", vec,
175                      plt_intr_nb_efd_get(intr_handle),
176                      plt_intr_max_intr_get(intr_handle));
177
178         /* Enable MSIX vectors to VFIO */
179         return irq_config(intr_handle, vec);
180 }
181
182 void
183 dev_irq_unregister(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
184                    void *data, unsigned int vec)
185 {
186         struct plt_intr_handle *tmp_handle;
187         uint8_t retries = 5; /* 5 ms */
188         int rc, fd;
189
190         if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) {
191                 plt_err("Error unregistering MSI-X interrupts vec:%d > %d", vec,
192                         plt_intr_max_intr_get(intr_handle));
193                 return;
194         }
195
196         tmp_handle = intr_handle;
197         fd = plt_intr_efds_index_get(intr_handle, vec);
198         if (fd == -1)
199                 return;
200
201         if (plt_intr_fd_set(tmp_handle, fd))
202                 return;
203
204         do {
205                 /* Un-register callback func from platform lib */
206                 rc = plt_intr_callback_unregister(tmp_handle, cb, data);
207                 /* Retry only if -EAGAIN */
208                 if (rc != -EAGAIN)
209                         break;
210                 plt_delay_ms(1);
211                 retries--;
212         } while (retries);
213
214         if (rc < 0) {
215                 plt_err("Error unregistering MSI-X vec %d cb, rc=%d", vec, rc);
216                 return;
217         }
218
219         plt_base_dbg("Disable vector:0x%x for vfio (efds: %d, max:%d)", vec,
220                      plt_intr_nb_efd_get(intr_handle),
221                      plt_intr_max_intr_get(intr_handle));
222
223         if (plt_intr_efds_index_get(intr_handle, vec) != -1)
224                 close(plt_intr_efds_index_get(intr_handle, vec));
225         /* Disable MSIX vectors from VFIO */
226         plt_intr_efds_index_set(intr_handle, vec, -1);
227
228         irq_config(intr_handle, vec);
229 }
230
231 #else
232
233 int
234 dev_irq_register(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
235                  void *data, unsigned int vec)
236 {
237         PLT_SET_USED(intr_handle);
238         PLT_SET_USED(cb);
239         PLT_SET_USED(data);
240         PLT_SET_USED(vec);
241
242         return -ENOTSUP;
243 }
244
245 void
246 dev_irq_unregister(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
247                    void *data, unsigned int vec)
248 {
249         PLT_SET_USED(intr_handle);
250         PLT_SET_USED(cb);
251         PLT_SET_USED(data);
252         PLT_SET_USED(vec);
253 }
254
255 int
256 dev_irqs_disable(struct plt_intr_handle *intr_handle)
257 {
258         PLT_SET_USED(intr_handle);
259
260         return -ENOTSUP;
261 }
262
263 #endif /* __linux__ */