Re: [PATCH] usb: typec: ucsi_acpi: Add LG Gram quirk

From: Heikki Krogerus
Date: Thu Jun 13 2024 - 06:53:26 EST


On Wed, Jun 12, 2024 at 02:13:10PM +0100, Diogo Ivo wrote:
> Some LG Gram laptops report a bogus connector change event after a
> GET_PDOS command for the partner's source PDOs, which disappears from
> the CCI after acknowledging the command. However, the subsequent
> GET_CONNECTOR_STATUS in ucsi_handle_connector_change() still reports
> this bogus change in bits 5 and 6, leading to the UCSI core re-checking
> the partner's source PDOs and thus to an infinite loop.
>
> Fix this by adding a quirk that signals when a potentially buggy GET_PDOS
> command is used, checks the status change report and clears it if it is a
> bogus event before sending it to the UCSI core.
>
> Signed-off-by: Diogo Ivo <diogo.ivo@xxxxxxxxxxxxxxxxxx>

Reviewed-by: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx>

> ---
> The models affected by this bug have been reported to be of several forms:
> 1xZ90Q, 1xZD90Q, 1xZB90Q, x = {5, 6, 7}, and as such this patch matches
> only on the final 90Q as well as the product family since the "90Q" string
> may collide with other LG models by being too short. If there are other
> better ways of achieving this match I would be happy to hear about them.
> ---
> drivers/usb/typec/ucsi/ucsi_acpi.c | 61 ++++++++++++++++++++++++++++++++++++++
> 1 file changed, 61 insertions(+)
>
> diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c
> index 8d112c3edae5..adf32ca0f761 100644
> --- a/drivers/usb/typec/ucsi/ucsi_acpi.c
> +++ b/drivers/usb/typec/ucsi/ucsi_acpi.c
> @@ -25,6 +25,7 @@ struct ucsi_acpi {
> unsigned long flags;
> #define UCSI_ACPI_COMMAND_PENDING 1
> #define UCSI_ACPI_ACK_PENDING 2
> +#define UCSI_ACPI_CHECK_BOGUS_EVENT 3
> guid_t guid;
> u64 cmd;
> };
> @@ -128,6 +129,58 @@ static const struct ucsi_operations ucsi_zenbook_ops = {
> .async_write = ucsi_acpi_async_write
> };
>
> +static int ucsi_gram_read(struct ucsi *ucsi, unsigned int offset,
> + void *val, size_t val_len)
> +{
> + u16 bogus_change = UCSI_CONSTAT_POWER_LEVEL_CHANGE |
> + UCSI_CONSTAT_PDOS_CHANGE;
> + struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
> + struct ucsi_connector_status *status;
> + int ret;
> +
> + ret = ucsi_acpi_read(ucsi, offset, val, val_len);
> + if (ret < 0)
> + return ret;
> +
> + if (UCSI_COMMAND(ua->cmd) == UCSI_GET_CONNECTOR_STATUS &&
> + test_bit(UCSI_ACPI_CHECK_BOGUS_EVENT, &ua->flags) &&
> + offset == UCSI_MESSAGE_IN) {
> + status = (struct ucsi_connector_status *)val;
> +
> + /* Clear the bogus change */
> + if (status->change == bogus_change)
> + status->change = 0;
> +
> + clear_bit(UCSI_ACPI_CHECK_BOGUS_EVENT, &ua->flags);
> + }
> +
> + return ret;
> +}
> +
> +static int ucsi_gram_sync_write(struct ucsi *ucsi, unsigned int offset,
> + const void *val, size_t val_len)
> +{
> + struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
> + int ret;
> +
> + ret = ucsi_acpi_sync_write(ucsi, offset, val, val_len);
> + if (ret < 0)
> + return ret;
> +
> + if (UCSI_COMMAND(ua->cmd) == UCSI_GET_PDOS &&
> + ua->cmd & UCSI_GET_PDOS_PARTNER_PDO(1) &&
> + ua->cmd & UCSI_GET_PDOS_SRC_PDOS)
> + set_bit(UCSI_ACPI_CHECK_BOGUS_EVENT, &ua->flags);
> +
> + return ret;
> +}
> +
> +static const struct ucsi_operations ucsi_gram_ops = {
> + .read = ucsi_gram_read,
> + .sync_write = ucsi_gram_sync_write,
> + .async_write = ucsi_acpi_async_write
> +};
> +
> static const struct dmi_system_id ucsi_acpi_quirks[] = {
> {
> .matches = {
> @@ -136,6 +189,14 @@ static const struct dmi_system_id ucsi_acpi_quirks[] = {
> },
> .driver_data = (void *)&ucsi_zenbook_ops,
> },
> + {
> + .matches = {
> + DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"),
> + DMI_MATCH(DMI_PRODUCT_FAMILY, "LG gram PC"),
> + DMI_MATCH(DMI_PRODUCT_NAME, "90Q"),
> + },
> + .driver_data = (void *)&ucsi_gram_ops,
> + },
> { }
> };
>
>
> ---
> base-commit: 5821bf2dffbe18fe1f097dbb027415fa15a38e9a
> change-id: 20240612-gram_quirk-ac150257c415
>
> Best regards,
> --
> Diogo Ivo <diogo.ivo@xxxxxxxxxxxxxxxxxx>

--
heikki