| .. | .. |
|---|
| 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 | /* |
|---|