| From foo@baz Mon Apr 9 17:09:24 CEST 2018 |
| From: Jisheng Zhang <jszhang@marvell.com> |
| Date: Wed, 26 Apr 2017 16:59:34 +0800 |
| Subject: usb: chipidea: properly handle host or gadget initialization failure |
| |
| From: Jisheng Zhang <jszhang@marvell.com> |
| |
| |
| [ Upstream commit c4a0bbbdb7f6e3c37fa6deb3ef28c5ed99da6175 ] |
| |
| If ci_hdrc_host_init() or ci_hdrc_gadget_init() returns error and the |
| error != -ENXIO, as Peter pointed out, "it stands for initialization |
| for host or gadget has failed", so we'd better return failure rather |
| continue. |
| |
| And before destroying the otg, i.e ci_hdrc_otg_destroy(ci), we should |
| also check ci->roles[CI_ROLE_GADGET]. |
| |
| Signed-off-by: Jisheng Zhang <jszhang@marvell.com> |
| Signed-off-by: Peter Chen <peter.chen@nxp.com> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/usb/chipidea/core.c | 29 +++++++++++++++++++++-------- |
| 1 file changed, 21 insertions(+), 8 deletions(-) |
| |
| --- a/drivers/usb/chipidea/core.c |
| +++ b/drivers/usb/chipidea/core.c |
| @@ -839,7 +839,7 @@ static inline void ci_role_destroy(struc |
| { |
| ci_hdrc_gadget_destroy(ci); |
| ci_hdrc_host_destroy(ci); |
| - if (ci->is_otg) |
| + if (ci->is_otg && ci->roles[CI_ROLE_GADGET]) |
| ci_hdrc_otg_destroy(ci); |
| } |
| |
| @@ -939,27 +939,35 @@ static int ci_hdrc_probe(struct platform |
| /* initialize role(s) before the interrupt is requested */ |
| if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { |
| ret = ci_hdrc_host_init(ci); |
| - if (ret) |
| - dev_info(dev, "doesn't support host\n"); |
| + if (ret) { |
| + if (ret == -ENXIO) |
| + dev_info(dev, "doesn't support host\n"); |
| + else |
| + goto deinit_phy; |
| + } |
| } |
| |
| if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { |
| ret = ci_hdrc_gadget_init(ci); |
| - if (ret) |
| - dev_info(dev, "doesn't support gadget\n"); |
| + if (ret) { |
| + if (ret == -ENXIO) |
| + dev_info(dev, "doesn't support gadget\n"); |
| + else |
| + goto deinit_host; |
| + } |
| } |
| |
| if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) { |
| dev_err(dev, "no supported roles\n"); |
| ret = -ENODEV; |
| - goto deinit_phy; |
| + goto deinit_gadget; |
| } |
| |
| if (ci->is_otg && ci->roles[CI_ROLE_GADGET]) { |
| ret = ci_hdrc_otg_init(ci); |
| if (ret) { |
| dev_err(dev, "init otg fails, ret = %d\n", ret); |
| - goto stop; |
| + goto deinit_gadget; |
| } |
| } |
| |
| @@ -1024,7 +1032,12 @@ static int ci_hdrc_probe(struct platform |
| |
| ci_extcon_unregister(ci); |
| stop: |
| - ci_role_destroy(ci); |
| + if (ci->is_otg && ci->roles[CI_ROLE_GADGET]) |
| + ci_hdrc_otg_destroy(ci); |
| +deinit_gadget: |
| + ci_hdrc_gadget_destroy(ci); |
| +deinit_host: |
| + ci_hdrc_host_destroy(ci); |
| deinit_phy: |
| ci_usb_phy_exit(ci); |
| |