[PATCH] usb: host: xhci-mtk: omit shared hcd if either root hub has no ports

Chunfeng Yun posted 1 patch 1 year, 10 months ago
drivers/usb/host/xhci-mtk.c | 72 +++++++++++++++++++++++--------------
1 file changed, 46 insertions(+), 26 deletions(-)
[PATCH] usb: host: xhci-mtk: omit shared hcd if either root hub has no ports
Posted by Chunfeng Yun 1 year, 10 months ago
There is error log when add a usb3 root hub without ports:
"hub 4-0:1.0: config failed, hub doesn't have any ports! (err -19)"

so omit the shared hcd if either of the root hubs has no ports, but
usually there is no usb3 port.

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
 drivers/usb/host/xhci-mtk.c | 72 +++++++++++++++++++++++--------------
 1 file changed, 46 insertions(+), 26 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
index 01705e559c42..cff3c4aea036 100644
--- a/drivers/usb/host/xhci-mtk.c
+++ b/drivers/usb/host/xhci-mtk.c
@@ -485,6 +485,7 @@ static int xhci_mtk_probe(struct platform_device *pdev)
 	const struct hc_driver *driver;
 	struct xhci_hcd *xhci;
 	struct resource *res;
+	struct usb_hcd *usb3_hcd;
 	struct usb_hcd *hcd;
 	int ret = -ENODEV;
 	int wakeup_irq;
@@ -593,6 +594,7 @@ static int xhci_mtk_probe(struct platform_device *pdev)
 
 	xhci = hcd_to_xhci(hcd);
 	xhci->main_hcd = hcd;
+	xhci->allow_single_roothub = 1;
 
 	/*
 	 * imod_interval is the interrupt moderation value in nanoseconds.
@@ -602,24 +604,29 @@ static int xhci_mtk_probe(struct platform_device *pdev)
 	xhci->imod_interval = 5000;
 	device_property_read_u32(dev, "imod-interval-ns", &xhci->imod_interval);
 
-	xhci->shared_hcd = usb_create_shared_hcd(driver, dev,
-			dev_name(dev), hcd);
-	if (!xhci->shared_hcd) {
-		ret = -ENOMEM;
-		goto disable_device_wakeup;
-	}
-
 	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (ret)
-		goto put_usb3_hcd;
+		goto disable_device_wakeup;
 
-	if (HCC_MAX_PSA(xhci->hcc_params) >= 4 &&
+	if (!xhci_has_one_roothub(xhci)) {
+		xhci->shared_hcd = usb_create_shared_hcd(driver, dev,
+							 dev_name(dev), hcd);
+		if (!xhci->shared_hcd) {
+			ret = -ENOMEM;
+			goto dealloc_usb2_hcd;
+		}
+	}
+
+	usb3_hcd = xhci_get_usb3_hcd(xhci);
+	if (usb3_hcd && HCC_MAX_PSA(xhci->hcc_params) >= 4 &&
 	    !(xhci->quirks & XHCI_BROKEN_STREAMS))
-		xhci->shared_hcd->can_do_streams = 1;
+		usb3_hcd->can_do_streams = 1;
 
-	ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
-	if (ret)
-		goto dealloc_usb2_hcd;
+	if (xhci->shared_hcd) {
+		ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
+		if (ret)
+			goto put_usb3_hcd;
+	}
 
 	if (wakeup_irq > 0) {
 		ret = dev_pm_set_dedicated_wake_irq_reverse(dev, wakeup_irq);
@@ -641,13 +648,13 @@ static int xhci_mtk_probe(struct platform_device *pdev)
 	usb_remove_hcd(xhci->shared_hcd);
 	xhci->shared_hcd = NULL;
 
-dealloc_usb2_hcd:
-	usb_remove_hcd(hcd);
-
 put_usb3_hcd:
-	xhci_mtk_sch_exit(mtk);
 	usb_put_hcd(xhci->shared_hcd);
 
+dealloc_usb2_hcd:
+	xhci_mtk_sch_exit(mtk);
+	usb_remove_hcd(hcd);
+
 disable_device_wakeup:
 	device_init_wakeup(dev, false);
 
@@ -679,10 +686,15 @@ static int xhci_mtk_remove(struct platform_device *pdev)
 	dev_pm_clear_wake_irq(dev);
 	device_init_wakeup(dev, false);
 
-	usb_remove_hcd(shared_hcd);
-	xhci->shared_hcd = NULL;
+	if (shared_hcd) {
+		usb_remove_hcd(shared_hcd);
+		xhci->shared_hcd = NULL;
+	}
 	usb_remove_hcd(hcd);
-	usb_put_hcd(shared_hcd);
+
+	if (shared_hcd)
+		usb_put_hcd(shared_hcd);
+
 	usb_put_hcd(hcd);
 	xhci_mtk_sch_exit(mtk);
 	clk_bulk_disable_unprepare(BULK_CLKS_NUM, mtk->clks);
@@ -700,13 +712,16 @@ static int __maybe_unused xhci_mtk_suspend(struct device *dev)
 	struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
 	struct usb_hcd *hcd = mtk->hcd;
 	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	struct usb_hcd *shared_hcd = xhci->shared_hcd;
 	int ret;
 
 	xhci_dbg(xhci, "%s: stop port polling\n", __func__);
 	clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
 	del_timer_sync(&hcd->rh_timer);
-	clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
-	del_timer_sync(&xhci->shared_hcd->rh_timer);
+	if (shared_hcd) {
+		clear_bit(HCD_FLAG_POLL_RH, &shared_hcd->flags);
+		del_timer_sync(&shared_hcd->rh_timer);
+	}
 
 	ret = xhci_mtk_host_disable(mtk);
 	if (ret)
@@ -718,8 +733,10 @@ static int __maybe_unused xhci_mtk_suspend(struct device *dev)
 
 restart_poll_rh:
 	xhci_dbg(xhci, "%s: restart port polling\n", __func__);
-	set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
-	usb_hcd_poll_rh_status(xhci->shared_hcd);
+	if (shared_hcd) {
+		set_bit(HCD_FLAG_POLL_RH, &shared_hcd->flags);
+		usb_hcd_poll_rh_status(shared_hcd);
+	}
 	set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
 	usb_hcd_poll_rh_status(hcd);
 	return ret;
@@ -730,6 +747,7 @@ static int __maybe_unused xhci_mtk_resume(struct device *dev)
 	struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
 	struct usb_hcd *hcd = mtk->hcd;
 	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	struct usb_hcd *shared_hcd = xhci->shared_hcd;
 	int ret;
 
 	usb_wakeup_set(mtk, false);
@@ -742,8 +760,10 @@ static int __maybe_unused xhci_mtk_resume(struct device *dev)
 		goto disable_clks;
 
 	xhci_dbg(xhci, "%s: restart port polling\n", __func__);
-	set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
-	usb_hcd_poll_rh_status(xhci->shared_hcd);
+	if (shared_hcd) {
+		set_bit(HCD_FLAG_POLL_RH, &shared_hcd->flags);
+		usb_hcd_poll_rh_status(shared_hcd);
+	}
 	set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
 	usb_hcd_poll_rh_status(hcd);
 	return 0;
-- 
2.18.0
Re: [PATCH] usb: host: xhci-mtk: omit shared hcd if either root hub has no ports
Posted by Mathias Nyman 1 year, 10 months ago
On 18.11.2022 13.01, Chunfeng Yun wrote:
> There is error log when add a usb3 root hub without ports:
> "hub 4-0:1.0: config failed, hub doesn't have any ports! (err -19)"
> 
> so omit the shared hcd if either of the root hubs has no ports, but
> usually there is no usb3 port.
> 
> Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> ---
>   drivers/usb/host/xhci-mtk.c | 72 +++++++++++++++++++++++--------------
>   1 file changed, 46 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
> index 01705e559c42..cff3c4aea036 100644
> --- a/drivers/usb/host/xhci-mtk.c
> +++ b/drivers/usb/host/xhci-mtk.c
> @@ -485,6 +485,7 @@ static int xhci_mtk_probe(struct platform_device *pdev)
>   	const struct hc_driver *driver;
>   	struct xhci_hcd *xhci;
>   	struct resource *res;
> +	struct usb_hcd *usb3_hcd;
>   	struct usb_hcd *hcd;
>   	int ret = -ENODEV;
>   	int wakeup_irq;
> @@ -593,6 +594,7 @@ static int xhci_mtk_probe(struct platform_device *pdev)
>   
>   	xhci = hcd_to_xhci(hcd);
>   	xhci->main_hcd = hcd;
> +	xhci->allow_single_roothub = 1;
>   
>   	/*
>   	 * imod_interval is the interrupt moderation value in nanoseconds.
> @@ -602,24 +604,29 @@ static int xhci_mtk_probe(struct platform_device *pdev)
>   	xhci->imod_interval = 5000;
>   	device_property_read_u32(dev, "imod-interval-ns", &xhci->imod_interval);
>   
> -	xhci->shared_hcd = usb_create_shared_hcd(driver, dev,
> -			dev_name(dev), hcd);
> -	if (!xhci->shared_hcd) {
> -		ret = -ENOMEM;
> -		goto disable_device_wakeup;
> -	}
> -
>   	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
>   	if (ret)
> -		goto put_usb3_hcd;
> +		goto disable_device_wakeup;
>   
> -	if (HCC_MAX_PSA(xhci->hcc_params) >= 4 &&
> +	if (!xhci_has_one_roothub(xhci)) {
> +		xhci->shared_hcd = usb_create_shared_hcd(driver, dev,
> +							 dev_name(dev), hcd);
> +		if (!xhci->shared_hcd) {
> +			ret = -ENOMEM;
> +			goto dealloc_usb2_hcd;
> +		}
> +	}
> +
> +	usb3_hcd = xhci_get_usb3_hcd(xhci);
> +	if (usb3_hcd && HCC_MAX_PSA(xhci->hcc_params) >= 4 &&
>   	    !(xhci->quirks & XHCI_BROKEN_STREAMS))
> -		xhci->shared_hcd->can_do_streams = 1;
> +		usb3_hcd->can_do_streams = 1;
>   
> -	ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
> -	if (ret)
> -		goto dealloc_usb2_hcd;
> +	if (xhci->shared_hcd) {
> +		ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
> +		if (ret)
> +			goto put_usb3_hcd;
> +	}
>   
>   	if (wakeup_irq > 0) {
>   		ret = dev_pm_set_dedicated_wake_irq_reverse(dev, wakeup_irq);
	
dev_pm_set_dedicated_wake_irq_reverse() can be called with just one hcd, if it fails
it will goto dealloc_usb3_hcd:

dealloc_usb3_hcd:
	usb_remove_hcd(xhci->shared_hcd);   // xhci->shared_hcd may be null
	xhci->shared_hcd = NULL; // causes usb_put_hcd() issues if shared_hcd exists

put_usb3_hcd:
         usb_put_hcd(xhci->shared_hcd); // shared_hcd may be set NULL above

-Mathias
Re: [PATCH] usb: host: xhci-mtk: omit shared hcd if either root hub has no ports
Posted by Chunfeng Yun (云春峰) 1 year, 10 months ago
On Wed, 2022-11-23 at 13:10 +0200, Mathias Nyman wrote:
> On 18.11.2022 13.01, Chunfeng Yun wrote:
> > There is error log when add a usb3 root hub without ports:
> > "hub 4-0:1.0: config failed, hub doesn't have any ports! (err -19)"
> > 
> > so omit the shared hcd if either of the root hubs has no ports, but
> > usually there is no usb3 port.
> > 
> > Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> > ---
> >   drivers/usb/host/xhci-mtk.c | 72 +++++++++++++++++++++++---------
> > -----
> >   1 file changed, 46 insertions(+), 26 deletions(-)
> > 
> > diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-
> > mtk.c
> > index 01705e559c42..cff3c4aea036 100644
> > --- a/drivers/usb/host/xhci-mtk.c
> > +++ b/drivers/usb/host/xhci-mtk.c
> > @@ -485,6 +485,7 @@ static int xhci_mtk_probe(struct
> > platform_device *pdev)
> >   	const struct hc_driver *driver;
> >   	struct xhci_hcd *xhci;
> >   	struct resource *res;
> > +	struct usb_hcd *usb3_hcd;
> >   	struct usb_hcd *hcd;
> >   	int ret = -ENODEV;
> >   	int wakeup_irq;
> > @@ -593,6 +594,7 @@ static int xhci_mtk_probe(struct
> > platform_device *pdev)
> >   
> >   	xhci = hcd_to_xhci(hcd);
> >   	xhci->main_hcd = hcd;
> > +	xhci->allow_single_roothub = 1;
> >   
> >   	/*
> >   	 * imod_interval is the interrupt moderation value in
> > nanoseconds.
> > @@ -602,24 +604,29 @@ static int xhci_mtk_probe(struct
> > platform_device *pdev)
> >   	xhci->imod_interval = 5000;
> >   	device_property_read_u32(dev, "imod-interval-ns", &xhci-
> > >imod_interval);
> >   
> > -	xhci->shared_hcd = usb_create_shared_hcd(driver, dev,
> > -			dev_name(dev), hcd);
> > -	if (!xhci->shared_hcd) {
> > -		ret = -ENOMEM;
> > -		goto disable_device_wakeup;
> > -	}
> > -
> >   	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
> >   	if (ret)
> > -		goto put_usb3_hcd;
> > +		goto disable_device_wakeup;
> >   
> > -	if (HCC_MAX_PSA(xhci->hcc_params) >= 4 &&
> > +	if (!xhci_has_one_roothub(xhci)) {
> > +		xhci->shared_hcd = usb_create_shared_hcd(driver, dev,
> > +							 dev_name(dev),
> > hcd);
> > +		if (!xhci->shared_hcd) {
> > +			ret = -ENOMEM;
> > +			goto dealloc_usb2_hcd;
> > +		}
> > +	}
> > +
> > +	usb3_hcd = xhci_get_usb3_hcd(xhci);
> > +	if (usb3_hcd && HCC_MAX_PSA(xhci->hcc_params) >= 4 &&
> >   	    !(xhci->quirks & XHCI_BROKEN_STREAMS))
> > -		xhci->shared_hcd->can_do_streams = 1;
> > +		usb3_hcd->can_do_streams = 1;
> >   
> > -	ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
> > -	if (ret)
> > -		goto dealloc_usb2_hcd;
> > +	if (xhci->shared_hcd) {
> > +		ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
> > +		if (ret)
> > +			goto put_usb3_hcd;
> > +	}
> >   
> >   	if (wakeup_irq > 0) {
> >   		ret = dev_pm_set_dedicated_wake_irq_reverse(dev,
> > wakeup_irq);
> 
> 	
> dev_pm_set_dedicated_wake_irq_reverse() can be called with just one
> hcd, if it fails
> it will goto dealloc_usb3_hcd:
> 
> dealloc_usb3_hcd:
> 	usb_remove_hcd(xhci->shared_hcd);   // xhci->shared_hcd may be 
> null
usb_remove_hcd() has handled NULL argument, no need check it here

> 	xhci->shared_hcd = NULL; // causes usb_put_hcd() issues if
> shared_hcd exists
This line shall be removed, I'll prepare a patch.

> 
> put_usb3_hcd:
>          usb_put_hcd(xhci->shared_hcd); // shared_hcd may be set NULL
> above
usb_put_hcd() has handled NULL argument, no need check it here

Thanks a lot

> 
> -Mathias
>   
Re: [PATCH] usb: host: xhci-mtk: omit shared hcd if either root hub has no ports
Posted by Macpaul Lin 1 year, 10 months ago

On 11/24/22 18:38, Chunfeng Yun (云春峰) wrote:
> On Wed, 2022-11-23 at 13:10 +0200, Mathias Nyman wrote:
>> On 18.11.2022 13.01, Chunfeng Yun wrote:
>>> There is error log when add a usb3 root hub without ports:
>>> "hub 4-0:1.0: config failed, hub doesn't have any ports! (err -19)"
>>>
>>> so omit the shared hcd if either of the root hubs has no ports, but
>>> usually there is no usb3 port.
>>>
>>> Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
>>> ---
>>>    drivers/usb/host/xhci-mtk.c | 72 +++++++++++++++++++++++---------

[deleted...]

Dear Chunfeng,

Since this issue has been reported by Canonical as a ticket
on launchpad (sorry, it has been reported as a private ticket...),
could you please to check if add "Cc: stable@vger.kernel.org" and 
"Fixes:" tags are valid?

If it is possible, please help to list dependent patches to backport
to stable tree also. Is it possible to include this patch in recent LTS 
tree?

Thanks
Macpaul Lin
Re: [PATCH] usb: host: xhci-mtk: omit shared hcd if either root hub has no ports
Posted by Chunfeng Yun (云春峰) 1 year, 10 months ago
On Wed, 2022-11-23 at 13:10 +0200, Mathias Nyman wrote:
> On 18.11.2022 13.01, Chunfeng Yun wrote:
> > There is error log when add a usb3 root hub without ports:
> > "hub 4-0:1.0: config failed, hub doesn't have any ports! (err -19)"
> > 
> > so omit the shared hcd if either of the root hubs has no ports, but
> > usually there is no usb3 port.
> > 
> > Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> > ---
> >   drivers/usb/host/xhci-mtk.c | 72 +++++++++++++++++++++++---------
> > -----
> >   1 file changed, 46 insertions(+), 26 deletions(-)
> > 
> > diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-
> > mtk.c
> > index 01705e559c42..cff3c4aea036 100644
> > --- a/drivers/usb/host/xhci-mtk.c
> > +++ b/drivers/usb/host/xhci-mtk.c
> > @@ -485,6 +485,7 @@ static int xhci_mtk_probe(struct
> > platform_device *pdev)
> >   	const struct hc_driver *driver;
> >   	struct xhci_hcd *xhci;
> >   	struct resource *res;
> > +	struct usb_hcd *usb3_hcd;
> >   	struct usb_hcd *hcd;
> >   	int ret = -ENODEV;
> >   	int wakeup_irq;
> > @@ -593,6 +594,7 @@ static int xhci_mtk_probe(struct
> > platform_device *pdev)
> >   
> >   	xhci = hcd_to_xhci(hcd);
> >   	xhci->main_hcd = hcd;
> > +	xhci->allow_single_roothub = 1;
> >   
> >   	/*
> >   	 * imod_interval is the interrupt moderation value in
> > nanoseconds.
> > @@ -602,24 +604,29 @@ static int xhci_mtk_probe(struct
> > platform_device *pdev)
> >   	xhci->imod_interval = 5000;
> >   	device_property_read_u32(dev, "imod-interval-ns", &xhci-
> > >imod_interval);
> >   
> > -	xhci->shared_hcd = usb_create_shared_hcd(driver, dev,
> > -			dev_name(dev), hcd);
> > -	if (!xhci->shared_hcd) {
> > -		ret = -ENOMEM;
> > -		goto disable_device_wakeup;
> > -	}
> > -
> >   	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
> >   	if (ret)
> > -		goto put_usb3_hcd;
> > +		goto disable_device_wakeup;
> >   
> > -	if (HCC_MAX_PSA(xhci->hcc_params) >= 4 &&
> > +	if (!xhci_has_one_roothub(xhci)) {
> > +		xhci->shared_hcd = usb_create_shared_hcd(driver, dev,
> > +							 dev_name(dev),
> > hcd);
> > +		if (!xhci->shared_hcd) {
> > +			ret = -ENOMEM;
> > +			goto dealloc_usb2_hcd;
> > +		}
> > +	}
> > +
> > +	usb3_hcd = xhci_get_usb3_hcd(xhci);
> > +	if (usb3_hcd && HCC_MAX_PSA(xhci->hcc_params) >= 4 &&
> >   	    !(xhci->quirks & XHCI_BROKEN_STREAMS))
> > -		xhci->shared_hcd->can_do_streams = 1;
> > +		usb3_hcd->can_do_streams = 1;
> >   
> > -	ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
> > -	if (ret)
> > -		goto dealloc_usb2_hcd;
> > +	if (xhci->shared_hcd) {
> > +		ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
> > +		if (ret)
> > +			goto put_usb3_hcd;
> > +	}
> >   
> >   	if (wakeup_irq > 0) {
> >   		ret = dev_pm_set_dedicated_wake_irq_reverse(dev,
> > wakeup_irq);
> 
> 	
> dev_pm_set_dedicated_wake_irq_reverse() can be called with just one
> hcd, if it fails
> it will goto dealloc_usb3_hcd:
> 
> dealloc_usb3_hcd:
> 	usb_remove_hcd(xhci->shared_hcd);   // xhci->shared_hcd may be
> null
> 	xhci->shared_hcd = NULL; // causes usb_put_hcd() issues if
> shared_hcd exists
> 
> put_usb3_hcd:
>          usb_put_hcd(xhci->shared_hcd); // shared_hcd may be set NULL
> above

I'll check it again, thanks

> 
> -Mathias
>   
Re: [PATCH] usb: host: xhci-mtk: omit shared hcd if either root hub has no ports
Posted by AngeloGioacchino Del Regno 1 year, 10 months ago
Il 18/11/22 12:01, Chunfeng Yun ha scritto:
> There is error log when add a usb3 root hub without ports:
> "hub 4-0:1.0: config failed, hub doesn't have any ports! (err -19)"
> 
> so omit the shared hcd if either of the root hubs has no ports, but
> usually there is no usb3 port.
> 
> Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>

Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>