diff options
| author | Yair Shachar <yair.shachar@amd.com> | 2015-05-20 07:09:39 -0400 |
|---|---|---|
| committer | Oded Gabbay <oded.gabbay@gmail.com> | 2015-06-03 04:34:35 -0400 |
| commit | f8bd13338a9a42358158954251969e66934ec3d1 (patch) | |
| tree | af276c178c11f7aeba8597ec2f6acc912745166a /drivers/gpu/drm/amd/amdkfd | |
| parent | 9448458998e27be7fcb9ebc58200be45a6429451 (diff) | |
drm/amdkfd: Implement address watch debugger IOCTL
v2:
- rename get_dbgmgr_mutex to kfd_get_dbgmgr_mutex to namespace it
- change void* to uint64_t inside ioctl arguments
- use kmalloc instead of kzalloc because we use copy_from_user
immediately after it
Signed-off-by: Yair Shachar <yair.shachar@amd.com>
Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
Diffstat (limited to 'drivers/gpu/drm/amd/amdkfd')
| -rw-r--r-- | drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 102 |
1 files changed, 101 insertions, 1 deletions
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 9e5261de0716..96c904b3acb7 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | |||
| @@ -528,7 +528,107 @@ static int kfd_ioctl_dbg_unrgesiter(struct file *filep, | |||
| 528 | static int kfd_ioctl_dbg_address_watch(struct file *filep, | 528 | static int kfd_ioctl_dbg_address_watch(struct file *filep, |
| 529 | struct kfd_process *p, void *data) | 529 | struct kfd_process *p, void *data) |
| 530 | { | 530 | { |
| 531 | long status = -EFAULT; | 531 | struct kfd_ioctl_dbg_address_watch_args *args = data; |
| 532 | struct kfd_dev *dev; | ||
| 533 | struct dbg_address_watch_info aw_info; | ||
| 534 | unsigned char *args_buff; | ||
| 535 | long status; | ||
| 536 | void __user *cmd_from_user; | ||
| 537 | uint64_t watch_mask_value = 0; | ||
| 538 | unsigned int args_idx = 0; | ||
| 539 | |||
| 540 | memset((void *) &aw_info, 0, sizeof(struct dbg_address_watch_info)); | ||
| 541 | |||
| 542 | dev = kfd_device_by_id(args->gpu_id); | ||
| 543 | if (dev == NULL) | ||
| 544 | return -EINVAL; | ||
| 545 | |||
| 546 | if (dev->device_info->asic_family == CHIP_CARRIZO) { | ||
| 547 | pr_debug("kfd_ioctl_dbg_wave_control not supported on CZ\n"); | ||
| 548 | return -EINVAL; | ||
| 549 | } | ||
| 550 | |||
| 551 | cmd_from_user = (void __user *) args->content_ptr; | ||
| 552 | |||
| 553 | /* Validate arguments */ | ||
| 554 | |||
| 555 | if ((args->buf_size_in_bytes > MAX_ALLOWED_AW_BUFF_SIZE) || | ||
| 556 | (args->buf_size_in_bytes <= sizeof(*args)) || | ||
| 557 | (cmd_from_user == NULL)) | ||
| 558 | return -EINVAL; | ||
| 559 | |||
| 560 | /* this is the actual buffer to work with */ | ||
| 561 | |||
| 562 | args_buff = kmalloc(args->buf_size_in_bytes - | ||
| 563 | sizeof(*args), GFP_KERNEL); | ||
| 564 | if (args_buff == NULL) | ||
| 565 | return -ENOMEM; | ||
| 566 | |||
| 567 | status = copy_from_user(args_buff, cmd_from_user, | ||
| 568 | args->buf_size_in_bytes - sizeof(*args)); | ||
| 569 | |||
| 570 | if (status != 0) { | ||
| 571 | pr_debug("Failed to copy address watch user data\n"); | ||
| 572 | kfree(args_buff); | ||
| 573 | return -EINVAL; | ||
| 574 | } | ||
| 575 | |||
| 576 | aw_info.process = p; | ||
| 577 | |||
| 578 | aw_info.num_watch_points = *((uint32_t *)(&args_buff[args_idx])); | ||
| 579 | args_idx += sizeof(aw_info.num_watch_points); | ||
| 580 | |||
| 581 | aw_info.watch_mode = (enum HSA_DBG_WATCH_MODE *) &args_buff[args_idx]; | ||
| 582 | args_idx += sizeof(enum HSA_DBG_WATCH_MODE) * aw_info.num_watch_points; | ||
| 583 | |||
| 584 | /* | ||
| 585 | * set watch address base pointer to point on the array base | ||
| 586 | * within args_buff | ||
| 587 | */ | ||
| 588 | aw_info.watch_address = (uint64_t *) &args_buff[args_idx]; | ||
| 589 | |||
| 590 | /* skip over the addresses buffer */ | ||
| 591 | args_idx += sizeof(aw_info.watch_address) * aw_info.num_watch_points; | ||
| 592 | |||
| 593 | if (args_idx >= args->buf_size_in_bytes) { | ||
| 594 | kfree(args_buff); | ||
| 595 | return -EINVAL; | ||
| 596 | } | ||
| 597 | |||
| 598 | watch_mask_value = (uint64_t) args_buff[args_idx]; | ||
| 599 | |||
| 600 | if (watch_mask_value > 0) { | ||
| 601 | /* | ||
| 602 | * There is an array of masks. | ||
| 603 | * set watch mask base pointer to point on the array base | ||
| 604 | * within args_buff | ||
| 605 | */ | ||
| 606 | aw_info.watch_mask = (uint64_t *) &args_buff[args_idx]; | ||
| 607 | |||
| 608 | /* skip over the masks buffer */ | ||
| 609 | args_idx += sizeof(aw_info.watch_mask) * | ||
| 610 | aw_info.num_watch_points; | ||
| 611 | } else { | ||
| 612 | /* just the NULL mask, set to NULL and skip over it */ | ||
| 613 | aw_info.watch_mask = NULL; | ||
| 614 | args_idx += sizeof(aw_info.watch_mask); | ||
| 615 | } | ||
| 616 | |||
| 617 | if (args_idx > args->buf_size_in_bytes) { | ||
| 618 | kfree(args_buff); | ||
| 619 | return -EINVAL; | ||
| 620 | } | ||
| 621 | |||
| 622 | /* Currently HSA Event is not supported for DBG */ | ||
| 623 | aw_info.watch_event = NULL; | ||
| 624 | |||
| 625 | mutex_lock(kfd_get_dbgmgr_mutex()); | ||
| 626 | |||
| 627 | status = kfd_dbgmgr_address_watch(dev->dbgmgr, &aw_info); | ||
| 628 | |||
| 629 | mutex_unlock(kfd_get_dbgmgr_mutex()); | ||
| 630 | |||
| 631 | kfree(args_buff); | ||
| 532 | 632 | ||
| 533 | return status; | 633 | return status; |
| 534 | } | 634 | } |
