summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c
diff options
context:
space:
mode:
authorPeter Daifuku <pdaifuku@nvidia.com>2017-01-25 21:50:44 -0500
committermobile promotions <svcmobile_promotions@nvidia.com>2017-03-22 22:46:40 -0400
commit23e92bee4a8f6b66dfd1f5082af2712c0ae0b602 (patch)
tree58ff8598ca40a9144b2c1d142b41379e543a2722 /drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c
parent7719eb94f7ef155cf097b599464cbaba4d9a80e0 (diff)
gpu: nvgpu: profiler create/free, hwpm reserve
Add support for creating/freeing profiler objects, hwpm reservations Bug 1775465 JIRA EVLR-680 JIRA EVLR-682 Change-Id: I4db83d00e4b0b552b05b9aae96dc553dd1257d88 Signed-off-by: Peter Daifuku <pdaifuku@nvidia.com> Reviewed-on: http://git-master/r/1294401 Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c350
1 files changed, 343 insertions, 7 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c b/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c
index 7eb742ed..12d81343 100644
--- a/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c
@@ -62,11 +62,11 @@ nvgpu_dbg_gpu_get_session_channel(struct dbg_session_gk20a *dbg_s)
62 return ch; 62 return ch;
63} 63}
64 64
65/* silly allocator - just increment session id */ 65/* silly allocator - just increment id */
66static atomic_t session_id = ATOMIC_INIT(0); 66static atomic_t unique_id = ATOMIC_INIT(0);
67static int generate_session_id(void) 67static int generate_unique_id(void)
68{ 68{
69 return atomic_add_return(1, &session_id); 69 return atomic_add_return(1, &unique_id);
70} 70}
71 71
72static int alloc_session(struct dbg_session_gk20a **_dbg_s) 72static int alloc_session(struct dbg_session_gk20a **_dbg_s)
@@ -80,11 +80,27 @@ static int alloc_session(struct dbg_session_gk20a **_dbg_s)
80 if (!dbg_s) 80 if (!dbg_s)
81 return -ENOMEM; 81 return -ENOMEM;
82 82
83 dbg_s->id = generate_session_id(); 83 dbg_s->id = generate_unique_id();
84 *_dbg_s = dbg_s; 84 *_dbg_s = dbg_s;
85 return 0; 85 return 0;
86} 86}
87 87
88static int alloc_profiler(struct dbg_profiler_object_data **_prof)
89{
90 struct dbg_profiler_object_data *prof;
91 *_prof = NULL;
92
93 gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg, "");
94
95 prof = kzalloc(sizeof(*prof), GFP_KERNEL);
96 if (!prof)
97 return -ENOMEM;
98
99 prof->prof_handle = generate_unique_id();
100 *_prof = prof;
101 return 0;
102}
103
88static int gk20a_dbg_gpu_do_dev_open(struct inode *inode, 104static int gk20a_dbg_gpu_do_dev_open(struct inode *inode,
89 struct file *filp, bool is_profiler) 105 struct file *filp, bool is_profiler)
90{ 106{
@@ -400,13 +416,28 @@ int dbg_unbind_single_channel_gk20a(struct dbg_session_gk20a *dbg_s,
400{ 416{
401 struct gk20a *g = dbg_s->g; 417 struct gk20a *g = dbg_s->g;
402 int chid; 418 int chid;
403 struct channel_gk20a *ch;
404 struct dbg_session_data *session_data; 419 struct dbg_session_data *session_data;
420 struct dbg_profiler_object_data *prof_obj, *tmp_obj;
405 421
406 gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg, ""); 422 gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg, "");
407 423
408 chid = ch_data->chid; 424 chid = ch_data->chid;
409 ch = g->fifo.channel + chid; 425
426 /* If there's a profiler ctx reservation record associated with this
427 * session/channel pair, release it.
428 */
429 list_for_each_entry_safe(prof_obj, tmp_obj, &g->profiler_objects,
430 prof_obj_entry) {
431 if ((prof_obj->session_id == dbg_s->id) &&
432 (prof_obj->ch->hw_chid == chid)) {
433 if (prof_obj->has_reservation) {
434 g->profiler_reservation_count--;
435 dbg_s->has_profiler_reservation = false;
436 }
437 list_del(&prof_obj->prof_obj_entry);
438 kfree(prof_obj);
439 }
440 }
410 441
411 list_del_init(&ch_data->ch_entry); 442 list_del_init(&ch_data->ch_entry);
412 443
@@ -480,6 +511,7 @@ int gk20a_dbg_gpu_dev_release(struct inode *inode, struct file *filp)
480{ 511{
481 struct dbg_session_gk20a *dbg_s = filp->private_data; 512 struct dbg_session_gk20a *dbg_s = filp->private_data;
482 struct gk20a *g = dbg_s->g; 513 struct gk20a *g = dbg_s->g;
514 struct dbg_profiler_object_data *prof_obj, *tmp_obj;
483 515
484 gk20a_dbg(gpu_dbg_gpu_dbg | gpu_dbg_fn, "%s", dev_name(dbg_s->dev)); 516 gk20a_dbg(gpu_dbg_gpu_dbg | gpu_dbg_fn, "%s", dev_name(dbg_s->dev));
485 517
@@ -494,6 +526,21 @@ int gk20a_dbg_gpu_dev_release(struct inode *inode, struct file *filp)
494 g->ops.dbg_session_ops.dbg_set_powergate(dbg_s, 526 g->ops.dbg_session_ops.dbg_set_powergate(dbg_s,
495 NVGPU_DBG_GPU_POWERGATE_MODE_ENABLE); 527 NVGPU_DBG_GPU_POWERGATE_MODE_ENABLE);
496 nvgpu_dbg_timeout_enable(dbg_s, NVGPU_DBG_GPU_IOCTL_TIMEOUT_ENABLE); 528 nvgpu_dbg_timeout_enable(dbg_s, NVGPU_DBG_GPU_IOCTL_TIMEOUT_ENABLE);
529
530 /* Per-context profiler objects were released when we called
531 * dbg_unbind_all_channels. We could still have global ones.
532 */
533 list_for_each_entry_safe(prof_obj, tmp_obj, &g->profiler_objects,
534 prof_obj_entry) {
535 if (prof_obj->session_id == dbg_s->id) {
536 if (prof_obj->has_reservation) {
537 g->global_profiler_reservation_held = false;
538 g->profiler_reservation_count--;
539 }
540 list_del(&prof_obj->prof_obj_entry);
541 kfree(prof_obj);
542 }
543 }
497 nvgpu_mutex_release(&g->dbg_sessions_lock); 544 nvgpu_mutex_release(&g->dbg_sessions_lock);
498 545
499 nvgpu_mutex_destroy(&dbg_s->ch_list_lock); 546 nvgpu_mutex_destroy(&dbg_s->ch_list_lock);
@@ -584,6 +631,15 @@ static int nvgpu_dbg_gpu_ioctl_suspend_resume_sm(
584 struct dbg_session_gk20a *dbg_s, 631 struct dbg_session_gk20a *dbg_s,
585 struct nvgpu_dbg_gpu_suspend_resume_all_sms_args *args); 632 struct nvgpu_dbg_gpu_suspend_resume_all_sms_args *args);
586 633
634static int nvgpu_ioctl_allocate_profiler_object(struct dbg_session_gk20a *dbg_s,
635 struct nvgpu_dbg_gpu_profiler_obj_mgt_args *args);
636
637static int nvgpu_ioctl_free_profiler_object(struct dbg_session_gk20a *dbg_s,
638 struct nvgpu_dbg_gpu_profiler_obj_mgt_args *args);
639
640static int nvgpu_ioctl_profiler_reserve(struct dbg_session_gk20a *dbg_s,
641 struct nvgpu_dbg_gpu_profiler_reserve_args *args);
642
587static int gk20a_perfbuf_map(struct dbg_session_gk20a *dbg_s, 643static int gk20a_perfbuf_map(struct dbg_session_gk20a *dbg_s,
588 struct nvgpu_dbg_gpu_perfbuf_map_args *args); 644 struct nvgpu_dbg_gpu_perfbuf_map_args *args);
589 645
@@ -1022,6 +1078,21 @@ long gk20a_dbg_gpu_dev_ioctl(struct file *filp, unsigned int cmd,
1022 (struct nvgpu_dbg_gpu_access_fb_memory_args *)buf); 1078 (struct nvgpu_dbg_gpu_access_fb_memory_args *)buf);
1023 break; 1079 break;
1024 1080
1081 case NVGPU_DBG_GPU_IOCTL_PROFILER_ALLOCATE:
1082 err = nvgpu_ioctl_allocate_profiler_object(dbg_s,
1083 (struct nvgpu_dbg_gpu_profiler_obj_mgt_args *)buf);
1084 break;
1085
1086 case NVGPU_DBG_GPU_IOCTL_PROFILER_FREE:
1087 err = nvgpu_ioctl_free_profiler_object(dbg_s,
1088 (struct nvgpu_dbg_gpu_profiler_obj_mgt_args *)buf);
1089 break;
1090
1091 case NVGPU_DBG_GPU_IOCTL_PROFILER_RESERVE:
1092 err = nvgpu_ioctl_profiler_reserve(dbg_s,
1093 (struct nvgpu_dbg_gpu_profiler_reserve_args *)buf);
1094 break;
1095
1025 default: 1096 default:
1026 gk20a_err(dev_from_gk20a(g), 1097 gk20a_err(dev_from_gk20a(g),
1027 "unrecognized dbg gpu ioctl cmd: 0x%x", 1098 "unrecognized dbg gpu ioctl cmd: 0x%x",
@@ -1357,6 +1428,16 @@ static int nvgpu_dbg_gpu_ioctl_hwpm_ctxsw_mode(struct dbg_session_gk20a *dbg_s,
1357 gk20a_dbg_fn("%s pm ctxsw mode = %d", 1428 gk20a_dbg_fn("%s pm ctxsw mode = %d",
1358 dev_name(dbg_s->dev), args->mode); 1429 dev_name(dbg_s->dev), args->mode);
1359 1430
1431 /* Must have a valid reservation to enable/disable hwpm cxtsw.
1432 * Just print an error message for now, but eventually this should
1433 * return an error, at the point where all client sw has been
1434 * cleaned up.
1435 */
1436 if (!dbg_s->has_profiler_reservation) {
1437 gk20a_err(dev_from_gk20a(g),
1438 "session doesn't have a valid reservation");
1439 }
1440
1360 err = gk20a_busy(g->dev); 1441 err = gk20a_busy(g->dev);
1361 if (err) { 1442 if (err) {
1362 gk20a_err(dev_from_gk20a(g), "failed to poweron"); 1443 gk20a_err(dev_from_gk20a(g), "failed to poweron");
@@ -1440,6 +1521,261 @@ clean_up:
1440 return err; 1521 return err;
1441} 1522}
1442 1523
1524static int nvgpu_ioctl_allocate_profiler_object(
1525 struct dbg_session_gk20a *dbg_s,
1526 struct nvgpu_dbg_gpu_profiler_obj_mgt_args *args)
1527{
1528 int err = 0;
1529 struct gk20a *g = get_gk20a(dbg_s->dev);
1530 struct dbg_profiler_object_data *prof_obj;
1531
1532 gk20a_dbg_fn("%s", dev_name(dbg_s->dev));
1533
1534 nvgpu_mutex_acquire(&g->dbg_sessions_lock);
1535
1536 err = alloc_profiler(&prof_obj);
1537 if (err)
1538 goto clean_up;
1539
1540 prof_obj->session_id = dbg_s->id;
1541
1542 if (dbg_s->is_profiler)
1543 prof_obj->ch = NULL;
1544 else {
1545 prof_obj->ch = nvgpu_dbg_gpu_get_session_channel(dbg_s);
1546 if (prof_obj->ch == NULL) {
1547 gk20a_err(dev_from_gk20a(g),
1548 "bind a channel for dbg session");
1549 kfree(prof_obj);
1550 err = -EINVAL;
1551 goto clean_up;
1552 }
1553 }
1554
1555 /* Return handle to client */
1556 args->profiler_handle = prof_obj->prof_handle;
1557
1558 INIT_LIST_HEAD(&prof_obj->prof_obj_entry);
1559
1560 list_add(&prof_obj->prof_obj_entry, &g->profiler_objects);
1561clean_up:
1562 nvgpu_mutex_release(&g->dbg_sessions_lock);
1563 return err;
1564}
1565
1566static int nvgpu_ioctl_free_profiler_object(
1567 struct dbg_session_gk20a *dbg_s,
1568 struct nvgpu_dbg_gpu_profiler_obj_mgt_args *args)
1569{
1570 int err = 0;
1571 struct gk20a *g = get_gk20a(dbg_s->dev);
1572 struct dbg_profiler_object_data *prof_obj, *tmp_obj;
1573 bool obj_found = false;
1574
1575 gk20a_dbg_fn("%s session_id = %d profiler_handle = %x",
1576 dev_name(dbg_s->dev), dbg_s->id, args->profiler_handle);
1577
1578 nvgpu_mutex_acquire(&g->dbg_sessions_lock);
1579
1580 /* Remove profiler object from the list, if a match is found */
1581 list_for_each_entry_safe(prof_obj, tmp_obj, &g->profiler_objects,
1582 prof_obj_entry) {
1583 if (prof_obj->prof_handle == args->profiler_handle) {
1584 if (prof_obj->session_id != dbg_s->id) {
1585 gk20a_err(dev_from_gk20a(g),
1586 "invalid handle %x",
1587 args->profiler_handle);
1588 err = -EINVAL;
1589 break;
1590 }
1591 if (prof_obj->has_reservation) {
1592 if (prof_obj->ch == NULL)
1593 g->global_profiler_reservation_held = false;
1594 g->profiler_reservation_count--;
1595 dbg_s->has_profiler_reservation = false;
1596 }
1597 list_del(&prof_obj->prof_obj_entry);
1598 kfree(prof_obj);
1599 obj_found = true;
1600 break;
1601 }
1602 }
1603 if (!obj_found) {
1604 gk20a_err(dev_from_gk20a(g), "profiler %x not found",
1605 args->profiler_handle);
1606 err = -EINVAL;
1607 }
1608
1609 nvgpu_mutex_release(&g->dbg_sessions_lock);
1610 return err;
1611}
1612
1613static struct dbg_profiler_object_data *find_matching_prof_obj(
1614 struct dbg_session_gk20a *dbg_s,
1615 u32 profiler_handle)
1616{
1617 struct gk20a *g = dbg_s->g;
1618 struct dbg_profiler_object_data *prof_obj;
1619
1620 list_for_each_entry(prof_obj, &g->profiler_objects, prof_obj_entry) {
1621 if (prof_obj->prof_handle == profiler_handle) {
1622 if (prof_obj->session_id != dbg_s->id) {
1623 gk20a_err(dev_from_gk20a(g),
1624 "invalid handle %x",
1625 profiler_handle);
1626 return NULL;
1627 }
1628 return prof_obj;
1629 }
1630 }
1631 return NULL;
1632}
1633
1634static int nvgpu_profiler_reserve_acquire(struct dbg_session_gk20a *dbg_s,
1635 u32 profiler_handle)
1636{
1637 struct gk20a *g = dbg_s->g;
1638 struct dbg_profiler_object_data *prof_obj, *my_prof_obj;
1639 int err = 0;
1640
1641 gk20a_dbg_fn("%s profiler_handle = %x", dev_name(dbg_s->dev), profiler_handle);
1642
1643 if (g->profiler_reservation_count < 0) {
1644 gk20a_err(dev_from_gk20a(g), "Negative reservation count!");
1645 return -EINVAL;
1646 }
1647
1648 nvgpu_mutex_acquire(&g->dbg_sessions_lock);
1649
1650 /* Find matching object. */
1651 my_prof_obj = find_matching_prof_obj(dbg_s, profiler_handle);
1652
1653 if (!my_prof_obj) {
1654 gk20a_err(dev_from_gk20a(g), "object not found");
1655 err = -EINVAL;
1656 goto exit;
1657 }
1658
1659 /* If we already have the reservation, we're done */
1660 if (my_prof_obj->has_reservation) {
1661 err = 0;
1662 goto exit;
1663 }
1664
1665 if (my_prof_obj->ch == NULL) {
1666 /* Global reservations are only allowed if there are no other
1667 * global or per-context reservations currently held
1668 */
1669 if (g->profiler_reservation_count > 0) {
1670 gk20a_err(dev_from_gk20a(g),
1671 "global reserve: have existing reservation");
1672 err = -EBUSY;
1673 goto exit;
1674 }
1675
1676 my_prof_obj->has_reservation = true;
1677 g->global_profiler_reservation_held = true;
1678 g->profiler_reservation_count = 1;
1679 dbg_s->has_profiler_reservation = true;
1680 } else if (g->global_profiler_reservation_held) {
1681 /* If there's a global reservation,
1682 * we can't take a per-context one.
1683 */
1684 gk20a_err(dev_from_gk20a(g),
1685 "per-ctxt reserve: global reservation in effect");
1686 err = -EBUSY;
1687 goto exit;
1688 } else if (gk20a_is_channel_marked_as_tsg(my_prof_obj->ch)) {
1689 /* TSG: check that another channel in the TSG
1690 * doesn't already have the reservation
1691 */
1692 int my_tsgid = my_prof_obj->ch->tsgid;
1693
1694 list_for_each_entry(prof_obj, &g->profiler_objects,
1695 prof_obj_entry) {
1696 if (prof_obj->has_reservation &&
1697 (prof_obj->ch->tsgid == my_tsgid)) {
1698 gk20a_err(dev_from_gk20a(g),
1699 "per-ctxt reserve (tsg): already reserved");
1700 err = -EBUSY;
1701 goto exit;
1702 }
1703 }
1704
1705 my_prof_obj->has_reservation = true;
1706 g->profiler_reservation_count++;
1707 dbg_s->has_profiler_reservation = true;
1708 } else {
1709 /* channel: check that some other profiler object doesn't
1710 * already have the reservation.
1711 */
1712 struct channel_gk20a *my_ch = my_prof_obj->ch;
1713
1714 list_for_each_entry(prof_obj, &g->profiler_objects,
1715 prof_obj_entry) {
1716 if (prof_obj->has_reservation &&
1717 (prof_obj->ch == my_ch)) {
1718 gk20a_err(dev_from_gk20a(g),
1719 "per-ctxt reserve (ch): already reserved");
1720 err = -EBUSY;
1721 goto exit;
1722 }
1723 }
1724
1725 my_prof_obj->has_reservation = true;
1726 g->profiler_reservation_count++;
1727 dbg_s->has_profiler_reservation = true;
1728 }
1729exit:
1730 nvgpu_mutex_release(&g->dbg_sessions_lock);
1731 return err;
1732}
1733
1734static int nvgpu_profiler_reserve_release(struct dbg_session_gk20a *dbg_s,
1735 u32 profiler_handle)
1736{
1737 struct gk20a *g = dbg_s->g;
1738 struct dbg_profiler_object_data *prof_obj;
1739 int err = 0;
1740
1741 gk20a_dbg_fn("%s profiler_handle = %x", dev_name(dbg_s->dev), profiler_handle);
1742
1743 nvgpu_mutex_acquire(&g->dbg_sessions_lock);
1744
1745 /* Find matching object. */
1746 prof_obj = find_matching_prof_obj(dbg_s, profiler_handle);
1747
1748 if (!prof_obj) {
1749 gk20a_err(dev_from_gk20a(g), "object not found");
1750 err = -EINVAL;
1751 goto exit;
1752 }
1753
1754 if (prof_obj->has_reservation) {
1755 prof_obj->has_reservation = false;
1756 if (prof_obj->ch == NULL)
1757 g->global_profiler_reservation_held = false;
1758 g->profiler_reservation_count--;
1759 dbg_s->has_profiler_reservation = false;
1760 } else {
1761 gk20a_err(dev_from_gk20a(g), "No reservation found");
1762 err = -EINVAL;
1763 goto exit;
1764 }
1765exit:
1766 nvgpu_mutex_release(&g->dbg_sessions_lock);
1767 return err;
1768}
1769
1770static int nvgpu_ioctl_profiler_reserve(struct dbg_session_gk20a *dbg_s,
1771 struct nvgpu_dbg_gpu_profiler_reserve_args *args)
1772{
1773 if (args->acquire)
1774 return nvgpu_profiler_reserve_acquire(dbg_s, args->profiler_handle);
1775
1776 return nvgpu_profiler_reserve_release(dbg_s, args->profiler_handle);
1777}
1778
1443static int gk20a_perfbuf_map(struct dbg_session_gk20a *dbg_s, 1779static int gk20a_perfbuf_map(struct dbg_session_gk20a *dbg_s,
1444 struct nvgpu_dbg_gpu_perfbuf_map_args *args) 1780 struct nvgpu_dbg_gpu_perfbuf_map_args *args)
1445{ 1781{