aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSrinivas Kandagatla <srinivas.kandagatla@linaro.org>2016-01-13 04:13:10 -0500
committerFelipe Balbi <balbi@kernel.org>2016-02-03 12:52:29 -0500
commita38a08dfaaab978dced63aa9cad45f0f62e23a66 (patch)
tree51cd781cbf004903380b570bda14313a2bab247f
parent36f90b0a2ddd60823fe193a85e60ff1906c2a9b3 (diff)
usb: phy: msm: fix error handling in probe.
This driver registers for extcon events as part of its probe, but never unregisters them in case of error in the probe path. There were multiple issues noticed due to this missing error handling. One of them is random crashes if the regulators are not ready yet by the time probe is invoked. Ivan's previous attempt [1] to fix this issue, did not really address all the failure cases like regualtor/get_irq failures. [1] https://lkml.org/lkml/2015/9/7/62 Without this patch the kernel would carsh with log: ... Unable to handle kernel paging request at virtual address 17d78410 pgd = ffffffc001a5c000 [17d78410] *pgd=00000000b6806003, *pud=00000000b6806003, *pmd=0000000000000000 Internal error: Oops: 96000005 [#1] PREEMPT SMP Modules linked in: CPU: 0 PID: 6 Comm: kworker/u8:0 Not tainted 4.4.0+ #48 Hardware name: Qualcomm Technologies, Inc. APQ 8016 SBC (DT) Workqueue: deferwq deferred_probe_work_func task: ffffffc03686e900 ti: ffffffc0368b0000 task.ti: ffffffc0368b0000 PC is at raw_notifier_chain_register+0x1c/0x44 LR is at extcon_register_notifier+0x88/0xc8 pc : [<ffffffc0000da43c>] lr : [<ffffffc000606298>] pstate: 80000085 sp : ffffffc0368b3a70 x29: ffffffc0368b3a70 x28: ffffffc03680c310 x27: ffffffc035518000 x26: ffffffc035518000 x25: ffffffc03bfa20e0 x24: ffffffc035580a18 x23: 0000000000000000 x22: ffffffc035518458 x21: ffffffc0355e9a60 x20: ffffffc035518000 x19: 0000000000000000 x18: 0000000000000028 x17: 0000000000000003 x16: ffffffc0018153c8 x15: 0000000000000001 x14: ffffffc03686f0f8 x13: ffffffc03686f0f8 x12: 0000000000000003 x11: 0000000000000001 x10: 0000000000000001 x9 : ffffffc03686f0f8 x8 : 0000e3872014c1a1 x7 : 0000000000000028 x6 : 0000000000000000 x5 : 0000000000000001 x4 : 0000000000000000 x3 : 00000000354fb170 x2 : 0000000017d78400 x1 : ffffffc0355e9a60 x0 : ffffffc0354fb268 Fixes: 591fc116f330 ("usb: phy: msm: Use extcon framework for VBUS and ID detection") CC: Stable <stable@vger.kernel.org> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Signed-off-by: Felipe Balbi <balbi@kernel.org>
-rw-r--r--drivers/usb/phy/phy-msm-usb.c37
1 files changed, 24 insertions, 13 deletions
diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c
index 0d19a6d61a71..970a30e155cb 100644
--- a/drivers/usb/phy/phy-msm-usb.c
+++ b/drivers/usb/phy/phy-msm-usb.c
@@ -1599,6 +1599,8 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
1599 &motg->id.nb); 1599 &motg->id.nb);
1600 if (ret < 0) { 1600 if (ret < 0) {
1601 dev_err(&pdev->dev, "register ID notifier failed\n"); 1601 dev_err(&pdev->dev, "register ID notifier failed\n");
1602 extcon_unregister_notifier(motg->vbus.extcon,
1603 EXTCON_USB, &motg->vbus.nb);
1602 return ret; 1604 return ret;
1603 } 1605 }
1604 1606
@@ -1660,15 +1662,6 @@ static int msm_otg_probe(struct platform_device *pdev)
1660 if (!motg) 1662 if (!motg)
1661 return -ENOMEM; 1663 return -ENOMEM;
1662 1664
1663 pdata = dev_get_platdata(&pdev->dev);
1664 if (!pdata) {
1665 if (!np)
1666 return -ENXIO;
1667 ret = msm_otg_read_dt(pdev, motg);
1668 if (ret)
1669 return ret;
1670 }
1671
1672 motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg), 1665 motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
1673 GFP_KERNEL); 1666 GFP_KERNEL);
1674 if (!motg->phy.otg) 1667 if (!motg->phy.otg)
@@ -1710,6 +1703,15 @@ static int msm_otg_probe(struct platform_device *pdev)
1710 if (!motg->regs) 1703 if (!motg->regs)
1711 return -ENOMEM; 1704 return -ENOMEM;
1712 1705
1706 pdata = dev_get_platdata(&pdev->dev);
1707 if (!pdata) {
1708 if (!np)
1709 return -ENXIO;
1710 ret = msm_otg_read_dt(pdev, motg);
1711 if (ret)
1712 return ret;
1713 }
1714
1713 /* 1715 /*
1714 * NOTE: The PHYs can be multiplexed between the chipidea controller 1716 * NOTE: The PHYs can be multiplexed between the chipidea controller
1715 * and the dwc3 controller, using a single bit. It is important that 1717 * and the dwc3 controller, using a single bit. It is important that
@@ -1717,8 +1719,10 @@ static int msm_otg_probe(struct platform_device *pdev)
1717 */ 1719 */
1718 if (motg->phy_number) { 1720 if (motg->phy_number) {
1719 phy_select = devm_ioremap_nocache(&pdev->dev, USB2_PHY_SEL, 4); 1721 phy_select = devm_ioremap_nocache(&pdev->dev, USB2_PHY_SEL, 4);
1720 if (!phy_select) 1722 if (!phy_select) {
1721 return -ENOMEM; 1723 ret = -ENOMEM;
1724 goto unregister_extcon;
1725 }
1722 /* Enable second PHY with the OTG port */ 1726 /* Enable second PHY with the OTG port */
1723 writel(0x1, phy_select); 1727 writel(0x1, phy_select);
1724 } 1728 }
@@ -1728,7 +1732,8 @@ static int msm_otg_probe(struct platform_device *pdev)
1728 motg->irq = platform_get_irq(pdev, 0); 1732 motg->irq = platform_get_irq(pdev, 0);
1729 if (motg->irq < 0) { 1733 if (motg->irq < 0) {
1730 dev_err(&pdev->dev, "platform_get_irq failed\n"); 1734 dev_err(&pdev->dev, "platform_get_irq failed\n");
1731 return motg->irq; 1735 ret = motg->irq;
1736 goto unregister_extcon;
1732 } 1737 }
1733 1738
1734 regs[0].supply = "vddcx"; 1739 regs[0].supply = "vddcx";
@@ -1737,7 +1742,7 @@ static int msm_otg_probe(struct platform_device *pdev)
1737 1742
1738 ret = devm_regulator_bulk_get(motg->phy.dev, ARRAY_SIZE(regs), regs); 1743 ret = devm_regulator_bulk_get(motg->phy.dev, ARRAY_SIZE(regs), regs);
1739 if (ret) 1744 if (ret)
1740 return ret; 1745 goto unregister_extcon;
1741 1746
1742 motg->vddcx = regs[0].consumer; 1747 motg->vddcx = regs[0].consumer;
1743 motg->v3p3 = regs[1].consumer; 1748 motg->v3p3 = regs[1].consumer;
@@ -1834,6 +1839,12 @@ disable_clks:
1834 clk_disable_unprepare(motg->clk); 1839 clk_disable_unprepare(motg->clk);
1835 if (!IS_ERR(motg->core_clk)) 1840 if (!IS_ERR(motg->core_clk))
1836 clk_disable_unprepare(motg->core_clk); 1841 clk_disable_unprepare(motg->core_clk);
1842unregister_extcon:
1843 extcon_unregister_notifier(motg->id.extcon,
1844 EXTCON_USB_HOST, &motg->id.nb);
1845 extcon_unregister_notifier(motg->vbus.extcon,
1846 EXTCON_USB, &motg->vbus.nb);
1847
1837 return ret; 1848 return ret;
1838} 1849}
1839 1850