1*14baf4d9SChristophe Lombard /* 2*14baf4d9SChristophe Lombard * Copyright 2015 IBM Corp. 3*14baf4d9SChristophe Lombard * 4*14baf4d9SChristophe Lombard * This program is free software; you can redistribute it and/or 5*14baf4d9SChristophe Lombard * modify it under the terms of the GNU General Public License 6*14baf4d9SChristophe Lombard * as published by the Free Software Foundation; either version 7*14baf4d9SChristophe Lombard * 2 of the License, or (at your option) any later version. 8*14baf4d9SChristophe Lombard */ 9*14baf4d9SChristophe Lombard 10*14baf4d9SChristophe Lombard #include <linux/spinlock.h> 11*14baf4d9SChristophe Lombard #include <linux/uaccess.h> 12*14baf4d9SChristophe Lombard #include <linux/delay.h> 13*14baf4d9SChristophe Lombard 14*14baf4d9SChristophe Lombard #include "cxl.h" 15*14baf4d9SChristophe Lombard #include "hcalls.h" 16*14baf4d9SChristophe Lombard #include "trace.h" 17*14baf4d9SChristophe Lombard 18*14baf4d9SChristophe Lombard 19*14baf4d9SChristophe Lombard static irqreturn_t guest_handle_psl_slice_error(struct cxl_context *ctx, u64 dsisr, 20*14baf4d9SChristophe Lombard u64 errstat) 21*14baf4d9SChristophe Lombard { 22*14baf4d9SChristophe Lombard pr_devel("in %s\n", __func__); 23*14baf4d9SChristophe Lombard dev_crit(&ctx->afu->dev, "PSL ERROR STATUS: 0x%.16llx\n", errstat); 24*14baf4d9SChristophe Lombard 25*14baf4d9SChristophe Lombard return cxl_ops->ack_irq(ctx, 0, errstat); 26*14baf4d9SChristophe Lombard } 27*14baf4d9SChristophe Lombard 28*14baf4d9SChristophe Lombard static ssize_t guest_collect_vpd(struct cxl *adapter, struct cxl_afu *afu, 29*14baf4d9SChristophe Lombard void *buf, size_t len) 30*14baf4d9SChristophe Lombard { 31*14baf4d9SChristophe Lombard unsigned int entries, mod; 32*14baf4d9SChristophe Lombard unsigned long **vpd_buf = NULL; 33*14baf4d9SChristophe Lombard struct sg_list *le; 34*14baf4d9SChristophe Lombard int rc = 0, i, tocopy; 35*14baf4d9SChristophe Lombard u64 out = 0; 36*14baf4d9SChristophe Lombard 37*14baf4d9SChristophe Lombard if (buf == NULL) 38*14baf4d9SChristophe Lombard return -EINVAL; 39*14baf4d9SChristophe Lombard 40*14baf4d9SChristophe Lombard /* number of entries in the list */ 41*14baf4d9SChristophe Lombard entries = len / SG_BUFFER_SIZE; 42*14baf4d9SChristophe Lombard mod = len % SG_BUFFER_SIZE; 43*14baf4d9SChristophe Lombard if (mod) 44*14baf4d9SChristophe Lombard entries++; 45*14baf4d9SChristophe Lombard 46*14baf4d9SChristophe Lombard if (entries > SG_MAX_ENTRIES) { 47*14baf4d9SChristophe Lombard entries = SG_MAX_ENTRIES; 48*14baf4d9SChristophe Lombard len = SG_MAX_ENTRIES * SG_BUFFER_SIZE; 49*14baf4d9SChristophe Lombard mod = 0; 50*14baf4d9SChristophe Lombard } 51*14baf4d9SChristophe Lombard 52*14baf4d9SChristophe Lombard vpd_buf = kzalloc(entries * sizeof(unsigned long *), GFP_KERNEL); 53*14baf4d9SChristophe Lombard if (!vpd_buf) 54*14baf4d9SChristophe Lombard return -ENOMEM; 55*14baf4d9SChristophe Lombard 56*14baf4d9SChristophe Lombard le = (struct sg_list *)get_zeroed_page(GFP_KERNEL); 57*14baf4d9SChristophe Lombard if (!le) { 58*14baf4d9SChristophe Lombard rc = -ENOMEM; 59*14baf4d9SChristophe Lombard goto err1; 60*14baf4d9SChristophe Lombard } 61*14baf4d9SChristophe Lombard 62*14baf4d9SChristophe Lombard for (i = 0; i < entries; i++) { 63*14baf4d9SChristophe Lombard vpd_buf[i] = (unsigned long *)get_zeroed_page(GFP_KERNEL); 64*14baf4d9SChristophe Lombard if (!vpd_buf[i]) { 65*14baf4d9SChristophe Lombard rc = -ENOMEM; 66*14baf4d9SChristophe Lombard goto err2; 67*14baf4d9SChristophe Lombard } 68*14baf4d9SChristophe Lombard le[i].phys_addr = cpu_to_be64(virt_to_phys(vpd_buf[i])); 69*14baf4d9SChristophe Lombard le[i].len = cpu_to_be64(SG_BUFFER_SIZE); 70*14baf4d9SChristophe Lombard if ((i == (entries - 1)) && mod) 71*14baf4d9SChristophe Lombard le[i].len = cpu_to_be64(mod); 72*14baf4d9SChristophe Lombard } 73*14baf4d9SChristophe Lombard 74*14baf4d9SChristophe Lombard if (adapter) 75*14baf4d9SChristophe Lombard rc = cxl_h_collect_vpd_adapter(adapter->guest->handle, 76*14baf4d9SChristophe Lombard virt_to_phys(le), entries, &out); 77*14baf4d9SChristophe Lombard else 78*14baf4d9SChristophe Lombard rc = cxl_h_collect_vpd(afu->guest->handle, 0, 79*14baf4d9SChristophe Lombard virt_to_phys(le), entries, &out); 80*14baf4d9SChristophe Lombard pr_devel("length of available (entries: %i), vpd: %#llx\n", 81*14baf4d9SChristophe Lombard entries, out); 82*14baf4d9SChristophe Lombard 83*14baf4d9SChristophe Lombard if (!rc) { 84*14baf4d9SChristophe Lombard /* 85*14baf4d9SChristophe Lombard * hcall returns in 'out' the size of available VPDs. 86*14baf4d9SChristophe Lombard * It fills the buffer with as much data as possible. 87*14baf4d9SChristophe Lombard */ 88*14baf4d9SChristophe Lombard if (out < len) 89*14baf4d9SChristophe Lombard len = out; 90*14baf4d9SChristophe Lombard rc = len; 91*14baf4d9SChristophe Lombard if (out) { 92*14baf4d9SChristophe Lombard for (i = 0; i < entries; i++) { 93*14baf4d9SChristophe Lombard if (len < SG_BUFFER_SIZE) 94*14baf4d9SChristophe Lombard tocopy = len; 95*14baf4d9SChristophe Lombard else 96*14baf4d9SChristophe Lombard tocopy = SG_BUFFER_SIZE; 97*14baf4d9SChristophe Lombard memcpy(buf, vpd_buf[i], tocopy); 98*14baf4d9SChristophe Lombard buf += tocopy; 99*14baf4d9SChristophe Lombard len -= tocopy; 100*14baf4d9SChristophe Lombard } 101*14baf4d9SChristophe Lombard } 102*14baf4d9SChristophe Lombard } 103*14baf4d9SChristophe Lombard err2: 104*14baf4d9SChristophe Lombard for (i = 0; i < entries; i++) { 105*14baf4d9SChristophe Lombard if (vpd_buf[i]) 106*14baf4d9SChristophe Lombard free_page((unsigned long) vpd_buf[i]); 107*14baf4d9SChristophe Lombard } 108*14baf4d9SChristophe Lombard free_page((unsigned long) le); 109*14baf4d9SChristophe Lombard err1: 110*14baf4d9SChristophe Lombard kfree(vpd_buf); 111*14baf4d9SChristophe Lombard return rc; 112*14baf4d9SChristophe Lombard } 113*14baf4d9SChristophe Lombard 114*14baf4d9SChristophe Lombard static int guest_get_irq_info(struct cxl_context *ctx, struct cxl_irq_info *info) 115*14baf4d9SChristophe Lombard { 116*14baf4d9SChristophe Lombard return cxl_h_collect_int_info(ctx->afu->guest->handle, ctx->process_token, info); 117*14baf4d9SChristophe Lombard } 118*14baf4d9SChristophe Lombard 119*14baf4d9SChristophe Lombard static irqreturn_t guest_psl_irq(int irq, void *data) 120*14baf4d9SChristophe Lombard { 121*14baf4d9SChristophe Lombard struct cxl_context *ctx = data; 122*14baf4d9SChristophe Lombard struct cxl_irq_info irq_info; 123*14baf4d9SChristophe Lombard int rc; 124*14baf4d9SChristophe Lombard 125*14baf4d9SChristophe Lombard pr_devel("%d: received PSL interrupt %i\n", ctx->pe, irq); 126*14baf4d9SChristophe Lombard rc = guest_get_irq_info(ctx, &irq_info); 127*14baf4d9SChristophe Lombard if (rc) { 128*14baf4d9SChristophe Lombard WARN(1, "Unable to get IRQ info: %i\n", rc); 129*14baf4d9SChristophe Lombard return IRQ_HANDLED; 130*14baf4d9SChristophe Lombard } 131*14baf4d9SChristophe Lombard 132*14baf4d9SChristophe Lombard rc = cxl_irq(irq, ctx, &irq_info); 133*14baf4d9SChristophe Lombard return rc; 134*14baf4d9SChristophe Lombard } 135*14baf4d9SChristophe Lombard 136*14baf4d9SChristophe Lombard static irqreturn_t guest_slice_irq_err(int irq, void *data) 137*14baf4d9SChristophe Lombard { 138*14baf4d9SChristophe Lombard struct cxl_afu *afu = data; 139*14baf4d9SChristophe Lombard int rc; 140*14baf4d9SChristophe Lombard u64 serr; 141*14baf4d9SChristophe Lombard 142*14baf4d9SChristophe Lombard WARN(irq, "CXL SLICE ERROR interrupt %i\n", irq); 143*14baf4d9SChristophe Lombard rc = cxl_h_get_fn_error_interrupt(afu->guest->handle, &serr); 144*14baf4d9SChristophe Lombard if (rc) { 145*14baf4d9SChristophe Lombard dev_crit(&afu->dev, "Couldn't read PSL_SERR_An: %d\n", rc); 146*14baf4d9SChristophe Lombard return IRQ_HANDLED; 147*14baf4d9SChristophe Lombard } 148*14baf4d9SChristophe Lombard dev_crit(&afu->dev, "PSL_SERR_An: 0x%.16llx\n", serr); 149*14baf4d9SChristophe Lombard 150*14baf4d9SChristophe Lombard rc = cxl_h_ack_fn_error_interrupt(afu->guest->handle, serr); 151*14baf4d9SChristophe Lombard if (rc) 152*14baf4d9SChristophe Lombard dev_crit(&afu->dev, "Couldn't ack slice error interrupt: %d\n", 153*14baf4d9SChristophe Lombard rc); 154*14baf4d9SChristophe Lombard 155*14baf4d9SChristophe Lombard return IRQ_HANDLED; 156*14baf4d9SChristophe Lombard } 157*14baf4d9SChristophe Lombard 158*14baf4d9SChristophe Lombard 159*14baf4d9SChristophe Lombard static int irq_alloc_range(struct cxl *adapter, int len, int *irq) 160*14baf4d9SChristophe Lombard { 161*14baf4d9SChristophe Lombard int i, n; 162*14baf4d9SChristophe Lombard struct irq_avail *cur; 163*14baf4d9SChristophe Lombard 164*14baf4d9SChristophe Lombard for (i = 0; i < adapter->guest->irq_nranges; i++) { 165*14baf4d9SChristophe Lombard cur = &adapter->guest->irq_avail[i]; 166*14baf4d9SChristophe Lombard n = bitmap_find_next_zero_area(cur->bitmap, cur->range, 167*14baf4d9SChristophe Lombard 0, len, 0); 168*14baf4d9SChristophe Lombard if (n < cur->range) { 169*14baf4d9SChristophe Lombard bitmap_set(cur->bitmap, n, len); 170*14baf4d9SChristophe Lombard *irq = cur->offset + n; 171*14baf4d9SChristophe Lombard pr_devel("guest: allocate IRQs %#x->%#x\n", 172*14baf4d9SChristophe Lombard *irq, *irq + len - 1); 173*14baf4d9SChristophe Lombard 174*14baf4d9SChristophe Lombard return 0; 175*14baf4d9SChristophe Lombard } 176*14baf4d9SChristophe Lombard } 177*14baf4d9SChristophe Lombard return -ENOSPC; 178*14baf4d9SChristophe Lombard } 179*14baf4d9SChristophe Lombard 180*14baf4d9SChristophe Lombard static int irq_free_range(struct cxl *adapter, int irq, int len) 181*14baf4d9SChristophe Lombard { 182*14baf4d9SChristophe Lombard int i, n; 183*14baf4d9SChristophe Lombard struct irq_avail *cur; 184*14baf4d9SChristophe Lombard 185*14baf4d9SChristophe Lombard if (len == 0) 186*14baf4d9SChristophe Lombard return -ENOENT; 187*14baf4d9SChristophe Lombard 188*14baf4d9SChristophe Lombard for (i = 0; i < adapter->guest->irq_nranges; i++) { 189*14baf4d9SChristophe Lombard cur = &adapter->guest->irq_avail[i]; 190*14baf4d9SChristophe Lombard if (irq >= cur->offset && 191*14baf4d9SChristophe Lombard (irq + len) <= (cur->offset + cur->range)) { 192*14baf4d9SChristophe Lombard n = irq - cur->offset; 193*14baf4d9SChristophe Lombard bitmap_clear(cur->bitmap, n, len); 194*14baf4d9SChristophe Lombard pr_devel("guest: release IRQs %#x->%#x\n", 195*14baf4d9SChristophe Lombard irq, irq + len - 1); 196*14baf4d9SChristophe Lombard return 0; 197*14baf4d9SChristophe Lombard } 198*14baf4d9SChristophe Lombard } 199*14baf4d9SChristophe Lombard return -ENOENT; 200*14baf4d9SChristophe Lombard } 201*14baf4d9SChristophe Lombard 202*14baf4d9SChristophe Lombard static int guest_reset(struct cxl *adapter) 203*14baf4d9SChristophe Lombard { 204*14baf4d9SChristophe Lombard int rc; 205*14baf4d9SChristophe Lombard 206*14baf4d9SChristophe Lombard pr_devel("Adapter reset request\n"); 207*14baf4d9SChristophe Lombard rc = cxl_h_reset_adapter(adapter->guest->handle); 208*14baf4d9SChristophe Lombard return rc; 209*14baf4d9SChristophe Lombard } 210*14baf4d9SChristophe Lombard 211*14baf4d9SChristophe Lombard static int guest_alloc_one_irq(struct cxl *adapter) 212*14baf4d9SChristophe Lombard { 213*14baf4d9SChristophe Lombard int irq; 214*14baf4d9SChristophe Lombard 215*14baf4d9SChristophe Lombard spin_lock(&adapter->guest->irq_alloc_lock); 216*14baf4d9SChristophe Lombard if (irq_alloc_range(adapter, 1, &irq)) 217*14baf4d9SChristophe Lombard irq = -ENOSPC; 218*14baf4d9SChristophe Lombard spin_unlock(&adapter->guest->irq_alloc_lock); 219*14baf4d9SChristophe Lombard return irq; 220*14baf4d9SChristophe Lombard } 221*14baf4d9SChristophe Lombard 222*14baf4d9SChristophe Lombard static void guest_release_one_irq(struct cxl *adapter, int irq) 223*14baf4d9SChristophe Lombard { 224*14baf4d9SChristophe Lombard spin_lock(&adapter->guest->irq_alloc_lock); 225*14baf4d9SChristophe Lombard irq_free_range(adapter, irq, 1); 226*14baf4d9SChristophe Lombard spin_unlock(&adapter->guest->irq_alloc_lock); 227*14baf4d9SChristophe Lombard } 228*14baf4d9SChristophe Lombard 229*14baf4d9SChristophe Lombard static int guest_alloc_irq_ranges(struct cxl_irq_ranges *irqs, 230*14baf4d9SChristophe Lombard struct cxl *adapter, unsigned int num) 231*14baf4d9SChristophe Lombard { 232*14baf4d9SChristophe Lombard int i, try, irq; 233*14baf4d9SChristophe Lombard 234*14baf4d9SChristophe Lombard memset(irqs, 0, sizeof(struct cxl_irq_ranges)); 235*14baf4d9SChristophe Lombard 236*14baf4d9SChristophe Lombard spin_lock(&adapter->guest->irq_alloc_lock); 237*14baf4d9SChristophe Lombard for (i = 0; i < CXL_IRQ_RANGES && num; i++) { 238*14baf4d9SChristophe Lombard try = num; 239*14baf4d9SChristophe Lombard while (try) { 240*14baf4d9SChristophe Lombard if (irq_alloc_range(adapter, try, &irq) == 0) 241*14baf4d9SChristophe Lombard break; 242*14baf4d9SChristophe Lombard try /= 2; 243*14baf4d9SChristophe Lombard } 244*14baf4d9SChristophe Lombard if (!try) 245*14baf4d9SChristophe Lombard goto error; 246*14baf4d9SChristophe Lombard irqs->offset[i] = irq; 247*14baf4d9SChristophe Lombard irqs->range[i] = try; 248*14baf4d9SChristophe Lombard num -= try; 249*14baf4d9SChristophe Lombard } 250*14baf4d9SChristophe Lombard if (num) 251*14baf4d9SChristophe Lombard goto error; 252*14baf4d9SChristophe Lombard spin_unlock(&adapter->guest->irq_alloc_lock); 253*14baf4d9SChristophe Lombard return 0; 254*14baf4d9SChristophe Lombard 255*14baf4d9SChristophe Lombard error: 256*14baf4d9SChristophe Lombard for (i = 0; i < CXL_IRQ_RANGES; i++) 257*14baf4d9SChristophe Lombard irq_free_range(adapter, irqs->offset[i], irqs->range[i]); 258*14baf4d9SChristophe Lombard spin_unlock(&adapter->guest->irq_alloc_lock); 259*14baf4d9SChristophe Lombard return -ENOSPC; 260*14baf4d9SChristophe Lombard } 261*14baf4d9SChristophe Lombard 262*14baf4d9SChristophe Lombard static void guest_release_irq_ranges(struct cxl_irq_ranges *irqs, 263*14baf4d9SChristophe Lombard struct cxl *adapter) 264*14baf4d9SChristophe Lombard { 265*14baf4d9SChristophe Lombard int i; 266*14baf4d9SChristophe Lombard 267*14baf4d9SChristophe Lombard spin_lock(&adapter->guest->irq_alloc_lock); 268*14baf4d9SChristophe Lombard for (i = 0; i < CXL_IRQ_RANGES; i++) 269*14baf4d9SChristophe Lombard irq_free_range(adapter, irqs->offset[i], irqs->range[i]); 270*14baf4d9SChristophe Lombard spin_unlock(&adapter->guest->irq_alloc_lock); 271*14baf4d9SChristophe Lombard } 272*14baf4d9SChristophe Lombard 273*14baf4d9SChristophe Lombard static int guest_register_serr_irq(struct cxl_afu *afu) 274*14baf4d9SChristophe Lombard { 275*14baf4d9SChristophe Lombard afu->err_irq_name = kasprintf(GFP_KERNEL, "cxl-%s-err", 276*14baf4d9SChristophe Lombard dev_name(&afu->dev)); 277*14baf4d9SChristophe Lombard if (!afu->err_irq_name) 278*14baf4d9SChristophe Lombard return -ENOMEM; 279*14baf4d9SChristophe Lombard 280*14baf4d9SChristophe Lombard if (!(afu->serr_virq = cxl_map_irq(afu->adapter, afu->serr_hwirq, 281*14baf4d9SChristophe Lombard guest_slice_irq_err, afu, afu->err_irq_name))) { 282*14baf4d9SChristophe Lombard kfree(afu->err_irq_name); 283*14baf4d9SChristophe Lombard afu->err_irq_name = NULL; 284*14baf4d9SChristophe Lombard return -ENOMEM; 285*14baf4d9SChristophe Lombard } 286*14baf4d9SChristophe Lombard 287*14baf4d9SChristophe Lombard return 0; 288*14baf4d9SChristophe Lombard } 289*14baf4d9SChristophe Lombard 290*14baf4d9SChristophe Lombard static void guest_release_serr_irq(struct cxl_afu *afu) 291*14baf4d9SChristophe Lombard { 292*14baf4d9SChristophe Lombard cxl_unmap_irq(afu->serr_virq, afu); 293*14baf4d9SChristophe Lombard cxl_ops->release_one_irq(afu->adapter, afu->serr_hwirq); 294*14baf4d9SChristophe Lombard kfree(afu->err_irq_name); 295*14baf4d9SChristophe Lombard } 296*14baf4d9SChristophe Lombard 297*14baf4d9SChristophe Lombard static int guest_ack_irq(struct cxl_context *ctx, u64 tfc, u64 psl_reset_mask) 298*14baf4d9SChristophe Lombard { 299*14baf4d9SChristophe Lombard return cxl_h_control_faults(ctx->afu->guest->handle, ctx->process_token, 300*14baf4d9SChristophe Lombard tfc >> 32, (psl_reset_mask != 0)); 301*14baf4d9SChristophe Lombard } 302*14baf4d9SChristophe Lombard 303*14baf4d9SChristophe Lombard static void disable_afu_irqs(struct cxl_context *ctx) 304*14baf4d9SChristophe Lombard { 305*14baf4d9SChristophe Lombard irq_hw_number_t hwirq; 306*14baf4d9SChristophe Lombard unsigned int virq; 307*14baf4d9SChristophe Lombard int r, i; 308*14baf4d9SChristophe Lombard 309*14baf4d9SChristophe Lombard pr_devel("Disabling AFU(%d) interrupts\n", ctx->afu->slice); 310*14baf4d9SChristophe Lombard for (r = 0; r < CXL_IRQ_RANGES; r++) { 311*14baf4d9SChristophe Lombard hwirq = ctx->irqs.offset[r]; 312*14baf4d9SChristophe Lombard for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) { 313*14baf4d9SChristophe Lombard virq = irq_find_mapping(NULL, hwirq); 314*14baf4d9SChristophe Lombard disable_irq(virq); 315*14baf4d9SChristophe Lombard } 316*14baf4d9SChristophe Lombard } 317*14baf4d9SChristophe Lombard } 318*14baf4d9SChristophe Lombard 319*14baf4d9SChristophe Lombard static void enable_afu_irqs(struct cxl_context *ctx) 320*14baf4d9SChristophe Lombard { 321*14baf4d9SChristophe Lombard irq_hw_number_t hwirq; 322*14baf4d9SChristophe Lombard unsigned int virq; 323*14baf4d9SChristophe Lombard int r, i; 324*14baf4d9SChristophe Lombard 325*14baf4d9SChristophe Lombard pr_devel("Enabling AFU(%d) interrupts\n", ctx->afu->slice); 326*14baf4d9SChristophe Lombard for (r = 0; r < CXL_IRQ_RANGES; r++) { 327*14baf4d9SChristophe Lombard hwirq = ctx->irqs.offset[r]; 328*14baf4d9SChristophe Lombard for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) { 329*14baf4d9SChristophe Lombard virq = irq_find_mapping(NULL, hwirq); 330*14baf4d9SChristophe Lombard enable_irq(virq); 331*14baf4d9SChristophe Lombard } 332*14baf4d9SChristophe Lombard } 333*14baf4d9SChristophe Lombard } 334*14baf4d9SChristophe Lombard 335*14baf4d9SChristophe Lombard static int _guest_afu_cr_readXX(int sz, struct cxl_afu *afu, int cr_idx, 336*14baf4d9SChristophe Lombard u64 offset, u64 *val) 337*14baf4d9SChristophe Lombard { 338*14baf4d9SChristophe Lombard unsigned long cr; 339*14baf4d9SChristophe Lombard char c; 340*14baf4d9SChristophe Lombard int rc = 0; 341*14baf4d9SChristophe Lombard 342*14baf4d9SChristophe Lombard if (afu->crs_len < sz) 343*14baf4d9SChristophe Lombard return -ENOENT; 344*14baf4d9SChristophe Lombard 345*14baf4d9SChristophe Lombard if (unlikely(offset >= afu->crs_len)) 346*14baf4d9SChristophe Lombard return -ERANGE; 347*14baf4d9SChristophe Lombard 348*14baf4d9SChristophe Lombard cr = get_zeroed_page(GFP_KERNEL); 349*14baf4d9SChristophe Lombard if (!cr) 350*14baf4d9SChristophe Lombard return -ENOMEM; 351*14baf4d9SChristophe Lombard 352*14baf4d9SChristophe Lombard rc = cxl_h_get_config(afu->guest->handle, cr_idx, offset, 353*14baf4d9SChristophe Lombard virt_to_phys((void *)cr), sz); 354*14baf4d9SChristophe Lombard if (rc) 355*14baf4d9SChristophe Lombard goto err; 356*14baf4d9SChristophe Lombard 357*14baf4d9SChristophe Lombard switch (sz) { 358*14baf4d9SChristophe Lombard case 1: 359*14baf4d9SChristophe Lombard c = *((char *) cr); 360*14baf4d9SChristophe Lombard *val = c; 361*14baf4d9SChristophe Lombard break; 362*14baf4d9SChristophe Lombard case 2: 363*14baf4d9SChristophe Lombard *val = in_le16((u16 *)cr); 364*14baf4d9SChristophe Lombard break; 365*14baf4d9SChristophe Lombard case 4: 366*14baf4d9SChristophe Lombard *val = in_le32((unsigned *)cr); 367*14baf4d9SChristophe Lombard break; 368*14baf4d9SChristophe Lombard case 8: 369*14baf4d9SChristophe Lombard *val = in_le64((u64 *)cr); 370*14baf4d9SChristophe Lombard break; 371*14baf4d9SChristophe Lombard default: 372*14baf4d9SChristophe Lombard WARN_ON(1); 373*14baf4d9SChristophe Lombard } 374*14baf4d9SChristophe Lombard err: 375*14baf4d9SChristophe Lombard free_page(cr); 376*14baf4d9SChristophe Lombard return rc; 377*14baf4d9SChristophe Lombard } 378*14baf4d9SChristophe Lombard 379*14baf4d9SChristophe Lombard static int guest_afu_cr_read32(struct cxl_afu *afu, int cr_idx, u64 offset, 380*14baf4d9SChristophe Lombard u32 *out) 381*14baf4d9SChristophe Lombard { 382*14baf4d9SChristophe Lombard int rc; 383*14baf4d9SChristophe Lombard u64 val; 384*14baf4d9SChristophe Lombard 385*14baf4d9SChristophe Lombard rc = _guest_afu_cr_readXX(4, afu, cr_idx, offset, &val); 386*14baf4d9SChristophe Lombard if (!rc) 387*14baf4d9SChristophe Lombard *out = (u32) val; 388*14baf4d9SChristophe Lombard return rc; 389*14baf4d9SChristophe Lombard } 390*14baf4d9SChristophe Lombard 391*14baf4d9SChristophe Lombard static int guest_afu_cr_read16(struct cxl_afu *afu, int cr_idx, u64 offset, 392*14baf4d9SChristophe Lombard u16 *out) 393*14baf4d9SChristophe Lombard { 394*14baf4d9SChristophe Lombard int rc; 395*14baf4d9SChristophe Lombard u64 val; 396*14baf4d9SChristophe Lombard 397*14baf4d9SChristophe Lombard rc = _guest_afu_cr_readXX(2, afu, cr_idx, offset, &val); 398*14baf4d9SChristophe Lombard if (!rc) 399*14baf4d9SChristophe Lombard *out = (u16) val; 400*14baf4d9SChristophe Lombard return rc; 401*14baf4d9SChristophe Lombard } 402*14baf4d9SChristophe Lombard 403*14baf4d9SChristophe Lombard static int guest_afu_cr_read8(struct cxl_afu *afu, int cr_idx, u64 offset, 404*14baf4d9SChristophe Lombard u8 *out) 405*14baf4d9SChristophe Lombard { 406*14baf4d9SChristophe Lombard int rc; 407*14baf4d9SChristophe Lombard u64 val; 408*14baf4d9SChristophe Lombard 409*14baf4d9SChristophe Lombard rc = _guest_afu_cr_readXX(1, afu, cr_idx, offset, &val); 410*14baf4d9SChristophe Lombard if (!rc) 411*14baf4d9SChristophe Lombard *out = (u8) val; 412*14baf4d9SChristophe Lombard return rc; 413*14baf4d9SChristophe Lombard } 414*14baf4d9SChristophe Lombard 415*14baf4d9SChristophe Lombard static int guest_afu_cr_read64(struct cxl_afu *afu, int cr_idx, u64 offset, 416*14baf4d9SChristophe Lombard u64 *out) 417*14baf4d9SChristophe Lombard { 418*14baf4d9SChristophe Lombard return _guest_afu_cr_readXX(8, afu, cr_idx, offset, out); 419*14baf4d9SChristophe Lombard } 420*14baf4d9SChristophe Lombard 421*14baf4d9SChristophe Lombard static int attach_afu_directed(struct cxl_context *ctx, u64 wed, u64 amr) 422*14baf4d9SChristophe Lombard { 423*14baf4d9SChristophe Lombard struct cxl_process_element_hcall *elem; 424*14baf4d9SChristophe Lombard struct cxl *adapter = ctx->afu->adapter; 425*14baf4d9SChristophe Lombard const struct cred *cred; 426*14baf4d9SChristophe Lombard u32 pid, idx; 427*14baf4d9SChristophe Lombard int rc, r, i; 428*14baf4d9SChristophe Lombard u64 mmio_addr, mmio_size; 429*14baf4d9SChristophe Lombard __be64 flags = 0; 430*14baf4d9SChristophe Lombard 431*14baf4d9SChristophe Lombard /* Must be 8 byte aligned and cannot cross a 4096 byte boundary */ 432*14baf4d9SChristophe Lombard if (!(elem = (struct cxl_process_element_hcall *) 433*14baf4d9SChristophe Lombard get_zeroed_page(GFP_KERNEL))) 434*14baf4d9SChristophe Lombard return -ENOMEM; 435*14baf4d9SChristophe Lombard 436*14baf4d9SChristophe Lombard elem->version = cpu_to_be64(CXL_PROCESS_ELEMENT_VERSION); 437*14baf4d9SChristophe Lombard if (ctx->kernel) { 438*14baf4d9SChristophe Lombard pid = 0; 439*14baf4d9SChristophe Lombard flags |= CXL_PE_TRANSLATION_ENABLED; 440*14baf4d9SChristophe Lombard flags |= CXL_PE_PRIVILEGED_PROCESS; 441*14baf4d9SChristophe Lombard if (mfmsr() & MSR_SF) 442*14baf4d9SChristophe Lombard flags |= CXL_PE_64_BIT; 443*14baf4d9SChristophe Lombard } else { 444*14baf4d9SChristophe Lombard pid = current->pid; 445*14baf4d9SChristophe Lombard flags |= CXL_PE_PROBLEM_STATE; 446*14baf4d9SChristophe Lombard flags |= CXL_PE_TRANSLATION_ENABLED; 447*14baf4d9SChristophe Lombard if (!test_tsk_thread_flag(current, TIF_32BIT)) 448*14baf4d9SChristophe Lombard flags |= CXL_PE_64_BIT; 449*14baf4d9SChristophe Lombard cred = get_current_cred(); 450*14baf4d9SChristophe Lombard if (uid_eq(cred->euid, GLOBAL_ROOT_UID)) 451*14baf4d9SChristophe Lombard flags |= CXL_PE_PRIVILEGED_PROCESS; 452*14baf4d9SChristophe Lombard put_cred(cred); 453*14baf4d9SChristophe Lombard } 454*14baf4d9SChristophe Lombard elem->flags = cpu_to_be64(flags); 455*14baf4d9SChristophe Lombard elem->common.tid = cpu_to_be32(0); /* Unused */ 456*14baf4d9SChristophe Lombard elem->common.pid = cpu_to_be32(pid); 457*14baf4d9SChristophe Lombard elem->common.csrp = cpu_to_be64(0); /* disable */ 458*14baf4d9SChristophe Lombard elem->common.aurp0 = cpu_to_be64(0); /* disable */ 459*14baf4d9SChristophe Lombard elem->common.aurp1 = cpu_to_be64(0); /* disable */ 460*14baf4d9SChristophe Lombard 461*14baf4d9SChristophe Lombard cxl_prefault(ctx, wed); 462*14baf4d9SChristophe Lombard 463*14baf4d9SChristophe Lombard elem->common.sstp0 = cpu_to_be64(ctx->sstp0); 464*14baf4d9SChristophe Lombard elem->common.sstp1 = cpu_to_be64(ctx->sstp1); 465*14baf4d9SChristophe Lombard for (r = 0; r < CXL_IRQ_RANGES; r++) { 466*14baf4d9SChristophe Lombard for (i = 0; i < ctx->irqs.range[r]; i++) { 467*14baf4d9SChristophe Lombard if (r == 0 && i == 0) { 468*14baf4d9SChristophe Lombard elem->pslVirtualIsn = cpu_to_be32(ctx->irqs.offset[0]); 469*14baf4d9SChristophe Lombard } else { 470*14baf4d9SChristophe Lombard idx = ctx->irqs.offset[r] + i - adapter->guest->irq_base_offset; 471*14baf4d9SChristophe Lombard elem->applicationVirtualIsnBitmap[idx / 8] |= 0x80 >> (idx % 8); 472*14baf4d9SChristophe Lombard } 473*14baf4d9SChristophe Lombard } 474*14baf4d9SChristophe Lombard } 475*14baf4d9SChristophe Lombard elem->common.amr = cpu_to_be64(amr); 476*14baf4d9SChristophe Lombard elem->common.wed = cpu_to_be64(wed); 477*14baf4d9SChristophe Lombard 478*14baf4d9SChristophe Lombard disable_afu_irqs(ctx); 479*14baf4d9SChristophe Lombard 480*14baf4d9SChristophe Lombard rc = cxl_h_attach_process(ctx->afu->guest->handle, elem, 481*14baf4d9SChristophe Lombard &ctx->process_token, &mmio_addr, &mmio_size); 482*14baf4d9SChristophe Lombard if (rc == H_SUCCESS) { 483*14baf4d9SChristophe Lombard if (ctx->master || !ctx->afu->pp_psa) { 484*14baf4d9SChristophe Lombard ctx->psn_phys = ctx->afu->psn_phys; 485*14baf4d9SChristophe Lombard ctx->psn_size = ctx->afu->adapter->ps_size; 486*14baf4d9SChristophe Lombard } else { 487*14baf4d9SChristophe Lombard ctx->psn_phys = mmio_addr; 488*14baf4d9SChristophe Lombard ctx->psn_size = mmio_size; 489*14baf4d9SChristophe Lombard } 490*14baf4d9SChristophe Lombard if (ctx->afu->pp_psa && mmio_size && 491*14baf4d9SChristophe Lombard ctx->afu->pp_size == 0) { 492*14baf4d9SChristophe Lombard /* 493*14baf4d9SChristophe Lombard * There's no property in the device tree to read the 494*14baf4d9SChristophe Lombard * pp_size. We only find out at the 1st attach. 495*14baf4d9SChristophe Lombard * Compared to bare-metal, it is too late and we 496*14baf4d9SChristophe Lombard * should really lock here. However, on powerVM, 497*14baf4d9SChristophe Lombard * pp_size is really only used to display in /sys. 498*14baf4d9SChristophe Lombard * Being discussed with pHyp for their next release. 499*14baf4d9SChristophe Lombard */ 500*14baf4d9SChristophe Lombard ctx->afu->pp_size = mmio_size; 501*14baf4d9SChristophe Lombard } 502*14baf4d9SChristophe Lombard /* from PAPR: process element is bytes 4-7 of process token */ 503*14baf4d9SChristophe Lombard ctx->external_pe = ctx->process_token & 0xFFFFFFFF; 504*14baf4d9SChristophe Lombard pr_devel("CXL pe=%i is known as %i for pHyp, mmio_size=%#llx", 505*14baf4d9SChristophe Lombard ctx->pe, ctx->external_pe, ctx->psn_size); 506*14baf4d9SChristophe Lombard ctx->pe_inserted = true; 507*14baf4d9SChristophe Lombard enable_afu_irqs(ctx); 508*14baf4d9SChristophe Lombard } 509*14baf4d9SChristophe Lombard 510*14baf4d9SChristophe Lombard free_page((u64)elem); 511*14baf4d9SChristophe Lombard return rc; 512*14baf4d9SChristophe Lombard } 513*14baf4d9SChristophe Lombard 514*14baf4d9SChristophe Lombard static int guest_attach_process(struct cxl_context *ctx, bool kernel, u64 wed, u64 amr) 515*14baf4d9SChristophe Lombard { 516*14baf4d9SChristophe Lombard pr_devel("in %s\n", __func__); 517*14baf4d9SChristophe Lombard 518*14baf4d9SChristophe Lombard ctx->kernel = kernel; 519*14baf4d9SChristophe Lombard if (ctx->afu->current_mode == CXL_MODE_DIRECTED) 520*14baf4d9SChristophe Lombard return attach_afu_directed(ctx, wed, amr); 521*14baf4d9SChristophe Lombard 522*14baf4d9SChristophe Lombard /* dedicated mode not supported on FW840 */ 523*14baf4d9SChristophe Lombard 524*14baf4d9SChristophe Lombard return -EINVAL; 525*14baf4d9SChristophe Lombard } 526*14baf4d9SChristophe Lombard 527*14baf4d9SChristophe Lombard static int detach_afu_directed(struct cxl_context *ctx) 528*14baf4d9SChristophe Lombard { 529*14baf4d9SChristophe Lombard if (!ctx->pe_inserted) 530*14baf4d9SChristophe Lombard return 0; 531*14baf4d9SChristophe Lombard if (cxl_h_detach_process(ctx->afu->guest->handle, ctx->process_token)) 532*14baf4d9SChristophe Lombard return -1; 533*14baf4d9SChristophe Lombard return 0; 534*14baf4d9SChristophe Lombard } 535*14baf4d9SChristophe Lombard 536*14baf4d9SChristophe Lombard static int guest_detach_process(struct cxl_context *ctx) 537*14baf4d9SChristophe Lombard { 538*14baf4d9SChristophe Lombard pr_devel("in %s\n", __func__); 539*14baf4d9SChristophe Lombard trace_cxl_detach(ctx); 540*14baf4d9SChristophe Lombard 541*14baf4d9SChristophe Lombard if (!cxl_ops->link_ok(ctx->afu->adapter)) 542*14baf4d9SChristophe Lombard return -EIO; 543*14baf4d9SChristophe Lombard 544*14baf4d9SChristophe Lombard if (ctx->afu->current_mode == CXL_MODE_DIRECTED) 545*14baf4d9SChristophe Lombard return detach_afu_directed(ctx); 546*14baf4d9SChristophe Lombard 547*14baf4d9SChristophe Lombard return -EINVAL; 548*14baf4d9SChristophe Lombard } 549*14baf4d9SChristophe Lombard 550*14baf4d9SChristophe Lombard static void guest_release_afu(struct device *dev) 551*14baf4d9SChristophe Lombard { 552*14baf4d9SChristophe Lombard struct cxl_afu *afu = to_cxl_afu(dev); 553*14baf4d9SChristophe Lombard 554*14baf4d9SChristophe Lombard pr_devel("%s\n", __func__); 555*14baf4d9SChristophe Lombard 556*14baf4d9SChristophe Lombard idr_destroy(&afu->contexts_idr); 557*14baf4d9SChristophe Lombard 558*14baf4d9SChristophe Lombard kfree(afu->guest); 559*14baf4d9SChristophe Lombard kfree(afu); 560*14baf4d9SChristophe Lombard } 561*14baf4d9SChristophe Lombard 562*14baf4d9SChristophe Lombard ssize_t cxl_guest_read_afu_vpd(struct cxl_afu *afu, void *buf, size_t len) 563*14baf4d9SChristophe Lombard { 564*14baf4d9SChristophe Lombard return guest_collect_vpd(NULL, afu, buf, len); 565*14baf4d9SChristophe Lombard } 566*14baf4d9SChristophe Lombard 567*14baf4d9SChristophe Lombard #define ERR_BUFF_MAX_COPY_SIZE PAGE_SIZE 568*14baf4d9SChristophe Lombard static ssize_t guest_afu_read_err_buffer(struct cxl_afu *afu, char *buf, 569*14baf4d9SChristophe Lombard loff_t off, size_t count) 570*14baf4d9SChristophe Lombard { 571*14baf4d9SChristophe Lombard void *tbuf = NULL; 572*14baf4d9SChristophe Lombard int rc = 0; 573*14baf4d9SChristophe Lombard 574*14baf4d9SChristophe Lombard tbuf = (void *) get_zeroed_page(GFP_KERNEL); 575*14baf4d9SChristophe Lombard if (!tbuf) 576*14baf4d9SChristophe Lombard return -ENOMEM; 577*14baf4d9SChristophe Lombard 578*14baf4d9SChristophe Lombard rc = cxl_h_get_afu_err(afu->guest->handle, 579*14baf4d9SChristophe Lombard off & 0x7, 580*14baf4d9SChristophe Lombard virt_to_phys(tbuf), 581*14baf4d9SChristophe Lombard count); 582*14baf4d9SChristophe Lombard if (rc) 583*14baf4d9SChristophe Lombard goto err; 584*14baf4d9SChristophe Lombard 585*14baf4d9SChristophe Lombard if (count > ERR_BUFF_MAX_COPY_SIZE) 586*14baf4d9SChristophe Lombard count = ERR_BUFF_MAX_COPY_SIZE - (off & 0x7); 587*14baf4d9SChristophe Lombard memcpy(buf, tbuf, count); 588*14baf4d9SChristophe Lombard err: 589*14baf4d9SChristophe Lombard free_page((u64)tbuf); 590*14baf4d9SChristophe Lombard 591*14baf4d9SChristophe Lombard return rc; 592*14baf4d9SChristophe Lombard } 593*14baf4d9SChristophe Lombard 594*14baf4d9SChristophe Lombard static int guest_afu_check_and_enable(struct cxl_afu *afu) 595*14baf4d9SChristophe Lombard { 596*14baf4d9SChristophe Lombard return 0; 597*14baf4d9SChristophe Lombard } 598*14baf4d9SChristophe Lombard 599*14baf4d9SChristophe Lombard static int activate_afu_directed(struct cxl_afu *afu) 600*14baf4d9SChristophe Lombard { 601*14baf4d9SChristophe Lombard int rc; 602*14baf4d9SChristophe Lombard 603*14baf4d9SChristophe Lombard dev_info(&afu->dev, "Activating AFU(%d) directed mode\n", afu->slice); 604*14baf4d9SChristophe Lombard 605*14baf4d9SChristophe Lombard afu->current_mode = CXL_MODE_DIRECTED; 606*14baf4d9SChristophe Lombard 607*14baf4d9SChristophe Lombard afu->num_procs = afu->max_procs_virtualised; 608*14baf4d9SChristophe Lombard 609*14baf4d9SChristophe Lombard if ((rc = cxl_chardev_m_afu_add(afu))) 610*14baf4d9SChristophe Lombard return rc; 611*14baf4d9SChristophe Lombard 612*14baf4d9SChristophe Lombard if ((rc = cxl_sysfs_afu_m_add(afu))) 613*14baf4d9SChristophe Lombard goto err; 614*14baf4d9SChristophe Lombard 615*14baf4d9SChristophe Lombard if ((rc = cxl_chardev_s_afu_add(afu))) 616*14baf4d9SChristophe Lombard goto err1; 617*14baf4d9SChristophe Lombard 618*14baf4d9SChristophe Lombard return 0; 619*14baf4d9SChristophe Lombard err1: 620*14baf4d9SChristophe Lombard cxl_sysfs_afu_m_remove(afu); 621*14baf4d9SChristophe Lombard err: 622*14baf4d9SChristophe Lombard cxl_chardev_afu_remove(afu); 623*14baf4d9SChristophe Lombard return rc; 624*14baf4d9SChristophe Lombard } 625*14baf4d9SChristophe Lombard 626*14baf4d9SChristophe Lombard static int guest_afu_activate_mode(struct cxl_afu *afu, int mode) 627*14baf4d9SChristophe Lombard { 628*14baf4d9SChristophe Lombard if (!mode) 629*14baf4d9SChristophe Lombard return 0; 630*14baf4d9SChristophe Lombard if (!(mode & afu->modes_supported)) 631*14baf4d9SChristophe Lombard return -EINVAL; 632*14baf4d9SChristophe Lombard 633*14baf4d9SChristophe Lombard if (mode == CXL_MODE_DIRECTED) 634*14baf4d9SChristophe Lombard return activate_afu_directed(afu); 635*14baf4d9SChristophe Lombard 636*14baf4d9SChristophe Lombard if (mode == CXL_MODE_DEDICATED) 637*14baf4d9SChristophe Lombard dev_err(&afu->dev, "Dedicated mode not supported\n"); 638*14baf4d9SChristophe Lombard 639*14baf4d9SChristophe Lombard return -EINVAL; 640*14baf4d9SChristophe Lombard } 641*14baf4d9SChristophe Lombard 642*14baf4d9SChristophe Lombard static int deactivate_afu_directed(struct cxl_afu *afu) 643*14baf4d9SChristophe Lombard { 644*14baf4d9SChristophe Lombard dev_info(&afu->dev, "Deactivating AFU(%d) directed mode\n", afu->slice); 645*14baf4d9SChristophe Lombard 646*14baf4d9SChristophe Lombard afu->current_mode = 0; 647*14baf4d9SChristophe Lombard afu->num_procs = 0; 648*14baf4d9SChristophe Lombard 649*14baf4d9SChristophe Lombard cxl_sysfs_afu_m_remove(afu); 650*14baf4d9SChristophe Lombard cxl_chardev_afu_remove(afu); 651*14baf4d9SChristophe Lombard 652*14baf4d9SChristophe Lombard cxl_ops->afu_reset(afu); 653*14baf4d9SChristophe Lombard 654*14baf4d9SChristophe Lombard return 0; 655*14baf4d9SChristophe Lombard } 656*14baf4d9SChristophe Lombard 657*14baf4d9SChristophe Lombard static int guest_afu_deactivate_mode(struct cxl_afu *afu, int mode) 658*14baf4d9SChristophe Lombard { 659*14baf4d9SChristophe Lombard if (!mode) 660*14baf4d9SChristophe Lombard return 0; 661*14baf4d9SChristophe Lombard if (!(mode & afu->modes_supported)) 662*14baf4d9SChristophe Lombard return -EINVAL; 663*14baf4d9SChristophe Lombard 664*14baf4d9SChristophe Lombard if (mode == CXL_MODE_DIRECTED) 665*14baf4d9SChristophe Lombard return deactivate_afu_directed(afu); 666*14baf4d9SChristophe Lombard return 0; 667*14baf4d9SChristophe Lombard } 668*14baf4d9SChristophe Lombard 669*14baf4d9SChristophe Lombard static int guest_afu_reset(struct cxl_afu *afu) 670*14baf4d9SChristophe Lombard { 671*14baf4d9SChristophe Lombard pr_devel("AFU(%d) reset request\n", afu->slice); 672*14baf4d9SChristophe Lombard return cxl_h_reset_afu(afu->guest->handle); 673*14baf4d9SChristophe Lombard } 674*14baf4d9SChristophe Lombard 675*14baf4d9SChristophe Lombard static int guest_map_slice_regs(struct cxl_afu *afu) 676*14baf4d9SChristophe Lombard { 677*14baf4d9SChristophe Lombard if (!(afu->p2n_mmio = ioremap(afu->guest->p2n_phys, afu->guest->p2n_size))) { 678*14baf4d9SChristophe Lombard dev_err(&afu->dev, "Error mapping AFU(%d) MMIO regions\n", 679*14baf4d9SChristophe Lombard afu->slice); 680*14baf4d9SChristophe Lombard return -ENOMEM; 681*14baf4d9SChristophe Lombard } 682*14baf4d9SChristophe Lombard return 0; 683*14baf4d9SChristophe Lombard } 684*14baf4d9SChristophe Lombard 685*14baf4d9SChristophe Lombard static void guest_unmap_slice_regs(struct cxl_afu *afu) 686*14baf4d9SChristophe Lombard { 687*14baf4d9SChristophe Lombard if (afu->p2n_mmio) 688*14baf4d9SChristophe Lombard iounmap(afu->p2n_mmio); 689*14baf4d9SChristophe Lombard } 690*14baf4d9SChristophe Lombard 691*14baf4d9SChristophe Lombard static bool guest_link_ok(struct cxl *cxl) 692*14baf4d9SChristophe Lombard { 693*14baf4d9SChristophe Lombard return true; 694*14baf4d9SChristophe Lombard } 695*14baf4d9SChristophe Lombard 696*14baf4d9SChristophe Lombard static int afu_properties_look_ok(struct cxl_afu *afu) 697*14baf4d9SChristophe Lombard { 698*14baf4d9SChristophe Lombard if (afu->pp_irqs < 0) { 699*14baf4d9SChristophe Lombard dev_err(&afu->dev, "Unexpected per-process minimum interrupt value\n"); 700*14baf4d9SChristophe Lombard return -EINVAL; 701*14baf4d9SChristophe Lombard } 702*14baf4d9SChristophe Lombard 703*14baf4d9SChristophe Lombard if (afu->max_procs_virtualised < 1) { 704*14baf4d9SChristophe Lombard dev_err(&afu->dev, "Unexpected max number of processes virtualised value\n"); 705*14baf4d9SChristophe Lombard return -EINVAL; 706*14baf4d9SChristophe Lombard } 707*14baf4d9SChristophe Lombard 708*14baf4d9SChristophe Lombard if (afu->crs_len < 0) { 709*14baf4d9SChristophe Lombard dev_err(&afu->dev, "Unexpected configuration record size value\n"); 710*14baf4d9SChristophe Lombard return -EINVAL; 711*14baf4d9SChristophe Lombard } 712*14baf4d9SChristophe Lombard 713*14baf4d9SChristophe Lombard return 0; 714*14baf4d9SChristophe Lombard } 715*14baf4d9SChristophe Lombard 716*14baf4d9SChristophe Lombard int cxl_guest_init_afu(struct cxl *adapter, int slice, struct device_node *afu_np) 717*14baf4d9SChristophe Lombard { 718*14baf4d9SChristophe Lombard struct cxl_afu *afu; 719*14baf4d9SChristophe Lombard bool free = true; 720*14baf4d9SChristophe Lombard int rc; 721*14baf4d9SChristophe Lombard 722*14baf4d9SChristophe Lombard pr_devel("in %s - AFU(%d)\n", __func__, slice); 723*14baf4d9SChristophe Lombard if (!(afu = cxl_alloc_afu(adapter, slice))) 724*14baf4d9SChristophe Lombard return -ENOMEM; 725*14baf4d9SChristophe Lombard 726*14baf4d9SChristophe Lombard if (!(afu->guest = kzalloc(sizeof(struct cxl_afu_guest), GFP_KERNEL))) { 727*14baf4d9SChristophe Lombard kfree(afu); 728*14baf4d9SChristophe Lombard return -ENOMEM; 729*14baf4d9SChristophe Lombard } 730*14baf4d9SChristophe Lombard 731*14baf4d9SChristophe Lombard if ((rc = dev_set_name(&afu->dev, "afu%i.%i", 732*14baf4d9SChristophe Lombard adapter->adapter_num, 733*14baf4d9SChristophe Lombard slice))) 734*14baf4d9SChristophe Lombard goto err1; 735*14baf4d9SChristophe Lombard 736*14baf4d9SChristophe Lombard adapter->slices++; 737*14baf4d9SChristophe Lombard 738*14baf4d9SChristophe Lombard if ((rc = cxl_of_read_afu_handle(afu, afu_np))) 739*14baf4d9SChristophe Lombard goto err1; 740*14baf4d9SChristophe Lombard 741*14baf4d9SChristophe Lombard if ((rc = cxl_ops->afu_reset(afu))) 742*14baf4d9SChristophe Lombard goto err1; 743*14baf4d9SChristophe Lombard 744*14baf4d9SChristophe Lombard if ((rc = cxl_of_read_afu_properties(afu, afu_np))) 745*14baf4d9SChristophe Lombard goto err1; 746*14baf4d9SChristophe Lombard 747*14baf4d9SChristophe Lombard if ((rc = afu_properties_look_ok(afu))) 748*14baf4d9SChristophe Lombard goto err1; 749*14baf4d9SChristophe Lombard 750*14baf4d9SChristophe Lombard if ((rc = guest_map_slice_regs(afu))) 751*14baf4d9SChristophe Lombard goto err1; 752*14baf4d9SChristophe Lombard 753*14baf4d9SChristophe Lombard if ((rc = guest_register_serr_irq(afu))) 754*14baf4d9SChristophe Lombard goto err2; 755*14baf4d9SChristophe Lombard 756*14baf4d9SChristophe Lombard /* 757*14baf4d9SChristophe Lombard * After we call this function we must not free the afu directly, even 758*14baf4d9SChristophe Lombard * if it returns an error! 759*14baf4d9SChristophe Lombard */ 760*14baf4d9SChristophe Lombard if ((rc = cxl_register_afu(afu))) 761*14baf4d9SChristophe Lombard goto err_put1; 762*14baf4d9SChristophe Lombard 763*14baf4d9SChristophe Lombard if ((rc = cxl_sysfs_afu_add(afu))) 764*14baf4d9SChristophe Lombard goto err_put1; 765*14baf4d9SChristophe Lombard 766*14baf4d9SChristophe Lombard /* 767*14baf4d9SChristophe Lombard * pHyp doesn't expose the programming models supported by the 768*14baf4d9SChristophe Lombard * AFU. pHyp currently only supports directed mode. If it adds 769*14baf4d9SChristophe Lombard * dedicated mode later, this version of cxl has no way to 770*14baf4d9SChristophe Lombard * detect it. So we'll initialize the driver, but the first 771*14baf4d9SChristophe Lombard * attach will fail. 772*14baf4d9SChristophe Lombard * Being discussed with pHyp to do better (likely new property) 773*14baf4d9SChristophe Lombard */ 774*14baf4d9SChristophe Lombard if (afu->max_procs_virtualised == 1) 775*14baf4d9SChristophe Lombard afu->modes_supported = CXL_MODE_DEDICATED; 776*14baf4d9SChristophe Lombard else 777*14baf4d9SChristophe Lombard afu->modes_supported = CXL_MODE_DIRECTED; 778*14baf4d9SChristophe Lombard 779*14baf4d9SChristophe Lombard if ((rc = cxl_afu_select_best_mode(afu))) 780*14baf4d9SChristophe Lombard goto err_put2; 781*14baf4d9SChristophe Lombard 782*14baf4d9SChristophe Lombard adapter->afu[afu->slice] = afu; 783*14baf4d9SChristophe Lombard 784*14baf4d9SChristophe Lombard afu->enabled = true; 785*14baf4d9SChristophe Lombard 786*14baf4d9SChristophe Lombard return 0; 787*14baf4d9SChristophe Lombard 788*14baf4d9SChristophe Lombard err_put2: 789*14baf4d9SChristophe Lombard cxl_sysfs_afu_remove(afu); 790*14baf4d9SChristophe Lombard err_put1: 791*14baf4d9SChristophe Lombard device_unregister(&afu->dev); 792*14baf4d9SChristophe Lombard free = false; 793*14baf4d9SChristophe Lombard guest_release_serr_irq(afu); 794*14baf4d9SChristophe Lombard err2: 795*14baf4d9SChristophe Lombard guest_unmap_slice_regs(afu); 796*14baf4d9SChristophe Lombard err1: 797*14baf4d9SChristophe Lombard if (free) { 798*14baf4d9SChristophe Lombard kfree(afu->guest); 799*14baf4d9SChristophe Lombard kfree(afu); 800*14baf4d9SChristophe Lombard } 801*14baf4d9SChristophe Lombard return rc; 802*14baf4d9SChristophe Lombard } 803*14baf4d9SChristophe Lombard 804*14baf4d9SChristophe Lombard void cxl_guest_remove_afu(struct cxl_afu *afu) 805*14baf4d9SChristophe Lombard { 806*14baf4d9SChristophe Lombard pr_devel("in %s - AFU(%d)\n", __func__, afu->slice); 807*14baf4d9SChristophe Lombard 808*14baf4d9SChristophe Lombard if (!afu) 809*14baf4d9SChristophe Lombard return; 810*14baf4d9SChristophe Lombard 811*14baf4d9SChristophe Lombard cxl_sysfs_afu_remove(afu); 812*14baf4d9SChristophe Lombard 813*14baf4d9SChristophe Lombard spin_lock(&afu->adapter->afu_list_lock); 814*14baf4d9SChristophe Lombard afu->adapter->afu[afu->slice] = NULL; 815*14baf4d9SChristophe Lombard spin_unlock(&afu->adapter->afu_list_lock); 816*14baf4d9SChristophe Lombard 817*14baf4d9SChristophe Lombard cxl_context_detach_all(afu); 818*14baf4d9SChristophe Lombard cxl_ops->afu_deactivate_mode(afu, afu->current_mode); 819*14baf4d9SChristophe Lombard guest_release_serr_irq(afu); 820*14baf4d9SChristophe Lombard guest_unmap_slice_regs(afu); 821*14baf4d9SChristophe Lombard 822*14baf4d9SChristophe Lombard device_unregister(&afu->dev); 823*14baf4d9SChristophe Lombard } 824*14baf4d9SChristophe Lombard 825*14baf4d9SChristophe Lombard static void free_adapter(struct cxl *adapter) 826*14baf4d9SChristophe Lombard { 827*14baf4d9SChristophe Lombard struct irq_avail *cur; 828*14baf4d9SChristophe Lombard int i; 829*14baf4d9SChristophe Lombard 830*14baf4d9SChristophe Lombard if (adapter->guest->irq_avail) { 831*14baf4d9SChristophe Lombard for (i = 0; i < adapter->guest->irq_nranges; i++) { 832*14baf4d9SChristophe Lombard cur = &adapter->guest->irq_avail[i]; 833*14baf4d9SChristophe Lombard kfree(cur->bitmap); 834*14baf4d9SChristophe Lombard } 835*14baf4d9SChristophe Lombard kfree(adapter->guest->irq_avail); 836*14baf4d9SChristophe Lombard } 837*14baf4d9SChristophe Lombard kfree(adapter->guest->status); 838*14baf4d9SChristophe Lombard cxl_remove_adapter_nr(adapter); 839*14baf4d9SChristophe Lombard kfree(adapter->guest); 840*14baf4d9SChristophe Lombard kfree(adapter); 841*14baf4d9SChristophe Lombard } 842*14baf4d9SChristophe Lombard 843*14baf4d9SChristophe Lombard static int properties_look_ok(struct cxl *adapter) 844*14baf4d9SChristophe Lombard { 845*14baf4d9SChristophe Lombard /* The absence of this property means that the operational 846*14baf4d9SChristophe Lombard * status is unknown or okay 847*14baf4d9SChristophe Lombard */ 848*14baf4d9SChristophe Lombard if (strlen(adapter->guest->status) && 849*14baf4d9SChristophe Lombard strcmp(adapter->guest->status, "okay")) { 850*14baf4d9SChristophe Lombard pr_err("ABORTING:Bad operational status of the device\n"); 851*14baf4d9SChristophe Lombard return -EINVAL; 852*14baf4d9SChristophe Lombard } 853*14baf4d9SChristophe Lombard 854*14baf4d9SChristophe Lombard return 0; 855*14baf4d9SChristophe Lombard } 856*14baf4d9SChristophe Lombard 857*14baf4d9SChristophe Lombard ssize_t cxl_guest_read_adapter_vpd(struct cxl *adapter, void *buf, size_t len) 858*14baf4d9SChristophe Lombard { 859*14baf4d9SChristophe Lombard return guest_collect_vpd(adapter, NULL, buf, len); 860*14baf4d9SChristophe Lombard } 861*14baf4d9SChristophe Lombard 862*14baf4d9SChristophe Lombard void cxl_guest_remove_adapter(struct cxl *adapter) 863*14baf4d9SChristophe Lombard { 864*14baf4d9SChristophe Lombard pr_devel("in %s\n", __func__); 865*14baf4d9SChristophe Lombard 866*14baf4d9SChristophe Lombard cxl_sysfs_adapter_remove(adapter); 867*14baf4d9SChristophe Lombard 868*14baf4d9SChristophe Lombard device_unregister(&adapter->dev); 869*14baf4d9SChristophe Lombard } 870*14baf4d9SChristophe Lombard 871*14baf4d9SChristophe Lombard static void release_adapter(struct device *dev) 872*14baf4d9SChristophe Lombard { 873*14baf4d9SChristophe Lombard free_adapter(to_cxl_adapter(dev)); 874*14baf4d9SChristophe Lombard } 875*14baf4d9SChristophe Lombard 876*14baf4d9SChristophe Lombard struct cxl *cxl_guest_init_adapter(struct device_node *np, struct platform_device *pdev) 877*14baf4d9SChristophe Lombard { 878*14baf4d9SChristophe Lombard struct cxl *adapter; 879*14baf4d9SChristophe Lombard bool free = true; 880*14baf4d9SChristophe Lombard int rc; 881*14baf4d9SChristophe Lombard 882*14baf4d9SChristophe Lombard if (!(adapter = cxl_alloc_adapter())) 883*14baf4d9SChristophe Lombard return ERR_PTR(-ENOMEM); 884*14baf4d9SChristophe Lombard 885*14baf4d9SChristophe Lombard if (!(adapter->guest = kzalloc(sizeof(struct cxl_guest), GFP_KERNEL))) { 886*14baf4d9SChristophe Lombard free_adapter(adapter); 887*14baf4d9SChristophe Lombard return ERR_PTR(-ENOMEM); 888*14baf4d9SChristophe Lombard } 889*14baf4d9SChristophe Lombard 890*14baf4d9SChristophe Lombard adapter->slices = 0; 891*14baf4d9SChristophe Lombard adapter->guest->pdev = pdev; 892*14baf4d9SChristophe Lombard adapter->dev.parent = &pdev->dev; 893*14baf4d9SChristophe Lombard adapter->dev.release = release_adapter; 894*14baf4d9SChristophe Lombard dev_set_drvdata(&pdev->dev, adapter); 895*14baf4d9SChristophe Lombard 896*14baf4d9SChristophe Lombard if ((rc = cxl_of_read_adapter_handle(adapter, np))) 897*14baf4d9SChristophe Lombard goto err1; 898*14baf4d9SChristophe Lombard 899*14baf4d9SChristophe Lombard if ((rc = cxl_of_read_adapter_properties(adapter, np))) 900*14baf4d9SChristophe Lombard goto err1; 901*14baf4d9SChristophe Lombard 902*14baf4d9SChristophe Lombard if ((rc = properties_look_ok(adapter))) 903*14baf4d9SChristophe Lombard goto err1; 904*14baf4d9SChristophe Lombard 905*14baf4d9SChristophe Lombard /* 906*14baf4d9SChristophe Lombard * After we call this function we must not free the adapter directly, 907*14baf4d9SChristophe Lombard * even if it returns an error! 908*14baf4d9SChristophe Lombard */ 909*14baf4d9SChristophe Lombard if ((rc = cxl_register_adapter(adapter))) 910*14baf4d9SChristophe Lombard goto err_put1; 911*14baf4d9SChristophe Lombard 912*14baf4d9SChristophe Lombard if ((rc = cxl_sysfs_adapter_add(adapter))) 913*14baf4d9SChristophe Lombard goto err_put1; 914*14baf4d9SChristophe Lombard 915*14baf4d9SChristophe Lombard return adapter; 916*14baf4d9SChristophe Lombard 917*14baf4d9SChristophe Lombard err_put1: 918*14baf4d9SChristophe Lombard device_unregister(&adapter->dev); 919*14baf4d9SChristophe Lombard free = false; 920*14baf4d9SChristophe Lombard err1: 921*14baf4d9SChristophe Lombard if (free) 922*14baf4d9SChristophe Lombard free_adapter(adapter); 923*14baf4d9SChristophe Lombard return ERR_PTR(rc); 924*14baf4d9SChristophe Lombard } 925*14baf4d9SChristophe Lombard 926*14baf4d9SChristophe Lombard const struct cxl_backend_ops cxl_guest_ops = { 927*14baf4d9SChristophe Lombard .module = THIS_MODULE, 928*14baf4d9SChristophe Lombard .adapter_reset = guest_reset, 929*14baf4d9SChristophe Lombard .alloc_one_irq = guest_alloc_one_irq, 930*14baf4d9SChristophe Lombard .release_one_irq = guest_release_one_irq, 931*14baf4d9SChristophe Lombard .alloc_irq_ranges = guest_alloc_irq_ranges, 932*14baf4d9SChristophe Lombard .release_irq_ranges = guest_release_irq_ranges, 933*14baf4d9SChristophe Lombard .setup_irq = NULL, 934*14baf4d9SChristophe Lombard .handle_psl_slice_error = guest_handle_psl_slice_error, 935*14baf4d9SChristophe Lombard .psl_interrupt = guest_psl_irq, 936*14baf4d9SChristophe Lombard .ack_irq = guest_ack_irq, 937*14baf4d9SChristophe Lombard .attach_process = guest_attach_process, 938*14baf4d9SChristophe Lombard .detach_process = guest_detach_process, 939*14baf4d9SChristophe Lombard .link_ok = guest_link_ok, 940*14baf4d9SChristophe Lombard .release_afu = guest_release_afu, 941*14baf4d9SChristophe Lombard .afu_read_err_buffer = guest_afu_read_err_buffer, 942*14baf4d9SChristophe Lombard .afu_check_and_enable = guest_afu_check_and_enable, 943*14baf4d9SChristophe Lombard .afu_activate_mode = guest_afu_activate_mode, 944*14baf4d9SChristophe Lombard .afu_deactivate_mode = guest_afu_deactivate_mode, 945*14baf4d9SChristophe Lombard .afu_reset = guest_afu_reset, 946*14baf4d9SChristophe Lombard .afu_cr_read8 = guest_afu_cr_read8, 947*14baf4d9SChristophe Lombard .afu_cr_read16 = guest_afu_cr_read16, 948*14baf4d9SChristophe Lombard .afu_cr_read32 = guest_afu_cr_read32, 949*14baf4d9SChristophe Lombard .afu_cr_read64 = guest_afu_cr_read64, 950*14baf4d9SChristophe Lombard }; 951