2021-11-08 15:10:26

by Ondřej Jirman

[permalink] [raw]
Subject: [PATCH v2] usb: typec: fusb302: Fix masking of comparator and bc_lvl interrupts

The code that enables either BC_LVL or COMP_CHNG interrupt in tcpm_set_cc
wrongly assumes that the interrupt is unmasked by writing 1 to the apropriate
bit in the mask register. In fact, interrupts are enabled when the mask
is 0, so the tcpm_set_cc enables interrupt for COMP_CHNG when it expects
BC_LVL interrupt to be enabled.

This causes inability of the driver to recognize cable unplug events
in host mode (unplug is recognized only via a COMP_CHNG interrupt).

In device mode this bug was masked by simultaneous triggering of the VBUS
change interrupt, because of loss of VBUS when the port peer is providing
power.

Fixes: 48242e30532b ("usb: typec: fusb302: Revert "Resolve fixed power role contract setup"")
Signed-off-by: Ondrej Jirman <[email protected]>
Cc: Hans de Goede <[email protected]>
---
drivers/usb/typec/tcpm/fusb302.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 7a2a17866a823..72f9001b07921 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -669,25 +669,27 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc)
ret = fusb302_i2c_mask_write(chip, FUSB_REG_MASK,
FUSB_REG_MASK_BC_LVL |
FUSB_REG_MASK_COMP_CHNG,
- FUSB_REG_MASK_COMP_CHNG);
+ FUSB_REG_MASK_BC_LVL);
if (ret < 0) {
fusb302_log(chip, "cannot set SRC interrupt, ret=%d",
ret);
goto done;
}
chip->intr_comp_chng = true;
+ chip->intr_bc_lvl = false;
break;
case TYPEC_CC_RD:
ret = fusb302_i2c_mask_write(chip, FUSB_REG_MASK,
FUSB_REG_MASK_BC_LVL |
FUSB_REG_MASK_COMP_CHNG,
- FUSB_REG_MASK_BC_LVL);
+ FUSB_REG_MASK_COMP_CHNG);
if (ret < 0) {
fusb302_log(chip, "cannot set SRC interrupt, ret=%d",
ret);
goto done;
}
chip->intr_bc_lvl = true;
+ chip->intr_comp_chng = false;
break;
default:
break;
--
2.33.1


2021-11-08 15:54:21

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH v2] usb: typec: fusb302: Fix masking of comparator and bc_lvl interrupts

Hi,

On 11/8/21 11:28, Ondrej Jirman wrote:
> The code that enables either BC_LVL or COMP_CHNG interrupt in tcpm_set_cc
> wrongly assumes that the interrupt is unmasked by writing 1 to the apropriate
> bit in the mask register. In fact, interrupts are enabled when the mask
> is 0, so the tcpm_set_cc enables interrupt for COMP_CHNG when it expects
> BC_LVL interrupt to be enabled.
>
> This causes inability of the driver to recognize cable unplug events
> in host mode (unplug is recognized only via a COMP_CHNG interrupt).
>
> In device mode this bug was masked by simultaneous triggering of the VBUS
> change interrupt, because of loss of VBUS when the port peer is providing
> power.
>
> Fixes: 48242e30532b ("usb: typec: fusb302: Revert "Resolve fixed power role contract setup"")
> Signed-off-by: Ondrej Jirman <[email protected]>
> Cc: Hans de Goede <[email protected]>

Thanks, patch looks good to me:

Reviewed-by: Hans de Goede <[email protected]>

Regards,

Hans

> ---
> drivers/usb/typec/tcpm/fusb302.c | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
> index 7a2a17866a823..72f9001b07921 100644
> --- a/drivers/usb/typec/tcpm/fusb302.c
> +++ b/drivers/usb/typec/tcpm/fusb302.c
> @@ -669,25 +669,27 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc)
> ret = fusb302_i2c_mask_write(chip, FUSB_REG_MASK,
> FUSB_REG_MASK_BC_LVL |
> FUSB_REG_MASK_COMP_CHNG,
> - FUSB_REG_MASK_COMP_CHNG);
> + FUSB_REG_MASK_BC_LVL);
> if (ret < 0) {
> fusb302_log(chip, "cannot set SRC interrupt, ret=%d",
> ret);
> goto done;
> }
> chip->intr_comp_chng = true;


> + chip->intr_bc_lvl = false;

FWIW this is not necessary because the fusb302_set_toggling(chip, TOGGLING_MODE_OFF)
already does this, but it makes the code more clear, so lets keep it.

> break;
> case TYPEC_CC_RD:
> ret = fusb302_i2c_mask_write(chip, FUSB_REG_MASK,
> FUSB_REG_MASK_BC_LVL |
> FUSB_REG_MASK_COMP_CHNG,
> - FUSB_REG_MASK_BC_LVL);
> + FUSB_REG_MASK_COMP_CHNG);
> if (ret < 0) {
> fusb302_log(chip, "cannot set SRC interrupt, ret=%d",
> ret);
> goto done;
> }
> chip->intr_bc_lvl = true;


> + chip->intr_comp_chng = false;

Idem.

> break;
> default:
> break;
>

Regards,

Hans

2021-11-15 07:13:04

by Heikki Krogerus

[permalink] [raw]
Subject: Re: [PATCH v2] usb: typec: fusb302: Fix masking of comparator and bc_lvl interrupts

On Mon, Nov 08, 2021 at 11:28:32AM +0100, Ondrej Jirman wrote:
> The code that enables either BC_LVL or COMP_CHNG interrupt in tcpm_set_cc
> wrongly assumes that the interrupt is unmasked by writing 1 to the apropriate
> bit in the mask register. In fact, interrupts are enabled when the mask
> is 0, so the tcpm_set_cc enables interrupt for COMP_CHNG when it expects
> BC_LVL interrupt to be enabled.
>
> This causes inability of the driver to recognize cable unplug events
> in host mode (unplug is recognized only via a COMP_CHNG interrupt).
>
> In device mode this bug was masked by simultaneous triggering of the VBUS
> change interrupt, because of loss of VBUS when the port peer is providing
> power.
>
> Fixes: 48242e30532b ("usb: typec: fusb302: Revert "Resolve fixed power role contract setup"")
> Signed-off-by: Ondrej Jirman <[email protected]>
> Cc: Hans de Goede <[email protected]>

Should this go to stable?

Acked-by: Heikki [email protected]

> ---
> drivers/usb/typec/tcpm/fusb302.c | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
> index 7a2a17866a823..72f9001b07921 100644
> --- a/drivers/usb/typec/tcpm/fusb302.c
> +++ b/drivers/usb/typec/tcpm/fusb302.c
> @@ -669,25 +669,27 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc)
> ret = fusb302_i2c_mask_write(chip, FUSB_REG_MASK,
> FUSB_REG_MASK_BC_LVL |
> FUSB_REG_MASK_COMP_CHNG,
> - FUSB_REG_MASK_COMP_CHNG);
> + FUSB_REG_MASK_BC_LVL);
> if (ret < 0) {
> fusb302_log(chip, "cannot set SRC interrupt, ret=%d",
> ret);
> goto done;
> }
> chip->intr_comp_chng = true;
> + chip->intr_bc_lvl = false;
> break;
> case TYPEC_CC_RD:
> ret = fusb302_i2c_mask_write(chip, FUSB_REG_MASK,
> FUSB_REG_MASK_BC_LVL |
> FUSB_REG_MASK_COMP_CHNG,
> - FUSB_REG_MASK_BC_LVL);
> + FUSB_REG_MASK_COMP_CHNG);
> if (ret < 0) {
> fusb302_log(chip, "cannot set SRC interrupt, ret=%d",
> ret);
> goto done;
> }
> chip->intr_bc_lvl = true;
> + chip->intr_comp_chng = false;
> break;
> default:
> break;

thanks,

--
heikki

2021-11-15 07:16:40

by Heikki Krogerus

[permalink] [raw]
Subject: Re: [PATCH v2] usb: typec: fusb302: Fix masking of comparator and bc_lvl interrupts

On Mon, Nov 15, 2021 at 09:11:48AM +0200, Heikki Krogerus wrote:
> On Mon, Nov 08, 2021 at 11:28:32AM +0100, Ondrej Jirman wrote:
> > The code that enables either BC_LVL or COMP_CHNG interrupt in tcpm_set_cc
> > wrongly assumes that the interrupt is unmasked by writing 1 to the apropriate
> > bit in the mask register. In fact, interrupts are enabled when the mask
> > is 0, so the tcpm_set_cc enables interrupt for COMP_CHNG when it expects
> > BC_LVL interrupt to be enabled.
> >
> > This causes inability of the driver to recognize cable unplug events
> > in host mode (unplug is recognized only via a COMP_CHNG interrupt).
> >
> > In device mode this bug was masked by simultaneous triggering of the VBUS
> > change interrupt, because of loss of VBUS when the port peer is providing
> > power.
> >
> > Fixes: 48242e30532b ("usb: typec: fusb302: Revert "Resolve fixed power role contract setup"")
> > Signed-off-by: Ondrej Jirman <[email protected]>
> > Cc: Hans de Goede <[email protected]>
>
> Should this go to stable?
>
> Acked-by: Heikki [email protected]

Sorry, that's wrong...

Acked-by: Heikki Krogerus <[email protected]>


> > ---
> > drivers/usb/typec/tcpm/fusb302.c | 6 ++++--
> > 1 file changed, 4 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
> > index 7a2a17866a823..72f9001b07921 100644
> > --- a/drivers/usb/typec/tcpm/fusb302.c
> > +++ b/drivers/usb/typec/tcpm/fusb302.c
> > @@ -669,25 +669,27 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc)
> > ret = fusb302_i2c_mask_write(chip, FUSB_REG_MASK,
> > FUSB_REG_MASK_BC_LVL |
> > FUSB_REG_MASK_COMP_CHNG,
> > - FUSB_REG_MASK_COMP_CHNG);
> > + FUSB_REG_MASK_BC_LVL);
> > if (ret < 0) {
> > fusb302_log(chip, "cannot set SRC interrupt, ret=%d",
> > ret);
> > goto done;
> > }
> > chip->intr_comp_chng = true;
> > + chip->intr_bc_lvl = false;
> > break;
> > case TYPEC_CC_RD:
> > ret = fusb302_i2c_mask_write(chip, FUSB_REG_MASK,
> > FUSB_REG_MASK_BC_LVL |
> > FUSB_REG_MASK_COMP_CHNG,
> > - FUSB_REG_MASK_BC_LVL);
> > + FUSB_REG_MASK_COMP_CHNG);
> > if (ret < 0) {
> > fusb302_log(chip, "cannot set SRC interrupt, ret=%d",
> > ret);
> > goto done;
> > }
> > chip->intr_bc_lvl = true;
> > + chip->intr_comp_chng = false;
> > break;
> > default:
> > break;
>
> thanks,

--
heikki

2021-11-15 08:58:42

by Ondřej Jirman

[permalink] [raw]
Subject: Re: [PATCH v2] usb: typec: fusb302: Fix masking of comparator and bc_lvl interrupts

On Mon, Nov 15, 2021 at 09:11:42AM +0200, Heikki Krogerus wrote:
> On Mon, Nov 08, 2021 at 11:28:32AM +0100, Ondrej Jirman wrote:
> > The code that enables either BC_LVL or COMP_CHNG interrupt in tcpm_set_cc
> > wrongly assumes that the interrupt is unmasked by writing 1 to the apropriate
> > bit in the mask register. In fact, interrupts are enabled when the mask
> > is 0, so the tcpm_set_cc enables interrupt for COMP_CHNG when it expects
> > BC_LVL interrupt to be enabled.
> >
> > This causes inability of the driver to recognize cable unplug events
> > in host mode (unplug is recognized only via a COMP_CHNG interrupt).
> >
> > In device mode this bug was masked by simultaneous triggering of the VBUS
> > change interrupt, because of loss of VBUS when the port peer is providing
> > power.
> >
> > Fixes: 48242e30532b ("usb: typec: fusb302: Revert "Resolve fixed power role contract setup"")
> > Signed-off-by: Ondrej Jirman <[email protected]>
> > Cc: Hans de Goede <[email protected]>
>
> Should this go to stable?

Without this patch, VBUS is not turned off when I disconnect a hub from the
Type-C port (because fusb302 will not notice the disconnect), and it stays on
until next plugin of some device, say a normal non PD charger.

So I guess for a brief period you can have both sides provide VBUS (until
fusb302/tcpm processes the next plugin). It may be a problem if VBUS was more
than 5V (not very likely for devices running this driver, I guess).

regards,
o.

> Acked-by: Heikki [email protected]
>
> > ---
> > drivers/usb/typec/tcpm/fusb302.c | 6 ++++--
> > 1 file changed, 4 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
> > index 7a2a17866a823..72f9001b07921 100644
> > --- a/drivers/usb/typec/tcpm/fusb302.c
> > +++ b/drivers/usb/typec/tcpm/fusb302.c
> > @@ -669,25 +669,27 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc)
> > ret = fusb302_i2c_mask_write(chip, FUSB_REG_MASK,
> > FUSB_REG_MASK_BC_LVL |
> > FUSB_REG_MASK_COMP_CHNG,
> > - FUSB_REG_MASK_COMP_CHNG);
> > + FUSB_REG_MASK_BC_LVL);
> > if (ret < 0) {
> > fusb302_log(chip, "cannot set SRC interrupt, ret=%d",
> > ret);
> > goto done;
> > }
> > chip->intr_comp_chng = true;
> > + chip->intr_bc_lvl = false;
> > break;
> > case TYPEC_CC_RD:
> > ret = fusb302_i2c_mask_write(chip, FUSB_REG_MASK,
> > FUSB_REG_MASK_BC_LVL |
> > FUSB_REG_MASK_COMP_CHNG,
> > - FUSB_REG_MASK_BC_LVL);
> > + FUSB_REG_MASK_COMP_CHNG);
> > if (ret < 0) {
> > fusb302_log(chip, "cannot set SRC interrupt, ret=%d",
> > ret);
> > goto done;
> > }
> > chip->intr_bc_lvl = true;
> > + chip->intr_comp_chng = false;
> > break;
> > default:
> > break;
>
> thanks,
>
> --
> heikki

2021-11-15 09:24:49

by Heikki Krogerus

[permalink] [raw]
Subject: Re: [PATCH v2] usb: typec: fusb302: Fix masking of comparator and bc_lvl interrupts

On Mon, Nov 15, 2021 at 09:55:32AM +0100, Ondřej Jirman wrote:
> On Mon, Nov 15, 2021 at 09:11:42AM +0200, Heikki Krogerus wrote:
> > On Mon, Nov 08, 2021 at 11:28:32AM +0100, Ondrej Jirman wrote:
> > > The code that enables either BC_LVL or COMP_CHNG interrupt in tcpm_set_cc
> > > wrongly assumes that the interrupt is unmasked by writing 1 to the apropriate
> > > bit in the mask register. In fact, interrupts are enabled when the mask
> > > is 0, so the tcpm_set_cc enables interrupt for COMP_CHNG when it expects
> > > BC_LVL interrupt to be enabled.
> > >
> > > This causes inability of the driver to recognize cable unplug events
> > > in host mode (unplug is recognized only via a COMP_CHNG interrupt).
> > >
> > > In device mode this bug was masked by simultaneous triggering of the VBUS
> > > change interrupt, because of loss of VBUS when the port peer is providing
> > > power.
> > >
> > > Fixes: 48242e30532b ("usb: typec: fusb302: Revert "Resolve fixed power role contract setup"")
> > > Signed-off-by: Ondrej Jirman <[email protected]>
> > > Cc: Hans de Goede <[email protected]>
> >
> > Should this go to stable?
>
> Without this patch, VBUS is not turned off when I disconnect a hub from the
> Type-C port (because fusb302 will not notice the disconnect), and it stays on
> until next plugin of some device, say a normal non PD charger.
>
> So I guess for a brief period you can have both sides provide VBUS (until
> fusb302/tcpm processes the next plugin). It may be a problem if VBUS was more
> than 5V (not very likely for devices running this driver, I guess).

OK. So this should find it's way to the stable kernel releases as
well, and it should have the appropriate "Cc: [email protected]"
tag:

https://www.kernel.org/doc/html/latest/process/submitting-patches.html#select-the-recipients-for-your-patch

thanks,

--
heikki