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

drm/amdgpu: refactor bad_page_work for corner case handling

When a poison is consumed on the guest before the guest receives the host's poison creation msg, a corner case may occur to have poison_handler complete processing earlier than it should to cause the guest to hang waiting for the req_bad_pages reply during a VF FLR, resulting in the VM becoming inaccessible in stress tests.

To fix this issue, this patch refactored the mailbox sequence by seperating the bad_page_work into two parts req_bad_pages_work and handle_bad_pages_work.
Old sequence:
1.Stop data exchange work
2.Guest sends MB_REQ_RAS_BAD_PAGES to host and keep polling for IDH_RAS_BAD_PAGES_READY
3.If the IDH_RAS_BAD_PAGES_READY arrives within timeout limit, re-init the data exchange region for updated bad page info
else timeout with error message
New sequence:
req_bad_pages_work:
1.Stop data exhange work
2.Guest sends MB_REQ_RAS_BAD_PAGES to host
Once Guest receives IDH_RAS_BAD_PAGES_READY event
handle_bad_pages_work:
3.re-init the data exchange region for updated bad page info

Signed-off-by: Chenglei Xie <Chenglei.Xie@amd.com>
Reviewed-by: Shravan Kumar Gande <Shravankumar.Gande@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Chenglei Xie and committed by
Alex Deucher
d2fa0ec6 fc4e990a

+58 -13
+2 -1
drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
··· 267 267 struct amdgpu_irq_src rcv_irq; 268 268 269 269 struct work_struct flr_work; 270 - struct work_struct bad_pages_work; 270 + struct work_struct req_bad_pages_work; 271 + struct work_struct handle_bad_pages_work; 271 272 272 273 struct amdgpu_mm_table mm_table; 273 274 const struct amdgpu_virt_ops *ops;
+28 -4
drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c
··· 292 292 } 293 293 } 294 294 295 - static void xgpu_ai_mailbox_bad_pages_work(struct work_struct *work) 295 + static void xgpu_ai_mailbox_req_bad_pages_work(struct work_struct *work) 296 296 { 297 - struct amdgpu_virt *virt = container_of(work, struct amdgpu_virt, bad_pages_work); 297 + struct amdgpu_virt *virt = container_of(work, struct amdgpu_virt, req_bad_pages_work); 298 298 struct amdgpu_device *adev = container_of(virt, struct amdgpu_device, virt); 299 299 300 300 if (down_read_trylock(&adev->reset_domain->sem)) { 301 301 amdgpu_virt_fini_data_exchange(adev); 302 302 amdgpu_virt_request_bad_pages(adev); 303 + up_read(&adev->reset_domain->sem); 304 + } 305 + } 306 + 307 + /** 308 + * xgpu_ai_mailbox_handle_bad_pages_work - Reinitialize the data exchange region to get fresh bad page information 309 + * @work: pointer to the work_struct 310 + * 311 + * This work handler is triggered when bad pages are ready, and it reinitializes 312 + * the data exchange region to retrieve updated bad page information from the host. 313 + */ 314 + static void xgpu_ai_mailbox_handle_bad_pages_work(struct work_struct *work) 315 + { 316 + struct amdgpu_virt *virt = container_of(work, struct amdgpu_virt, handle_bad_pages_work); 317 + struct amdgpu_device *adev = container_of(virt, struct amdgpu_device, virt); 318 + 319 + if (down_read_trylock(&adev->reset_domain->sem)) { 320 + amdgpu_virt_fini_data_exchange(adev); 303 321 amdgpu_virt_init_data_exchange(adev); 304 322 up_read(&adev->reset_domain->sem); 305 323 } ··· 345 327 struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); 346 328 347 329 switch (event) { 330 + case IDH_RAS_BAD_PAGES_READY: 331 + xgpu_ai_mailbox_send_ack(adev); 332 + if (amdgpu_sriov_runtime(adev)) 333 + schedule_work(&adev->virt.handle_bad_pages_work); 334 + break; 348 335 case IDH_RAS_BAD_PAGES_NOTIFICATION: 349 336 xgpu_ai_mailbox_send_ack(adev); 350 337 if (amdgpu_sriov_runtime(adev)) 351 - schedule_work(&adev->virt.bad_pages_work); 338 + schedule_work(&adev->virt.req_bad_pages_work); 352 339 break; 353 340 case IDH_UNRECOV_ERR_NOTIFICATION: 354 341 xgpu_ai_mailbox_send_ack(adev); ··· 438 415 } 439 416 440 417 INIT_WORK(&adev->virt.flr_work, xgpu_ai_mailbox_flr_work); 441 - INIT_WORK(&adev->virt.bad_pages_work, xgpu_ai_mailbox_bad_pages_work); 418 + INIT_WORK(&adev->virt.req_bad_pages_work, xgpu_ai_mailbox_req_bad_pages_work); 419 + INIT_WORK(&adev->virt.handle_bad_pages_work, xgpu_ai_mailbox_handle_bad_pages_work); 442 420 443 421 return 0; 444 422 }
+28 -7
drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c
··· 202 202 case IDH_REQ_RAS_CPER_DUMP: 203 203 event = IDH_RAS_CPER_DUMP_READY; 204 204 break; 205 - case IDH_REQ_RAS_BAD_PAGES: 206 - event = IDH_RAS_BAD_PAGES_READY; 207 - break; 208 205 default: 209 206 break; 210 207 } ··· 356 359 } 357 360 } 358 361 359 - static void xgpu_nv_mailbox_bad_pages_work(struct work_struct *work) 362 + static void xgpu_nv_mailbox_req_bad_pages_work(struct work_struct *work) 360 363 { 361 - struct amdgpu_virt *virt = container_of(work, struct amdgpu_virt, bad_pages_work); 364 + struct amdgpu_virt *virt = container_of(work, struct amdgpu_virt, req_bad_pages_work); 362 365 struct amdgpu_device *adev = container_of(virt, struct amdgpu_device, virt); 363 366 364 367 if (down_read_trylock(&adev->reset_domain->sem)) { 365 368 amdgpu_virt_fini_data_exchange(adev); 366 369 amdgpu_virt_request_bad_pages(adev); 370 + up_read(&adev->reset_domain->sem); 371 + } 372 + } 373 + 374 + /** 375 + * xgpu_nv_mailbox_handle_bad_pages_work - Reinitialize the data exchange region to get fresh bad page information 376 + * @work: pointer to the work_struct 377 + * 378 + * This work handler is triggered when bad pages are ready, and it reinitializes 379 + * the data exchange region to retrieve updated bad page information from the host. 380 + */ 381 + static void xgpu_nv_mailbox_handle_bad_pages_work(struct work_struct *work) 382 + { 383 + struct amdgpu_virt *virt = container_of(work, struct amdgpu_virt, handle_bad_pages_work); 384 + struct amdgpu_device *adev = container_of(virt, struct amdgpu_device, virt); 385 + 386 + if (down_read_trylock(&adev->reset_domain->sem)) { 387 + amdgpu_virt_fini_data_exchange(adev); 367 388 amdgpu_virt_init_data_exchange(adev); 368 389 up_read(&adev->reset_domain->sem); 369 390 } ··· 412 397 struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); 413 398 414 399 switch (event) { 400 + case IDH_RAS_BAD_PAGES_READY: 401 + xgpu_nv_mailbox_send_ack(adev); 402 + if (amdgpu_sriov_runtime(adev)) 403 + schedule_work(&adev->virt.handle_bad_pages_work); 404 + break; 415 405 case IDH_RAS_BAD_PAGES_NOTIFICATION: 416 406 xgpu_nv_mailbox_send_ack(adev); 417 407 if (amdgpu_sriov_runtime(adev)) 418 - schedule_work(&adev->virt.bad_pages_work); 408 + schedule_work(&adev->virt.req_bad_pages_work); 419 409 break; 420 410 case IDH_UNRECOV_ERR_NOTIFICATION: 421 411 xgpu_nv_mailbox_send_ack(adev); ··· 505 485 } 506 486 507 487 INIT_WORK(&adev->virt.flr_work, xgpu_nv_mailbox_flr_work); 508 - INIT_WORK(&adev->virt.bad_pages_work, xgpu_nv_mailbox_bad_pages_work); 488 + INIT_WORK(&adev->virt.req_bad_pages_work, xgpu_nv_mailbox_req_bad_pages_work); 489 + INIT_WORK(&adev->virt.handle_bad_pages_work, xgpu_nv_mailbox_handle_bad_pages_work); 509 490 510 491 return 0; 511 492 }
-1
drivers/gpu/drm/amd/amdgpu/soc15.c
··· 741 741 void soc15_set_virt_ops(struct amdgpu_device *adev) 742 742 { 743 743 adev->virt.ops = &xgpu_ai_virt_ops; 744 - 745 744 /* init soc15 reg base early enough so we can 746 745 * request request full access for sriov before 747 746 * set_ip_blocks. */