blob: 4f1e0997f7852f71aad0ca0bffa05140f602308a [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001From 8f0239c9385028a0c15306966c66a56315b11dbc Mon Sep 17 00:00:00 2001
2From: Diana Craciun <diana.craciun@nxp.com>
3Date: Tue, 1 Oct 2019 16:44:04 +0300
4Subject: [PATCH] vfio/fsl-mc: trigger an interrupt via eventfd
5
6This patch allows to set an eventfd for fsl-mc device interrupt
7and also to trigger the interrupt eventfd from userspace for testing.
8
9All fsl-mc device interrupts are MSI type. This does not yet handle
10correctly DPRC container interrupt where re-scanning on container is
11required.
12
13Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
14Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
15---
16 drivers/vfio/fsl-mc/vfio_fsl_mc.c | 20 +++-
17 drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c | 165 +++++++++++++++++++++++++++++-
18 drivers/vfio/fsl-mc/vfio_fsl_mc_private.h | 10 ++
19 3 files changed, 193 insertions(+), 2 deletions(-)
20
21--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
22+++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
23@@ -144,12 +144,30 @@ err_reg_init:
24 static void vfio_fsl_mc_release(void *device_data)
25 {
26 struct vfio_fsl_mc_device *vdev = device_data;
27+ int ret;
28
29 mutex_lock(&vdev->reflck->lock);
30
31- if (!(--vdev->refcnt))
32+ if (!(--vdev->refcnt)) {
33+ struct fsl_mc_device *mc_dev = vdev->mc_dev;
34+ struct device *cont_dev = fsl_mc_cont_dev(&mc_dev->dev);
35+ struct fsl_mc_device *mc_cont = to_fsl_mc_device(cont_dev);
36+ struct fsl_mc_bus *mc_bus;
37+
38+ mc_bus = to_fsl_mc_bus(mc_cont);
39+
40 vfio_fsl_mc_regions_cleanup(vdev);
41
42+ /* reset the device before cleaning up the interrupts */
43+ ret = dprc_reset_container(mc_dev->mc_io, 0,
44+ mc_dev->mc_handle,
45+ mc_dev->obj_desc.id);
46+
47+ vfio_fsl_mc_irqs_cleanup(vdev);
48+
49+ fsl_mc_cleanup_irq_pool(mc_bus);
50+ }
51+
52 mutex_unlock(&vdev->reflck->lock);
53
54 module_put(THIS_MODULE);
55--- a/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c
56+++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c
57@@ -29,12 +29,154 @@ static int vfio_fsl_mc_irq_unmask(struct
58 return -EINVAL;
59 }
60
61+int vfio_fsl_mc_irqs_allocate(struct vfio_fsl_mc_device *vdev)
62+{
63+ struct fsl_mc_device *mc_dev = vdev->mc_dev;
64+ struct vfio_fsl_mc_irq *mc_irq;
65+ int irq_count;
66+ int ret, i;
67+
68+ /* Device does not support any interrupt */
69+ if (mc_dev->obj_desc.irq_count == 0)
70+ return 0;
71+
72+ /* interrupts were already allocated for this device */
73+ if (vdev->mc_irqs)
74+ return 0;
75+
76+ irq_count = mc_dev->obj_desc.irq_count;
77+
78+ mc_irq = kcalloc(irq_count, sizeof(*mc_irq), GFP_KERNEL);
79+ if (mc_irq == NULL)
80+ return -ENOMEM;
81+
82+ /* Allocate IRQs */
83+ ret = fsl_mc_allocate_irqs(mc_dev);
84+ if (ret) {
85+ kfree(mc_irq);
86+ return ret;
87+ }
88+
89+ for (i = 0; i < irq_count; i++) {
90+ mc_irq[i].count = 1;
91+ mc_irq[i].flags = VFIO_IRQ_INFO_EVENTFD;
92+ }
93+
94+ vdev->mc_irqs = mc_irq;
95+
96+ return 0;
97+}
98+static irqreturn_t vfio_fsl_mc_irq_handler(int irq_num, void *arg)
99+{
100+ struct vfio_fsl_mc_irq *mc_irq = (struct vfio_fsl_mc_irq *)arg;
101+
102+ eventfd_signal(mc_irq->trigger, 1);
103+ return IRQ_HANDLED;
104+}
105+
106+static int vfio_set_trigger(struct vfio_fsl_mc_device *vdev,
107+ int index, int fd)
108+{
109+ struct vfio_fsl_mc_irq *irq = &vdev->mc_irqs[index];
110+ struct eventfd_ctx *trigger;
111+ int hwirq;
112+ int ret;
113+
114+ hwirq = vdev->mc_dev->irqs[index]->msi_desc->irq;
115+ if (irq->trigger) {
116+ free_irq(hwirq, irq);
117+ kfree(irq->name);
118+ eventfd_ctx_put(irq->trigger);
119+ irq->trigger = NULL;
120+ }
121+
122+ if (fd < 0) /* Disable only */
123+ return 0;
124+
125+ irq->name = kasprintf(GFP_KERNEL, "vfio-irq[%d](%s)",
126+ hwirq, dev_name(&vdev->mc_dev->dev));
127+ if (!irq->name)
128+ return -ENOMEM;
129+
130+ trigger = eventfd_ctx_fdget(fd);
131+ if (IS_ERR(trigger)) {
132+ kfree(irq->name);
133+ return PTR_ERR(trigger);
134+ }
135+
136+ irq->trigger = trigger;
137+
138+ ret = request_irq(hwirq, vfio_fsl_mc_irq_handler, 0,
139+ irq->name, irq);
140+ if (ret) {
141+ kfree(irq->name);
142+ eventfd_ctx_put(trigger);
143+ irq->trigger = NULL;
144+ return ret;
145+ }
146+
147+ return 0;
148+}
149+
150 static int vfio_fsl_mc_set_irq_trigger(struct vfio_fsl_mc_device *vdev,
151 unsigned int index, unsigned int start,
152 unsigned int count, uint32_t flags,
153 void *data)
154 {
155- return -EINVAL;
156+ struct fsl_mc_device *mc_dev = vdev->mc_dev;
157+ struct fsl_mc_bus *mc_bus;
158+ int ret, hwirq;
159+ struct vfio_fsl_mc_irq *irq;
160+ struct device *cont_dev = fsl_mc_cont_dev(&mc_dev->dev);
161+ struct fsl_mc_device *mc_cont = to_fsl_mc_device(cont_dev);
162+
163+ if (start != 0 || count != 1)
164+ return -EINVAL;
165+
166+ mc_bus = to_fsl_mc_bus(mc_cont);
167+
168+ mutex_lock(&vdev->reflck->lock);
169+ if (!mc_bus->irq_resources) {
170+
171+ ret = fsl_mc_populate_irq_pool(mc_bus,
172+ FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
173+ if (ret)
174+ goto unlock;
175+ }
176+
177+ ret = vfio_fsl_mc_irqs_allocate(vdev);
178+ if (ret)
179+ goto unlock;
180+ mutex_unlock(&vdev->reflck->lock);
181+
182+ if (!count && (flags & VFIO_IRQ_SET_DATA_NONE))
183+ return vfio_set_trigger(vdev, index, -1);
184+
185+ if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
186+ int32_t fd = *(int32_t *)data;
187+
188+ return vfio_set_trigger(vdev, index, fd);
189+ }
190+
191+ hwirq = vdev->mc_dev->irqs[index]->msi_desc->irq;
192+
193+ irq = &vdev->mc_irqs[index];
194+
195+ if (flags & VFIO_IRQ_SET_DATA_NONE) {
196+ vfio_fsl_mc_irq_handler(hwirq, irq);
197+
198+ } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
199+ uint8_t trigger = *(uint8_t *)data;
200+
201+ if (trigger)
202+ vfio_fsl_mc_irq_handler(hwirq, irq);
203+ }
204+
205+ return 0;
206+
207+unlock:
208+ mutex_unlock(&vdev->reflck->lock);
209+ return ret;
210 }
211 int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev,
212 uint32_t flags, unsigned int index,
213@@ -60,3 +202,24 @@ int vfio_fsl_mc_set_irqs_ioctl(struct vf
214
215 return ret;
216 }
217+
218+/* Free All IRQs for the given MC object */
219+void vfio_fsl_mc_irqs_cleanup(struct vfio_fsl_mc_device *vdev)
220+{
221+ struct fsl_mc_device *mc_dev = vdev->mc_dev;
222+ int irq_count = mc_dev->obj_desc.irq_count;
223+ int i;
224+
225+ /* Device does not support any interrupt or the interrupts
226+ * were not configured
227+ */
228+ if (mc_dev->obj_desc.irq_count == 0 || !vdev->mc_irqs)
229+ return;
230+
231+ for (i = 0; i < irq_count; i++)
232+ vfio_set_trigger(vdev, i, -1);
233+
234+ fsl_mc_free_irqs(mc_dev);
235+ kfree(vdev->mc_irqs);
236+ vdev->mc_irqs = NULL;
237+}
238--- a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
239+++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
240@@ -15,6 +15,13 @@
241 #define VFIO_FSL_MC_INDEX_TO_OFFSET(index) \
242 ((u64)(index) << VFIO_FSL_MC_OFFSET_SHIFT)
243
244+struct vfio_fsl_mc_irq {
245+ u32 flags;
246+ u32 count;
247+ struct eventfd_ctx *trigger;
248+ char *name;
249+};
250+
251 struct vfio_fsl_mc_reflck {
252 struct kref kref;
253 struct mutex lock;
254@@ -33,6 +40,7 @@ struct vfio_fsl_mc_device {
255 u32 num_regions;
256 struct vfio_fsl_mc_region *regions;
257 struct vfio_fsl_mc_reflck *reflck;
258+ struct vfio_fsl_mc_irq *mc_irqs;
259 };
260
261 int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev,
262@@ -40,4 +48,6 @@ int vfio_fsl_mc_set_irqs_ioctl(struct vf
263 unsigned int start, unsigned int count,
264 void *data);
265
266+void vfio_fsl_mc_irqs_cleanup(struct vfio_fsl_mc_device *vdev);
267+
268 #endif /* VFIO_PCI_PRIVATE_H */