diff options
Diffstat (limited to 'drivers/acpi/acpi_pcc.c')
| -rw-r--r-- | drivers/acpi/acpi_pcc.c | 30 | 
1 files changed, 26 insertions, 4 deletions
diff --git a/drivers/acpi/acpi_pcc.c b/drivers/acpi/acpi_pcc.c index 41e3ebd204ff..3e252be047b8 100644 --- a/drivers/acpi/acpi_pcc.c +++ b/drivers/acpi/acpi_pcc.c @@ -23,6 +23,12 @@  #include <acpi/pcc.h> +/* + * Arbitrary retries in case the remote processor is slow to respond + * to PCC commands + */ +#define PCC_CMD_WAIT_RETRIES_NUM	500ULL +  struct pcc_data {  	struct pcc_mbox_chan *pcc_chan;  	void __iomem *pcc_comm_addr; @@ -31,7 +37,7 @@ struct pcc_data {  	struct acpi_pcc_info ctx;  }; -struct acpi_pcc_info pcc_ctx; +static struct acpi_pcc_info pcc_ctx;  static void pcc_rx_callback(struct mbox_client *cl, void *m)  { @@ -63,6 +69,7 @@ acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,  	if (IS_ERR(data->pcc_chan)) {  		pr_err("Failed to find PCC channel for subspace %d\n",  		       ctx->subspace_id); +		kfree(data);  		return AE_NOT_FOUND;  	} @@ -72,6 +79,8 @@ acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,  	if (!data->pcc_comm_addr) {  		pr_err("Failed to ioremap PCC comm region mem for %d\n",  		       ctx->subspace_id); +		pcc_mbox_free_channel(data->pcc_chan); +		kfree(data);  		return AE_NO_MEMORY;  	} @@ -86,6 +95,7 @@ acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr,  {  	int ret;  	struct pcc_data *data = region_context; +	u64 usecs_lat;  	reinit_completion(&data->done); @@ -96,10 +106,22 @@ acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr,  	if (ret < 0)  		return AE_ERROR; -	if (data->pcc_chan->mchan->mbox->txdone_irq) -		wait_for_completion(&data->done); +	if (data->pcc_chan->mchan->mbox->txdone_irq) { +		/* +		 * pcc_chan->latency is just a Nominal value. In reality the remote +		 * processor could be much slower to reply. So add an arbitrary +		 * amount of wait on top of Nominal. +		 */ +		usecs_lat = PCC_CMD_WAIT_RETRIES_NUM * data->pcc_chan->latency; +		ret = wait_for_completion_timeout(&data->done, +						  usecs_to_jiffies(usecs_lat)); +		if (ret == 0) { +			pr_err("PCC command executed timeout!\n"); +			return AE_TIME; +		} +	} -	mbox_client_txdone(data->pcc_chan->mchan, ret); +	mbox_chan_txdone(data->pcc_chan->mchan, ret);  	memcpy_fromio(value, data->pcc_comm_addr, data->ctx.length);  | 
