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