aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/cxl/irq.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-12-11 20:48:14 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-12-11 20:48:14 -0500
commit140cd7fb04a4a2bc09a30980bc8104cc89e09330 (patch)
tree776d57c7508f946d592de4334d4d3cb50fd36220 /drivers/misc/cxl/irq.c
parent27afc5dbda52ee3dbcd0bda7375c917c6936b470 (diff)
parent56548fc0e86cb9156af7a7e1f15ba78f251dafaf (diff)
Merge tag 'powerpc-3.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mpe/linux
Pull powerpc updates from Michael Ellerman: "Some nice cleanups like removing bootmem, and removal of __get_cpu_var(). There is one patch to mm/gup.c. This is the generic GUP implementation, but is only used by us and arm(64). We have an ack from Steve Capper, and although we didn't get an ack from Andrew he told us to take the patch through the powerpc tree. There's one cxl patch. This is in drivers/misc, but Greg said he was happy for us to manage fixes for it. There is an infrastructure patch to support an IPMI driver for OPAL. There is also an RTC driver for OPAL. We weren't able to get any response from the RTC maintainer, Alessandro Zummo, so in the end we just merged the driver. The usual batch of Freescale updates from Scott" * tag 'powerpc-3.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mpe/linux: (101 commits) powerpc/powernv: Return to cpu offline loop when finished in KVM guest powerpc/book3s: Fix partial invalidation of TLBs in MCE code. powerpc/mm: don't do tlbie for updatepp request with NO HPTE fault powerpc/xmon: Cleanup the breakpoint flags powerpc/xmon: Enable HW instruction breakpoint on POWER8 powerpc/mm/thp: Use tlbiel if possible powerpc/mm/thp: Remove code duplication powerpc/mm/hugetlb: Sanity check gigantic hugepage count powerpc/oprofile: Disable pagefaults during user stack read powerpc/mm: Check for matching hpte without taking hpte lock powerpc: Drop useless warning in eeh_init() powerpc/powernv: Cleanup unused MCE definitions/declarations. powerpc/eeh: Dump PHB diag-data early powerpc/eeh: Recover EEH error on ownership change for BCM5719 powerpc/eeh: Set EEH_PE_RESET on PE reset powerpc/eeh: Refactor eeh_reset_pe() powerpc: Remove more traces of bootmem powerpc/pseries: Initialise nvram_pstore_info's buf_lock cxl: Name interrupts in /proc/interrupt cxl: Return error to PSL if IRQ demultiplexing fails & print clearer warning ...
Diffstat (limited to 'drivers/misc/cxl/irq.c')
-rw-r--r--drivers/misc/cxl/irq.c144
1 files changed, 117 insertions, 27 deletions
diff --git a/drivers/misc/cxl/irq.c b/drivers/misc/cxl/irq.c
index 336020c8e1af..c294925f73ee 100644
--- a/drivers/misc/cxl/irq.c
+++ b/drivers/misc/cxl/irq.c
@@ -92,20 +92,13 @@ static irqreturn_t schedule_cxl_fault(struct cxl_context *ctx, u64 dsisr, u64 da
92 return IRQ_HANDLED; 92 return IRQ_HANDLED;
93} 93}
94 94
95static irqreturn_t cxl_irq(int irq, void *data) 95static irqreturn_t cxl_irq(int irq, void *data, struct cxl_irq_info *irq_info)
96{ 96{
97 struct cxl_context *ctx = data; 97 struct cxl_context *ctx = data;
98 struct cxl_irq_info irq_info;
99 u64 dsisr, dar; 98 u64 dsisr, dar;
100 int result;
101
102 if ((result = cxl_get_irq(ctx, &irq_info))) {
103 WARN(1, "Unable to get CXL IRQ Info: %i\n", result);
104 return IRQ_HANDLED;
105 }
106 99
107 dsisr = irq_info.dsisr; 100 dsisr = irq_info->dsisr;
108 dar = irq_info.dar; 101 dar = irq_info->dar;
109 102
110 pr_devel("CXL interrupt %i for afu pe: %i DSISR: %#llx DAR: %#llx\n", irq, ctx->pe, dsisr, dar); 103 pr_devel("CXL interrupt %i for afu pe: %i DSISR: %#llx DAR: %#llx\n", irq, ctx->pe, dsisr, dar);
111 104
@@ -149,9 +142,9 @@ static irqreturn_t cxl_irq(int irq, void *data)
149 if (dsisr & CXL_PSL_DSISR_An_UR) 142 if (dsisr & CXL_PSL_DSISR_An_UR)
150 pr_devel("CXL interrupt: AURP PTE not found\n"); 143 pr_devel("CXL interrupt: AURP PTE not found\n");
151 if (dsisr & CXL_PSL_DSISR_An_PE) 144 if (dsisr & CXL_PSL_DSISR_An_PE)
152 return handle_psl_slice_error(ctx, dsisr, irq_info.errstat); 145 return handle_psl_slice_error(ctx, dsisr, irq_info->errstat);
153 if (dsisr & CXL_PSL_DSISR_An_AE) { 146 if (dsisr & CXL_PSL_DSISR_An_AE) {
154 pr_devel("CXL interrupt: AFU Error %.llx\n", irq_info.afu_err); 147 pr_devel("CXL interrupt: AFU Error %.llx\n", irq_info->afu_err);
155 148
156 if (ctx->pending_afu_err) { 149 if (ctx->pending_afu_err) {
157 /* 150 /*
@@ -163,10 +156,10 @@ static irqreturn_t cxl_irq(int irq, void *data)
163 */ 156 */
164 dev_err_ratelimited(&ctx->afu->dev, "CXL AFU Error " 157 dev_err_ratelimited(&ctx->afu->dev, "CXL AFU Error "
165 "undelivered to pe %i: %.llx\n", 158 "undelivered to pe %i: %.llx\n",
166 ctx->pe, irq_info.afu_err); 159 ctx->pe, irq_info->afu_err);
167 } else { 160 } else {
168 spin_lock(&ctx->lock); 161 spin_lock(&ctx->lock);
169 ctx->afu_err = irq_info.afu_err; 162 ctx->afu_err = irq_info->afu_err;
170 ctx->pending_afu_err = 1; 163 ctx->pending_afu_err = 1;
171 spin_unlock(&ctx->lock); 164 spin_unlock(&ctx->lock);
172 165
@@ -182,24 +175,43 @@ static irqreturn_t cxl_irq(int irq, void *data)
182 return IRQ_HANDLED; 175 return IRQ_HANDLED;
183} 176}
184 177
178static irqreturn_t fail_psl_irq(struct cxl_afu *afu, struct cxl_irq_info *irq_info)
179{
180 if (irq_info->dsisr & CXL_PSL_DSISR_TRANS)
181 cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE);
182 else
183 cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A);
184
185 return IRQ_HANDLED;
186}
187
185static irqreturn_t cxl_irq_multiplexed(int irq, void *data) 188static irqreturn_t cxl_irq_multiplexed(int irq, void *data)
186{ 189{
187 struct cxl_afu *afu = data; 190 struct cxl_afu *afu = data;
188 struct cxl_context *ctx; 191 struct cxl_context *ctx;
192 struct cxl_irq_info irq_info;
189 int ph = cxl_p2n_read(afu, CXL_PSL_PEHandle_An) & 0xffff; 193 int ph = cxl_p2n_read(afu, CXL_PSL_PEHandle_An) & 0xffff;
190 int ret; 194 int ret;
191 195
196 if ((ret = cxl_get_irq(afu, &irq_info))) {
197 WARN(1, "Unable to get CXL IRQ Info: %i\n", ret);
198 return fail_psl_irq(afu, &irq_info);
199 }
200
192 rcu_read_lock(); 201 rcu_read_lock();
193 ctx = idr_find(&afu->contexts_idr, ph); 202 ctx = idr_find(&afu->contexts_idr, ph);
194 if (ctx) { 203 if (ctx) {
195 ret = cxl_irq(irq, ctx); 204 ret = cxl_irq(irq, ctx, &irq_info);
196 rcu_read_unlock(); 205 rcu_read_unlock();
197 return ret; 206 return ret;
198 } 207 }
199 rcu_read_unlock(); 208 rcu_read_unlock();
200 209
201 WARN(1, "Unable to demultiplex CXL PSL IRQ\n"); 210 WARN(1, "Unable to demultiplex CXL PSL IRQ for PE %i DSISR %.16llx DAR"
202 return IRQ_HANDLED; 211 " %.16llx\n(Possible AFU HW issue - was a term/remove acked"
212 " with outstanding transactions?)\n", ph, irq_info.dsisr,
213 irq_info.dar);
214 return fail_psl_irq(afu, &irq_info);
203} 215}
204 216
205static irqreturn_t cxl_irq_afu(int irq, void *data) 217static irqreturn_t cxl_irq_afu(int irq, void *data)
@@ -243,7 +255,7 @@ static irqreturn_t cxl_irq_afu(int irq, void *data)
243} 255}
244 256
245unsigned int cxl_map_irq(struct cxl *adapter, irq_hw_number_t hwirq, 257unsigned int cxl_map_irq(struct cxl *adapter, irq_hw_number_t hwirq,
246 irq_handler_t handler, void *cookie) 258 irq_handler_t handler, void *cookie, const char *name)
247{ 259{
248 unsigned int virq; 260 unsigned int virq;
249 int result; 261 int result;
@@ -259,7 +271,7 @@ unsigned int cxl_map_irq(struct cxl *adapter, irq_hw_number_t hwirq,
259 271
260 pr_devel("hwirq %#lx mapped to virq %u\n", hwirq, virq); 272 pr_devel("hwirq %#lx mapped to virq %u\n", hwirq, virq);
261 273
262 result = request_irq(virq, handler, 0, "cxl", cookie); 274 result = request_irq(virq, handler, 0, name, cookie);
263 if (result) { 275 if (result) {
264 dev_warn(&adapter->dev, "cxl_map_irq: request_irq failed: %i\n", result); 276 dev_warn(&adapter->dev, "cxl_map_irq: request_irq failed: %i\n", result);
265 return 0; 277 return 0;
@@ -278,14 +290,15 @@ static int cxl_register_one_irq(struct cxl *adapter,
278 irq_handler_t handler, 290 irq_handler_t handler,
279 void *cookie, 291 void *cookie,
280 irq_hw_number_t *dest_hwirq, 292 irq_hw_number_t *dest_hwirq,
281 unsigned int *dest_virq) 293 unsigned int *dest_virq,
294 const char *name)
282{ 295{
283 int hwirq, virq; 296 int hwirq, virq;
284 297
285 if ((hwirq = cxl_alloc_one_irq(adapter)) < 0) 298 if ((hwirq = cxl_alloc_one_irq(adapter)) < 0)
286 return hwirq; 299 return hwirq;
287 300
288 if (!(virq = cxl_map_irq(adapter, hwirq, handler, cookie))) 301 if (!(virq = cxl_map_irq(adapter, hwirq, handler, cookie, name)))
289 goto err; 302 goto err;
290 303
291 *dest_hwirq = hwirq; 304 *dest_hwirq = hwirq;
@@ -302,10 +315,19 @@ int cxl_register_psl_err_irq(struct cxl *adapter)
302{ 315{
303 int rc; 316 int rc;
304 317
318 adapter->irq_name = kasprintf(GFP_KERNEL, "cxl-%s-err",
319 dev_name(&adapter->dev));
320 if (!adapter->irq_name)
321 return -ENOMEM;
322
305 if ((rc = cxl_register_one_irq(adapter, cxl_irq_err, adapter, 323 if ((rc = cxl_register_one_irq(adapter, cxl_irq_err, adapter,
306 &adapter->err_hwirq, 324 &adapter->err_hwirq,
307 &adapter->err_virq))) 325 &adapter->err_virq,
326 adapter->irq_name))) {
327 kfree(adapter->irq_name);
328 adapter->irq_name = NULL;
308 return rc; 329 return rc;
330 }
309 331
310 cxl_p1_write(adapter, CXL_PSL_ErrIVTE, adapter->err_hwirq & 0xffff); 332 cxl_p1_write(adapter, CXL_PSL_ErrIVTE, adapter->err_hwirq & 0xffff);
311 333
@@ -317,6 +339,7 @@ void cxl_release_psl_err_irq(struct cxl *adapter)
317 cxl_p1_write(adapter, CXL_PSL_ErrIVTE, 0x0000000000000000); 339 cxl_p1_write(adapter, CXL_PSL_ErrIVTE, 0x0000000000000000);
318 cxl_unmap_irq(adapter->err_virq, adapter); 340 cxl_unmap_irq(adapter->err_virq, adapter);
319 cxl_release_one_irq(adapter, adapter->err_hwirq); 341 cxl_release_one_irq(adapter, adapter->err_hwirq);
342 kfree(adapter->irq_name);
320} 343}
321 344
322int cxl_register_serr_irq(struct cxl_afu *afu) 345int cxl_register_serr_irq(struct cxl_afu *afu)
@@ -324,10 +347,18 @@ int cxl_register_serr_irq(struct cxl_afu *afu)
324 u64 serr; 347 u64 serr;
325 int rc; 348 int rc;
326 349
350 afu->err_irq_name = kasprintf(GFP_KERNEL, "cxl-%s-err",
351 dev_name(&afu->dev));
352 if (!afu->err_irq_name)
353 return -ENOMEM;
354
327 if ((rc = cxl_register_one_irq(afu->adapter, cxl_slice_irq_err, afu, 355 if ((rc = cxl_register_one_irq(afu->adapter, cxl_slice_irq_err, afu,
328 &afu->serr_hwirq, 356 &afu->serr_hwirq,
329 &afu->serr_virq))) 357 &afu->serr_virq, afu->err_irq_name))) {
358 kfree(afu->err_irq_name);
359 afu->err_irq_name = NULL;
330 return rc; 360 return rc;
361 }
331 362
332 serr = cxl_p1n_read(afu, CXL_PSL_SERR_An); 363 serr = cxl_p1n_read(afu, CXL_PSL_SERR_An);
333 serr = (serr & 0x00ffffffffff0000ULL) | (afu->serr_hwirq & 0xffff); 364 serr = (serr & 0x00ffffffffff0000ULL) | (afu->serr_hwirq & 0xffff);
@@ -341,24 +372,50 @@ void cxl_release_serr_irq(struct cxl_afu *afu)
341 cxl_p1n_write(afu, CXL_PSL_SERR_An, 0x0000000000000000); 372 cxl_p1n_write(afu, CXL_PSL_SERR_An, 0x0000000000000000);
342 cxl_unmap_irq(afu->serr_virq, afu); 373 cxl_unmap_irq(afu->serr_virq, afu);
343 cxl_release_one_irq(afu->adapter, afu->serr_hwirq); 374 cxl_release_one_irq(afu->adapter, afu->serr_hwirq);
375 kfree(afu->err_irq_name);
344} 376}
345 377
346int cxl_register_psl_irq(struct cxl_afu *afu) 378int cxl_register_psl_irq(struct cxl_afu *afu)
347{ 379{
348 return cxl_register_one_irq(afu->adapter, cxl_irq_multiplexed, afu, 380 int rc;
349 &afu->psl_hwirq, &afu->psl_virq); 381
382 afu->psl_irq_name = kasprintf(GFP_KERNEL, "cxl-%s",
383 dev_name(&afu->dev));
384 if (!afu->psl_irq_name)
385 return -ENOMEM;
386
387 if ((rc = cxl_register_one_irq(afu->adapter, cxl_irq_multiplexed, afu,
388 &afu->psl_hwirq, &afu->psl_virq,
389 afu->psl_irq_name))) {
390 kfree(afu->psl_irq_name);
391 afu->psl_irq_name = NULL;
392 }
393 return rc;
350} 394}
351 395
352void cxl_release_psl_irq(struct cxl_afu *afu) 396void cxl_release_psl_irq(struct cxl_afu *afu)
353{ 397{
354 cxl_unmap_irq(afu->psl_virq, afu); 398 cxl_unmap_irq(afu->psl_virq, afu);
355 cxl_release_one_irq(afu->adapter, afu->psl_hwirq); 399 cxl_release_one_irq(afu->adapter, afu->psl_hwirq);
400 kfree(afu->psl_irq_name);
401}
402
403void afu_irq_name_free(struct cxl_context *ctx)
404{
405 struct cxl_irq_name *irq_name, *tmp;
406
407 list_for_each_entry_safe(irq_name, tmp, &ctx->irq_names, list) {
408 kfree(irq_name->name);
409 list_del(&irq_name->list);
410 kfree(irq_name);
411 }
356} 412}
357 413
358int afu_register_irqs(struct cxl_context *ctx, u32 count) 414int afu_register_irqs(struct cxl_context *ctx, u32 count)
359{ 415{
360 irq_hw_number_t hwirq; 416 irq_hw_number_t hwirq;
361 int rc, r, i; 417 int rc, r, i, j = 1;
418 struct cxl_irq_name *irq_name;
362 419
363 if ((rc = cxl_alloc_irq_ranges(&ctx->irqs, ctx->afu->adapter, count))) 420 if ((rc = cxl_alloc_irq_ranges(&ctx->irqs, ctx->afu->adapter, count)))
364 return rc; 421 return rc;
@@ -372,15 +429,47 @@ int afu_register_irqs(struct cxl_context *ctx, u32 count)
372 sizeof(*ctx->irq_bitmap), GFP_KERNEL); 429 sizeof(*ctx->irq_bitmap), GFP_KERNEL);
373 if (!ctx->irq_bitmap) 430 if (!ctx->irq_bitmap)
374 return -ENOMEM; 431 return -ENOMEM;
432
433 /*
434 * Allocate names first. If any fail, bail out before allocating
435 * actual hardware IRQs.
436 */
437 INIT_LIST_HEAD(&ctx->irq_names);
438 for (r = 1; r < CXL_IRQ_RANGES; r++) {
439 for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) {
440 irq_name = kmalloc(sizeof(struct cxl_irq_name),
441 GFP_KERNEL);
442 if (!irq_name)
443 goto out;
444 irq_name->name = kasprintf(GFP_KERNEL, "cxl-%s-pe%i-%i",
445 dev_name(&ctx->afu->dev),
446 ctx->pe, j);
447 if (!irq_name->name) {
448 kfree(irq_name);
449 goto out;
450 }
451 /* Add to tail so next look get the correct order */
452 list_add_tail(&irq_name->list, &ctx->irq_names);
453 j++;
454 }
455 }
456
457 /* We've allocated all memory now, so let's do the irq allocations */
458 irq_name = list_first_entry(&ctx->irq_names, struct cxl_irq_name, list);
375 for (r = 1; r < CXL_IRQ_RANGES; r++) { 459 for (r = 1; r < CXL_IRQ_RANGES; r++) {
376 hwirq = ctx->irqs.offset[r]; 460 hwirq = ctx->irqs.offset[r];
377 for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) { 461 for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) {
378 cxl_map_irq(ctx->afu->adapter, hwirq, 462 cxl_map_irq(ctx->afu->adapter, hwirq,
379 cxl_irq_afu, ctx); 463 cxl_irq_afu, ctx, irq_name->name);
464 irq_name = list_next_entry(irq_name, list);
380 } 465 }
381 } 466 }
382 467
383 return 0; 468 return 0;
469
470out:
471 afu_irq_name_free(ctx);
472 return -ENOMEM;
384} 473}
385 474
386void afu_release_irqs(struct cxl_context *ctx) 475void afu_release_irqs(struct cxl_context *ctx)
@@ -398,5 +487,6 @@ void afu_release_irqs(struct cxl_context *ctx)
398 } 487 }
399 } 488 }
400 489
490 afu_irq_name_free(ctx);
401 cxl_release_irq_ranges(&ctx->irqs, ctx->afu->adapter); 491 cxl_release_irq_ranges(&ctx->irqs, ctx->afu->adapter);
402} 492}