]>
Commit | Line | Data |
---|---|---|
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/module.h> | |
11 | #include <linux/kernel.h> | |
12 | #include <linux/bitmap.h> | |
13 | #include <linux/sched.h> | |
14 | #include <linux/pid.h> | |
15 | #include <linux/fs.h> | |
16 | #include <linux/mm.h> | |
17 | #include <linux/debugfs.h> | |
18 | #include <linux/slab.h> | |
19 | #include <linux/idr.h> | |
20 | #include <asm/cputable.h> | |
21 | #include <asm/current.h> | |
22 | #include <asm/copro.h> | |
23 | ||
24 | #include "cxl.h" | |
25 | ||
26 | /* | |
27 | * Allocates space for a CXL context. | |
28 | */ | |
29 | struct cxl_context *cxl_context_alloc(void) | |
30 | { | |
31 | return kzalloc(sizeof(struct cxl_context), GFP_KERNEL); | |
32 | } | |
33 | ||
34 | /* | |
35 | * Initialises a CXL context. | |
36 | */ | |
37 | int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master) | |
38 | { | |
39 | int i; | |
40 | ||
41 | spin_lock_init(&ctx->sste_lock); | |
42 | ctx->afu = afu; | |
43 | ctx->master = master; | |
44 | ctx->pid = NULL; /* Set in start work ioctl */ | |
45 | ||
46 | /* | |
47 | * Allocate the segment table before we put it in the IDR so that we | |
48 | * can always access it when dereferenced from IDR. For the same | |
49 | * reason, the segment table is only destroyed after the context is | |
50 | * removed from the IDR. Access to this in the IOCTL is protected by | |
51 | * Linux filesytem symantics (can't IOCTL until open is complete). | |
52 | */ | |
53 | i = cxl_alloc_sst(ctx); | |
54 | if (i) | |
55 | return i; | |
56 | ||
57 | INIT_WORK(&ctx->fault_work, cxl_handle_fault); | |
58 | ||
59 | init_waitqueue_head(&ctx->wq); | |
60 | spin_lock_init(&ctx->lock); | |
61 | ||
62 | ctx->irq_bitmap = NULL; | |
63 | ctx->pending_irq = false; | |
64 | ctx->pending_fault = false; | |
65 | ctx->pending_afu_err = false; | |
66 | ||
67 | /* | |
68 | * When we have to destroy all contexts in cxl_context_detach_all() we | |
69 | * end up with afu_release_irqs() called from inside a | |
70 | * idr_for_each_entry(). Hence we need to make sure that anything | |
71 | * dereferenced from this IDR is ok before we allocate the IDR here. | |
72 | * This clears out the IRQ ranges to ensure this. | |
73 | */ | |
74 | for (i = 0; i < CXL_IRQ_RANGES; i++) | |
75 | ctx->irqs.range[i] = 0; | |
76 | ||
77 | mutex_init(&ctx->status_mutex); | |
78 | ||
79 | ctx->status = OPENED; | |
80 | ||
81 | /* | |
82 | * Allocating IDR! We better make sure everything's setup that | |
83 | * dereferences from it. | |
84 | */ | |
ee41d11d | 85 | mutex_lock(&afu->contexts_lock); |
f204e0b8 | 86 | idr_preload(GFP_KERNEL); |
f204e0b8 IM |
87 | i = idr_alloc(&ctx->afu->contexts_idr, ctx, 0, |
88 | ctx->afu->num_procs, GFP_NOWAIT); | |
f204e0b8 | 89 | idr_preload_end(); |
ee41d11d | 90 | mutex_unlock(&afu->contexts_lock); |
f204e0b8 IM |
91 | if (i < 0) |
92 | return i; | |
93 | ||
94 | ctx->pe = i; | |
95 | ctx->elem = &ctx->afu->spa[i]; | |
96 | ctx->pe_inserted = false; | |
97 | return 0; | |
98 | } | |
99 | ||
100 | /* | |
101 | * Map a per-context mmio space into the given vma. | |
102 | */ | |
103 | int cxl_context_iomap(struct cxl_context *ctx, struct vm_area_struct *vma) | |
104 | { | |
105 | u64 len = vma->vm_end - vma->vm_start; | |
106 | len = min(len, ctx->psn_size); | |
107 | ||
108 | if (ctx->afu->current_mode == CXL_MODE_DEDICATED) { | |
109 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | |
110 | return vm_iomap_memory(vma, ctx->afu->psn_phys, ctx->afu->adapter->ps_size); | |
111 | } | |
112 | ||
113 | /* make sure there is a valid per process space for this AFU */ | |
114 | if ((ctx->master && !ctx->afu->psa) || (!ctx->afu->pp_psa)) { | |
115 | pr_devel("AFU doesn't support mmio space\n"); | |
116 | return -EINVAL; | |
117 | } | |
118 | ||
119 | /* Can't mmap until the AFU is enabled */ | |
120 | if (!ctx->afu->enabled) | |
121 | return -EBUSY; | |
122 | ||
123 | pr_devel("%s: mmio physical: %llx pe: %i master:%i\n", __func__, | |
124 | ctx->psn_phys, ctx->pe , ctx->master); | |
125 | ||
126 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | |
127 | return vm_iomap_memory(vma, ctx->psn_phys, len); | |
128 | } | |
129 | ||
130 | /* | |
131 | * Detach a context from the hardware. This disables interrupts and doesn't | |
132 | * return until all outstanding interrupts for this context have completed. The | |
133 | * hardware should no longer access *ctx after this has returned. | |
134 | */ | |
135 | static void __detach_context(struct cxl_context *ctx) | |
136 | { | |
137 | enum cxl_context_status status; | |
138 | ||
139 | mutex_lock(&ctx->status_mutex); | |
140 | status = ctx->status; | |
141 | ctx->status = CLOSED; | |
142 | mutex_unlock(&ctx->status_mutex); | |
143 | if (status != STARTED) | |
144 | return; | |
145 | ||
146 | WARN_ON(cxl_detach_process(ctx)); | |
147 | afu_release_irqs(ctx); | |
148 | flush_work(&ctx->fault_work); /* Only needed for dedicated process */ | |
149 | wake_up_all(&ctx->wq); | |
150 | } | |
151 | ||
152 | /* | |
153 | * Detach the given context from the AFU. This doesn't actually | |
154 | * free the context but it should stop the context running in hardware | |
155 | * (ie. prevent this context from generating any further interrupts | |
156 | * so that it can be freed). | |
157 | */ | |
158 | void cxl_context_detach(struct cxl_context *ctx) | |
159 | { | |
160 | __detach_context(ctx); | |
161 | } | |
162 | ||
163 | /* | |
164 | * Detach all contexts on the given AFU. | |
165 | */ | |
166 | void cxl_context_detach_all(struct cxl_afu *afu) | |
167 | { | |
168 | struct cxl_context *ctx; | |
169 | int tmp; | |
170 | ||
ee41d11d IM |
171 | mutex_lock(&afu->contexts_lock); |
172 | idr_for_each_entry(&afu->contexts_idr, ctx, tmp) { | |
f204e0b8 IM |
173 | /* |
174 | * Anything done in here needs to be setup before the IDR is | |
175 | * created and torn down after the IDR removed | |
176 | */ | |
177 | __detach_context(ctx); | |
ee41d11d IM |
178 | } |
179 | mutex_unlock(&afu->contexts_lock); | |
f204e0b8 IM |
180 | } |
181 | ||
182 | void cxl_context_free(struct cxl_context *ctx) | |
183 | { | |
ee41d11d | 184 | mutex_lock(&ctx->afu->contexts_lock); |
f204e0b8 | 185 | idr_remove(&ctx->afu->contexts_idr, ctx->pe); |
ee41d11d | 186 | mutex_unlock(&ctx->afu->contexts_lock); |
f204e0b8 IM |
187 | synchronize_rcu(); |
188 | ||
189 | free_page((u64)ctx->sstp); | |
190 | ctx->sstp = NULL; | |
191 | ||
192 | put_pid(ctx->pid); | |
193 | kfree(ctx); | |
194 | } |