11bb76ff1Sjsg // SPDX-License-Identifier: GPL-2.0 OR MIT
2fb4d8502Sjsg /*
31bb76ff1Sjsg * Copyright 2014-2022 Advanced Micro Devices, Inc.
4fb4d8502Sjsg *
5fb4d8502Sjsg * Permission is hereby granted, free of charge, to any person obtaining a
6fb4d8502Sjsg * copy of this software and associated documentation files (the "Software"),
7fb4d8502Sjsg * to deal in the Software without restriction, including without limitation
8fb4d8502Sjsg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9fb4d8502Sjsg * and/or sell copies of the Software, and to permit persons to whom the
10fb4d8502Sjsg * Software is furnished to do so, subject to the following conditions:
11fb4d8502Sjsg *
12fb4d8502Sjsg * The above copyright notice and this permission notice shall be included in
13fb4d8502Sjsg * all copies or substantial portions of the Software.
14fb4d8502Sjsg *
15fb4d8502Sjsg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16fb4d8502Sjsg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17fb4d8502Sjsg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18fb4d8502Sjsg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19fb4d8502Sjsg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20fb4d8502Sjsg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21fb4d8502Sjsg * OTHER DEALINGS IN THE SOFTWARE.
22fb4d8502Sjsg */
23fb4d8502Sjsg
24fb4d8502Sjsg /*
25fb4d8502Sjsg * KFD Interrupts.
26fb4d8502Sjsg *
27fb4d8502Sjsg * AMD GPUs deliver interrupts by pushing an interrupt description onto the
28fb4d8502Sjsg * interrupt ring and then sending an interrupt. KGD receives the interrupt
29fb4d8502Sjsg * in ISR and sends us a pointer to each new entry on the interrupt ring.
30fb4d8502Sjsg *
31fb4d8502Sjsg * We generally can't process interrupt-signaled events from ISR, so we call
32fb4d8502Sjsg * out to each interrupt client module (currently only the scheduler) to ask if
33fb4d8502Sjsg * each interrupt is interesting. If they return true, then it requires further
34fb4d8502Sjsg * processing so we copy it to an internal interrupt ring and call each
35fb4d8502Sjsg * interrupt client again from a work-queue.
36fb4d8502Sjsg *
37fb4d8502Sjsg * There's no acknowledgment for the interrupts we use. The hardware simply
38fb4d8502Sjsg * queues a new interrupt each time without waiting.
39fb4d8502Sjsg *
40fb4d8502Sjsg * The fixed-size internal queue means that it's possible for us to lose
41fb4d8502Sjsg * interrupts because we have no back-pressure to the hardware.
42fb4d8502Sjsg */
43fb4d8502Sjsg
44fb4d8502Sjsg #include <linux/slab.h>
45fb4d8502Sjsg #include <linux/device.h>
46fb4d8502Sjsg #include <linux/kfifo.h>
47fb4d8502Sjsg #include "kfd_priv.h"
48fb4d8502Sjsg
49fb4d8502Sjsg #define KFD_IH_NUM_ENTRIES 8192
50fb4d8502Sjsg
51fb4d8502Sjsg static void interrupt_wq(struct work_struct *);
52fb4d8502Sjsg
kfd_interrupt_init(struct kfd_node * node)53*f005ef32Sjsg int kfd_interrupt_init(struct kfd_node *node)
54fb4d8502Sjsg {
55fb4d8502Sjsg int r;
56fb4d8502Sjsg
57*f005ef32Sjsg r = kfifo_alloc(&node->ih_fifo,
58*f005ef32Sjsg KFD_IH_NUM_ENTRIES * node->kfd->device_info.ih_ring_entry_size,
59fb4d8502Sjsg GFP_KERNEL);
60fb4d8502Sjsg if (r) {
61*f005ef32Sjsg dev_err(node->adev->dev, "Failed to allocate IH fifo\n");
62fb4d8502Sjsg return r;
63fb4d8502Sjsg }
64fb4d8502Sjsg
65*f005ef32Sjsg node->ih_wq = alloc_workqueue("KFD IH", WQ_HIGHPRI, 1);
66*f005ef32Sjsg if (unlikely(!node->ih_wq)) {
67*f005ef32Sjsg kfifo_free(&node->ih_fifo);
68*f005ef32Sjsg dev_err(node->adev->dev, "Failed to allocate KFD IH workqueue\n");
6954f904ebSjsg return -ENOMEM;
7054f904ebSjsg }
71*f005ef32Sjsg spin_lock_init(&node->interrupt_lock);
72fb4d8502Sjsg
73*f005ef32Sjsg INIT_WORK(&node->interrupt_work, interrupt_wq);
74fb4d8502Sjsg
75*f005ef32Sjsg node->interrupts_active = true;
76fb4d8502Sjsg
77fb4d8502Sjsg /*
78fb4d8502Sjsg * After this function returns, the interrupt will be enabled. This
79fb4d8502Sjsg * barrier ensures that the interrupt running on a different processor
80fb4d8502Sjsg * sees all the above writes.
81fb4d8502Sjsg */
82fb4d8502Sjsg smp_wmb();
83fb4d8502Sjsg
84fb4d8502Sjsg return 0;
85fb4d8502Sjsg }
86fb4d8502Sjsg
kfd_interrupt_exit(struct kfd_node * node)87*f005ef32Sjsg void kfd_interrupt_exit(struct kfd_node *node)
88fb4d8502Sjsg {
89fb4d8502Sjsg /*
90fb4d8502Sjsg * Stop the interrupt handler from writing to the ring and scheduling
91fb4d8502Sjsg * workqueue items. The spinlock ensures that any interrupt running
92fb4d8502Sjsg * after we have unlocked sees interrupts_active = false.
93fb4d8502Sjsg */
94fb4d8502Sjsg unsigned long flags;
95fb4d8502Sjsg
96*f005ef32Sjsg spin_lock_irqsave(&node->interrupt_lock, flags);
97*f005ef32Sjsg node->interrupts_active = false;
98*f005ef32Sjsg spin_unlock_irqrestore(&node->interrupt_lock, flags);
99fb4d8502Sjsg
100fb4d8502Sjsg /*
101fb4d8502Sjsg * flush_work ensures that there are no outstanding
102fb4d8502Sjsg * work-queue items that will access interrupt_ring. New work items
103fb4d8502Sjsg * can't be created because we stopped interrupt handling above.
104fb4d8502Sjsg */
105*f005ef32Sjsg flush_workqueue(node->ih_wq);
106fb4d8502Sjsg
107*f005ef32Sjsg kfifo_free(&node->ih_fifo);
108fb4d8502Sjsg }
109fb4d8502Sjsg
110fb4d8502Sjsg /*
111fb4d8502Sjsg * Assumption: single reader/writer. This function is not re-entrant
112fb4d8502Sjsg */
enqueue_ih_ring_entry(struct kfd_node * node,const void * ih_ring_entry)113*f005ef32Sjsg bool enqueue_ih_ring_entry(struct kfd_node *node, const void *ih_ring_entry)
114fb4d8502Sjsg {
115fb4d8502Sjsg int count;
116fb4d8502Sjsg
117*f005ef32Sjsg count = kfifo_in(&node->ih_fifo, ih_ring_entry,
118*f005ef32Sjsg node->kfd->device_info.ih_ring_entry_size);
119*f005ef32Sjsg if (count != node->kfd->device_info.ih_ring_entry_size) {
120*f005ef32Sjsg dev_dbg_ratelimited(node->adev->dev,
121fb4d8502Sjsg "Interrupt ring overflow, dropping interrupt %d\n",
122fb4d8502Sjsg count);
123fb4d8502Sjsg return false;
124fb4d8502Sjsg }
125fb4d8502Sjsg
126fb4d8502Sjsg return true;
127fb4d8502Sjsg }
128fb4d8502Sjsg
129fb4d8502Sjsg /*
130fb4d8502Sjsg * Assumption: single reader/writer. This function is not re-entrant
131fb4d8502Sjsg */
dequeue_ih_ring_entry(struct kfd_node * node,void * ih_ring_entry)132*f005ef32Sjsg static bool dequeue_ih_ring_entry(struct kfd_node *node, void *ih_ring_entry)
133fb4d8502Sjsg {
134fb4d8502Sjsg int count;
135fb4d8502Sjsg
136*f005ef32Sjsg count = kfifo_out(&node->ih_fifo, ih_ring_entry,
137*f005ef32Sjsg node->kfd->device_info.ih_ring_entry_size);
138fb4d8502Sjsg
139*f005ef32Sjsg WARN_ON(count && count != node->kfd->device_info.ih_ring_entry_size);
140fb4d8502Sjsg
141*f005ef32Sjsg return count == node->kfd->device_info.ih_ring_entry_size;
142fb4d8502Sjsg }
143fb4d8502Sjsg
interrupt_wq(struct work_struct * work)144fb4d8502Sjsg static void interrupt_wq(struct work_struct *work)
145fb4d8502Sjsg {
146*f005ef32Sjsg struct kfd_node *dev = container_of(work, struct kfd_node,
147fb4d8502Sjsg interrupt_work);
148fb4d8502Sjsg uint32_t ih_ring_entry[KFD_MAX_RING_ENTRY_SIZE];
1491bb76ff1Sjsg unsigned long start_jiffies = jiffies;
150fb4d8502Sjsg
151*f005ef32Sjsg if (dev->kfd->device_info.ih_ring_entry_size > sizeof(ih_ring_entry)) {
1521bb76ff1Sjsg dev_err_once(dev->adev->dev, "Ring entry too small\n");
153fb4d8502Sjsg return;
154fb4d8502Sjsg }
155fb4d8502Sjsg
1561bb76ff1Sjsg while (dequeue_ih_ring_entry(dev, ih_ring_entry)) {
157*f005ef32Sjsg dev->kfd->device_info.event_interrupt_class->interrupt_wq(dev,
158fb4d8502Sjsg ih_ring_entry);
1591bb76ff1Sjsg if (time_is_before_jiffies(start_jiffies + HZ)) {
1601bb76ff1Sjsg /* If we spent more than a second processing signals,
1611bb76ff1Sjsg * reschedule the worker to avoid soft-lockup warnings
1621bb76ff1Sjsg */
1631bb76ff1Sjsg queue_work(dev->ih_wq, &dev->interrupt_work);
1641bb76ff1Sjsg break;
1651bb76ff1Sjsg }
1661bb76ff1Sjsg }
167fb4d8502Sjsg }
168fb4d8502Sjsg
interrupt_is_wanted(struct kfd_node * dev,const uint32_t * ih_ring_entry,uint32_t * patched_ihre,bool * flag)169*f005ef32Sjsg bool interrupt_is_wanted(struct kfd_node *dev,
170fb4d8502Sjsg const uint32_t *ih_ring_entry,
171fb4d8502Sjsg uint32_t *patched_ihre, bool *flag)
172fb4d8502Sjsg {
173fb4d8502Sjsg /* integer and bitwise OR so there is no boolean short-circuiting */
174fb4d8502Sjsg unsigned int wanted = 0;
175fb4d8502Sjsg
176*f005ef32Sjsg wanted |= dev->kfd->device_info.event_interrupt_class->interrupt_isr(dev,
177fb4d8502Sjsg ih_ring_entry, patched_ihre, flag);
178fb4d8502Sjsg
179fb4d8502Sjsg return wanted != 0;
180fb4d8502Sjsg }
181