diff options
author | David Nieto <dmartineznie@nvidia.com> | 2017-02-13 14:22:59 -0500 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2017-03-20 19:39:50 -0400 |
commit | 469308becaff326da02fcf791e803e812e1cf9f8 (patch) | |
tree | 2acc6d432a7a6023c3d6bb034df8ac0e9cb6bfbf /drivers | |
parent | 50f371f891c889c782187036c31132fa94c573ac (diff) |
gpu: nvgpu: fix arbiter teardown on PCI
The driver is not properly tearing down the arbiter on the PCI driver
unload. This change makes sure that the workqueues are drained before
tearing down the driver
bug 200277762
JIRA: EVLR-1023
Change-Id: If98fd00e27949ba1569dd26e2af02b75897231a7
Signed-off-by: David Nieto <dmartineznie@nvidia.com>
Reviewed-on: http://git-master/r/1320147
Reviewed-by: svccoveritychecker <svccoveritychecker@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk_arb.c | 67 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c | 18 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/pci.c | 4 |
3 files changed, 63 insertions, 26 deletions
diff --git a/drivers/gpu/nvgpu/clk/clk_arb.c b/drivers/gpu/nvgpu/clk/clk_arb.c index 44b442d8..30447d3e 100644 --- a/drivers/gpu/nvgpu/clk/clk_arb.c +++ b/drivers/gpu/nvgpu/clk/clk_arb.c | |||
@@ -403,7 +403,8 @@ void nvgpu_clk_arb_schedule_alarm(struct gk20a *g, u32 alarm) | |||
403 | struct nvgpu_clk_arb *arb = g->clk_arb; | 403 | struct nvgpu_clk_arb *arb = g->clk_arb; |
404 | 404 | ||
405 | nvgpu_clk_arb_set_global_alarm(g, alarm); | 405 | nvgpu_clk_arb_set_global_alarm(g, alarm); |
406 | queue_work(arb->update_work_queue, &arb->update_fn_work); | 406 | if (arb->update_work_queue) |
407 | queue_work(arb->update_work_queue, &arb->update_fn_work); | ||
407 | } | 408 | } |
408 | 409 | ||
409 | static void nvgpu_clk_arb_clear_global_alarm(struct gk20a *g, u32 alarm) | 410 | static void nvgpu_clk_arb_clear_global_alarm(struct gk20a *g, u32 alarm) |
@@ -455,8 +456,30 @@ static void nvgpu_clk_arb_set_global_alarm(struct gk20a *g, u32 alarm) | |||
455 | 456 | ||
456 | void nvgpu_clk_arb_cleanup_arbiter(struct gk20a *g) | 457 | void nvgpu_clk_arb_cleanup_arbiter(struct gk20a *g) |
457 | { | 458 | { |
459 | struct nvgpu_clk_arb *arb = g->clk_arb; | ||
460 | int index; | ||
461 | |||
462 | if (arb) { | ||
463 | cancel_work_sync(&arb->vf_table_fn_work); | ||
464 | destroy_workqueue(arb->vf_table_work_queue); | ||
465 | arb->vf_table_work_queue = NULL; | ||
466 | |||
467 | cancel_work_sync(&arb->update_fn_work); | ||
468 | destroy_workqueue(arb->update_work_queue); | ||
469 | arb->update_work_queue = NULL; | ||
470 | |||
471 | kfree(arb->gpc2clk_f_points); | ||
472 | kfree(arb->mclk_f_points); | ||
473 | |||
474 | for (index = 0; index < 2; index++) { | ||
475 | kfree(arb->vf_table_pool[index].gpc2clk_points); | ||
476 | kfree(arb->vf_table_pool[index].mclk_points); | ||
477 | } | ||
478 | } | ||
479 | |||
458 | nvgpu_mutex_destroy(&g->clk_arb->pstate_lock); | 480 | nvgpu_mutex_destroy(&g->clk_arb->pstate_lock); |
459 | kfree(g->clk_arb); | 481 | kfree(g->clk_arb); |
482 | g->clk_arb = NULL; | ||
460 | } | 483 | } |
461 | 484 | ||
462 | static int nvgpu_clk_arb_install_fd(struct gk20a *g, | 485 | static int nvgpu_clk_arb_install_fd(struct gk20a *g, |
@@ -575,9 +598,11 @@ static void nvgpu_clk_arb_free_session(struct kref *refcount) | |||
575 | 598 | ||
576 | gk20a_dbg_fn(""); | 599 | gk20a_dbg_fn(""); |
577 | 600 | ||
578 | nvgpu_spinlock_acquire(&arb->sessions_lock); | 601 | if (arb) { |
579 | list_del_rcu(&session->link); | 602 | nvgpu_spinlock_acquire(&arb->sessions_lock); |
580 | nvgpu_spinlock_release(&arb->sessions_lock); | 603 | list_del_rcu(&session->link); |
604 | nvgpu_spinlock_release(&arb->sessions_lock); | ||
605 | } | ||
581 | 606 | ||
582 | head = llist_del_all(&session->targets); | 607 | head = llist_del_all(&session->targets); |
583 | llist_for_each_entry_safe(dev, tmp, head, node) { | 608 | llist_for_each_entry_safe(dev, tmp, head, node) { |
@@ -596,8 +621,8 @@ void nvgpu_clk_arb_release_session(struct gk20a *g, | |||
596 | 621 | ||
597 | session->zombie = true; | 622 | session->zombie = true; |
598 | kref_put(&session->refcount, nvgpu_clk_arb_free_session); | 623 | kref_put(&session->refcount, nvgpu_clk_arb_free_session); |
599 | 624 | if (arb && arb->update_work_queue) | |
600 | queue_work(arb->update_work_queue, &arb->update_fn_work); | 625 | queue_work(arb->update_work_queue, &arb->update_fn_work); |
601 | } | 626 | } |
602 | 627 | ||
603 | int nvgpu_clk_arb_install_event_fd(struct gk20a *g, | 628 | int nvgpu_clk_arb_install_event_fd(struct gk20a *g, |
@@ -964,8 +989,8 @@ exit_vf_table: | |||
964 | if (status < 0) | 989 | if (status < 0) |
965 | nvgpu_clk_arb_set_global_alarm(g, | 990 | nvgpu_clk_arb_set_global_alarm(g, |
966 | EVENT(ALARM_VF_TABLE_UPDATE_FAILED)); | 991 | EVENT(ALARM_VF_TABLE_UPDATE_FAILED)); |
967 | 992 | if (arb->update_work_queue) | |
968 | queue_work(arb->update_work_queue, &arb->update_fn_work); | 993 | queue_work(arb->update_work_queue, &arb->update_fn_work); |
969 | 994 | ||
970 | return status; | 995 | return status; |
971 | } | 996 | } |
@@ -973,8 +998,8 @@ exit_vf_table: | |||
973 | void nvgpu_clk_arb_schedule_vf_table_update(struct gk20a *g) | 998 | void nvgpu_clk_arb_schedule_vf_table_update(struct gk20a *g) |
974 | { | 999 | { |
975 | struct nvgpu_clk_arb *arb = g->clk_arb; | 1000 | struct nvgpu_clk_arb *arb = g->clk_arb; |
976 | 1001 | if (arb->vf_table_work_queue) | |
977 | queue_work(arb->vf_table_work_queue, &arb->vf_table_fn_work); | 1002 | queue_work(arb->vf_table_work_queue, &arb->vf_table_fn_work); |
978 | } | 1003 | } |
979 | 1004 | ||
980 | static void nvgpu_clk_arb_run_vf_table_cb(struct work_struct *work) | 1005 | static void nvgpu_clk_arb_run_vf_table_cb(struct work_struct *work) |
@@ -991,8 +1016,9 @@ static void nvgpu_clk_arb_run_vf_table_cb(struct work_struct *work) | |||
991 | "failed to cache VF table"); | 1016 | "failed to cache VF table"); |
992 | nvgpu_clk_arb_set_global_alarm(g, | 1017 | nvgpu_clk_arb_set_global_alarm(g, |
993 | EVENT(ALARM_VF_TABLE_UPDATE_FAILED)); | 1018 | EVENT(ALARM_VF_TABLE_UPDATE_FAILED)); |
994 | 1019 | if (arb->update_work_queue) | |
995 | queue_work(arb->update_work_queue, &arb->update_fn_work); | 1020 | queue_work(arb->update_work_queue, |
1021 | &arb->update_fn_work); | ||
996 | 1022 | ||
997 | return; | 1023 | return; |
998 | } | 1024 | } |
@@ -1490,8 +1516,8 @@ int nvgpu_clk_arb_commit_request_fd(struct gk20a *g, | |||
1490 | } | 1516 | } |
1491 | kref_get(&dev->refcount); | 1517 | kref_get(&dev->refcount); |
1492 | llist_add(&dev->node, &session->targets); | 1518 | llist_add(&dev->node, &session->targets); |
1493 | 1519 | if (arb->update_work_queue) | |
1494 | queue_work(arb->update_work_queue, &arb->update_fn_work); | 1520 | queue_work(arb->update_work_queue, &arb->update_fn_work); |
1495 | 1521 | ||
1496 | fdput_fd: | 1522 | fdput_fd: |
1497 | fdput(fd); | 1523 | fdput(fd); |
@@ -1568,15 +1594,12 @@ static int nvgpu_clk_arb_release_completion_dev(struct inode *inode, | |||
1568 | { | 1594 | { |
1569 | struct nvgpu_clk_dev *dev = filp->private_data; | 1595 | struct nvgpu_clk_dev *dev = filp->private_data; |
1570 | struct nvgpu_clk_session *session = dev->session; | 1596 | struct nvgpu_clk_session *session = dev->session; |
1571 | struct nvgpu_clk_arb *arb; | ||
1572 | 1597 | ||
1573 | arb = session->g->clk_arb; | ||
1574 | 1598 | ||
1575 | gk20a_dbg_fn(""); | 1599 | gk20a_dbg_fn(""); |
1576 | 1600 | ||
1577 | kref_put(&session->refcount, nvgpu_clk_arb_free_session); | 1601 | kref_put(&session->refcount, nvgpu_clk_arb_free_session); |
1578 | kref_put(&dev->refcount, nvgpu_clk_arb_free_fd); | 1602 | kref_put(&dev->refcount, nvgpu_clk_arb_free_fd); |
1579 | |||
1580 | return 0; | 1603 | return 0; |
1581 | } | 1604 | } |
1582 | 1605 | ||
@@ -1591,15 +1614,17 @@ static int nvgpu_clk_arb_release_event_dev(struct inode *inode, | |||
1591 | 1614 | ||
1592 | gk20a_dbg_fn(""); | 1615 | gk20a_dbg_fn(""); |
1593 | 1616 | ||
1594 | nvgpu_spinlock_acquire(&arb->users_lock); | 1617 | if (arb) { |
1595 | list_del_rcu(&dev->link); | 1618 | nvgpu_spinlock_acquire(&arb->users_lock); |
1596 | nvgpu_spinlock_release(&arb->users_lock); | 1619 | list_del_rcu(&dev->link); |
1620 | nvgpu_spinlock_release(&arb->users_lock); | ||
1621 | } | ||
1597 | 1622 | ||
1598 | synchronize_rcu(); | 1623 | synchronize_rcu(); |
1599 | kref_put(&session->refcount, nvgpu_clk_arb_free_session); | 1624 | kref_put(&session->refcount, nvgpu_clk_arb_free_session); |
1600 | 1625 | ||
1601 | nvgpu_clk_notification_queue_free(&dev->queue); | 1626 | nvgpu_clk_notification_queue_free(&dev->queue); |
1602 | kfree(dev); | 1627 | kref_put(&dev->refcount, nvgpu_clk_arb_free_fd); |
1603 | 1628 | ||
1604 | return 0; | 1629 | return 0; |
1605 | } | 1630 | } |
diff --git a/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c b/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c index 5a4a2251..753623fa 100644 --- a/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c | |||
@@ -39,6 +39,7 @@ | |||
39 | 39 | ||
40 | struct gk20a_ctrl_priv { | 40 | struct gk20a_ctrl_priv { |
41 | struct device *dev; | 41 | struct device *dev; |
42 | struct gk20a *g; | ||
42 | #ifdef CONFIG_ARCH_TEGRA_18x_SOC | 43 | #ifdef CONFIG_ARCH_TEGRA_18x_SOC |
43 | struct nvgpu_clk_session *clk_session; | 44 | struct nvgpu_clk_session *clk_session; |
44 | #endif | 45 | #endif |
@@ -58,35 +59,42 @@ int gk20a_ctrl_dev_open(struct inode *inode, struct file *filp) | |||
58 | priv = kzalloc(sizeof(struct gk20a_ctrl_priv), GFP_KERNEL); | 59 | priv = kzalloc(sizeof(struct gk20a_ctrl_priv), GFP_KERNEL); |
59 | if (!priv) | 60 | if (!priv) |
60 | return -ENOMEM; | 61 | return -ENOMEM; |
61 | |||
62 | filp->private_data = priv; | 62 | filp->private_data = priv; |
63 | priv->dev = g->dev; | 63 | priv->dev = g->dev; |
64 | /* | ||
65 | * We dont close the arbiter fd's after driver teardown to support | ||
66 | * GPU_LOST events, so we store g here, instead of dereferencing the | ||
67 | * dev structure on teardown | ||
68 | */ | ||
69 | priv->g = g; | ||
64 | 70 | ||
65 | if (!g->gr.sw_ready) { | 71 | if (!g->gr.sw_ready) { |
66 | err = gk20a_busy(g->dev); | 72 | err = gk20a_busy(g->dev); |
67 | if (err) | 73 | if (err) |
68 | return err; | 74 | return err; |
69 | |||
70 | gk20a_idle(g->dev); | 75 | gk20a_idle(g->dev); |
71 | } | 76 | } |
72 | 77 | ||
73 | #ifdef CONFIG_ARCH_TEGRA_18x_SOC | 78 | #ifdef CONFIG_ARCH_TEGRA_18x_SOC |
74 | err = nvgpu_clk_arb_init_session(g, &priv->clk_session); | 79 | err = nvgpu_clk_arb_init_session(g, &priv->clk_session); |
80 | if (err) | ||
81 | return err; | ||
75 | #endif | 82 | #endif |
83 | |||
76 | return err; | 84 | return err; |
77 | } | 85 | } |
78 | |||
79 | int gk20a_ctrl_dev_release(struct inode *inode, struct file *filp) | 86 | int gk20a_ctrl_dev_release(struct inode *inode, struct file *filp) |
80 | { | 87 | { |
81 | struct gk20a_ctrl_priv *priv = filp->private_data; | 88 | struct gk20a_ctrl_priv *priv = filp->private_data; |
89 | struct gk20a *g = priv->g; | ||
82 | 90 | ||
83 | gk20a_dbg_fn(""); | 91 | gk20a_dbg_fn(""); |
84 | 92 | ||
85 | #ifdef CONFIG_ARCH_TEGRA_18x_SOC | 93 | #ifdef CONFIG_ARCH_TEGRA_18x_SOC |
86 | if (priv->clk_session) | 94 | if (priv->clk_session) |
87 | nvgpu_clk_arb_release_session(gk20a_from_dev(priv->dev), | 95 | nvgpu_clk_arb_release_session(g, priv->clk_session); |
88 | priv->clk_session); | ||
89 | #endif | 96 | #endif |
97 | |||
90 | kfree(priv); | 98 | kfree(priv); |
91 | 99 | ||
92 | return 0; | 100 | return 0; |
diff --git a/drivers/gpu/nvgpu/pci.c b/drivers/gpu/nvgpu/pci.c index 69e16267..7ef626c2 100644 --- a/drivers/gpu/nvgpu/pci.c +++ b/drivers/gpu/nvgpu/pci.c | |||
@@ -460,6 +460,10 @@ static void nvgpu_pci_remove(struct pci_dev *pdev) | |||
460 | gk20a_wait_for_idle(&pdev->dev); | 460 | gk20a_wait_for_idle(&pdev->dev); |
461 | gk20a_dbg(gpu_dbg_shutdown, "Driver idle.\n"); | 461 | gk20a_dbg(gpu_dbg_shutdown, "Driver idle.\n"); |
462 | 462 | ||
463 | #ifdef CONFIG_ARCH_TEGRA_18x_SOC | ||
464 | nvgpu_clk_arb_cleanup_arbiter(g); | ||
465 | #endif | ||
466 | |||
463 | gk20a_user_deinit(g->dev, &nvgpu_pci_class); | 467 | gk20a_user_deinit(g->dev, &nvgpu_pci_class); |
464 | gk20a_dbg(gpu_dbg_shutdown, "User de-init done.\b"); | 468 | gk20a_dbg(gpu_dbg_shutdown, "User de-init done.\b"); |
465 | 469 | ||