Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

accel/ivpu: Limit number of maximum contexts and doorbells per user

Implement per-user resource limits to prevent resource exhaustion.

Root users can allocate all available contexts (128) and doorbells
(255), while non-root users are limited to half of the available
resources (64 contexts and 127 doorbells respectively).

This prevents scenarios where a single user could monopolize NPU
resources and starve other users on multi-user systems.

Change doorbell ID and command queue ID allocation errors to debug
messages as those are user triggered.

Signed-off-by: Karol Wachowski <karol.wachowski@linux.intel.com>
Reviewed-by: Lizhi Hou <lizhi.hou@amd.com>
Signed-off-by: Maciej Falkowski <maciej.falkowski@linux.intel.com>
Link: https://patch.msgid.link/20260302202207.469442-1-maciej.falkowski@linux.intel.com

authored by

Karol Wachowski and committed by
Maciej Falkowski
86a14330 6716101a

+136 -20
+88 -6
drivers/accel/ivpu/ivpu_drv.c
··· 67 67 module_param_named(force_snoop, ivpu_force_snoop, bool, 0444); 68 68 MODULE_PARM_DESC(force_snoop, "Force snooping for NPU host memory access"); 69 69 70 + static struct ivpu_user_limits *ivpu_user_limits_alloc(struct ivpu_device *vdev, uid_t uid) 71 + { 72 + struct ivpu_user_limits *limits; 73 + 74 + limits = kzalloc_obj(*limits); 75 + if (!limits) 76 + return ERR_PTR(-ENOMEM); 77 + 78 + kref_init(&limits->ref); 79 + atomic_set(&limits->db_count, 0); 80 + limits->vdev = vdev; 81 + limits->uid = uid; 82 + 83 + /* Allow root user to allocate all contexts */ 84 + if (uid == 0) { 85 + limits->max_ctx_count = ivpu_get_context_count(vdev); 86 + limits->max_db_count = ivpu_get_doorbell_count(vdev); 87 + } else { 88 + limits->max_ctx_count = ivpu_get_context_count(vdev) / 2; 89 + limits->max_db_count = ivpu_get_doorbell_count(vdev) / 2; 90 + } 91 + 92 + hash_add(vdev->user_limits, &limits->hash_node, uid); 93 + 94 + return limits; 95 + } 96 + 97 + static struct ivpu_user_limits *ivpu_user_limits_get(struct ivpu_device *vdev) 98 + { 99 + struct ivpu_user_limits *limits; 100 + uid_t uid = current_uid().val; 101 + 102 + guard(mutex)(&vdev->user_limits_lock); 103 + 104 + hash_for_each_possible(vdev->user_limits, limits, hash_node, uid) { 105 + if (limits->uid == uid) { 106 + if (kref_read(&limits->ref) >= limits->max_ctx_count) { 107 + ivpu_dbg(vdev, IOCTL, "User %u exceeded max ctx count %u\n", uid, 108 + limits->max_ctx_count); 109 + return ERR_PTR(-EMFILE); 110 + } 111 + 112 + kref_get(&limits->ref); 113 + return limits; 114 + } 115 + } 116 + 117 + return ivpu_user_limits_alloc(vdev, uid); 118 + } 119 + 120 + static void ivpu_user_limits_release(struct kref *ref) 121 + { 122 + struct ivpu_user_limits *limits = container_of(ref, struct ivpu_user_limits, ref); 123 + struct ivpu_device *vdev = limits->vdev; 124 + 125 + lockdep_assert_held(&vdev->user_limits_lock); 126 + drm_WARN_ON(&vdev->drm, atomic_read(&limits->db_count)); 127 + hash_del(&limits->hash_node); 128 + kfree(limits); 129 + } 130 + 131 + static void ivpu_user_limits_put(struct ivpu_device *vdev, struct ivpu_user_limits *limits) 132 + { 133 + guard(mutex)(&vdev->user_limits_lock); 134 + kref_put(&limits->ref, ivpu_user_limits_release); 135 + } 136 + 70 137 struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv) 71 138 { 72 139 struct ivpu_device *vdev = file_priv->vdev; ··· 177 110 mutex_unlock(&vdev->context_list_lock); 178 111 pm_runtime_put_autosuspend(vdev->drm.dev); 179 112 113 + ivpu_user_limits_put(vdev, file_priv->user_limits); 180 114 mutex_destroy(&file_priv->ms_lock); 181 115 mutex_destroy(&file_priv->lock); 182 116 kfree(file_priv); ··· 237 169 args->value = ivpu_hw_dpu_max_freq_get(vdev); 238 170 break; 239 171 case DRM_IVPU_PARAM_NUM_CONTEXTS: 240 - args->value = ivpu_get_context_count(vdev); 172 + args->value = file_priv->user_limits->max_ctx_count; 241 173 break; 242 174 case DRM_IVPU_PARAM_CONTEXT_BASE_ADDRESS: 243 175 args->value = vdev->hw->ranges.user.start; ··· 299 231 { 300 232 struct ivpu_device *vdev = to_ivpu_device(dev); 301 233 struct ivpu_file_priv *file_priv; 234 + struct ivpu_user_limits *limits; 302 235 u32 ctx_id; 303 236 int idx, ret; 304 237 305 238 if (!drm_dev_enter(dev, &idx)) 306 239 return -ENODEV; 307 240 241 + limits = ivpu_user_limits_get(vdev); 242 + if (IS_ERR(limits)) { 243 + ret = PTR_ERR(limits); 244 + goto err_dev_exit; 245 + } 246 + 308 247 file_priv = kzalloc_obj(*file_priv); 309 248 if (!file_priv) { 310 249 ret = -ENOMEM; 311 - goto err_dev_exit; 250 + goto err_user_limits_put; 312 251 } 313 252 314 253 INIT_LIST_HEAD(&file_priv->ms_instance_list); 315 254 316 255 file_priv->vdev = vdev; 317 256 file_priv->bound = true; 257 + file_priv->user_limits = limits; 318 258 kref_init(&file_priv->ref); 319 259 mutex_init(&file_priv->lock); 320 260 mutex_init(&file_priv->ms_lock); ··· 360 284 mutex_destroy(&file_priv->ms_lock); 361 285 mutex_destroy(&file_priv->lock); 362 286 kfree(file_priv); 287 + err_user_limits_put: 288 + ivpu_user_limits_put(vdev, limits); 363 289 err_dev_exit: 364 290 drm_dev_exit(idx); 365 291 return ret; ··· 421 343 ivpu_ipc_consumer_del(vdev, &cons); 422 344 423 345 if (!ret && ipc_hdr.data_addr != IVPU_IPC_BOOT_MSG_DATA_ADDR) { 424 - ivpu_err(vdev, "Invalid NPU ready message: 0x%x\n", 425 - ipc_hdr.data_addr); 346 + ivpu_err(vdev, "Invalid NPU ready message: 0x%x\n", ipc_hdr.data_addr); 426 347 return -EIO; 427 348 } 428 349 ··· 530 453 } 531 454 532 455 static const struct file_operations ivpu_fops = { 533 - .owner = THIS_MODULE, 456 + .owner = THIS_MODULE, 534 457 DRM_ACCEL_FOPS, 535 458 #ifdef CONFIG_PROC_FS 536 459 .show_fdinfo = drm_show_fdinfo, ··· 669 592 xa_init_flags(&vdev->submitted_jobs_xa, XA_FLAGS_ALLOC1); 670 593 xa_init_flags(&vdev->db_xa, XA_FLAGS_ALLOC1); 671 594 INIT_LIST_HEAD(&vdev->bo_list); 595 + hash_init(vdev->user_limits); 672 596 673 597 vdev->db_limit.min = IVPU_MIN_DB; 674 598 vdev->db_limit.max = IVPU_MAX_DB; 675 599 676 600 ret = drmm_mutex_init(&vdev->drm, &vdev->context_list_lock); 601 + if (ret) 602 + goto err_xa_destroy; 603 + 604 + ret = drmm_mutex_init(&vdev->drm, &vdev->user_limits_lock); 677 605 if (ret) 678 606 goto err_xa_destroy; 679 607 ··· 799 717 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PTL_P) }, 800 718 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_WCL) }, 801 719 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_NVL) }, 802 - { } 720 + {} 803 721 }; 804 722 MODULE_DEVICE_TABLE(pci, ivpu_pci_ids); 805 723
+22 -4
drivers/accel/ivpu/ivpu_drv.h
··· 12 12 #include <drm/drm_mm.h> 13 13 #include <drm/drm_print.h> 14 14 15 + #include <linux/hashtable.h> 15 16 #include <linux/pci.h> 16 17 #include <linux/xarray.h> 17 18 #include <uapi/drm/ivpu_accel.h> ··· 44 43 /* SSID 1 is used by the VPU to represent reserved context */ 45 44 #define IVPU_RESERVED_CONTEXT_MMU_SSID 1 46 45 #define IVPU_USER_CONTEXT_MIN_SSID 2 47 - #define IVPU_USER_CONTEXT_MAX_SSID (IVPU_USER_CONTEXT_MIN_SSID + 63) 46 + #define IVPU_USER_CONTEXT_MAX_SSID (IVPU_USER_CONTEXT_MIN_SSID + 128) 48 47 49 48 #define IVPU_MIN_DB 1 50 49 #define IVPU_MAX_DB 255 51 50 52 51 #define IVPU_JOB_ID_JOB_MASK GENMASK(7, 0) 53 52 #define IVPU_JOB_ID_CONTEXT_MASK GENMASK(31, 8) 54 - 55 - #define IVPU_NUM_PRIORITIES 4 56 - #define IVPU_NUM_CMDQS_PER_CTX (IVPU_NUM_PRIORITIES) 57 53 58 54 #define IVPU_CMDQ_MIN_ID 1 59 55 #define IVPU_CMDQ_MAX_ID 255 ··· 121 123 struct ivpu_ipc_info; 122 124 struct ivpu_pm_info; 123 125 126 + struct ivpu_user_limits { 127 + struct hlist_node hash_node; 128 + struct ivpu_device *vdev; 129 + struct kref ref; 130 + u32 max_ctx_count; 131 + u32 max_db_count; 132 + u32 uid; 133 + atomic_t db_count; 134 + }; 135 + 124 136 struct ivpu_device { 125 137 struct drm_device drm; 126 138 void __iomem *regb; ··· 150 142 struct mutex context_list_lock; /* Protects user context addition/removal */ 151 143 struct xarray context_xa; 152 144 struct xa_limit context_xa_limit; 145 + DECLARE_HASHTABLE(user_limits, 8); 146 + struct mutex user_limits_lock; /* Protects user_limits */ 153 147 154 148 struct xarray db_xa; 155 149 struct xa_limit db_limit; ··· 199 189 struct list_head ms_instance_list; 200 190 struct ivpu_bo *ms_info_bo; 201 191 struct xa_limit job_limit; 192 + struct ivpu_user_limits *user_limits; 202 193 u32 job_id_next; 203 194 struct xa_limit cmdq_limit; 204 195 u32 cmdq_id_next; ··· 295 284 struct xa_limit ctx_limit = vdev->context_xa_limit; 296 285 297 286 return (ctx_limit.max - ctx_limit.min + 1); 287 + } 288 + 289 + static inline u32 ivpu_get_doorbell_count(struct ivpu_device *vdev) 290 + { 291 + struct xa_limit db_limit = vdev->db_limit; 292 + 293 + return (db_limit.max - db_limit.min + 1); 298 294 } 299 295 300 296 static inline u32 ivpu_get_platform(struct ivpu_device *vdev)
+26 -10
drivers/accel/ivpu/ivpu_job.c
··· 173 173 ret = xa_alloc_cyclic(&file_priv->cmdq_xa, &cmdq->id, cmdq, file_priv->cmdq_limit, 174 174 &file_priv->cmdq_id_next, GFP_KERNEL); 175 175 if (ret < 0) { 176 - ivpu_err(vdev, "Failed to allocate command queue ID: %d\n", ret); 176 + ivpu_dbg(vdev, IOCTL, "Failed to allocate command queue ID: %d\n", ret); 177 177 goto err_free_cmdq; 178 178 } 179 179 ··· 215 215 216 216 static int ivpu_register_db(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq) 217 217 { 218 + struct ivpu_user_limits *limits = file_priv->user_limits; 218 219 struct ivpu_device *vdev = file_priv->vdev; 219 220 int ret; 221 + 222 + if (atomic_inc_return(&limits->db_count) > limits->max_db_count) { 223 + ivpu_dbg(vdev, IOCTL, "Maximum number of %u doorbells for uid %u reached\n", 224 + limits->max_db_count, limits->uid); 225 + ret = -EBUSY; 226 + goto err_dec_db_count; 227 + } 220 228 221 229 ret = xa_alloc_cyclic(&vdev->db_xa, &cmdq->db_id, NULL, vdev->db_limit, &vdev->db_next, 222 230 GFP_KERNEL); 223 231 if (ret < 0) { 224 - ivpu_err(vdev, "Failed to allocate doorbell ID: %d\n", ret); 225 - return ret; 232 + ivpu_dbg(vdev, IOCTL, "Failed to allocate doorbell ID: %d\n", ret); 233 + goto err_dec_db_count; 226 234 } 227 235 228 236 if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) ··· 239 231 else 240 232 ret = ivpu_jsm_register_db(vdev, file_priv->ctx.id, cmdq->db_id, 241 233 cmdq->mem->vpu_addr, ivpu_bo_size(cmdq->mem)); 242 - 243 - if (!ret) { 244 - ivpu_dbg(vdev, JOB, "DB %d registered to cmdq %d ctx %d priority %d\n", 245 - cmdq->db_id, cmdq->id, file_priv->ctx.id, cmdq->priority); 246 - } else { 234 + if (ret) { 247 235 xa_erase(&vdev->db_xa, cmdq->db_id); 248 236 cmdq->db_id = 0; 237 + goto err_dec_db_count; 249 238 } 250 239 240 + ivpu_dbg(vdev, JOB, "DB %d registered to cmdq %d ctx %d priority %d\n", 241 + cmdq->db_id, cmdq->id, file_priv->ctx.id, cmdq->priority); 242 + return 0; 243 + 244 + err_dec_db_count: 245 + atomic_dec(&limits->db_count); 251 246 return ret; 252 247 } 253 248 ··· 309 298 } 310 299 311 300 xa_erase(&file_priv->vdev->db_xa, cmdq->db_id); 301 + atomic_dec(&file_priv->user_limits->db_count); 312 302 cmdq->db_id = 0; 313 303 314 304 return 0; ··· 325 313 326 314 static void ivpu_cmdq_destroy(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq) 327 315 { 316 + lockdep_assert_held(&file_priv->lock); 328 317 ivpu_cmdq_unregister(file_priv, cmdq); 329 318 xa_erase(&file_priv->cmdq_xa, cmdq->id); 330 319 ivpu_cmdq_free(file_priv, cmdq); ··· 393 380 mutex_lock(&file_priv->lock); 394 381 395 382 xa_for_each(&file_priv->cmdq_xa, cmdq_id, cmdq) { 396 - xa_erase(&file_priv->vdev->db_xa, cmdq->db_id); 397 - cmdq->db_id = 0; 383 + if (cmdq->db_id) { 384 + xa_erase(&file_priv->vdev->db_xa, cmdq->db_id); 385 + atomic_dec(&file_priv->user_limits->db_count); 386 + cmdq->db_id = 0; 387 + } 398 388 } 399 389 400 390 mutex_unlock(&file_priv->lock);