diff mbox series

[v3,4/4] usb: typec: ucsi: retry find role swithch when module load late

Message ID 1649843891-15554-5-git-send-email-quic_linyyuan@quicinc.com (mailing list archive)
State Superseded
Headers show
Series usb: typec: ucsi: allow retry to find role switch | expand

Commit Message

Linyu Yuan April 13, 2022, 9:58 a.m. UTC
When role switch enabled, return -EAGAIN if fail to find it due to
module load ordering issue, then restart ucsi init work to find
it again every 100ms.

It also means change ucsi init work to delayed_work.

Signed-off-by: Linyu Yuan <quic_linyyuan@quicinc.com>
---
v2: keep original con->num in debug log
v3: change return value from -EAGAIN to PTR_ERR()

 drivers/usb/typec/ucsi/ucsi.c | 28 ++++++++++++++++------------
 drivers/usb/typec/ucsi/ucsi.h |  2 +-
 2 files changed, 17 insertions(+), 13 deletions(-)

Comments

Heikki Krogerus April 13, 2022, 12:39 p.m. UTC | #1
Hi,

You have to make the subject line a bit more clear. Perhaps you could
just say "Wait for the USB role switches".

On Wed, Apr 13, 2022 at 05:58:11PM +0800, Linyu Yuan wrote:
> When role switch enabled, return -EAGAIN if fail to find it due to
> module load ordering issue, then restart ucsi init work to find
> it again every 100ms.

It looks like you did not update that.

> It also means change ucsi init work to delayed_work.

So from where does that 100ms come from?

> Signed-off-by: Linyu Yuan <quic_linyyuan@quicinc.com>
> ---
> v2: keep original con->num in debug log
> v3: change return value from -EAGAIN to PTR_ERR()
> 
>  drivers/usb/typec/ucsi/ucsi.c | 28 ++++++++++++++++------------
>  drivers/usb/typec/ucsi/ucsi.h |  2 +-
>  2 files changed, 17 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
> index ce9192e..63c25dd 100644
> --- a/drivers/usb/typec/ucsi/ucsi.c
> +++ b/drivers/usb/typec/ucsi/ucsi.c
> @@ -1053,6 +1053,14 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
>  	con->num = index + 1;
>  	con->ucsi = ucsi;
>  
> +	cap->fwnode = ucsi_find_fwnode(con);
> +	con->usb_role_sw = fwnode_usb_role_switch_get(cap->fwnode);
> +	if (IS_ERR(con->usb_role_sw)) {
> +		dev_err(ucsi->dev, "con%d: failed to get usb role switch\n",
> +			con->num);
> +		return PTR_ERR(con->usb_role_sw);
> +	}
> +
>  	/* Delay other interactions with the con until registration is complete */
>  	mutex_lock(&con->lock);
>  
> @@ -1088,7 +1096,6 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
>  	if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DEBUG_ACCESSORY)
>  		*accessory = TYPEC_ACCESSORY_DEBUG;
>  
> -	cap->fwnode = ucsi_find_fwnode(con);
>  	cap->driver_data = con;
>  	cap->ops = &ucsi_ops;
>  
> @@ -1147,13 +1154,6 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
>  		ucsi_port_psy_changed(con);
>  	}
>  
> -	con->usb_role_sw = fwnode_usb_role_switch_get(cap->fwnode);
> -	if (IS_ERR(con->usb_role_sw)) {
> -		dev_err(ucsi->dev, "con%d: failed to get usb role switch\n",
> -			con->num);
> -		con->usb_role_sw = NULL;
> -	}
> -
>  	/* Only notify USB controller if partner supports USB data */
>  	if (!(UCSI_CONSTAT_PARTNER_FLAGS(con->status.flags) & UCSI_CONSTAT_PARTNER_FLAG_USB))
>  		u_role = USB_ROLE_NONE;
> @@ -1286,12 +1286,16 @@ static int ucsi_init(struct ucsi *ucsi)
>  
>  static void ucsi_init_work(struct work_struct *work)
>  {
> -	struct ucsi *ucsi = container_of(work, struct ucsi, work);
> +	struct ucsi *ucsi = container_of(work, struct ucsi, work.work);
>  	int ret;
>  
>  	ret = ucsi_init(ucsi);
>  	if (ret)
>  		dev_err(ucsi->dev, "PPM init failed (%d)\n", ret);
> +
> +

Extra line.

> +	if (ret == -EPROBE_DEFER)
> +		queue_delayed_work(system_long_wq, &ucsi->work, HZ/10);

You have to stop queueing that eventually. You need a counter.

I'm still not sure why do you want to queue this same work again and
again? Why not just call ucsi_init() in a loop?

        int my_counter = 1000;

        while (ucsi_init(ucsi) == -EPROBE_DEFER && my_counter--)
                msleep(10);

>  }
>  
>  /**
> @@ -1331,7 +1335,7 @@ struct ucsi *ucsi_create(struct device *dev, const struct ucsi_operations *ops)
>  	if (!ucsi)
>  		return ERR_PTR(-ENOMEM);
>  
> -	INIT_WORK(&ucsi->work, ucsi_init_work);
> +	INIT_DELAYED_WORK(&ucsi->work, ucsi_init_work);
>  	mutex_init(&ucsi->ppm_lock);
>  	ucsi->dev = dev;
>  	ucsi->ops = ops;
> @@ -1366,7 +1370,7 @@ int ucsi_register(struct ucsi *ucsi)
>  	if (!ucsi->version)
>  		return -ENODEV;
>  
> -	queue_work(system_long_wq, &ucsi->work);
> +	queue_delayed_work(system_long_wq, &ucsi->work, 0);
>  
>  	return 0;
>  }
> @@ -1383,7 +1387,7 @@ void ucsi_unregister(struct ucsi *ucsi)
>  	u64 cmd = UCSI_SET_NOTIFICATION_ENABLE;
>  
>  	/* Make sure that we are not in the middle of driver initialization */
> -	cancel_work_sync(&ucsi->work);
> +	cancel_delayed_work_sync(&ucsi->work);
>  
>  	/* Disable notifications */
>  	ucsi->ops->async_write(ucsi, UCSI_CONTROL, &cmd, sizeof(cmd));
> diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h
> index 280f1e1..3812017 100644
> --- a/drivers/usb/typec/ucsi/ucsi.h
> +++ b/drivers/usb/typec/ucsi/ucsi.h
> @@ -287,7 +287,7 @@ struct ucsi {
>  	struct ucsi_capability cap;
>  	struct ucsi_connector *connector;
>  
> -	struct work_struct work;
> +	struct delayed_work work;
>  
>  	/* PPM Communication lock */
>  	struct mutex ppm_lock;
> -- 
> 2.7.4

thanks,
Linyu Yuan April 13, 2022, 1:42 p.m. UTC | #2
> From: Heikki Krogerus <heikki.krogerus@linux.intel.com>
> Sent: Wednesday, April 13, 2022 8:40 PM
> To: Linyu Yuan (QUIC) <quic_linyyuan@quicinc.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>; linux-
> usb@vger.kernel.org; Jack Pham (QUIC) <quic_jackp@quicinc.com>
> Subject: Re: [PATCH v3 4/4] usb: typec: ucsi: retry find role swithch when
> module load late
> 
> Hi,
> 
> You have to make the subject line a bit more clear. Perhaps you could
> just say "Wait for the USB role switches".

Sound great, will change once all discussion in this thread done.

> 
> On Wed, Apr 13, 2022 at 05:58:11PM +0800, Linyu Yuan wrote:
> > When role switch enabled, return -EAGAIN if fail to find it due to
> > module load ordering issue, then restart ucsi init work to find
> > it again every 100ms.
> 
> It looks like you did not update that.

Sorry, will update later.

> 
> > It also means change ucsi init work to delayed_work.
> 
> So from where does that 100ms come from?

Yes, no place define it, just an experiment value.
Any suggestion ?

> 
> > Signed-off-by: Linyu Yuan <quic_linyyuan@quicinc.com>
> > ---
> > v2: keep original con->num in debug log
> > v3: change return value from -EAGAIN to PTR_ERR()
> >
> >  drivers/usb/typec/ucsi/ucsi.c | 28 ++++++++++++++++------------
> >  drivers/usb/typec/ucsi/ucsi.h |  2 +-
> >  2 files changed, 17 insertions(+), 13 deletions(-)
> >
> > diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
> > index ce9192e..63c25dd 100644
> > --- a/drivers/usb/typec/ucsi/ucsi.c
> > +++ b/drivers/usb/typec/ucsi/ucsi.c
> > @@ -1053,6 +1053,14 @@ static int ucsi_register_port(struct ucsi *ucsi, int
> index)
> >  	con->num = index + 1;
> >  	con->ucsi = ucsi;
> >
> > +	cap->fwnode = ucsi_find_fwnode(con);
> > +	con->usb_role_sw = fwnode_usb_role_switch_get(cap->fwnode);
> > +	if (IS_ERR(con->usb_role_sw)) {
> > +		dev_err(ucsi->dev, "con%d: failed to get usb role switch\n",
> > +			con->num);
> > +		return PTR_ERR(con->usb_role_sw);
> > +	}
> > +
> >  	/* Delay other interactions with the con until registration is complete
> */
> >  	mutex_lock(&con->lock);
> >
> > @@ -1088,7 +1096,6 @@ static int ucsi_register_port(struct ucsi *ucsi, int
> index)
> >  	if (con->cap.op_mode &
> UCSI_CONCAP_OPMODE_DEBUG_ACCESSORY)
> >  		*accessory = TYPEC_ACCESSORY_DEBUG;
> >
> > -	cap->fwnode = ucsi_find_fwnode(con);
> >  	cap->driver_data = con;
> >  	cap->ops = &ucsi_ops;
> >
> > @@ -1147,13 +1154,6 @@ static int ucsi_register_port(struct ucsi *ucsi, int
> index)
> >  		ucsi_port_psy_changed(con);
> >  	}
> >
> > -	con->usb_role_sw = fwnode_usb_role_switch_get(cap->fwnode);
> > -	if (IS_ERR(con->usb_role_sw)) {
> > -		dev_err(ucsi->dev, "con%d: failed to get usb role switch\n",
> > -			con->num);
> > -		con->usb_role_sw = NULL;
> > -	}
> > -
> >  	/* Only notify USB controller if partner supports USB data */
> >  	if (!(UCSI_CONSTAT_PARTNER_FLAGS(con->status.flags) &
> UCSI_CONSTAT_PARTNER_FLAG_USB))
> >  		u_role = USB_ROLE_NONE;
> > @@ -1286,12 +1286,16 @@ static int ucsi_init(struct ucsi *ucsi)
> >
> >  static void ucsi_init_work(struct work_struct *work)
> >  {
> > -	struct ucsi *ucsi = container_of(work, struct ucsi, work);
> > +	struct ucsi *ucsi = container_of(work, struct ucsi, work.work);
> >  	int ret;
> >
> >  	ret = ucsi_init(ucsi);
> >  	if (ret)
> >  		dev_err(ucsi->dev, "PPM init failed (%d)\n", ret);
> > +
> > +
> 
> Extra line.
> 
> > +	if (ret == -EPROBE_DEFER)
> > +		queue_delayed_work(system_long_wq, &ucsi->work,
> HZ/10);
> 
> You have to stop queueing that eventually. You need a counter.
> 
> I'm still not sure why do you want to queue this same work again and
> again? Why not just call ucsi_init() in a loop?

Will follow your suggestion below.

> 
>         int my_counter = 1000;
So you prefer 10 second in total ?
If so, next version, I will change it to 500, as msleep(20), check next.
> 
>         while (ucsi_init(ucsi) == -EPROBE_DEFER && my_counter--)
>                 msleep(10);
In checkpatch.pl, it suggest msleep no less than 20ms each time.
msleep(20) ?

> 
> >  }

Great idea, it will be less code change.

> >
> >  /**
> > @@ -1331,7 +1335,7 @@ struct ucsi *ucsi_create(struct device *dev, const
> struct ucsi_operations *ops)
> >  	if (!ucsi)
> >  		return ERR_PTR(-ENOMEM);
> >
> > -	INIT_WORK(&ucsi->work, ucsi_init_work);
> > +	INIT_DELAYED_WORK(&ucsi->work, ucsi_init_work);
> >  	mutex_init(&ucsi->ppm_lock);
> >  	ucsi->dev = dev;
> >  	ucsi->ops = ops;
> > @@ -1366,7 +1370,7 @@ int ucsi_register(struct ucsi *ucsi)
> >  	if (!ucsi->version)
> >  		return -ENODEV;
> >
> > -	queue_work(system_long_wq, &ucsi->work);
> > +	queue_delayed_work(system_long_wq, &ucsi->work, 0);
> >
> >  	return 0;
> >  }
> > @@ -1383,7 +1387,7 @@ void ucsi_unregister(struct ucsi *ucsi)
> >  	u64 cmd = UCSI_SET_NOTIFICATION_ENABLE;
> >
> >  	/* Make sure that we are not in the middle of driver initialization */
> > -	cancel_work_sync(&ucsi->work);
> > +	cancel_delayed_work_sync(&ucsi->work);
> >
> >  	/* Disable notifications */
> >  	ucsi->ops->async_write(ucsi, UCSI_CONTROL, &cmd, sizeof(cmd));
> > diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h
> > index 280f1e1..3812017 100644
> > --- a/drivers/usb/typec/ucsi/ucsi.h
> > +++ b/drivers/usb/typec/ucsi/ucsi.h
> > @@ -287,7 +287,7 @@ struct ucsi {
> >  	struct ucsi_capability cap;
> >  	struct ucsi_connector *connector;
> >
> > -	struct work_struct work;
> > +	struct delayed_work work;
> >
> >  	/* PPM Communication lock */
> >  	struct mutex ppm_lock;
> > --
> > 2.7.4
> 
> thanks,
> 
> --
> heikki
Linyu Yuan April 21, 2022, 7:40 a.m. UTC | #3
> From: Linyu Yuan (QUIC) <quic_linyyuan@quicinc.com>
> Sent: Wednesday, April 13, 2022 9:43 PM
> To: Heikki Krogerus <heikki.krogerus@linux.intel.com>; Linyu Yuan (QUIC)
> <quic_linyyuan@quicinc.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>; linux-
> usb@vger.kernel.org; Jack Pham (QUIC) <quic_jackp@quicinc.com>
> Subject: RE: [PATCH v3 4/4] usb: typec: ucsi: retry find role swithch when
> module load late
> 
> > From: Heikki Krogerus <heikki.krogerus@linux.intel.com>
> > Sent: Wednesday, April 13, 2022 8:40 PM
> > To: Linyu Yuan (QUIC) <quic_linyyuan@quicinc.com>
> > Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>; linux-
> > usb@vger.kernel.org; Jack Pham (QUIC) <quic_jackp@quicinc.com>
> > Subject: Re: [PATCH v3 4/4] usb: typec: ucsi: retry find role swithch when
> > module load late
> >
> > Hi,
> >
> > You have to make the subject line a bit more clear. Perhaps you could
> > just say "Wait for the USB role switches".
> 
> Sound great, will change once all discussion in this thread done.
> 
> >
> > On Wed, Apr 13, 2022 at 05:58:11PM +0800, Linyu Yuan wrote:
> > > When role switch enabled, return -EAGAIN if fail to find it due to
> > > module load ordering issue, then restart ucsi init work to find
> > > it again every 100ms.
> >
> > It looks like you did not update that.
> 
> Sorry, will update later.
> 
> >
> > > It also means change ucsi init work to delayed_work.
> >
> > So from where does that 100ms come from?
> 
> Yes, no place define it, just an experiment value.
> Any suggestion ?
> 
> >
> > > Signed-off-by: Linyu Yuan <quic_linyyuan@quicinc.com>
> > > ---
> > > v2: keep original con->num in debug log
> > > v3: change return value from -EAGAIN to PTR_ERR()
> > >
> > >  drivers/usb/typec/ucsi/ucsi.c | 28 ++++++++++++++++------------
> > >  drivers/usb/typec/ucsi/ucsi.h |  2 +-
> > >  2 files changed, 17 insertions(+), 13 deletions(-)
> > >
> > > diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
> > > index ce9192e..63c25dd 100644
> > > --- a/drivers/usb/typec/ucsi/ucsi.c
> > > +++ b/drivers/usb/typec/ucsi/ucsi.c
> > > @@ -1053,6 +1053,14 @@ static int ucsi_register_port(struct ucsi *ucsi,
> int
> > index)
> > >  	con->num = index + 1;
> > >  	con->ucsi = ucsi;
> > >
> > > +	cap->fwnode = ucsi_find_fwnode(con);
> > > +	con->usb_role_sw = fwnode_usb_role_switch_get(cap->fwnode);
> > > +	if (IS_ERR(con->usb_role_sw)) {
> > > +		dev_err(ucsi->dev, "con%d: failed to get usb role switch\n",
> > > +			con->num);
> > > +		return PTR_ERR(con->usb_role_sw);
> > > +	}
> > > +
> > >  	/* Delay other interactions with the con until registration is complete
> > */
> > >  	mutex_lock(&con->lock);
> > >
> > > @@ -1088,7 +1096,6 @@ static int ucsi_register_port(struct ucsi *ucsi, int
> > index)
> > >  	if (con->cap.op_mode &
> > UCSI_CONCAP_OPMODE_DEBUG_ACCESSORY)
> > >  		*accessory = TYPEC_ACCESSORY_DEBUG;
> > >
> > > -	cap->fwnode = ucsi_find_fwnode(con);
> > >  	cap->driver_data = con;
> > >  	cap->ops = &ucsi_ops;
> > >
> > > @@ -1147,13 +1154,6 @@ static int ucsi_register_port(struct ucsi *ucsi,
> int
> > index)
> > >  		ucsi_port_psy_changed(con);
> > >  	}
> > >
> > > -	con->usb_role_sw = fwnode_usb_role_switch_get(cap->fwnode);
> > > -	if (IS_ERR(con->usb_role_sw)) {
> > > -		dev_err(ucsi->dev, "con%d: failed to get usb role switch\n",
> > > -			con->num);
> > > -		con->usb_role_sw = NULL;
> > > -	}
> > > -
> > >  	/* Only notify USB controller if partner supports USB data */
> > >  	if (!(UCSI_CONSTAT_PARTNER_FLAGS(con->status.flags) &
> > UCSI_CONSTAT_PARTNER_FLAG_USB))
> > >  		u_role = USB_ROLE_NONE;
> > > @@ -1286,12 +1286,16 @@ static int ucsi_init(struct ucsi *ucsi)
> > >
> > >  static void ucsi_init_work(struct work_struct *work)
> > >  {
> > > -	struct ucsi *ucsi = container_of(work, struct ucsi, work);
> > > +	struct ucsi *ucsi = container_of(work, struct ucsi, work.work);
> > >  	int ret;
> > >
> > >  	ret = ucsi_init(ucsi);
> > >  	if (ret)
> > >  		dev_err(ucsi->dev, "PPM init failed (%d)\n", ret);
> > > +
> > > +
> >
> > Extra line.
> >
> > > +	if (ret == -EPROBE_DEFER)
> > > +		queue_delayed_work(system_long_wq, &ucsi->work,
> > HZ/10);
> >
> > You have to stop queueing that eventually. You need a counter.
> >
> > I'm still not sure why do you want to queue this same work again and
> > again? Why not just call ucsi_init() in a loop?
> 
> Will follow your suggestion below.
> 
> >
> >         int my_counter = 1000;
> So you prefer 10 second in total ?
> If so, next version, I will change it to 500, as msleep(20), check next.
> >
> >         while (ucsi_init(ucsi) == -EPROBE_DEFER && my_counter--)
> >                 msleep(10);
> In checkpatch.pl, it suggest msleep no less than 20ms each time.
> msleep(20) ?
> 
> >
> > >  }
> 
> Great idea, it will be less code change.


Sorry, I think there is one concern of your suggestion is that
As the while loop inside the worker, if we can this worker,
It may spent too much time.

Although my original design is crazy(queue worker again inside it),
but it allow cancel worker wait short time.

please let me know what is your suggestion now.
> 
> > >
> > >  /**
> > > @@ -1331,7 +1335,7 @@ struct ucsi *ucsi_create(struct device *dev,
> const
> > struct ucsi_operations *ops)
> > >  	if (!ucsi)
> > >  		return ERR_PTR(-ENOMEM);
> > >
> > > -	INIT_WORK(&ucsi->work, ucsi_init_work);
> > > +	INIT_DELAYED_WORK(&ucsi->work, ucsi_init_work);
> > >  	mutex_init(&ucsi->ppm_lock);
> > >  	ucsi->dev = dev;
> > >  	ucsi->ops = ops;
> > > @@ -1366,7 +1370,7 @@ int ucsi_register(struct ucsi *ucsi)
> > >  	if (!ucsi->version)
> > >  		return -ENODEV;
> > >
> > > -	queue_work(system_long_wq, &ucsi->work);
> > > +	queue_delayed_work(system_long_wq, &ucsi->work, 0);
> > >
> > >  	return 0;
> > >  }
> > > @@ -1383,7 +1387,7 @@ void ucsi_unregister(struct ucsi *ucsi)
> > >  	u64 cmd = UCSI_SET_NOTIFICATION_ENABLE;
> > >
> > >  	/* Make sure that we are not in the middle of driver initialization */
> > > -	cancel_work_sync(&ucsi->work);
> > > +	cancel_delayed_work_sync(&ucsi->work);
> > >
> > >  	/* Disable notifications */
> > >  	ucsi->ops->async_write(ucsi, UCSI_CONTROL, &cmd, sizeof(cmd));
> > > diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h
> > > index 280f1e1..3812017 100644
> > > --- a/drivers/usb/typec/ucsi/ucsi.h
> > > +++ b/drivers/usb/typec/ucsi/ucsi.h
> > > @@ -287,7 +287,7 @@ struct ucsi {
> > >  	struct ucsi_capability cap;
> > >  	struct ucsi_connector *connector;
> > >
> > > -	struct work_struct work;
> > > +	struct delayed_work work;
> > >
> > >  	/* PPM Communication lock */
> > >  	struct mutex ppm_lock;
> > > --
> > > 2.7.4
> >
> > thanks,
> >
> > --
> > heikki
Heikki Krogerus April 21, 2022, 7:54 a.m. UTC | #4
Hi,

On Thu, Apr 21, 2022 at 07:40:56AM +0000, Linyu Yuan (QUIC) wrote:
> > > >  static void ucsi_init_work(struct work_struct *work)
> > > >  {
> > > > -	struct ucsi *ucsi = container_of(work, struct ucsi, work);
> > > > +	struct ucsi *ucsi = container_of(work, struct ucsi, work.work);
> > > >  	int ret;
> > > >
> > > >  	ret = ucsi_init(ucsi);
> > > >  	if (ret)
> > > >  		dev_err(ucsi->dev, "PPM init failed (%d)\n", ret);
> > > > +
> > > > +
> > >
> > > Extra line.
> > >
> > > > +	if (ret == -EPROBE_DEFER)
> > > > +		queue_delayed_work(system_long_wq, &ucsi->work,
> > > HZ/10);
> > >
> > > You have to stop queueing that eventually. You need a counter.
> > >
> > > I'm still not sure why do you want to queue this same work again and
> > > again? Why not just call ucsi_init() in a loop?
> > 
> > Will follow your suggestion below.
> > 
> > >
> > >         int my_counter = 1000;
> > So you prefer 10 second in total ?
> > If so, next version, I will change it to 500, as msleep(20), check next.
> > >
> > >         while (ucsi_init(ucsi) == -EPROBE_DEFER && my_counter--)
> > >                 msleep(10);
> > In checkpatch.pl, it suggest msleep no less than 20ms each time.
> > msleep(20) ?
> > 
> > >
> > > >  }
> > 
> > Great idea, it will be less code change.
> 
> 
> Sorry, I think there is one concern of your suggestion is that
> As the while loop inside the worker, if we can this worker,
> It may spent too much time.
> 
> Although my original design is crazy(queue worker again inside it),
> but it allow cancel worker wait short time.
> 
> please let me know what is your suggestion now.

OK, that's a good point. So just re-schedule the work like you do.

thanks,
diff mbox series

Patch

diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index ce9192e..63c25dd 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -1053,6 +1053,14 @@  static int ucsi_register_port(struct ucsi *ucsi, int index)
 	con->num = index + 1;
 	con->ucsi = ucsi;
 
+	cap->fwnode = ucsi_find_fwnode(con);
+	con->usb_role_sw = fwnode_usb_role_switch_get(cap->fwnode);
+	if (IS_ERR(con->usb_role_sw)) {
+		dev_err(ucsi->dev, "con%d: failed to get usb role switch\n",
+			con->num);
+		return PTR_ERR(con->usb_role_sw);
+	}
+
 	/* Delay other interactions with the con until registration is complete */
 	mutex_lock(&con->lock);
 
@@ -1088,7 +1096,6 @@  static int ucsi_register_port(struct ucsi *ucsi, int index)
 	if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DEBUG_ACCESSORY)
 		*accessory = TYPEC_ACCESSORY_DEBUG;
 
-	cap->fwnode = ucsi_find_fwnode(con);
 	cap->driver_data = con;
 	cap->ops = &ucsi_ops;
 
@@ -1147,13 +1154,6 @@  static int ucsi_register_port(struct ucsi *ucsi, int index)
 		ucsi_port_psy_changed(con);
 	}
 
-	con->usb_role_sw = fwnode_usb_role_switch_get(cap->fwnode);
-	if (IS_ERR(con->usb_role_sw)) {
-		dev_err(ucsi->dev, "con%d: failed to get usb role switch\n",
-			con->num);
-		con->usb_role_sw = NULL;
-	}
-
 	/* Only notify USB controller if partner supports USB data */
 	if (!(UCSI_CONSTAT_PARTNER_FLAGS(con->status.flags) & UCSI_CONSTAT_PARTNER_FLAG_USB))
 		u_role = USB_ROLE_NONE;
@@ -1286,12 +1286,16 @@  static int ucsi_init(struct ucsi *ucsi)
 
 static void ucsi_init_work(struct work_struct *work)
 {
-	struct ucsi *ucsi = container_of(work, struct ucsi, work);
+	struct ucsi *ucsi = container_of(work, struct ucsi, work.work);
 	int ret;
 
 	ret = ucsi_init(ucsi);
 	if (ret)
 		dev_err(ucsi->dev, "PPM init failed (%d)\n", ret);
+
+
+	if (ret == -EPROBE_DEFER)
+		queue_delayed_work(system_long_wq, &ucsi->work, HZ/10);
 }
 
 /**
@@ -1331,7 +1335,7 @@  struct ucsi *ucsi_create(struct device *dev, const struct ucsi_operations *ops)
 	if (!ucsi)
 		return ERR_PTR(-ENOMEM);
 
-	INIT_WORK(&ucsi->work, ucsi_init_work);
+	INIT_DELAYED_WORK(&ucsi->work, ucsi_init_work);
 	mutex_init(&ucsi->ppm_lock);
 	ucsi->dev = dev;
 	ucsi->ops = ops;
@@ -1366,7 +1370,7 @@  int ucsi_register(struct ucsi *ucsi)
 	if (!ucsi->version)
 		return -ENODEV;
 
-	queue_work(system_long_wq, &ucsi->work);
+	queue_delayed_work(system_long_wq, &ucsi->work, 0);
 
 	return 0;
 }
@@ -1383,7 +1387,7 @@  void ucsi_unregister(struct ucsi *ucsi)
 	u64 cmd = UCSI_SET_NOTIFICATION_ENABLE;
 
 	/* Make sure that we are not in the middle of driver initialization */
-	cancel_work_sync(&ucsi->work);
+	cancel_delayed_work_sync(&ucsi->work);
 
 	/* Disable notifications */
 	ucsi->ops->async_write(ucsi, UCSI_CONTROL, &cmd, sizeof(cmd));
diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h
index 280f1e1..3812017 100644
--- a/drivers/usb/typec/ucsi/ucsi.h
+++ b/drivers/usb/typec/ucsi/ucsi.h
@@ -287,7 +287,7 @@  struct ucsi {
 	struct ucsi_capability cap;
 	struct ucsi_connector *connector;
 
-	struct work_struct work;
+	struct delayed_work work;
 
 	/* PPM Communication lock */
 	struct mutex ppm_lock;