0001
0002
0003
0004
0005
0006
0007 #define pr_fmt(fmt) "vas: " fmt
0008
0009 #include <linux/kernel.h>
0010 #include <linux/types.h>
0011 #include <linux/slab.h>
0012 #include <linux/uaccess.h>
0013 #include <linux/kthread.h>
0014 #include <linux/sched/signal.h>
0015 #include <linux/mmu_context.h>
0016 #include <asm/icswx.h>
0017
0018 #include "vas.h"
0019
0020
0021
0022
0023
0024
0025
0026
0027 #define VAS_FAULT_WIN_FIFO_SIZE (4 << 20)
0028
0029 static void dump_fifo(struct vas_instance *vinst, void *entry)
0030 {
0031 unsigned long *end = vinst->fault_fifo + vinst->fault_fifo_size;
0032 unsigned long *fifo = entry;
0033 int i;
0034
0035 pr_err("Fault fifo size %d, Max crbs %d\n", vinst->fault_fifo_size,
0036 vinst->fault_fifo_size / CRB_SIZE);
0037
0038
0039 pr_err("Fault FIFO Dump:\n");
0040 for (i = 0; i < 10*(CRB_SIZE/8) && fifo < end; i += 4, fifo += 4) {
0041 pr_err("[%.3d, %p]: 0x%.16lx 0x%.16lx 0x%.16lx 0x%.16lx\n",
0042 i, fifo, *fifo, *(fifo+1), *(fifo+2), *(fifo+3));
0043 }
0044 }
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066 irqreturn_t vas_fault_thread_fn(int irq, void *data)
0067 {
0068 struct vas_instance *vinst = data;
0069 struct coprocessor_request_block *crb, *entry;
0070 struct coprocessor_request_block buf;
0071 struct pnv_vas_window *window;
0072 unsigned long flags;
0073 void *fifo;
0074
0075 crb = &buf;
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096 while (true) {
0097 spin_lock_irqsave(&vinst->fault_lock, flags);
0098
0099
0100
0101
0102
0103
0104 fifo = vinst->fault_fifo + (vinst->fault_crbs * CRB_SIZE);
0105 entry = fifo;
0106
0107 if ((entry->stamp.nx.pswid == cpu_to_be32(FIFO_INVALID_ENTRY))
0108 || (entry->ccw & cpu_to_be32(CCW0_INVALID))) {
0109 vinst->fifo_in_progress = 0;
0110 spin_unlock_irqrestore(&vinst->fault_lock, flags);
0111 return IRQ_HANDLED;
0112 }
0113
0114 spin_unlock_irqrestore(&vinst->fault_lock, flags);
0115 vinst->fault_crbs++;
0116 if (vinst->fault_crbs == (vinst->fault_fifo_size / CRB_SIZE))
0117 vinst->fault_crbs = 0;
0118
0119 memcpy(crb, fifo, CRB_SIZE);
0120 entry->stamp.nx.pswid = cpu_to_be32(FIFO_INVALID_ENTRY);
0121 entry->ccw |= cpu_to_be32(CCW0_INVALID);
0122
0123
0124
0125 vas_return_credit(vinst->fault_win, false);
0126
0127 pr_devel("VAS[%d] fault_fifo %p, fifo %p, fault_crbs %d\n",
0128 vinst->vas_id, vinst->fault_fifo, fifo,
0129 vinst->fault_crbs);
0130
0131 vas_dump_crb(crb);
0132 window = vas_pswid_to_window(vinst,
0133 be32_to_cpu(crb->stamp.nx.pswid));
0134
0135 if (IS_ERR(window)) {
0136
0137
0138
0139
0140
0141
0142
0143
0144 dump_fifo(vinst, (void *)entry);
0145 pr_err("VAS[%d] fault_fifo %p, fifo %p, pswid 0x%x, fault_crbs %d bad CRB?\n",
0146 vinst->vas_id, vinst->fault_fifo, fifo,
0147 be32_to_cpu(crb->stamp.nx.pswid),
0148 vinst->fault_crbs);
0149
0150 WARN_ON_ONCE(1);
0151 } else {
0152
0153
0154
0155 if (window->user_win)
0156 vas_update_csb(crb, &window->vas_win.task_ref);
0157 else
0158 WARN_ON_ONCE(!window->user_win);
0159
0160
0161
0162
0163
0164 vas_return_credit(window, true);
0165 }
0166 }
0167 }
0168
0169 irqreturn_t vas_fault_handler(int irq, void *dev_id)
0170 {
0171 struct vas_instance *vinst = dev_id;
0172 irqreturn_t ret = IRQ_WAKE_THREAD;
0173 unsigned long flags;
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183 spin_lock_irqsave(&vinst->fault_lock, flags);
0184
0185 if (vinst->fifo_in_progress)
0186 ret = IRQ_HANDLED;
0187 else
0188 vinst->fifo_in_progress = 1;
0189
0190 spin_unlock_irqrestore(&vinst->fault_lock, flags);
0191
0192 return ret;
0193 }
0194
0195
0196
0197
0198
0199 int vas_setup_fault_window(struct vas_instance *vinst)
0200 {
0201 struct vas_rx_win_attr attr;
0202 struct vas_window *win;
0203
0204 vinst->fault_fifo_size = VAS_FAULT_WIN_FIFO_SIZE;
0205 vinst->fault_fifo = kzalloc(vinst->fault_fifo_size, GFP_KERNEL);
0206 if (!vinst->fault_fifo) {
0207 pr_err("Unable to alloc %d bytes for fault_fifo\n",
0208 vinst->fault_fifo_size);
0209 return -ENOMEM;
0210 }
0211
0212
0213
0214
0215 memset(vinst->fault_fifo, FIFO_INVALID_ENTRY, vinst->fault_fifo_size);
0216 vas_init_rx_win_attr(&attr, VAS_COP_TYPE_FAULT);
0217
0218 attr.rx_fifo_size = vinst->fault_fifo_size;
0219 attr.rx_fifo = __pa(vinst->fault_fifo);
0220
0221
0222
0223
0224
0225
0226 attr.wcreds_max = vinst->fault_fifo_size / CRB_SIZE;
0227 attr.lnotify_lpid = 0;
0228 attr.lnotify_pid = mfspr(SPRN_PID);
0229 attr.lnotify_tid = mfspr(SPRN_PID);
0230
0231 win = vas_rx_win_open(vinst->vas_id, VAS_COP_TYPE_FAULT, &attr);
0232 if (IS_ERR(win)) {
0233 pr_err("VAS: Error %ld opening FaultWin\n", PTR_ERR(win));
0234 kfree(vinst->fault_fifo);
0235 return PTR_ERR(win);
0236 }
0237
0238 vinst->fault_win = container_of(win, struct pnv_vas_window, vas_win);
0239
0240 pr_devel("VAS: Created FaultWin %d, LPID/PID/TID [%d/%d/%d]\n",
0241 vinst->fault_win->vas_win.winid, attr.lnotify_lpid,
0242 attr.lnotify_pid, attr.lnotify_tid);
0243
0244 return 0;
0245 }