diff options
author | Manikanta Maddireddy <mmaddireddy@nvidia.com> | 2018-11-03 11:10:27 -0400 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2018-11-24 04:20:42 -0500 |
commit | 8b0b7a920036c37ff4e7beb1e5af6396b8e43bfe (patch) | |
tree | 33db296fb7b18982416223ac96de2e0e20cdb935 | |
parent | f723fb69fc8c56c2850f7a4c16eb5c2b6dbf6246 (diff) |
PCI: tegra: Fix module remove sequence
Removing root port driver module will cause PERST# assert, which is
processed by execute pex_ep_event_pex_rst_assert() function in kthread
context. If endpoint driver module is removed immediately it will
free the interrupt, sometimes this happens before PERST# assert irq
is processed. To deinit controller execute pex_ep_event_pex_rst_assert()
function in rmmod. To avoid the race condition between the kthread and
rmmod, synchronize pex_ep_event_pex_rst_assert() function using mutex
lock.
bug 2422300
Change-Id: Id08c667c32aa240a150a2e8bb7b01367bec291f7
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1953518
Reviewed-by: Vidya Sagar <vidyas@nvidia.com>
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
-rw-r--r-- | drivers/pci/ep/pcie-tegra-dw-ep.c | 26 |
1 files changed, 14 insertions, 12 deletions
diff --git a/drivers/pci/ep/pcie-tegra-dw-ep.c b/drivers/pci/ep/pcie-tegra-dw-ep.c index 68ff635a6..517ad45c9 100644 --- a/drivers/pci/ep/pcie-tegra-dw-ep.c +++ b/drivers/pci/ep/pcie-tegra-dw-ep.c | |||
@@ -282,8 +282,6 @@ enum ep_event { | |||
282 | EP_PEX_RST_ASSERT, | 282 | EP_PEX_RST_ASSERT, |
283 | EP_PEX_HOT_RST_DONE, | 283 | EP_PEX_HOT_RST_DONE, |
284 | EP_PEX_BME_CHANGE, | 284 | EP_PEX_BME_CHANGE, |
285 | EP_EVENT_EXIT, | ||
286 | EP_EVENT_INVALID, | ||
287 | }; | 285 | }; |
288 | 286 | ||
289 | enum margin_cmds { | 287 | enum margin_cmds { |
@@ -319,6 +317,7 @@ struct tegra_pcie_dw_ep { | |||
319 | int ep_state; | 317 | int ep_state; |
320 | struct phy **phy; | 318 | struct phy **phy; |
321 | struct task_struct *pcie_ep_task; | 319 | struct task_struct *pcie_ep_task; |
320 | struct mutex disable_lock; | ||
322 | wait_queue_head_t wq; | 321 | wait_queue_head_t wq; |
323 | DECLARE_KFIFO(event_fifo, u32, EVENT_QUEUE_LEN); | 322 | DECLARE_KFIFO(event_fifo, u32, EVENT_QUEUE_LEN); |
324 | u32 bar0_size; | 323 | u32 bar0_size; |
@@ -579,8 +578,11 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw_ep *pcie) | |||
579 | u32 val = 0; | 578 | u32 val = 0; |
580 | int ret = 0, count = 0; | 579 | int ret = 0, count = 0; |
581 | 580 | ||
582 | if (pcie->ep_state == EP_STATE_DISABLED) | 581 | mutex_lock(&pcie->disable_lock); |
582 | if (pcie->ep_state == EP_STATE_DISABLED) { | ||
583 | mutex_unlock(&pcie->disable_lock); | ||
583 | return; | 584 | return; |
585 | } | ||
584 | 586 | ||
585 | /* disable LTSSM */ | 587 | /* disable LTSSM */ |
586 | val = readl(pcie->appl_base + APPL_CTRL); | 588 | val = readl(pcie->appl_base + APPL_CTRL); |
@@ -621,6 +623,7 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw_ep *pcie) | |||
621 | } | 623 | } |
622 | 624 | ||
623 | pcie->ep_state = EP_STATE_DISABLED; | 625 | pcie->ep_state = EP_STATE_DISABLED; |
626 | mutex_unlock(&pcie->disable_lock); | ||
624 | dev_info(pcie->dev, "EP deinit done\n"); | 627 | dev_info(pcie->dev, "EP deinit done\n"); |
625 | } | 628 | } |
626 | 629 | ||
@@ -947,13 +950,12 @@ static int pcie_ep_work_thread(void *p) | |||
947 | struct tegra_pcie_dw_ep *pcie = (struct tegra_pcie_dw_ep *)p; | 950 | struct tegra_pcie_dw_ep *pcie = (struct tegra_pcie_dw_ep *)p; |
948 | u32 event = 0; | 951 | u32 event = 0; |
949 | 952 | ||
950 | while (1) { | 953 | while (!kthread_should_stop()) { |
951 | wait_event_interruptible(pcie->wq, | 954 | wait_event_interruptible(pcie->wq, |
952 | !kfifo_is_empty(&pcie->event_fifo)); | 955 | !kfifo_is_empty(&pcie->event_fifo) || |
953 | 956 | kthread_should_stop()); | |
954 | if (kthread_should_stop()) | 957 | if (kthread_should_stop()) |
955 | break; | 958 | break; |
956 | |||
957 | if (!kfifo_get(&pcie->event_fifo, &event)) { | 959 | if (!kfifo_get(&pcie->event_fifo, &event)) { |
958 | dev_warn(pcie->dev, "empty kfifo\n"); | 960 | dev_warn(pcie->dev, "empty kfifo\n"); |
959 | continue; | 961 | continue; |
@@ -992,10 +994,8 @@ static void tegra_pcie_disable_phy(struct tegra_pcie_dw_ep *pcie) | |||
992 | { | 994 | { |
993 | int phy_count = pcie->phy_count; | 995 | int phy_count = pcie->phy_count; |
994 | 996 | ||
995 | while (phy_count--) { | 997 | while (phy_count--) |
996 | phy_power_off(pcie->phy[phy_count]); | ||
997 | phy_exit(pcie->phy[phy_count]); | 998 | phy_exit(pcie->phy[phy_count]); |
998 | } | ||
999 | } | 999 | } |
1000 | 1000 | ||
1001 | static int tegra_pcie_init_phy(struct tegra_pcie_dw_ep *pcie) | 1001 | static int tegra_pcie_init_phy(struct tegra_pcie_dw_ep *pcie) |
@@ -1424,6 +1424,7 @@ static int tegra_pcie_dw_ep_probe(struct platform_device *pdev) | |||
1424 | 1424 | ||
1425 | pcie->dev = &pdev->dev; | 1425 | pcie->dev = &pdev->dev; |
1426 | pcie->ep_state = EP_STATE_DISABLED; | 1426 | pcie->ep_state = EP_STATE_DISABLED; |
1427 | mutex_init(&pcie->disable_lock); | ||
1427 | 1428 | ||
1428 | ret = of_property_read_u32(np, "num-lanes", &pcie->num_lanes); | 1429 | ret = of_property_read_u32(np, "num-lanes", &pcie->num_lanes); |
1429 | if (ret < 0) { | 1430 | if (ret < 0) { |
@@ -1777,9 +1778,10 @@ static int tegra_pcie_dw_ep_remove(struct platform_device *pdev) | |||
1777 | 1778 | ||
1778 | debugfs_remove_recursive(pcie->debugfs); | 1779 | debugfs_remove_recursive(pcie->debugfs); |
1779 | 1780 | ||
1780 | if (!kfifo_put(&pcie->event_fifo, EP_EVENT_EXIT)) | ||
1781 | dev_err(pcie->dev, "EVENT: fifo is full\n"); | ||
1782 | kthread_stop(pcie->pcie_ep_task); | 1781 | kthread_stop(pcie->pcie_ep_task); |
1782 | pex_ep_event_pex_rst_assert(pcie); | ||
1783 | |||
1784 | pm_runtime_disable(pcie->dev); | ||
1783 | 1785 | ||
1784 | tegra_bwmgr_unregister(pcie->emc_bw); | 1786 | tegra_bwmgr_unregister(pcie->emc_bw); |
1785 | 1787 | ||