cxl: Update cxl_irq() prototype
[deliverable/linux.git] / drivers / misc / cxl / irq.c
CommitLineData
f204e0b8
IM
1/*
2 * Copyright 2014 IBM Corp.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9
10#include <linux/interrupt.h>
11#include <linux/workqueue.h>
12#include <linux/sched.h>
13#include <linux/wait.h>
14#include <linux/slab.h>
15#include <linux/pid.h>
16#include <asm/cputable.h>
ec249dd8 17#include <misc/cxl-base.h>
f204e0b8
IM
18
19#include "cxl.h"
9bcf28cd 20#include "trace.h"
f204e0b8 21
f204e0b8
IM
22static irqreturn_t schedule_cxl_fault(struct cxl_context *ctx, u64 dsisr, u64 dar)
23{
24 ctx->dsisr = dsisr;
25 ctx->dar = dar;
26 schedule_work(&ctx->fault_work);
27 return IRQ_HANDLED;
28}
29
6d625ed9 30irqreturn_t cxl_irq(int irq, struct cxl_context *ctx, struct cxl_irq_info *irq_info)
f204e0b8 31{
f204e0b8 32 u64 dsisr, dar;
f204e0b8 33
bc78b05b
IM
34 dsisr = irq_info->dsisr;
35 dar = irq_info->dar;
f204e0b8 36
9bcf28cd
IM
37 trace_cxl_psl_irq(ctx, irq, dsisr, dar);
38
f204e0b8
IM
39 pr_devel("CXL interrupt %i for afu pe: %i DSISR: %#llx DAR: %#llx\n", irq, ctx->pe, dsisr, dar);
40
41 if (dsisr & CXL_PSL_DSISR_An_DS) {
42 /*
43 * We don't inherently need to sleep to handle this, but we do
44 * need to get a ref to the task's mm, which we can't do from
45 * irq context without the potential for a deadlock since it
46 * takes the task_lock. An alternate option would be to keep a
47 * reference to the task's mm the entire time it has cxl open,
48 * but to do that we need to solve the issue where we hold a
49 * ref to the mm, but the mm can hold a ref to the fd after an
50 * mmap preventing anything from being cleaned up.
51 */
52 pr_devel("Scheduling segment miss handling for later pe: %i\n", ctx->pe);
53 return schedule_cxl_fault(ctx, dsisr, dar);
54 }
55
56 if (dsisr & CXL_PSL_DSISR_An_M)
57 pr_devel("CXL interrupt: PTE not found\n");
58 if (dsisr & CXL_PSL_DSISR_An_P)
59 pr_devel("CXL interrupt: Storage protection violation\n");
60 if (dsisr & CXL_PSL_DSISR_An_A)
61 pr_devel("CXL interrupt: AFU lock access to write through or cache inhibited storage\n");
62 if (dsisr & CXL_PSL_DSISR_An_S)
63 pr_devel("CXL interrupt: Access was afu_wr or afu_zero\n");
64 if (dsisr & CXL_PSL_DSISR_An_K)
65 pr_devel("CXL interrupt: Access not permitted by virtual page class key protection\n");
66
67 if (dsisr & CXL_PSL_DSISR_An_DM) {
68 /*
69 * In some cases we might be able to handle the fault
70 * immediately if hash_page would succeed, but we still need
71 * the task's mm, which as above we can't get without a lock
72 */
73 pr_devel("Scheduling page fault handling for later pe: %i\n", ctx->pe);
74 return schedule_cxl_fault(ctx, dsisr, dar);
75 }
76 if (dsisr & CXL_PSL_DSISR_An_ST)
77 WARN(1, "CXL interrupt: Segment Table PTE not found\n");
78 if (dsisr & CXL_PSL_DSISR_An_UR)
79 pr_devel("CXL interrupt: AURP PTE not found\n");
80 if (dsisr & CXL_PSL_DSISR_An_PE)
5be587b1
FB
81 return cxl_ops->handle_psl_slice_error(ctx, dsisr,
82 irq_info->errstat);
f204e0b8 83 if (dsisr & CXL_PSL_DSISR_An_AE) {
de369538 84 pr_devel("CXL interrupt: AFU Error 0x%016llx\n", irq_info->afu_err);
f204e0b8
IM
85
86 if (ctx->pending_afu_err) {
87 /*
88 * This shouldn't happen - the PSL treats these errors
89 * as fatal and will have reset the AFU, so there's not
90 * much point buffering multiple AFU errors.
91 * OTOH if we DO ever see a storm of these come in it's
92 * probably best that we log them somewhere:
93 */
94 dev_err_ratelimited(&ctx->afu->dev, "CXL AFU Error "
de369538 95 "undelivered to pe %i: 0x%016llx\n",
bc78b05b 96 ctx->pe, irq_info->afu_err);
f204e0b8
IM
97 } else {
98 spin_lock(&ctx->lock);
bc78b05b 99 ctx->afu_err = irq_info->afu_err;
f204e0b8
IM
100 ctx->pending_afu_err = 1;
101 spin_unlock(&ctx->lock);
102
103 wake_up_all(&ctx->wq);
104 }
105
5be587b1 106 cxl_ops->ack_irq(ctx, CXL_PSL_TFC_An_A, 0);
a6130ed2 107 return IRQ_HANDLED;
f204e0b8
IM
108 }
109 if (dsisr & CXL_PSL_DSISR_An_OC)
110 pr_devel("CXL interrupt: OS Context Warning\n");
111
112 WARN(1, "Unhandled CXL PSL IRQ\n");
113 return IRQ_HANDLED;
114}
115
f204e0b8
IM
116static irqreturn_t cxl_irq_afu(int irq, void *data)
117{
118 struct cxl_context *ctx = data;
119 irq_hw_number_t hwirq = irqd_to_hwirq(irq_get_irq_data(irq));
120 int irq_off, afu_irq = 1;
121 __u16 range;
122 int r;
123
124 for (r = 1; r < CXL_IRQ_RANGES; r++) {
125 irq_off = hwirq - ctx->irqs.offset[r];
126 range = ctx->irqs.range[r];
127 if (irq_off >= 0 && irq_off < range) {
128 afu_irq += irq_off;
129 break;
130 }
131 afu_irq += range;
132 }
133 if (unlikely(r >= CXL_IRQ_RANGES)) {
134 WARN(1, "Recieved AFU IRQ out of range for pe %i (virq %i hwirq %lx)\n",
135 ctx->pe, irq, hwirq);
136 return IRQ_HANDLED;
137 }
138
9bcf28cd 139 trace_cxl_afu_irq(ctx, afu_irq, irq, hwirq);
f204e0b8
IM
140 pr_devel("Received AFU interrupt %i for pe: %i (virq %i hwirq %lx)\n",
141 afu_irq, ctx->pe, irq, hwirq);
142
143 if (unlikely(!ctx->irq_bitmap)) {
144 WARN(1, "Recieved AFU IRQ for context with no IRQ bitmap\n");
145 return IRQ_HANDLED;
146 }
147 spin_lock(&ctx->lock);
148 set_bit(afu_irq - 1, ctx->irq_bitmap);
149 ctx->pending_irq = true;
150 spin_unlock(&ctx->lock);
151
152 wake_up_all(&ctx->wq);
153
154 return IRQ_HANDLED;
155}
156
157unsigned int cxl_map_irq(struct cxl *adapter, irq_hw_number_t hwirq,
80fa93fc 158 irq_handler_t handler, void *cookie, const char *name)
f204e0b8
IM
159{
160 unsigned int virq;
161 int result;
162
163 /* IRQ Domain? */
164 virq = irq_create_mapping(NULL, hwirq);
165 if (!virq) {
166 dev_warn(&adapter->dev, "cxl_map_irq: irq_create_mapping failed\n");
167 return 0;
168 }
169
5be587b1
FB
170 if (cxl_ops->setup_irq)
171 cxl_ops->setup_irq(adapter, hwirq, virq);
f204e0b8
IM
172
173 pr_devel("hwirq %#lx mapped to virq %u\n", hwirq, virq);
174
80fa93fc 175 result = request_irq(virq, handler, 0, name, cookie);
f204e0b8
IM
176 if (result) {
177 dev_warn(&adapter->dev, "cxl_map_irq: request_irq failed: %i\n", result);
178 return 0;
179 }
180
181 return virq;
182}
183
184void cxl_unmap_irq(unsigned int virq, void *cookie)
185{
186 free_irq(virq, cookie);
187 irq_dispose_mapping(virq);
188}
189
86331862
CL
190int cxl_register_one_irq(struct cxl *adapter,
191 irq_handler_t handler,
192 void *cookie,
193 irq_hw_number_t *dest_hwirq,
194 unsigned int *dest_virq,
195 const char *name)
f204e0b8
IM
196{
197 int hwirq, virq;
198
5be587b1 199 if ((hwirq = cxl_ops->alloc_one_irq(adapter)) < 0)
f204e0b8
IM
200 return hwirq;
201
80fa93fc 202 if (!(virq = cxl_map_irq(adapter, hwirq, handler, cookie, name)))
f204e0b8
IM
203 goto err;
204
205 *dest_hwirq = hwirq;
206 *dest_virq = virq;
207
208 return 0;
209
210err:
5be587b1 211 cxl_ops->release_one_irq(adapter, hwirq);
f204e0b8
IM
212 return -ENOMEM;
213}
214
8dde152e 215void afu_irq_name_free(struct cxl_context *ctx)
80fa93fc
MN
216{
217 struct cxl_irq_name *irq_name, *tmp;
218
219 list_for_each_entry_safe(irq_name, tmp, &ctx->irq_names, list) {
220 kfree(irq_name->name);
221 list_del(&irq_name->list);
222 kfree(irq_name);
223 }
f204e0b8
IM
224}
225
c358d84b 226int afu_allocate_irqs(struct cxl_context *ctx, u32 count)
f204e0b8 227{
80fa93fc
MN
228 int rc, r, i, j = 1;
229 struct cxl_irq_name *irq_name;
f204e0b8 230
a6897f39
VJ
231 /* Initialize the list head to hold irq names */
232 INIT_LIST_HEAD(&ctx->irq_names);
233
5be587b1
FB
234 if ((rc = cxl_ops->alloc_irq_ranges(&ctx->irqs, ctx->afu->adapter,
235 count)))
f204e0b8
IM
236 return rc;
237
238 /* Multiplexed PSL Interrupt */
239 ctx->irqs.offset[0] = ctx->afu->psl_hwirq;
240 ctx->irqs.range[0] = 1;
241
242 ctx->irq_count = count;
243 ctx->irq_bitmap = kcalloc(BITS_TO_LONGS(count),
244 sizeof(*ctx->irq_bitmap), GFP_KERNEL);
245 if (!ctx->irq_bitmap)
a6897f39 246 goto out;
80fa93fc
MN
247
248 /*
249 * Allocate names first. If any fail, bail out before allocating
250 * actual hardware IRQs.
251 */
80fa93fc 252 for (r = 1; r < CXL_IRQ_RANGES; r++) {
d3383aaa 253 for (i = 0; i < ctx->irqs.range[r]; i++) {
80fa93fc
MN
254 irq_name = kmalloc(sizeof(struct cxl_irq_name),
255 GFP_KERNEL);
256 if (!irq_name)
257 goto out;
258 irq_name->name = kasprintf(GFP_KERNEL, "cxl-%s-pe%i-%i",
259 dev_name(&ctx->afu->dev),
260 ctx->pe, j);
261 if (!irq_name->name) {
262 kfree(irq_name);
263 goto out;
264 }
265 /* Add to tail so next look get the correct order */
266 list_add_tail(&irq_name->list, &ctx->irq_names);
267 j++;
268 }
269 }
c358d84b
MN
270 return 0;
271
272out:
5be587b1 273 cxl_ops->release_irq_ranges(&ctx->irqs, ctx->afu->adapter);
c358d84b
MN
274 afu_irq_name_free(ctx);
275 return -ENOMEM;
276}
277
3d6b040e 278static void afu_register_hwirqs(struct cxl_context *ctx)
c358d84b
MN
279{
280 irq_hw_number_t hwirq;
281 struct cxl_irq_name *irq_name;
282 int r,i;
80fa93fc
MN
283
284 /* We've allocated all memory now, so let's do the irq allocations */
285 irq_name = list_first_entry(&ctx->irq_names, struct cxl_irq_name, list);
f204e0b8
IM
286 for (r = 1; r < CXL_IRQ_RANGES; r++) {
287 hwirq = ctx->irqs.offset[r];
288 for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) {
289 cxl_map_irq(ctx->afu->adapter, hwirq,
80fa93fc
MN
290 cxl_irq_afu, ctx, irq_name->name);
291 irq_name = list_next_entry(irq_name, list);
f204e0b8
IM
292 }
293 }
c358d84b 294}
f204e0b8 295
c358d84b
MN
296int afu_register_irqs(struct cxl_context *ctx, u32 count)
297{
298 int rc;
80fa93fc 299
c358d84b
MN
300 rc = afu_allocate_irqs(ctx, count);
301 if (rc)
302 return rc;
303
304 afu_register_hwirqs(ctx);
305 return 0;
d56d301b 306}
f204e0b8 307
6428832a 308void afu_release_irqs(struct cxl_context *ctx, void *cookie)
f204e0b8
IM
309{
310 irq_hw_number_t hwirq;
311 unsigned int virq;
312 int r, i;
313
314 for (r = 1; r < CXL_IRQ_RANGES; r++) {
315 hwirq = ctx->irqs.offset[r];
316 for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) {
317 virq = irq_find_mapping(NULL, hwirq);
318 if (virq)
6428832a 319 cxl_unmap_irq(virq, cookie);
f204e0b8
IM
320 }
321 }
322
80fa93fc 323 afu_irq_name_free(ctx);
5be587b1 324 cxl_ops->release_irq_ranges(&ctx->irqs, ctx->afu->adapter);
8c7dd08a 325
8c7dd08a 326 ctx->irq_count = 0;
f204e0b8 327}
This page took 0.0901999999999999 seconds and 5 git commands to generate.