linux-usb.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Heikki Krogerus <heikki.krogerus@linux.intel.com>
To: Ajay Gupta <ajaykuee@gmail.com>
Cc: wsa@the-dreams.de, linux-usb@vger.kernel.org,
	linux-i2c@vger.kernel.org, Ajay Gupta <ajayg@nvidia.com>
Subject: Re: [PATCH v4 5/5] usb: typec: ucsi: ccg: add runtime pm workaround
Date: Fri, 7 Jun 2019 11:25:55 +0300	[thread overview]
Message-ID: <20190607082555.GC10298@kuha.fi.intel.com> (raw)
In-Reply-To: <20190603170545.24004-6-ajayg@nvidia.com>

On Mon, Jun 03, 2019 at 10:05:45AM -0700, Ajay Gupta wrote:
> From: Ajay Gupta <ajayg@nvidia.com>
> 
> Cypress USB Type-C CCGx controller firmware version 3.1.10
> (which is being used in many NVIDIA GPU cards) has known issue of
> not triggering interrupt when a USB device is hot plugged to runtime
> resume the controller. If any GPU card gets latest kernel with runtime
> pm support but does not get latest fixed firmware then also it should
> continue to work and therefore a workaround is required to check for
> any connector change event.
> 
> The workaround is that i2c bus driver will call pm_request_resume()
> to runtime resume ucsi_ccg driver. CCG driver will call the ISR
> for any connector change event for NVIDIA GPU card and only if it has
> old CCG firmware with the known issue.
> 
> Signed-off-by: Ajay Gupta <ajayg@nvidia.com>

Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>

> ---
> Changes from v3->v4: None
> 
>  drivers/usb/typec/ucsi/ucsi_ccg.c | 80 +++++++++++++++++++++++++++++--
>  1 file changed, 76 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c
> index b15bc6c29c46..a5b81c011148 100644
> --- a/drivers/usb/typec/ucsi/ucsi_ccg.c
> +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
> @@ -109,12 +109,21 @@ struct version_format {
>  	__le16 build;
>  	u8 patch;
>  	u8 ver;
> +#define CCG_VERSION_PATCH(x) ((x) << 16)
> +#define CCG_VERSION(x)	((x) << 24)
>  #define CCG_VERSION_MIN_SHIFT (0)
>  #define CCG_VERSION_MIN_MASK (0xf << CCG_VERSION_MIN_SHIFT)
>  #define CCG_VERSION_MAJ_SHIFT (4)
>  #define CCG_VERSION_MAJ_MASK (0xf << CCG_VERSION_MAJ_SHIFT)
>  } __packed;
>  
> +/*
> + * Firmware version 3.1.10 or earlier, built for NVIDIA has known issue
> + * of missing interrupt when a device is connected for runtime resume
> + */
> +#define CCG_FW_BUILD_NVIDIA	(('n' << 8) | 'v')
> +#define CCG_OLD_FW_VERSION	(CCG_VERSION(0x31) | CCG_VERSION_PATCH(10))
> +
>  struct version_info {
>  	struct version_format base;
>  	struct version_format app;
> @@ -172,6 +181,7 @@ struct ucsi_ccg {
>  	struct ccg_dev_info info;
>  	/* version info for boot, primary and secondary */
>  	struct version_info version[FW2 + 1];
> +	u32 fw_version;
>  	/* CCG HPI communication flags */
>  	unsigned long flags;
>  #define RESET_PENDING	0
> @@ -185,6 +195,8 @@ struct ucsi_ccg {
>  
>  	/* fw build with vendor information */
>  	u16 fw_build;
> +	bool run_isr; /* flag to call ISR routine during resume */
> +	struct work_struct pm_work;
>  };
>  
>  static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
> @@ -212,6 +224,18 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
>  	if (quirks && quirks->max_read_len)
>  		max_read_len = quirks->max_read_len;
>  
> +	if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
> +	    uc->fw_version <= CCG_OLD_FW_VERSION) {
> +		mutex_lock(&uc->lock);
> +		/*
> +		 * Do not schedule pm_work to run ISR in
> +		 * ucsi_ccg_runtime_resume() after pm_runtime_get_sync()
> +		 * since we are already in ISR path.
> +		 */
> +		uc->run_isr = false;
> +		mutex_unlock(&uc->lock);
> +	}
> +
>  	pm_runtime_get_sync(uc->dev);
>  	while (rem_len > 0) {
>  		msgs[1].buf = &data[len - rem_len];
> @@ -254,6 +278,18 @@ static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
>  	msgs[0].len = len + sizeof(rab);
>  	msgs[0].buf = buf;
>  
> +	if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
> +	    uc->fw_version <= CCG_OLD_FW_VERSION) {
> +		mutex_lock(&uc->lock);
> +		/*
> +		 * Do not schedule pm_work to run ISR in
> +		 * ucsi_ccg_runtime_resume() after pm_runtime_get_sync()
> +		 * since we are already in ISR path.
> +		 */
> +		uc->run_isr = false;
> +		mutex_unlock(&uc->lock);
> +	}
> +
>  	pm_runtime_get_sync(uc->dev);
>  	status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
>  	if (status < 0) {
> @@ -383,6 +419,13 @@ static irqreturn_t ccg_irq_handler(int irq, void *data)
>  	return IRQ_HANDLED;
>  }
>  
> +static void ccg_pm_workaround_work(struct work_struct *pm_work)
> +{
> +	struct ucsi_ccg *uc = container_of(pm_work, struct ucsi_ccg, pm_work);
> +
> +	ucsi_notify(uc->ucsi);
> +}
> +
>  static int get_fw_info(struct ucsi_ccg *uc)
>  {
>  	int err;
> @@ -392,6 +435,9 @@ static int get_fw_info(struct ucsi_ccg *uc)
>  	if (err < 0)
>  		return err;
>  
> +	uc->fw_version = CCG_VERSION(uc->version[FW2].app.ver) |
> +			CCG_VERSION_PATCH(uc->version[FW2].app.patch);
> +
>  	err = ccg_read(uc, CCGX_RAB_DEVICE_MODE, (u8 *)(&uc->info),
>  		       sizeof(uc->info));
>  	if (err < 0)
> @@ -740,11 +786,12 @@ static bool ccg_check_fw_version(struct ucsi_ccg *uc, const char *fw_name,
>  	}
>  
>  	/* compare input version with FWCT version */
> -	cur_version = le16_to_cpu(app->build) | app->patch << 16 |
> -			app->ver << 24;
> +	cur_version = le16_to_cpu(app->build) | CCG_VERSION_PATCH(app->patch) |
> +			CCG_VERSION(app->ver);
>  
> -	new_version = le16_to_cpu(fw_cfg.app.build) | fw_cfg.app.patch << 16 |
> -			fw_cfg.app.ver << 24;
> +	new_version = le16_to_cpu(fw_cfg.app.build) |
> +			CCG_VERSION_PATCH(fw_cfg.app.patch) |
> +			CCG_VERSION(fw_cfg.app.ver);
>  
>  	if (!ccg_check_vendor_version(uc, app, &fw_cfg))
>  		goto out_release_firmware;
> @@ -1084,8 +1131,10 @@ static int ucsi_ccg_probe(struct i2c_client *client,
>  	uc->ppm.sync = ucsi_ccg_sync;
>  	uc->dev = dev;
>  	uc->client = client;
> +	uc->run_isr = true;
>  	mutex_init(&uc->lock);
>  	INIT_WORK(&uc->work, ccg_update_firmware);
> +	INIT_WORK(&uc->pm_work, ccg_pm_workaround_work);
>  
>  	/* Only fail FW flashing when FW build information is not provided */
>  	status = device_property_read_u16(dev, "ccgx,firmware-build",
> @@ -1153,6 +1202,7 @@ static int ucsi_ccg_remove(struct i2c_client *client)
>  {
>  	struct ucsi_ccg *uc = i2c_get_clientdata(client);
>  
> +	cancel_work_sync(&uc->pm_work);
>  	cancel_work_sync(&uc->work);
>  	ucsi_unregister_ppm(uc->ucsi);
>  	pm_runtime_disable(uc->dev);
> @@ -1183,6 +1233,28 @@ static int ucsi_ccg_runtime_suspend(struct device *dev)
>  
>  static int ucsi_ccg_runtime_resume(struct device *dev)
>  {
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct ucsi_ccg *uc = i2c_get_clientdata(client);
> +	bool schedule = true;
> +
> +	/*
> +	 * Firmware version 3.1.10 or earlier, built for NVIDIA has known issue
> +	 * of missing interrupt when a device is connected for runtime resume.
> +	 * Schedule a work to call ISR as a workaround.
> +	 */
> +	if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
> +	    uc->fw_version <= CCG_OLD_FW_VERSION) {
> +		mutex_lock(&uc->lock);
> +		if (!uc->run_isr) {
> +			uc->run_isr = true;
> +			schedule = false;
> +		}
> +		mutex_unlock(&uc->lock);
> +
> +		if (schedule)
> +			schedule_work(&uc->pm_work);
> +	}
> +
>  	return 0;
>  }
>  
> -- 
> 2.17.1

thanks,

-- 
heikki

      reply	other threads:[~2019-06-07  8:26 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-06-03 17:05 [PATCH v4 0/5] usb: typec: ucsi: ccg: add runtime pm support Ajay Gupta
2019-06-03 17:05 ` [PATCH v4 1/5] i2c: nvidia-gpu: refactor master_xfer Ajay Gupta
2019-06-07  8:33   ` Wolfram Sang
2019-06-07 15:47     ` Ajay Gupta
2019-06-03 17:05 ` [PATCH v4 2/5] i2c: nvidia-gpu: add runtime pm support Ajay Gupta
2019-06-07  8:33   ` Wolfram Sang
2019-06-07 15:47     ` Ajay Gupta
2019-06-03 17:05 ` [PATCH v4 3/5] usb: typec: ucsi: ccg: enable " Ajay Gupta
2019-06-07  8:25   ` Heikki Krogerus
2019-06-07  8:27     ` Wolfram Sang
2019-06-07 15:46       ` Ajay Gupta
2019-06-03 17:05 ` [PATCH v4 4/5] i2c: nvidia-gpu: resume ccgx i2c client Ajay Gupta
2019-06-03 17:05 ` [PATCH v4 5/5] usb: typec: ucsi: ccg: add runtime pm workaround Ajay Gupta
2019-06-07  8:25   ` Heikki Krogerus [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190607082555.GC10298@kuha.fi.intel.com \
    --to=heikki.krogerus@linux.intel.com \
    --cc=ajayg@nvidia.com \
    --cc=ajaykuee@gmail.com \
    --cc=linux-i2c@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=wsa@the-dreams.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).