.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * SN Platform GRU Driver |
---|
3 | 4 | * |
---|
.. | .. |
---|
9 | 10 | * from the GRU driver. |
---|
10 | 11 | * |
---|
11 | 12 | * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. |
---|
12 | | - * |
---|
13 | | - * This program is free software; you can redistribute it and/or modify |
---|
14 | | - * it under the terms of the GNU General Public License as published by |
---|
15 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
16 | | - * (at your option) any later version. |
---|
17 | | - * |
---|
18 | | - * This program is distributed in the hope that it will be useful, |
---|
19 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
20 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
21 | | - * GNU General Public License for more details. |
---|
22 | | - * |
---|
23 | | - * You should have received a copy of the GNU General Public License |
---|
24 | | - * along with this program; if not, write to the Free Software |
---|
25 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
26 | 13 | */ |
---|
27 | 14 | |
---|
28 | 15 | #include <linux/kernel.h> |
---|
.. | .. |
---|
220 | 207 | * MMUOPS notifier callout functions |
---|
221 | 208 | */ |
---|
222 | 209 | static int gru_invalidate_range_start(struct mmu_notifier *mn, |
---|
223 | | - struct mm_struct *mm, |
---|
224 | | - unsigned long start, unsigned long end, |
---|
225 | | - bool blockable) |
---|
| 210 | + const struct mmu_notifier_range *range) |
---|
226 | 211 | { |
---|
227 | 212 | struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct, |
---|
228 | 213 | ms_notifier); |
---|
.. | .. |
---|
230 | 215 | STAT(mmu_invalidate_range); |
---|
231 | 216 | atomic_inc(&gms->ms_range_active); |
---|
232 | 217 | gru_dbg(grudev, "gms %p, start 0x%lx, end 0x%lx, act %d\n", gms, |
---|
233 | | - start, end, atomic_read(&gms->ms_range_active)); |
---|
234 | | - gru_flush_tlb_range(gms, start, end - start); |
---|
| 218 | + range->start, range->end, atomic_read(&gms->ms_range_active)); |
---|
| 219 | + gru_flush_tlb_range(gms, range->start, range->end - range->start); |
---|
235 | 220 | |
---|
236 | 221 | return 0; |
---|
237 | 222 | } |
---|
238 | 223 | |
---|
239 | 224 | static void gru_invalidate_range_end(struct mmu_notifier *mn, |
---|
240 | | - struct mm_struct *mm, unsigned long start, |
---|
241 | | - unsigned long end) |
---|
| 225 | + const struct mmu_notifier_range *range) |
---|
242 | 226 | { |
---|
243 | 227 | struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct, |
---|
244 | 228 | ms_notifier); |
---|
.. | .. |
---|
247 | 231 | (void)atomic_dec_and_test(&gms->ms_range_active); |
---|
248 | 232 | |
---|
249 | 233 | wake_up_all(&gms->ms_wait_queue); |
---|
250 | | - gru_dbg(grudev, "gms %p, start 0x%lx, end 0x%lx\n", gms, start, end); |
---|
| 234 | + gru_dbg(grudev, "gms %p, start 0x%lx, end 0x%lx\n", |
---|
| 235 | + gms, range->start, range->end); |
---|
251 | 236 | } |
---|
252 | 237 | |
---|
253 | | -static void gru_release(struct mmu_notifier *mn, struct mm_struct *mm) |
---|
| 238 | +static struct mmu_notifier *gru_alloc_notifier(struct mm_struct *mm) |
---|
254 | 239 | { |
---|
255 | | - struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct, |
---|
256 | | - ms_notifier); |
---|
| 240 | + struct gru_mm_struct *gms; |
---|
257 | 241 | |
---|
258 | | - gms->ms_released = 1; |
---|
259 | | - gru_dbg(grudev, "gms %p\n", gms); |
---|
| 242 | + gms = kzalloc(sizeof(*gms), GFP_KERNEL); |
---|
| 243 | + if (!gms) |
---|
| 244 | + return ERR_PTR(-ENOMEM); |
---|
| 245 | + STAT(gms_alloc); |
---|
| 246 | + spin_lock_init(&gms->ms_asid_lock); |
---|
| 247 | + init_waitqueue_head(&gms->ms_wait_queue); |
---|
| 248 | + |
---|
| 249 | + return &gms->ms_notifier; |
---|
260 | 250 | } |
---|
261 | 251 | |
---|
| 252 | +static void gru_free_notifier(struct mmu_notifier *mn) |
---|
| 253 | +{ |
---|
| 254 | + kfree(container_of(mn, struct gru_mm_struct, ms_notifier)); |
---|
| 255 | + STAT(gms_free); |
---|
| 256 | +} |
---|
262 | 257 | |
---|
263 | 258 | static const struct mmu_notifier_ops gru_mmuops = { |
---|
264 | | - .flags = MMU_INVALIDATE_DOES_NOT_BLOCK, |
---|
265 | 259 | .invalidate_range_start = gru_invalidate_range_start, |
---|
266 | 260 | .invalidate_range_end = gru_invalidate_range_end, |
---|
267 | | - .release = gru_release, |
---|
| 261 | + .alloc_notifier = gru_alloc_notifier, |
---|
| 262 | + .free_notifier = gru_free_notifier, |
---|
268 | 263 | }; |
---|
269 | | - |
---|
270 | | -/* Move this to the basic mmu_notifier file. But for now... */ |
---|
271 | | -static struct mmu_notifier *mmu_find_ops(struct mm_struct *mm, |
---|
272 | | - const struct mmu_notifier_ops *ops) |
---|
273 | | -{ |
---|
274 | | - struct mmu_notifier *mn, *gru_mn = NULL; |
---|
275 | | - |
---|
276 | | - if (mm->mmu_notifier_mm) { |
---|
277 | | - rcu_read_lock(); |
---|
278 | | - hlist_for_each_entry_rcu(mn, &mm->mmu_notifier_mm->list, |
---|
279 | | - hlist) |
---|
280 | | - if (mn->ops == ops) { |
---|
281 | | - gru_mn = mn; |
---|
282 | | - break; |
---|
283 | | - } |
---|
284 | | - rcu_read_unlock(); |
---|
285 | | - } |
---|
286 | | - return gru_mn; |
---|
287 | | -} |
---|
288 | 264 | |
---|
289 | 265 | struct gru_mm_struct *gru_register_mmu_notifier(void) |
---|
290 | 266 | { |
---|
291 | | - struct gru_mm_struct *gms; |
---|
292 | 267 | struct mmu_notifier *mn; |
---|
293 | | - int err; |
---|
294 | 268 | |
---|
295 | | - mn = mmu_find_ops(current->mm, &gru_mmuops); |
---|
296 | | - if (mn) { |
---|
297 | | - gms = container_of(mn, struct gru_mm_struct, ms_notifier); |
---|
298 | | - atomic_inc(&gms->ms_refcnt); |
---|
299 | | - } else { |
---|
300 | | - gms = kzalloc(sizeof(*gms), GFP_KERNEL); |
---|
301 | | - if (!gms) |
---|
302 | | - return ERR_PTR(-ENOMEM); |
---|
303 | | - STAT(gms_alloc); |
---|
304 | | - spin_lock_init(&gms->ms_asid_lock); |
---|
305 | | - gms->ms_notifier.ops = &gru_mmuops; |
---|
306 | | - atomic_set(&gms->ms_refcnt, 1); |
---|
307 | | - init_waitqueue_head(&gms->ms_wait_queue); |
---|
308 | | - err = __mmu_notifier_register(&gms->ms_notifier, current->mm); |
---|
309 | | - if (err) |
---|
310 | | - goto error; |
---|
311 | | - } |
---|
312 | | - if (gms) |
---|
313 | | - gru_dbg(grudev, "gms %p, refcnt %d\n", gms, |
---|
314 | | - atomic_read(&gms->ms_refcnt)); |
---|
315 | | - return gms; |
---|
316 | | -error: |
---|
317 | | - kfree(gms); |
---|
318 | | - return ERR_PTR(err); |
---|
| 269 | + mn = mmu_notifier_get_locked(&gru_mmuops, current->mm); |
---|
| 270 | + if (IS_ERR(mn)) |
---|
| 271 | + return ERR_CAST(mn); |
---|
| 272 | + |
---|
| 273 | + return container_of(mn, struct gru_mm_struct, ms_notifier); |
---|
319 | 274 | } |
---|
320 | 275 | |
---|
321 | 276 | void gru_drop_mmu_notifier(struct gru_mm_struct *gms) |
---|
322 | 277 | { |
---|
323 | | - gru_dbg(grudev, "gms %p, refcnt %d, released %d\n", gms, |
---|
324 | | - atomic_read(&gms->ms_refcnt), gms->ms_released); |
---|
325 | | - if (atomic_dec_return(&gms->ms_refcnt) == 0) { |
---|
326 | | - if (!gms->ms_released) |
---|
327 | | - mmu_notifier_unregister(&gms->ms_notifier, current->mm); |
---|
328 | | - kfree(gms); |
---|
329 | | - STAT(gms_free); |
---|
330 | | - } |
---|
| 278 | + mmu_notifier_put(&gms->ms_notifier); |
---|
331 | 279 | } |
---|
332 | 280 | |
---|
333 | 281 | /* |
---|