xref: /dpdk/drivers/common/cnxk/roc_irq.c (revision 20c29a0e4602b9c7be5ea299457f909846c3785d)
101bc01e1SJerin Jacob /* SPDX-License-Identifier: BSD-3-Clause
201bc01e1SJerin Jacob  * Copyright(C) 2021 Marvell.
301bc01e1SJerin Jacob  */
401bc01e1SJerin Jacob 
501bc01e1SJerin Jacob #include "roc_api.h"
601bc01e1SJerin Jacob #include "roc_priv.h"
701bc01e1SJerin Jacob 
801bc01e1SJerin Jacob #if defined(__linux__)
901bc01e1SJerin Jacob 
1001bc01e1SJerin Jacob #include <inttypes.h>
1101bc01e1SJerin Jacob #include <linux/vfio.h>
1201bc01e1SJerin Jacob #include <sys/eventfd.h>
1301bc01e1SJerin Jacob #include <sys/ioctl.h>
1401bc01e1SJerin Jacob #include <unistd.h>
1501bc01e1SJerin Jacob 
1601bc01e1SJerin Jacob #define MSIX_IRQ_SET_BUF_LEN                                                   \
1739ac394aSHarman Kalra 	(sizeof(struct vfio_irq_set) + sizeof(int) *			       \
18*20c29a0eSSunil Kumar Kori 			((uint32_t)plt_intr_max_intr_get(intr_handle)))
1901bc01e1SJerin Jacob 
2001bc01e1SJerin Jacob static int
2101bc01e1SJerin Jacob irq_get_info(struct plt_intr_handle *intr_handle)
2201bc01e1SJerin Jacob {
2301bc01e1SJerin Jacob 	struct vfio_irq_info irq = {.argsz = sizeof(irq)};
24d61138d4SHarman Kalra 	int rc, vfio_dev_fd;
2501bc01e1SJerin Jacob 
2601bc01e1SJerin Jacob 	irq.index = VFIO_PCI_MSIX_IRQ_INDEX;
2701bc01e1SJerin Jacob 
28d61138d4SHarman Kalra 	vfio_dev_fd = plt_intr_dev_fd_get(intr_handle);
29d61138d4SHarman Kalra 	rc = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_IRQ_INFO, &irq);
3001bc01e1SJerin Jacob 	if (rc < 0) {
3101bc01e1SJerin Jacob 		plt_err("Failed to get IRQ info rc=%d errno=%d", rc, errno);
3201bc01e1SJerin Jacob 		return rc;
3301bc01e1SJerin Jacob 	}
3401bc01e1SJerin Jacob 
3501bc01e1SJerin Jacob 	plt_base_dbg("Flags=0x%x index=0x%x count=0x%x max_intr_vec_id=0x%x",
3601bc01e1SJerin Jacob 		     irq.flags, irq.index, irq.count, PLT_MAX_RXTX_INTR_VEC_ID);
3701bc01e1SJerin Jacob 
3839ac394aSHarman Kalra 	if (irq.count == 0) {
3901bc01e1SJerin Jacob 		plt_err("HW max=%d > PLT_MAX_RXTX_INTR_VEC_ID: %d", irq.count,
4001bc01e1SJerin Jacob 			PLT_MAX_RXTX_INTR_VEC_ID);
41d61138d4SHarman Kalra 		plt_intr_max_intr_set(intr_handle, PLT_MAX_RXTX_INTR_VEC_ID);
4201bc01e1SJerin Jacob 	} else {
43d61138d4SHarman Kalra 		if (plt_intr_max_intr_set(intr_handle, irq.count))
44d61138d4SHarman Kalra 			return -1;
4501bc01e1SJerin Jacob 	}
4601bc01e1SJerin Jacob 
4701bc01e1SJerin Jacob 	return 0;
4801bc01e1SJerin Jacob }
4901bc01e1SJerin Jacob 
5001bc01e1SJerin Jacob static int
5101bc01e1SJerin Jacob irq_config(struct plt_intr_handle *intr_handle, unsigned int vec)
5201bc01e1SJerin Jacob {
5301bc01e1SJerin Jacob 	char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
5401bc01e1SJerin Jacob 	struct vfio_irq_set *irq_set;
55d61138d4SHarman Kalra 	int len, rc, vfio_dev_fd;
5601bc01e1SJerin Jacob 	int32_t *fd_ptr;
5701bc01e1SJerin Jacob 
58d61138d4SHarman Kalra 	if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) {
5901bc01e1SJerin Jacob 		plt_err("vector=%d greater than max_intr=%d", vec,
60d61138d4SHarman Kalra 			plt_intr_max_intr_get(intr_handle));
6101bc01e1SJerin Jacob 		return -EINVAL;
6201bc01e1SJerin Jacob 	}
6301bc01e1SJerin Jacob 
6401bc01e1SJerin Jacob 	len = sizeof(struct vfio_irq_set) + sizeof(int32_t);
6501bc01e1SJerin Jacob 
6601bc01e1SJerin Jacob 	irq_set = (struct vfio_irq_set *)irq_set_buf;
6701bc01e1SJerin Jacob 	irq_set->argsz = len;
6801bc01e1SJerin Jacob 
6901bc01e1SJerin Jacob 	irq_set->start = vec;
7001bc01e1SJerin Jacob 	irq_set->count = 1;
7101bc01e1SJerin Jacob 	irq_set->flags =
7201bc01e1SJerin Jacob 		VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
7301bc01e1SJerin Jacob 	irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
7401bc01e1SJerin Jacob 
7501bc01e1SJerin Jacob 	/* Use vec fd to set interrupt vectors */
7601bc01e1SJerin Jacob 	fd_ptr = (int32_t *)&irq_set->data[0];
77d61138d4SHarman Kalra 	fd_ptr[0] = plt_intr_efds_index_get(intr_handle, vec);
7801bc01e1SJerin Jacob 
79d61138d4SHarman Kalra 	vfio_dev_fd = plt_intr_dev_fd_get(intr_handle);
80d61138d4SHarman Kalra 	rc = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
8101bc01e1SJerin Jacob 	if (rc)
8201bc01e1SJerin Jacob 		plt_err("Failed to set_irqs vector=0x%x rc=%d", vec, rc);
8301bc01e1SJerin Jacob 
8401bc01e1SJerin Jacob 	return rc;
8501bc01e1SJerin Jacob }
8601bc01e1SJerin Jacob 
8701bc01e1SJerin Jacob static int
8801bc01e1SJerin Jacob irq_init(struct plt_intr_handle *intr_handle)
8901bc01e1SJerin Jacob {
9001bc01e1SJerin Jacob 	char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
9101bc01e1SJerin Jacob 	struct vfio_irq_set *irq_set;
92d61138d4SHarman Kalra 	int len, rc, vfio_dev_fd;
9301bc01e1SJerin Jacob 	int32_t *fd_ptr;
9401bc01e1SJerin Jacob 	uint32_t i;
9501bc01e1SJerin Jacob 
9601bc01e1SJerin Jacob 	len = sizeof(struct vfio_irq_set) +
97d61138d4SHarman Kalra 	      sizeof(int32_t) * plt_intr_max_intr_get(intr_handle);
9801bc01e1SJerin Jacob 
9901bc01e1SJerin Jacob 	irq_set = (struct vfio_irq_set *)irq_set_buf;
10001bc01e1SJerin Jacob 	irq_set->argsz = len;
10101bc01e1SJerin Jacob 	irq_set->start = 0;
102d61138d4SHarman Kalra 	irq_set->count = plt_intr_max_intr_get(intr_handle);
10301bc01e1SJerin Jacob 	irq_set->flags =
10401bc01e1SJerin Jacob 		VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
10501bc01e1SJerin Jacob 	irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
10601bc01e1SJerin Jacob 
10701bc01e1SJerin Jacob 	fd_ptr = (int32_t *)&irq_set->data[0];
10801bc01e1SJerin Jacob 	for (i = 0; i < irq_set->count; i++)
10901bc01e1SJerin Jacob 		fd_ptr[i] = -1;
11001bc01e1SJerin Jacob 
111d61138d4SHarman Kalra 	vfio_dev_fd = plt_intr_dev_fd_get(intr_handle);
112d61138d4SHarman Kalra 	rc = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
11301bc01e1SJerin Jacob 	if (rc)
11401bc01e1SJerin Jacob 		plt_err("Failed to set irqs vector rc=%d", rc);
11501bc01e1SJerin Jacob 
11601bc01e1SJerin Jacob 	return rc;
11701bc01e1SJerin Jacob }
11801bc01e1SJerin Jacob 
11901bc01e1SJerin Jacob int
12001bc01e1SJerin Jacob dev_irqs_disable(struct plt_intr_handle *intr_handle)
12101bc01e1SJerin Jacob {
12201bc01e1SJerin Jacob 	/* Clear max_intr to indicate re-init next time */
123d61138d4SHarman Kalra 	plt_intr_max_intr_set(intr_handle, 0);
12401bc01e1SJerin Jacob 	return plt_intr_disable(intr_handle);
12501bc01e1SJerin Jacob }
12601bc01e1SJerin Jacob 
12701bc01e1SJerin Jacob int
128993107f0SShijith Thotton dev_irq_reconfigure(struct plt_intr_handle *intr_handle, uint16_t max_intr)
129993107f0SShijith Thotton {
130993107f0SShijith Thotton 	/* Disable interrupts if enabled. */
131993107f0SShijith Thotton 	if (plt_intr_max_intr_get(intr_handle))
132993107f0SShijith Thotton 		dev_irqs_disable(intr_handle);
133993107f0SShijith Thotton 
134993107f0SShijith Thotton 	plt_intr_max_intr_set(intr_handle, max_intr);
135993107f0SShijith Thotton 	return irq_init(intr_handle);
136993107f0SShijith Thotton }
137993107f0SShijith Thotton 
138993107f0SShijith Thotton int
13901bc01e1SJerin Jacob dev_irq_register(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
14001bc01e1SJerin Jacob 		 void *data, unsigned int vec)
14101bc01e1SJerin Jacob {
142d61138d4SHarman Kalra 	struct plt_intr_handle *tmp_handle;
143d61138d4SHarman Kalra 	uint32_t nb_efd, tmp_nb_efd;
144d61138d4SHarman Kalra 	int rc, fd;
14501bc01e1SJerin Jacob 
14601bc01e1SJerin Jacob 	/* If no max_intr read from VFIO */
147d61138d4SHarman Kalra 	if (plt_intr_max_intr_get(intr_handle) == 0) {
14801bc01e1SJerin Jacob 		irq_get_info(intr_handle);
14901bc01e1SJerin Jacob 		irq_init(intr_handle);
15001bc01e1SJerin Jacob 	}
15101bc01e1SJerin Jacob 
152d61138d4SHarman Kalra 	if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) {
153d61138d4SHarman Kalra 		plt_err("Vector=%d greater than max_intr=%d or ",
154d61138d4SHarman Kalra 			vec, plt_intr_max_intr_get(intr_handle));
15501bc01e1SJerin Jacob 		return -EINVAL;
15601bc01e1SJerin Jacob 	}
15701bc01e1SJerin Jacob 
158d61138d4SHarman Kalra 	tmp_handle = intr_handle;
15901bc01e1SJerin Jacob 	/* Create new eventfd for interrupt vector */
160d61138d4SHarman Kalra 	fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
161d61138d4SHarman Kalra 	if (fd == -1)
16201bc01e1SJerin Jacob 		return -ENODEV;
16301bc01e1SJerin Jacob 
164d61138d4SHarman Kalra 	if (plt_intr_fd_set(tmp_handle, fd))
165d61138d4SHarman Kalra 		return -errno;
166d61138d4SHarman Kalra 
16701bc01e1SJerin Jacob 	/* Register vector interrupt callback */
168d61138d4SHarman Kalra 	rc = plt_intr_callback_register(tmp_handle, cb, data);
16901bc01e1SJerin Jacob 	if (rc) {
17001bc01e1SJerin Jacob 		plt_err("Failed to register vector:0x%x irq callback.", vec);
17101bc01e1SJerin Jacob 		return rc;
17201bc01e1SJerin Jacob 	}
17301bc01e1SJerin Jacob 
17414f7e5d4SGowrishankar Muthukrishnan 	rc = plt_intr_efds_index_set(intr_handle, vec, fd);
17514f7e5d4SGowrishankar Muthukrishnan 	if (rc)
17614f7e5d4SGowrishankar Muthukrishnan 		return rc;
17714f7e5d4SGowrishankar Muthukrishnan 
178d61138d4SHarman Kalra 	nb_efd = (vec > (uint32_t)plt_intr_nb_efd_get(intr_handle)) ?
179d61138d4SHarman Kalra 		vec : (uint32_t)plt_intr_nb_efd_get(intr_handle);
180d61138d4SHarman Kalra 	plt_intr_nb_efd_set(intr_handle, nb_efd);
18101bc01e1SJerin Jacob 
182d61138d4SHarman Kalra 	tmp_nb_efd = plt_intr_nb_efd_get(intr_handle) + 1;
183d61138d4SHarman Kalra 	if (tmp_nb_efd > (uint32_t)plt_intr_max_intr_get(intr_handle))
184d61138d4SHarman Kalra 		plt_intr_max_intr_set(intr_handle, tmp_nb_efd);
18501bc01e1SJerin Jacob 	plt_base_dbg("Enable vector:0x%x for vfio (efds: %d, max:%d)", vec,
186d61138d4SHarman Kalra 		     plt_intr_nb_efd_get(intr_handle),
187d61138d4SHarman Kalra 		     plt_intr_max_intr_get(intr_handle));
18801bc01e1SJerin Jacob 
18901bc01e1SJerin Jacob 	/* Enable MSIX vectors to VFIO */
19001bc01e1SJerin Jacob 	return irq_config(intr_handle, vec);
19101bc01e1SJerin Jacob }
19201bc01e1SJerin Jacob 
19301bc01e1SJerin Jacob void
19401bc01e1SJerin Jacob dev_irq_unregister(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
19501bc01e1SJerin Jacob 		   void *data, unsigned int vec)
19601bc01e1SJerin Jacob {
197d61138d4SHarman Kalra 	struct plt_intr_handle *tmp_handle;
19801bc01e1SJerin Jacob 	uint8_t retries = 5; /* 5 ms */
199d61138d4SHarman Kalra 	int rc, fd;
20001bc01e1SJerin Jacob 
201d61138d4SHarman Kalra 	if (vec > (uint32_t)plt_intr_max_intr_get(intr_handle)) {
20201bc01e1SJerin Jacob 		plt_err("Error unregistering MSI-X interrupts vec:%d > %d", vec,
203d61138d4SHarman Kalra 			plt_intr_max_intr_get(intr_handle));
20401bc01e1SJerin Jacob 		return;
20501bc01e1SJerin Jacob 	}
20601bc01e1SJerin Jacob 
207d61138d4SHarman Kalra 	tmp_handle = intr_handle;
208d61138d4SHarman Kalra 	fd = plt_intr_efds_index_get(intr_handle, vec);
209d61138d4SHarman Kalra 	if (fd == -1)
210d61138d4SHarman Kalra 		return;
211d61138d4SHarman Kalra 
212d61138d4SHarman Kalra 	if (plt_intr_fd_set(tmp_handle, fd))
21301bc01e1SJerin Jacob 		return;
21401bc01e1SJerin Jacob 
21501bc01e1SJerin Jacob 	do {
21601bc01e1SJerin Jacob 		/* Un-register callback func from platform lib */
217d61138d4SHarman Kalra 		rc = plt_intr_callback_unregister(tmp_handle, cb, data);
21801bc01e1SJerin Jacob 		/* Retry only if -EAGAIN */
21901bc01e1SJerin Jacob 		if (rc != -EAGAIN)
22001bc01e1SJerin Jacob 			break;
22101bc01e1SJerin Jacob 		plt_delay_ms(1);
22201bc01e1SJerin Jacob 		retries--;
22301bc01e1SJerin Jacob 	} while (retries);
22401bc01e1SJerin Jacob 
22501bc01e1SJerin Jacob 	if (rc < 0) {
22601bc01e1SJerin Jacob 		plt_err("Error unregistering MSI-X vec %d cb, rc=%d", vec, rc);
22701bc01e1SJerin Jacob 		return;
22801bc01e1SJerin Jacob 	}
22901bc01e1SJerin Jacob 
23001bc01e1SJerin Jacob 	plt_base_dbg("Disable vector:0x%x for vfio (efds: %d, max:%d)", vec,
231d61138d4SHarman Kalra 		     plt_intr_nb_efd_get(intr_handle),
232d61138d4SHarman Kalra 		     plt_intr_max_intr_get(intr_handle));
23301bc01e1SJerin Jacob 
234d61138d4SHarman Kalra 	if (plt_intr_efds_index_get(intr_handle, vec) != -1)
235d61138d4SHarman Kalra 		close(plt_intr_efds_index_get(intr_handle, vec));
23601bc01e1SJerin Jacob 	/* Disable MSIX vectors from VFIO */
237d61138d4SHarman Kalra 	plt_intr_efds_index_set(intr_handle, vec, -1);
238d61138d4SHarman Kalra 
23901bc01e1SJerin Jacob 	irq_config(intr_handle, vec);
24001bc01e1SJerin Jacob }
24101bc01e1SJerin Jacob 
24201bc01e1SJerin Jacob #else
24301bc01e1SJerin Jacob 
24401bc01e1SJerin Jacob int
24501bc01e1SJerin Jacob dev_irq_register(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
24601bc01e1SJerin Jacob 		 void *data, unsigned int vec)
24701bc01e1SJerin Jacob {
24801bc01e1SJerin Jacob 	PLT_SET_USED(intr_handle);
24901bc01e1SJerin Jacob 	PLT_SET_USED(cb);
25001bc01e1SJerin Jacob 	PLT_SET_USED(data);
25101bc01e1SJerin Jacob 	PLT_SET_USED(vec);
25201bc01e1SJerin Jacob 
25301bc01e1SJerin Jacob 	return -ENOTSUP;
25401bc01e1SJerin Jacob }
25501bc01e1SJerin Jacob 
25601bc01e1SJerin Jacob void
25701bc01e1SJerin Jacob dev_irq_unregister(struct plt_intr_handle *intr_handle, plt_intr_callback_fn cb,
25801bc01e1SJerin Jacob 		   void *data, unsigned int vec)
25901bc01e1SJerin Jacob {
26001bc01e1SJerin Jacob 	PLT_SET_USED(intr_handle);
26101bc01e1SJerin Jacob 	PLT_SET_USED(cb);
26201bc01e1SJerin Jacob 	PLT_SET_USED(data);
26301bc01e1SJerin Jacob 	PLT_SET_USED(vec);
26401bc01e1SJerin Jacob }
26501bc01e1SJerin Jacob 
26601bc01e1SJerin Jacob int
26701bc01e1SJerin Jacob dev_irqs_disable(struct plt_intr_handle *intr_handle)
26801bc01e1SJerin Jacob {
26901bc01e1SJerin Jacob 	PLT_SET_USED(intr_handle);
27001bc01e1SJerin Jacob 
27101bc01e1SJerin Jacob 	return -ENOTSUP;
27201bc01e1SJerin Jacob }
27301bc01e1SJerin Jacob 
27401bc01e1SJerin Jacob #endif /* __linux__ */
275