1*f204e0b8SIan Munsie /* 2*f204e0b8SIan Munsie * Copyright 2014 IBM Corp. 3*f204e0b8SIan Munsie * 4*f204e0b8SIan Munsie * This program is free software; you can redistribute it and/or 5*f204e0b8SIan Munsie * modify it under the terms of the GNU General Public License 6*f204e0b8SIan Munsie * as published by the Free Software Foundation; either version 7*f204e0b8SIan Munsie * 2 of the License, or (at your option) any later version. 8*f204e0b8SIan Munsie */ 9*f204e0b8SIan Munsie 10*f204e0b8SIan Munsie #include <linux/interrupt.h> 11*f204e0b8SIan Munsie #include <linux/workqueue.h> 12*f204e0b8SIan Munsie #include <linux/sched.h> 13*f204e0b8SIan Munsie #include <linux/wait.h> 14*f204e0b8SIan Munsie #include <linux/slab.h> 15*f204e0b8SIan Munsie #include <linux/pid.h> 16*f204e0b8SIan Munsie #include <asm/cputable.h> 17*f204e0b8SIan Munsie #include <misc/cxl.h> 18*f204e0b8SIan Munsie 19*f204e0b8SIan Munsie #include "cxl.h" 20*f204e0b8SIan Munsie 21*f204e0b8SIan Munsie /* XXX: This is implementation specific */ 22*f204e0b8SIan Munsie static irqreturn_t handle_psl_slice_error(struct cxl_context *ctx, u64 dsisr, u64 errstat) 23*f204e0b8SIan Munsie { 24*f204e0b8SIan Munsie u64 fir1, fir2, fir_slice, serr, afu_debug; 25*f204e0b8SIan Munsie 26*f204e0b8SIan Munsie fir1 = cxl_p1_read(ctx->afu->adapter, CXL_PSL_FIR1); 27*f204e0b8SIan Munsie fir2 = cxl_p1_read(ctx->afu->adapter, CXL_PSL_FIR2); 28*f204e0b8SIan Munsie fir_slice = cxl_p1n_read(ctx->afu, CXL_PSL_FIR_SLICE_An); 29*f204e0b8SIan Munsie serr = cxl_p1n_read(ctx->afu, CXL_PSL_SERR_An); 30*f204e0b8SIan Munsie afu_debug = cxl_p1n_read(ctx->afu, CXL_AFU_DEBUG_An); 31*f204e0b8SIan Munsie 32*f204e0b8SIan Munsie dev_crit(&ctx->afu->dev, "PSL ERROR STATUS: 0x%.16llx\n", errstat); 33*f204e0b8SIan Munsie dev_crit(&ctx->afu->dev, "PSL_FIR1: 0x%.16llx\n", fir1); 34*f204e0b8SIan Munsie dev_crit(&ctx->afu->dev, "PSL_FIR2: 0x%.16llx\n", fir2); 35*f204e0b8SIan Munsie dev_crit(&ctx->afu->dev, "PSL_SERR_An: 0x%.16llx\n", serr); 36*f204e0b8SIan Munsie dev_crit(&ctx->afu->dev, "PSL_FIR_SLICE_An: 0x%.16llx\n", fir_slice); 37*f204e0b8SIan Munsie dev_crit(&ctx->afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%.16llx\n", afu_debug); 38*f204e0b8SIan Munsie 39*f204e0b8SIan Munsie dev_crit(&ctx->afu->dev, "STOPPING CXL TRACE\n"); 40*f204e0b8SIan Munsie cxl_stop_trace(ctx->afu->adapter); 41*f204e0b8SIan Munsie 42*f204e0b8SIan Munsie return cxl_ack_irq(ctx, 0, errstat); 43*f204e0b8SIan Munsie } 44*f204e0b8SIan Munsie 45*f204e0b8SIan Munsie irqreturn_t cxl_slice_irq_err(int irq, void *data) 46*f204e0b8SIan Munsie { 47*f204e0b8SIan Munsie struct cxl_afu *afu = data; 48*f204e0b8SIan Munsie u64 fir_slice, errstat, serr, afu_debug; 49*f204e0b8SIan Munsie 50*f204e0b8SIan Munsie WARN(irq, "CXL SLICE ERROR interrupt %i\n", irq); 51*f204e0b8SIan Munsie 52*f204e0b8SIan Munsie serr = cxl_p1n_read(afu, CXL_PSL_SERR_An); 53*f204e0b8SIan Munsie fir_slice = cxl_p1n_read(afu, CXL_PSL_FIR_SLICE_An); 54*f204e0b8SIan Munsie errstat = cxl_p2n_read(afu, CXL_PSL_ErrStat_An); 55*f204e0b8SIan Munsie afu_debug = cxl_p1n_read(afu, CXL_AFU_DEBUG_An); 56*f204e0b8SIan Munsie dev_crit(&afu->dev, "PSL_SERR_An: 0x%.16llx\n", serr); 57*f204e0b8SIan Munsie dev_crit(&afu->dev, "PSL_FIR_SLICE_An: 0x%.16llx\n", fir_slice); 58*f204e0b8SIan Munsie dev_crit(&afu->dev, "CXL_PSL_ErrStat_An: 0x%.16llx\n", errstat); 59*f204e0b8SIan Munsie dev_crit(&afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%.16llx\n", afu_debug); 60*f204e0b8SIan Munsie 61*f204e0b8SIan Munsie cxl_p1n_write(afu, CXL_PSL_SERR_An, serr); 62*f204e0b8SIan Munsie 63*f204e0b8SIan Munsie return IRQ_HANDLED; 64*f204e0b8SIan Munsie } 65*f204e0b8SIan Munsie 66*f204e0b8SIan Munsie static irqreturn_t cxl_irq_err(int irq, void *data) 67*f204e0b8SIan Munsie { 68*f204e0b8SIan Munsie struct cxl *adapter = data; 69*f204e0b8SIan Munsie u64 fir1, fir2, err_ivte; 70*f204e0b8SIan Munsie 71*f204e0b8SIan Munsie WARN(1, "CXL ERROR interrupt %i\n", irq); 72*f204e0b8SIan Munsie 73*f204e0b8SIan Munsie err_ivte = cxl_p1_read(adapter, CXL_PSL_ErrIVTE); 74*f204e0b8SIan Munsie dev_crit(&adapter->dev, "PSL_ErrIVTE: 0x%.16llx\n", err_ivte); 75*f204e0b8SIan Munsie 76*f204e0b8SIan Munsie dev_crit(&adapter->dev, "STOPPING CXL TRACE\n"); 77*f204e0b8SIan Munsie cxl_stop_trace(adapter); 78*f204e0b8SIan Munsie 79*f204e0b8SIan Munsie fir1 = cxl_p1_read(adapter, CXL_PSL_FIR1); 80*f204e0b8SIan Munsie fir2 = cxl_p1_read(adapter, CXL_PSL_FIR2); 81*f204e0b8SIan Munsie 82*f204e0b8SIan Munsie dev_crit(&adapter->dev, "PSL_FIR1: 0x%.16llx\nPSL_FIR2: 0x%.16llx\n", fir1, fir2); 83*f204e0b8SIan Munsie 84*f204e0b8SIan Munsie return IRQ_HANDLED; 85*f204e0b8SIan Munsie } 86*f204e0b8SIan Munsie 87*f204e0b8SIan Munsie static irqreturn_t schedule_cxl_fault(struct cxl_context *ctx, u64 dsisr, u64 dar) 88*f204e0b8SIan Munsie { 89*f204e0b8SIan Munsie ctx->dsisr = dsisr; 90*f204e0b8SIan Munsie ctx->dar = dar; 91*f204e0b8SIan Munsie schedule_work(&ctx->fault_work); 92*f204e0b8SIan Munsie return IRQ_HANDLED; 93*f204e0b8SIan Munsie } 94*f204e0b8SIan Munsie 95*f204e0b8SIan Munsie static irqreturn_t cxl_irq(int irq, void *data) 96*f204e0b8SIan Munsie { 97*f204e0b8SIan Munsie struct cxl_context *ctx = data; 98*f204e0b8SIan Munsie struct cxl_irq_info irq_info; 99*f204e0b8SIan Munsie u64 dsisr, dar; 100*f204e0b8SIan Munsie int result; 101*f204e0b8SIan Munsie 102*f204e0b8SIan Munsie if ((result = cxl_get_irq(ctx, &irq_info))) { 103*f204e0b8SIan Munsie WARN(1, "Unable to get CXL IRQ Info: %i\n", result); 104*f204e0b8SIan Munsie return IRQ_HANDLED; 105*f204e0b8SIan Munsie } 106*f204e0b8SIan Munsie 107*f204e0b8SIan Munsie dsisr = irq_info.dsisr; 108*f204e0b8SIan Munsie dar = irq_info.dar; 109*f204e0b8SIan Munsie 110*f204e0b8SIan Munsie pr_devel("CXL interrupt %i for afu pe: %i DSISR: %#llx DAR: %#llx\n", irq, ctx->pe, dsisr, dar); 111*f204e0b8SIan Munsie 112*f204e0b8SIan Munsie if (dsisr & CXL_PSL_DSISR_An_DS) { 113*f204e0b8SIan Munsie /* 114*f204e0b8SIan Munsie * We don't inherently need to sleep to handle this, but we do 115*f204e0b8SIan Munsie * need to get a ref to the task's mm, which we can't do from 116*f204e0b8SIan Munsie * irq context without the potential for a deadlock since it 117*f204e0b8SIan Munsie * takes the task_lock. An alternate option would be to keep a 118*f204e0b8SIan Munsie * reference to the task's mm the entire time it has cxl open, 119*f204e0b8SIan Munsie * but to do that we need to solve the issue where we hold a 120*f204e0b8SIan Munsie * ref to the mm, but the mm can hold a ref to the fd after an 121*f204e0b8SIan Munsie * mmap preventing anything from being cleaned up. 122*f204e0b8SIan Munsie */ 123*f204e0b8SIan Munsie pr_devel("Scheduling segment miss handling for later pe: %i\n", ctx->pe); 124*f204e0b8SIan Munsie return schedule_cxl_fault(ctx, dsisr, dar); 125*f204e0b8SIan Munsie } 126*f204e0b8SIan Munsie 127*f204e0b8SIan Munsie if (dsisr & CXL_PSL_DSISR_An_M) 128*f204e0b8SIan Munsie pr_devel("CXL interrupt: PTE not found\n"); 129*f204e0b8SIan Munsie if (dsisr & CXL_PSL_DSISR_An_P) 130*f204e0b8SIan Munsie pr_devel("CXL interrupt: Storage protection violation\n"); 131*f204e0b8SIan Munsie if (dsisr & CXL_PSL_DSISR_An_A) 132*f204e0b8SIan Munsie pr_devel("CXL interrupt: AFU lock access to write through or cache inhibited storage\n"); 133*f204e0b8SIan Munsie if (dsisr & CXL_PSL_DSISR_An_S) 134*f204e0b8SIan Munsie pr_devel("CXL interrupt: Access was afu_wr or afu_zero\n"); 135*f204e0b8SIan Munsie if (dsisr & CXL_PSL_DSISR_An_K) 136*f204e0b8SIan Munsie pr_devel("CXL interrupt: Access not permitted by virtual page class key protection\n"); 137*f204e0b8SIan Munsie 138*f204e0b8SIan Munsie if (dsisr & CXL_PSL_DSISR_An_DM) { 139*f204e0b8SIan Munsie /* 140*f204e0b8SIan Munsie * In some cases we might be able to handle the fault 141*f204e0b8SIan Munsie * immediately if hash_page would succeed, but we still need 142*f204e0b8SIan Munsie * the task's mm, which as above we can't get without a lock 143*f204e0b8SIan Munsie */ 144*f204e0b8SIan Munsie pr_devel("Scheduling page fault handling for later pe: %i\n", ctx->pe); 145*f204e0b8SIan Munsie return schedule_cxl_fault(ctx, dsisr, dar); 146*f204e0b8SIan Munsie } 147*f204e0b8SIan Munsie if (dsisr & CXL_PSL_DSISR_An_ST) 148*f204e0b8SIan Munsie WARN(1, "CXL interrupt: Segment Table PTE not found\n"); 149*f204e0b8SIan Munsie if (dsisr & CXL_PSL_DSISR_An_UR) 150*f204e0b8SIan Munsie pr_devel("CXL interrupt: AURP PTE not found\n"); 151*f204e0b8SIan Munsie if (dsisr & CXL_PSL_DSISR_An_PE) 152*f204e0b8SIan Munsie return handle_psl_slice_error(ctx, dsisr, irq_info.errstat); 153*f204e0b8SIan Munsie if (dsisr & CXL_PSL_DSISR_An_AE) { 154*f204e0b8SIan Munsie pr_devel("CXL interrupt: AFU Error %.llx\n", irq_info.afu_err); 155*f204e0b8SIan Munsie 156*f204e0b8SIan Munsie if (ctx->pending_afu_err) { 157*f204e0b8SIan Munsie /* 158*f204e0b8SIan Munsie * This shouldn't happen - the PSL treats these errors 159*f204e0b8SIan Munsie * as fatal and will have reset the AFU, so there's not 160*f204e0b8SIan Munsie * much point buffering multiple AFU errors. 161*f204e0b8SIan Munsie * OTOH if we DO ever see a storm of these come in it's 162*f204e0b8SIan Munsie * probably best that we log them somewhere: 163*f204e0b8SIan Munsie */ 164*f204e0b8SIan Munsie dev_err_ratelimited(&ctx->afu->dev, "CXL AFU Error " 165*f204e0b8SIan Munsie "undelivered to pe %i: %.llx\n", 166*f204e0b8SIan Munsie ctx->pe, irq_info.afu_err); 167*f204e0b8SIan Munsie } else { 168*f204e0b8SIan Munsie spin_lock(&ctx->lock); 169*f204e0b8SIan Munsie ctx->afu_err = irq_info.afu_err; 170*f204e0b8SIan Munsie ctx->pending_afu_err = 1; 171*f204e0b8SIan Munsie spin_unlock(&ctx->lock); 172*f204e0b8SIan Munsie 173*f204e0b8SIan Munsie wake_up_all(&ctx->wq); 174*f204e0b8SIan Munsie } 175*f204e0b8SIan Munsie 176*f204e0b8SIan Munsie cxl_ack_irq(ctx, CXL_PSL_TFC_An_A, 0); 177*f204e0b8SIan Munsie } 178*f204e0b8SIan Munsie if (dsisr & CXL_PSL_DSISR_An_OC) 179*f204e0b8SIan Munsie pr_devel("CXL interrupt: OS Context Warning\n"); 180*f204e0b8SIan Munsie 181*f204e0b8SIan Munsie WARN(1, "Unhandled CXL PSL IRQ\n"); 182*f204e0b8SIan Munsie return IRQ_HANDLED; 183*f204e0b8SIan Munsie } 184*f204e0b8SIan Munsie 185*f204e0b8SIan Munsie static irqreturn_t cxl_irq_multiplexed(int irq, void *data) 186*f204e0b8SIan Munsie { 187*f204e0b8SIan Munsie struct cxl_afu *afu = data; 188*f204e0b8SIan Munsie struct cxl_context *ctx; 189*f204e0b8SIan Munsie int ph = cxl_p2n_read(afu, CXL_PSL_PEHandle_An) & 0xffff; 190*f204e0b8SIan Munsie int ret; 191*f204e0b8SIan Munsie 192*f204e0b8SIan Munsie rcu_read_lock(); 193*f204e0b8SIan Munsie ctx = idr_find(&afu->contexts_idr, ph); 194*f204e0b8SIan Munsie if (ctx) { 195*f204e0b8SIan Munsie ret = cxl_irq(irq, ctx); 196*f204e0b8SIan Munsie rcu_read_unlock(); 197*f204e0b8SIan Munsie return ret; 198*f204e0b8SIan Munsie } 199*f204e0b8SIan Munsie rcu_read_unlock(); 200*f204e0b8SIan Munsie 201*f204e0b8SIan Munsie WARN(1, "Unable to demultiplex CXL PSL IRQ\n"); 202*f204e0b8SIan Munsie return IRQ_HANDLED; 203*f204e0b8SIan Munsie } 204*f204e0b8SIan Munsie 205*f204e0b8SIan Munsie static irqreturn_t cxl_irq_afu(int irq, void *data) 206*f204e0b8SIan Munsie { 207*f204e0b8SIan Munsie struct cxl_context *ctx = data; 208*f204e0b8SIan Munsie irq_hw_number_t hwirq = irqd_to_hwirq(irq_get_irq_data(irq)); 209*f204e0b8SIan Munsie int irq_off, afu_irq = 1; 210*f204e0b8SIan Munsie __u16 range; 211*f204e0b8SIan Munsie int r; 212*f204e0b8SIan Munsie 213*f204e0b8SIan Munsie for (r = 1; r < CXL_IRQ_RANGES; r++) { 214*f204e0b8SIan Munsie irq_off = hwirq - ctx->irqs.offset[r]; 215*f204e0b8SIan Munsie range = ctx->irqs.range[r]; 216*f204e0b8SIan Munsie if (irq_off >= 0 && irq_off < range) { 217*f204e0b8SIan Munsie afu_irq += irq_off; 218*f204e0b8SIan Munsie break; 219*f204e0b8SIan Munsie } 220*f204e0b8SIan Munsie afu_irq += range; 221*f204e0b8SIan Munsie } 222*f204e0b8SIan Munsie if (unlikely(r >= CXL_IRQ_RANGES)) { 223*f204e0b8SIan Munsie WARN(1, "Recieved AFU IRQ out of range for pe %i (virq %i hwirq %lx)\n", 224*f204e0b8SIan Munsie ctx->pe, irq, hwirq); 225*f204e0b8SIan Munsie return IRQ_HANDLED; 226*f204e0b8SIan Munsie } 227*f204e0b8SIan Munsie 228*f204e0b8SIan Munsie pr_devel("Received AFU interrupt %i for pe: %i (virq %i hwirq %lx)\n", 229*f204e0b8SIan Munsie afu_irq, ctx->pe, irq, hwirq); 230*f204e0b8SIan Munsie 231*f204e0b8SIan Munsie if (unlikely(!ctx->irq_bitmap)) { 232*f204e0b8SIan Munsie WARN(1, "Recieved AFU IRQ for context with no IRQ bitmap\n"); 233*f204e0b8SIan Munsie return IRQ_HANDLED; 234*f204e0b8SIan Munsie } 235*f204e0b8SIan Munsie spin_lock(&ctx->lock); 236*f204e0b8SIan Munsie set_bit(afu_irq - 1, ctx->irq_bitmap); 237*f204e0b8SIan Munsie ctx->pending_irq = true; 238*f204e0b8SIan Munsie spin_unlock(&ctx->lock); 239*f204e0b8SIan Munsie 240*f204e0b8SIan Munsie wake_up_all(&ctx->wq); 241*f204e0b8SIan Munsie 242*f204e0b8SIan Munsie return IRQ_HANDLED; 243*f204e0b8SIan Munsie } 244*f204e0b8SIan Munsie 245*f204e0b8SIan Munsie unsigned int cxl_map_irq(struct cxl *adapter, irq_hw_number_t hwirq, 246*f204e0b8SIan Munsie irq_handler_t handler, void *cookie) 247*f204e0b8SIan Munsie { 248*f204e0b8SIan Munsie unsigned int virq; 249*f204e0b8SIan Munsie int result; 250*f204e0b8SIan Munsie 251*f204e0b8SIan Munsie /* IRQ Domain? */ 252*f204e0b8SIan Munsie virq = irq_create_mapping(NULL, hwirq); 253*f204e0b8SIan Munsie if (!virq) { 254*f204e0b8SIan Munsie dev_warn(&adapter->dev, "cxl_map_irq: irq_create_mapping failed\n"); 255*f204e0b8SIan Munsie return 0; 256*f204e0b8SIan Munsie } 257*f204e0b8SIan Munsie 258*f204e0b8SIan Munsie cxl_setup_irq(adapter, hwirq, virq); 259*f204e0b8SIan Munsie 260*f204e0b8SIan Munsie pr_devel("hwirq %#lx mapped to virq %u\n", hwirq, virq); 261*f204e0b8SIan Munsie 262*f204e0b8SIan Munsie result = request_irq(virq, handler, 0, "cxl", cookie); 263*f204e0b8SIan Munsie if (result) { 264*f204e0b8SIan Munsie dev_warn(&adapter->dev, "cxl_map_irq: request_irq failed: %i\n", result); 265*f204e0b8SIan Munsie return 0; 266*f204e0b8SIan Munsie } 267*f204e0b8SIan Munsie 268*f204e0b8SIan Munsie return virq; 269*f204e0b8SIan Munsie } 270*f204e0b8SIan Munsie 271*f204e0b8SIan Munsie void cxl_unmap_irq(unsigned int virq, void *cookie) 272*f204e0b8SIan Munsie { 273*f204e0b8SIan Munsie free_irq(virq, cookie); 274*f204e0b8SIan Munsie irq_dispose_mapping(virq); 275*f204e0b8SIan Munsie } 276*f204e0b8SIan Munsie 277*f204e0b8SIan Munsie static int cxl_register_one_irq(struct cxl *adapter, 278*f204e0b8SIan Munsie irq_handler_t handler, 279*f204e0b8SIan Munsie void *cookie, 280*f204e0b8SIan Munsie irq_hw_number_t *dest_hwirq, 281*f204e0b8SIan Munsie unsigned int *dest_virq) 282*f204e0b8SIan Munsie { 283*f204e0b8SIan Munsie int hwirq, virq; 284*f204e0b8SIan Munsie 285*f204e0b8SIan Munsie if ((hwirq = cxl_alloc_one_irq(adapter)) < 0) 286*f204e0b8SIan Munsie return hwirq; 287*f204e0b8SIan Munsie 288*f204e0b8SIan Munsie if (!(virq = cxl_map_irq(adapter, hwirq, handler, cookie))) 289*f204e0b8SIan Munsie goto err; 290*f204e0b8SIan Munsie 291*f204e0b8SIan Munsie *dest_hwirq = hwirq; 292*f204e0b8SIan Munsie *dest_virq = virq; 293*f204e0b8SIan Munsie 294*f204e0b8SIan Munsie return 0; 295*f204e0b8SIan Munsie 296*f204e0b8SIan Munsie err: 297*f204e0b8SIan Munsie cxl_release_one_irq(adapter, hwirq); 298*f204e0b8SIan Munsie return -ENOMEM; 299*f204e0b8SIan Munsie } 300*f204e0b8SIan Munsie 301*f204e0b8SIan Munsie int cxl_register_psl_err_irq(struct cxl *adapter) 302*f204e0b8SIan Munsie { 303*f204e0b8SIan Munsie int rc; 304*f204e0b8SIan Munsie 305*f204e0b8SIan Munsie if ((rc = cxl_register_one_irq(adapter, cxl_irq_err, adapter, 306*f204e0b8SIan Munsie &adapter->err_hwirq, 307*f204e0b8SIan Munsie &adapter->err_virq))) 308*f204e0b8SIan Munsie return rc; 309*f204e0b8SIan Munsie 310*f204e0b8SIan Munsie cxl_p1_write(adapter, CXL_PSL_ErrIVTE, adapter->err_hwirq & 0xffff); 311*f204e0b8SIan Munsie 312*f204e0b8SIan Munsie return 0; 313*f204e0b8SIan Munsie } 314*f204e0b8SIan Munsie 315*f204e0b8SIan Munsie void cxl_release_psl_err_irq(struct cxl *adapter) 316*f204e0b8SIan Munsie { 317*f204e0b8SIan Munsie cxl_p1_write(adapter, CXL_PSL_ErrIVTE, 0x0000000000000000); 318*f204e0b8SIan Munsie cxl_unmap_irq(adapter->err_virq, adapter); 319*f204e0b8SIan Munsie cxl_release_one_irq(adapter, adapter->err_hwirq); 320*f204e0b8SIan Munsie } 321*f204e0b8SIan Munsie 322*f204e0b8SIan Munsie int cxl_register_serr_irq(struct cxl_afu *afu) 323*f204e0b8SIan Munsie { 324*f204e0b8SIan Munsie u64 serr; 325*f204e0b8SIan Munsie int rc; 326*f204e0b8SIan Munsie 327*f204e0b8SIan Munsie if ((rc = cxl_register_one_irq(afu->adapter, cxl_slice_irq_err, afu, 328*f204e0b8SIan Munsie &afu->serr_hwirq, 329*f204e0b8SIan Munsie &afu->serr_virq))) 330*f204e0b8SIan Munsie return rc; 331*f204e0b8SIan Munsie 332*f204e0b8SIan Munsie serr = cxl_p1n_read(afu, CXL_PSL_SERR_An); 333*f204e0b8SIan Munsie serr = (serr & 0x00ffffffffff0000ULL) | (afu->serr_hwirq & 0xffff); 334*f204e0b8SIan Munsie cxl_p1n_write(afu, CXL_PSL_SERR_An, serr); 335*f204e0b8SIan Munsie 336*f204e0b8SIan Munsie return 0; 337*f204e0b8SIan Munsie } 338*f204e0b8SIan Munsie 339*f204e0b8SIan Munsie void cxl_release_serr_irq(struct cxl_afu *afu) 340*f204e0b8SIan Munsie { 341*f204e0b8SIan Munsie cxl_p1n_write(afu, CXL_PSL_SERR_An, 0x0000000000000000); 342*f204e0b8SIan Munsie cxl_unmap_irq(afu->serr_virq, afu); 343*f204e0b8SIan Munsie cxl_release_one_irq(afu->adapter, afu->serr_hwirq); 344*f204e0b8SIan Munsie } 345*f204e0b8SIan Munsie 346*f204e0b8SIan Munsie int cxl_register_psl_irq(struct cxl_afu *afu) 347*f204e0b8SIan Munsie { 348*f204e0b8SIan Munsie return cxl_register_one_irq(afu->adapter, cxl_irq_multiplexed, afu, 349*f204e0b8SIan Munsie &afu->psl_hwirq, &afu->psl_virq); 350*f204e0b8SIan Munsie } 351*f204e0b8SIan Munsie 352*f204e0b8SIan Munsie void cxl_release_psl_irq(struct cxl_afu *afu) 353*f204e0b8SIan Munsie { 354*f204e0b8SIan Munsie cxl_unmap_irq(afu->psl_virq, afu); 355*f204e0b8SIan Munsie cxl_release_one_irq(afu->adapter, afu->psl_hwirq); 356*f204e0b8SIan Munsie } 357*f204e0b8SIan Munsie 358*f204e0b8SIan Munsie int afu_register_irqs(struct cxl_context *ctx, u32 count) 359*f204e0b8SIan Munsie { 360*f204e0b8SIan Munsie irq_hw_number_t hwirq; 361*f204e0b8SIan Munsie int rc, r, i; 362*f204e0b8SIan Munsie 363*f204e0b8SIan Munsie if ((rc = cxl_alloc_irq_ranges(&ctx->irqs, ctx->afu->adapter, count))) 364*f204e0b8SIan Munsie return rc; 365*f204e0b8SIan Munsie 366*f204e0b8SIan Munsie /* Multiplexed PSL Interrupt */ 367*f204e0b8SIan Munsie ctx->irqs.offset[0] = ctx->afu->psl_hwirq; 368*f204e0b8SIan Munsie ctx->irqs.range[0] = 1; 369*f204e0b8SIan Munsie 370*f204e0b8SIan Munsie ctx->irq_count = count; 371*f204e0b8SIan Munsie ctx->irq_bitmap = kcalloc(BITS_TO_LONGS(count), 372*f204e0b8SIan Munsie sizeof(*ctx->irq_bitmap), GFP_KERNEL); 373*f204e0b8SIan Munsie if (!ctx->irq_bitmap) 374*f204e0b8SIan Munsie return -ENOMEM; 375*f204e0b8SIan Munsie for (r = 1; r < CXL_IRQ_RANGES; r++) { 376*f204e0b8SIan Munsie hwirq = ctx->irqs.offset[r]; 377*f204e0b8SIan Munsie for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) { 378*f204e0b8SIan Munsie cxl_map_irq(ctx->afu->adapter, hwirq, 379*f204e0b8SIan Munsie cxl_irq_afu, ctx); 380*f204e0b8SIan Munsie } 381*f204e0b8SIan Munsie } 382*f204e0b8SIan Munsie 383*f204e0b8SIan Munsie return 0; 384*f204e0b8SIan Munsie } 385*f204e0b8SIan Munsie 386*f204e0b8SIan Munsie void afu_release_irqs(struct cxl_context *ctx) 387*f204e0b8SIan Munsie { 388*f204e0b8SIan Munsie irq_hw_number_t hwirq; 389*f204e0b8SIan Munsie unsigned int virq; 390*f204e0b8SIan Munsie int r, i; 391*f204e0b8SIan Munsie 392*f204e0b8SIan Munsie for (r = 1; r < CXL_IRQ_RANGES; r++) { 393*f204e0b8SIan Munsie hwirq = ctx->irqs.offset[r]; 394*f204e0b8SIan Munsie for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) { 395*f204e0b8SIan Munsie virq = irq_find_mapping(NULL, hwirq); 396*f204e0b8SIan Munsie if (virq) 397*f204e0b8SIan Munsie cxl_unmap_irq(virq, ctx); 398*f204e0b8SIan Munsie } 399*f204e0b8SIan Munsie } 400*f204e0b8SIan Munsie 401*f204e0b8SIan Munsie cxl_release_irq_ranges(&ctx->irqs, ctx->afu->adapter); 402*f204e0b8SIan Munsie } 403