| .. | .. |
|---|
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note |
|---|
| 2 | 2 | /* |
|---|
| 3 | 3 | * |
|---|
| 4 | | - * (C) COPYRIGHT 2019-2021 ARM Limited. All rights reserved. |
|---|
| 4 | + * (C) COPYRIGHT 2019-2022 ARM Limited. All rights reserved. |
|---|
| 5 | 5 | * |
|---|
| 6 | 6 | * This program is free software and is provided to you under the terms of the |
|---|
| 7 | 7 | * GNU General Public License version 2 as published by the Free Software |
|---|
| .. | .. |
|---|
| 27 | 27 | #include <linux/module.h> |
|---|
| 28 | 28 | #if IS_ENABLED(CONFIG_DEBUG_FS) |
|---|
| 29 | 29 | #include <linux/debugfs.h> |
|---|
| 30 | +#include <linux/version_compat_defs.h> |
|---|
| 30 | 31 | #endif |
|---|
| 31 | 32 | #include <linux/mm.h> |
|---|
| 32 | 33 | #include <linux/memory_group_manager.h> |
|---|
| .. | .. |
|---|
| 41 | 42 | static inline vm_fault_t vmf_insert_pfn_prot(struct vm_area_struct *vma, |
|---|
| 42 | 43 | unsigned long addr, unsigned long pfn, pgprot_t pgprot) |
|---|
| 43 | 44 | { |
|---|
| 44 | | - int err; |
|---|
| 45 | | - |
|---|
| 46 | | -#if ((KERNEL_VERSION(4, 4, 147) >= LINUX_VERSION_CODE) || \ |
|---|
| 47 | | - ((KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE) && \ |
|---|
| 48 | | - (KERNEL_VERSION(4, 5, 0) <= LINUX_VERSION_CODE))) |
|---|
| 49 | | - if (pgprot_val(pgprot) != pgprot_val(vma->vm_page_prot)) |
|---|
| 50 | | - return VM_FAULT_SIGBUS; |
|---|
| 51 | | - |
|---|
| 52 | | - err = vm_insert_pfn(vma, addr, pfn); |
|---|
| 53 | | -#else |
|---|
| 54 | | - err = vm_insert_pfn_prot(vma, addr, pfn, pgprot); |
|---|
| 55 | | -#endif |
|---|
| 45 | + int err = vm_insert_pfn_prot(vma, addr, pfn, pgprot); |
|---|
| 56 | 46 | |
|---|
| 57 | 47 | if (unlikely(err == -ENOMEM)) |
|---|
| 58 | 48 | return VM_FAULT_OOM; |
|---|
| .. | .. |
|---|
| 62 | 52 | return VM_FAULT_NOPAGE; |
|---|
| 63 | 53 | } |
|---|
| 64 | 54 | #endif |
|---|
| 55 | + |
|---|
| 56 | +#define PTE_PBHA_SHIFT (59) |
|---|
| 57 | +#define PTE_PBHA_MASK ((uint64_t)0xf << PTE_PBHA_SHIFT) |
|---|
| 58 | +#define PTE_RES_BIT_MULTI_AS_SHIFT (63) |
|---|
| 65 | 59 | |
|---|
| 66 | 60 | #define IMPORTED_MEMORY_ID (MEMORY_GROUP_MANAGER_NR_GROUPS - 1) |
|---|
| 67 | 61 | |
|---|
| .. | .. |
|---|
| 140 | 134 | return 0; |
|---|
| 141 | 135 | } |
|---|
| 142 | 136 | |
|---|
| 143 | | -DEFINE_SIMPLE_ATTRIBUTE(fops_mgm_size, mgm_size_get, NULL, "%llu\n"); |
|---|
| 144 | | -DEFINE_SIMPLE_ATTRIBUTE(fops_mgm_lp_size, mgm_lp_size_get, NULL, "%llu\n"); |
|---|
| 145 | | - |
|---|
| 146 | | -DEFINE_SIMPLE_ATTRIBUTE(fops_mgm_insert_pfn, mgm_insert_pfn_get, NULL, |
|---|
| 147 | | - "%llu\n"); |
|---|
| 148 | | - |
|---|
| 149 | | -DEFINE_SIMPLE_ATTRIBUTE(fops_mgm_update_gpu_pte, mgm_update_gpu_pte_get, NULL, |
|---|
| 150 | | - "%llu\n"); |
|---|
| 137 | +DEFINE_DEBUGFS_ATTRIBUTE(fops_mgm_size, mgm_size_get, NULL, "%llu\n"); |
|---|
| 138 | +DEFINE_DEBUGFS_ATTRIBUTE(fops_mgm_lp_size, mgm_lp_size_get, NULL, "%llu\n"); |
|---|
| 139 | +DEFINE_DEBUGFS_ATTRIBUTE(fops_mgm_insert_pfn, mgm_insert_pfn_get, NULL, "%llu\n"); |
|---|
| 140 | +DEFINE_DEBUGFS_ATTRIBUTE(fops_mgm_update_gpu_pte, mgm_update_gpu_pte_get, NULL, "%llu\n"); |
|---|
| 151 | 141 | |
|---|
| 152 | 142 | static void mgm_term_debugfs(struct mgm_groups *data) |
|---|
| 153 | 143 | { |
|---|
| .. | .. |
|---|
| 166 | 156 | */ |
|---|
| 167 | 157 | mgm_data->mgm_debugfs_root = |
|---|
| 168 | 158 | debugfs_create_dir("physical-memory-group-manager", NULL); |
|---|
| 169 | | - if (IS_ERR(mgm_data->mgm_debugfs_root)) { |
|---|
| 159 | + if (IS_ERR_OR_NULL(mgm_data->mgm_debugfs_root)) { |
|---|
| 170 | 160 | dev_err(mgm_data->dev, "fail to create debugfs root directory\n"); |
|---|
| 171 | 161 | return -ENODEV; |
|---|
| 172 | 162 | } |
|---|
| .. | .. |
|---|
| 179 | 169 | "group_%d", i); |
|---|
| 180 | 170 | g = debugfs_create_dir(debugfs_group_name, |
|---|
| 181 | 171 | mgm_data->mgm_debugfs_root); |
|---|
| 182 | | - if (IS_ERR(g)) { |
|---|
| 172 | + if (IS_ERR_OR_NULL(g)) { |
|---|
| 183 | 173 | dev_err(mgm_data->dev, "fail to create group[%d]\n", i); |
|---|
| 184 | 174 | goto remove_debugfs; |
|---|
| 185 | 175 | } |
|---|
| 186 | 176 | |
|---|
| 187 | 177 | e = debugfs_create_file("size", 0444, g, &mgm_data->groups[i], |
|---|
| 188 | 178 | &fops_mgm_size); |
|---|
| 189 | | - if (IS_ERR(e)) { |
|---|
| 179 | + if (IS_ERR_OR_NULL(e)) { |
|---|
| 190 | 180 | dev_err(mgm_data->dev, "fail to create size[%d]\n", i); |
|---|
| 191 | 181 | goto remove_debugfs; |
|---|
| 192 | 182 | } |
|---|
| 193 | 183 | |
|---|
| 194 | 184 | e = debugfs_create_file("lp_size", 0444, g, |
|---|
| 195 | 185 | &mgm_data->groups[i], &fops_mgm_lp_size); |
|---|
| 196 | | - if (IS_ERR(e)) { |
|---|
| 186 | + if (IS_ERR_OR_NULL(e)) { |
|---|
| 197 | 187 | dev_err(mgm_data->dev, |
|---|
| 198 | 188 | "fail to create lp_size[%d]\n", i); |
|---|
| 199 | 189 | goto remove_debugfs; |
|---|
| .. | .. |
|---|
| 201 | 191 | |
|---|
| 202 | 192 | e = debugfs_create_file("insert_pfn", 0444, g, |
|---|
| 203 | 193 | &mgm_data->groups[i], &fops_mgm_insert_pfn); |
|---|
| 204 | | - if (IS_ERR(e)) { |
|---|
| 194 | + if (IS_ERR_OR_NULL(e)) { |
|---|
| 205 | 195 | dev_err(mgm_data->dev, |
|---|
| 206 | 196 | "fail to create insert_pfn[%d]\n", i); |
|---|
| 207 | 197 | goto remove_debugfs; |
|---|
| .. | .. |
|---|
| 209 | 199 | |
|---|
| 210 | 200 | e = debugfs_create_file("update_gpu_pte", 0444, g, |
|---|
| 211 | 201 | &mgm_data->groups[i], &fops_mgm_update_gpu_pte); |
|---|
| 212 | | - if (IS_ERR(e)) { |
|---|
| 202 | + if (IS_ERR_OR_NULL(e)) { |
|---|
| 213 | 203 | dev_err(mgm_data->dev, |
|---|
| 214 | 204 | "fail to create update_gpu_pte[%d]\n", i); |
|---|
| 215 | 205 | goto remove_debugfs; |
|---|
| .. | .. |
|---|
| 238 | 228 | |
|---|
| 239 | 229 | #define ORDER_SMALL_PAGE 0 |
|---|
| 240 | 230 | #define ORDER_LARGE_PAGE 9 |
|---|
| 241 | | -static void update_size(struct memory_group_manager_device *mgm_dev, int |
|---|
| 242 | | - group_id, int order, bool alloc) |
|---|
| 231 | +static void update_size(struct memory_group_manager_device *mgm_dev, unsigned int group_id, |
|---|
| 232 | + int order, bool alloc) |
|---|
| 243 | 233 | { |
|---|
| 244 | 234 | struct mgm_groups *data = mgm_dev->data; |
|---|
| 245 | 235 | |
|---|
| .. | .. |
|---|
| 275 | 265 | struct mgm_groups *const data = mgm_dev->data; |
|---|
| 276 | 266 | struct page *p; |
|---|
| 277 | 267 | |
|---|
| 278 | | - dev_dbg(data->dev, "%s(mgm_dev=%p, group_id=%d gfp_mask=0x%x order=%u\n", |
|---|
| 279 | | - __func__, (void *)mgm_dev, group_id, gfp_mask, order); |
|---|
| 268 | + dev_dbg(data->dev, "%s(mgm_dev=%pK, group_id=%d gfp_mask=0x%x order=%u\n", __func__, |
|---|
| 269 | + (void *)mgm_dev, group_id, gfp_mask, order); |
|---|
| 280 | 270 | |
|---|
| 281 | 271 | if (WARN_ON(group_id < 0) || |
|---|
| 282 | 272 | WARN_ON(group_id >= MEMORY_GROUP_MANAGER_NR_GROUPS)) |
|---|
| .. | .. |
|---|
| 301 | 291 | { |
|---|
| 302 | 292 | struct mgm_groups *const data = mgm_dev->data; |
|---|
| 303 | 293 | |
|---|
| 304 | | - dev_dbg(data->dev, "%s(mgm_dev=%p, group_id=%d page=%p order=%u\n", |
|---|
| 305 | | - __func__, (void *)mgm_dev, group_id, (void *)page, order); |
|---|
| 294 | + dev_dbg(data->dev, "%s(mgm_dev=%pK, group_id=%d page=%pK order=%u\n", __func__, |
|---|
| 295 | + (void *)mgm_dev, group_id, (void *)page, order); |
|---|
| 306 | 296 | |
|---|
| 307 | 297 | if (WARN_ON(group_id < 0) || |
|---|
| 308 | 298 | WARN_ON(group_id >= MEMORY_GROUP_MANAGER_NR_GROUPS)) |
|---|
| .. | .. |
|---|
| 319 | 309 | { |
|---|
| 320 | 310 | struct mgm_groups *const data = mgm_dev->data; |
|---|
| 321 | 311 | |
|---|
| 322 | | - dev_dbg(data->dev, "%s(mgm_dev=%p, import_data=%p (type=%d)\n", |
|---|
| 323 | | - __func__, (void *)mgm_dev, (void *)import_data, |
|---|
| 324 | | - (int)import_data->type); |
|---|
| 312 | + dev_dbg(data->dev, "%s(mgm_dev=%pK, import_data=%pK (type=%d)\n", __func__, (void *)mgm_dev, |
|---|
| 313 | + (void *)import_data, (int)import_data->type); |
|---|
| 325 | 314 | |
|---|
| 326 | 315 | if (!WARN_ON(!import_data)) { |
|---|
| 327 | 316 | WARN_ON(!import_data->u.dma_buf); |
|---|
| .. | .. |
|---|
| 338 | 327 | int const mmu_level, u64 pte) |
|---|
| 339 | 328 | { |
|---|
| 340 | 329 | struct mgm_groups *const data = mgm_dev->data; |
|---|
| 341 | | - const u32 pbha_bit_pos = 59; /* bits 62:59 */ |
|---|
| 342 | | - const u32 pbha_bit_mask = 0xf; /* 4-bit */ |
|---|
| 343 | 330 | |
|---|
| 344 | | - dev_dbg(data->dev, |
|---|
| 345 | | - "%s(mgm_dev=%p, group_id=%d, mmu_level=%d, pte=0x%llx)\n", |
|---|
| 346 | | - __func__, (void *)mgm_dev, group_id, mmu_level, pte); |
|---|
| 331 | + dev_dbg(data->dev, "%s(mgm_dev=%pK, group_id=%d, mmu_level=%d, pte=0x%llx)\n", __func__, |
|---|
| 332 | + (void *)mgm_dev, group_id, mmu_level, pte); |
|---|
| 347 | 333 | |
|---|
| 348 | 334 | if (WARN_ON(group_id < 0) || |
|---|
| 349 | 335 | WARN_ON(group_id >= MEMORY_GROUP_MANAGER_NR_GROUPS)) |
|---|
| 350 | 336 | return pte; |
|---|
| 351 | 337 | |
|---|
| 352 | | - pte |= ((u64)group_id & pbha_bit_mask) << pbha_bit_pos; |
|---|
| 338 | + pte |= ((u64)group_id << PTE_PBHA_SHIFT) & PTE_PBHA_MASK; |
|---|
| 339 | + |
|---|
| 340 | + /* Address could be translated into a different bus address here */ |
|---|
| 341 | + pte |= ((u64)1 << PTE_RES_BIT_MULTI_AS_SHIFT); |
|---|
| 353 | 342 | |
|---|
| 354 | 343 | data->groups[group_id].update_gpu_pte++; |
|---|
| 344 | + |
|---|
| 345 | + return pte; |
|---|
| 346 | +} |
|---|
| 347 | + |
|---|
| 348 | +static u64 example_mgm_pte_to_original_pte(struct memory_group_manager_device *const mgm_dev, |
|---|
| 349 | + int const group_id, int const mmu_level, u64 pte) |
|---|
| 350 | +{ |
|---|
| 351 | + /* Undo the group ID modification */ |
|---|
| 352 | + pte &= ~PTE_PBHA_MASK; |
|---|
| 353 | + /* Undo the bit set */ |
|---|
| 354 | + pte &= ~((u64)1 << PTE_RES_BIT_MULTI_AS_SHIFT); |
|---|
| 355 | 355 | |
|---|
| 356 | 356 | return pte; |
|---|
| 357 | 357 | } |
|---|
| .. | .. |
|---|
| 365 | 365 | vm_fault_t fault; |
|---|
| 366 | 366 | |
|---|
| 367 | 367 | dev_dbg(data->dev, |
|---|
| 368 | | - "%s(mgm_dev=%p, group_id=%d, vma=%p, addr=0x%lx, pfn=0x%lx, prot=0x%llx)\n", |
|---|
| 368 | + "%s(mgm_dev=%pK, group_id=%d, vma=%pK, addr=0x%lx, pfn=0x%lx, prot=0x%llx)\n", |
|---|
| 369 | 369 | __func__, (void *)mgm_dev, group_id, (void *)vma, addr, pfn, |
|---|
| 370 | | - (unsigned long long int) pgprot_val(prot)); |
|---|
| 370 | + (unsigned long long)pgprot_val(prot)); |
|---|
| 371 | 371 | |
|---|
| 372 | 372 | if (WARN_ON(group_id < 0) || |
|---|
| 373 | 373 | WARN_ON(group_id >= MEMORY_GROUP_MANAGER_NR_GROUPS)) |
|---|
| .. | .. |
|---|
| 431 | 431 | example_mgm_get_import_memory_id; |
|---|
| 432 | 432 | mgm_dev->ops.mgm_vmf_insert_pfn_prot = example_mgm_vmf_insert_pfn_prot; |
|---|
| 433 | 433 | mgm_dev->ops.mgm_update_gpu_pte = example_mgm_update_gpu_pte; |
|---|
| 434 | + mgm_dev->ops.mgm_pte_to_original_pte = example_mgm_pte_to_original_pte; |
|---|
| 434 | 435 | |
|---|
| 435 | 436 | mgm_data = kzalloc(sizeof(*mgm_data), GFP_KERNEL); |
|---|
| 436 | 437 | if (!mgm_data) { |
|---|