diff mbox series

[v4,4/4] firmware: arm_scmi: Add qcom hvc/shmem transport support

Message ID 20230911194359.27547-5-quic_nkela@quicinc.com (mailing list archive)
State New, archived
Headers show
Series Add qcom hvc/shmem transport support | expand

Commit Message

Nikunj Kela Sept. 11, 2023, 7:43 p.m. UTC
This change adds the support for SCMI message exchange on Qualcomm
virtual platforms.

The hypervisor associates an object-id also known as capability-id
with each hvc doorbell object. The capability-id is used to identify the
doorbell from the VM's capability namespace, similar to a file-descriptor.

The hypervisor, in addition to the function-id, expects the capability-id
to be passed in x1 register when HVC call is invoked.

The function-id & capability-id are allocated by the hypervisor on bootup
and are stored in the shmem region by the firmware before starting Linux.

Signed-off-by: Nikunj Kela <quic_nkela@quicinc.com>
---
 drivers/firmware/arm_scmi/driver.c |  1 +
 drivers/firmware/arm_scmi/smc.c    | 47 ++++++++++++++++++++++++++----
 2 files changed, 43 insertions(+), 5 deletions(-)

Comments

Brian Masney Oct. 2, 2023, 6:34 p.m. UTC | #1
On Mon, Sep 11, 2023 at 12:43:59PM -0700, Nikunj Kela wrote:
> This change adds the support for SCMI message exchange on Qualcomm
> virtual platforms.
> 
> The hypervisor associates an object-id also known as capability-id
> with each hvc doorbell object. The capability-id is used to identify the
> doorbell from the VM's capability namespace, similar to a file-descriptor.
> 
> The hypervisor, in addition to the function-id, expects the capability-id
> to be passed in x1 register when HVC call is invoked.
> 
> The function-id & capability-id are allocated by the hypervisor on bootup
> and are stored in the shmem region by the firmware before starting Linux.
> 
> Signed-off-by: Nikunj Kela <quic_nkela@quicinc.com>
> ---
>  drivers/firmware/arm_scmi/driver.c |  1 +
>  drivers/firmware/arm_scmi/smc.c    | 47 ++++++++++++++++++++++++++----
>  2 files changed, 43 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
> index 87383c05424b..ea344bc6ae49 100644
> --- a/drivers/firmware/arm_scmi/driver.c
> +++ b/drivers/firmware/arm_scmi/driver.c
> @@ -2915,6 +2915,7 @@ static const struct of_device_id scmi_of_match[] = {
>  #ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC
>  	{ .compatible = "arm,scmi-smc", .data = &scmi_smc_desc},
>  	{ .compatible = "arm,scmi-smc-param", .data = &scmi_smc_desc},
> +	{ .compatible = "qcom,scmi-hvc-shmem", .data = &scmi_smc_desc},
>  #endif
>  #ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO
>  	{ .compatible = "arm,scmi-virtio", .data = &scmi_virtio_desc},
> diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c
> index 0a0b7e401159..94ec07fdc14a 100644
> --- a/drivers/firmware/arm_scmi/smc.c
> +++ b/drivers/firmware/arm_scmi/smc.c
> @@ -50,6 +50,9 @@
>   * @func_id: smc/hvc call function id
>   * @param_page: 4K page number of the shmem channel
>   * @param_offset: Offset within the 4K page of the shmem channel
> + * @cap_id: hvc doorbell's capability id to be used on Qualcomm virtual
> + *	    platforms
> + * @qcom_xport: Flag to indicate the transport on Qualcomm virtual platforms
>   */
>  
>  struct scmi_smc {
> @@ -63,6 +66,8 @@ struct scmi_smc {
>  	u32 func_id;
>  	u32 param_page;
>  	u32 param_offset;
> +	u64 cap_id;
> +	bool qcom_xport;
>  };

[snip]

>  static irqreturn_t smc_msg_done_isr(int irq, void *data)
> @@ -129,6 +134,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
>  	struct resource res;
>  	struct device_node *np;
>  	u32 func_id;
> +	u64 cap_id;
>  	int ret;

[snip]

> +		func_id = readl((void __iomem *)(scmi_info->shmem) + size - 16);
> +#ifdef CONFIG_ARM64
> +		cap_id = readq((void __iomem *)(scmi_info->shmem) + size - 8);
> +#else
> +		/* capability-id is 32 bit wide on 32bit machines */
> +		cap_id = readl((void __iomem *)(scmi_info->shmem) + size - 8);
> +#endif

The 32 bit case is defined as a u64 in two places above.

> +
> +		/* The func-id & capability-id are kept in last 16 bytes of shmem.
> +		 *     +-------+
> +		 *     |       |
> +		 *     | shmem |
> +		 *     |       |
> +		 *     |       |
> +		 *     +-------+ <-- (size - 16)
> +		 *     | funcId|
> +		 *     +-------+ <-- (size - 8)
> +		 *     | capId |
> +		 *     +-------+ <-- size
> +		 */

Personally I'd add one more space to the right side of the table after
funcId.

> -	arm_smccc_1_1_invoke(scmi_info->func_id, page, offset, 0, 0, 0, 0, 0,
> -			     &res);
> +	if (scmi_info->qcom_xport)
> +		arm_smccc_1_1_hvc(scmi_info->func_id, cap_id, 0, 0, 0, 0, 0, 0,
> +				  &res);
> +	else
> +		arm_smccc_1_1_invoke(scmi_info->func_id, page, offset, 0, 0, 0,
> +				     0, 0, &res);

Does it make sense to call this variable qcom_xport? Would hvc_xport be
a more appropriate name?

Brian
Brian Masney Oct. 2, 2023, 6:39 p.m. UTC | #2
On Mon, Oct 02, 2023 at 02:34:06PM -0400, Brian Masney wrote:
> On Mon, Sep 11, 2023 at 12:43:59PM -0700, Nikunj Kela wrote:
> > +		func_id = readl((void __iomem *)(scmi_info->shmem) + size - 16);
> > +#ifdef CONFIG_ARM64
> > +		cap_id = readq((void __iomem *)(scmi_info->shmem) + size - 8);
> > +#else
> > +		/* capability-id is 32 bit wide on 32bit machines */
> > +		cap_id = readl((void __iomem *)(scmi_info->shmem) + size - 8);
> > +#endif
> 
> The 32 bit case is defined as a u64 in two places above.

Also should the 32 bit case be 'size - 4' instead of 'size - 8'? Sorry
I just noticed that as soon as I pressed send.

Brian
Nikunj Kela Oct. 2, 2023, 6:42 p.m. UTC | #3
On 10/2/2023 11:34 AM, Brian Masney wrote:
> On Mon, Sep 11, 2023 at 12:43:59PM -0700, Nikunj Kela wrote:
>> This change adds the support for SCMI message exchange on Qualcomm
>> virtual platforms.
>>
>> The hypervisor associates an object-id also known as capability-id
>> with each hvc doorbell object. The capability-id is used to identify the
>> doorbell from the VM's capability namespace, similar to a file-descriptor.
>>
>> The hypervisor, in addition to the function-id, expects the capability-id
>> to be passed in x1 register when HVC call is invoked.
>>
>> The function-id & capability-id are allocated by the hypervisor on bootup
>> and are stored in the shmem region by the firmware before starting Linux.
>>
>> Signed-off-by: Nikunj Kela <quic_nkela@quicinc.com>
>> ---
>>   drivers/firmware/arm_scmi/driver.c |  1 +
>>   drivers/firmware/arm_scmi/smc.c    | 47 ++++++++++++++++++++++++++----
>>   2 files changed, 43 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
>> index 87383c05424b..ea344bc6ae49 100644
>> --- a/drivers/firmware/arm_scmi/driver.c
>> +++ b/drivers/firmware/arm_scmi/driver.c
>> @@ -2915,6 +2915,7 @@ static const struct of_device_id scmi_of_match[] = {
>>   #ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC
>>   	{ .compatible = "arm,scmi-smc", .data = &scmi_smc_desc},
>>   	{ .compatible = "arm,scmi-smc-param", .data = &scmi_smc_desc},
>> +	{ .compatible = "qcom,scmi-hvc-shmem", .data = &scmi_smc_desc},
>>   #endif
>>   #ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO
>>   	{ .compatible = "arm,scmi-virtio", .data = &scmi_virtio_desc},
>> diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c
>> index 0a0b7e401159..94ec07fdc14a 100644
>> --- a/drivers/firmware/arm_scmi/smc.c
>> +++ b/drivers/firmware/arm_scmi/smc.c
>> @@ -50,6 +50,9 @@
>>    * @func_id: smc/hvc call function id
>>    * @param_page: 4K page number of the shmem channel
>>    * @param_offset: Offset within the 4K page of the shmem channel
>> + * @cap_id: hvc doorbell's capability id to be used on Qualcomm virtual
>> + *	    platforms
>> + * @qcom_xport: Flag to indicate the transport on Qualcomm virtual platforms
>>    */
>>   
>>   struct scmi_smc {
>> @@ -63,6 +66,8 @@ struct scmi_smc {
>>   	u32 func_id;
>>   	u32 param_page;
>>   	u32 param_offset;
>> +	u64 cap_id;
>> +	bool qcom_xport;
>>   };
> [snip]
>
>>   static irqreturn_t smc_msg_done_isr(int irq, void *data)
>> @@ -129,6 +134,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
>>   	struct resource res;
>>   	struct device_node *np;
>>   	u32 func_id;
>> +	u64 cap_id;
>>   	int ret;
> [snip]
>
>> +		func_id = readl((void __iomem *)(scmi_info->shmem) + size - 16);
>> +#ifdef CONFIG_ARM64
>> +		cap_id = readq((void __iomem *)(scmi_info->shmem) + size - 8);
>> +#else
>> +		/* capability-id is 32 bit wide on 32bit machines */
>> +		cap_id = readl((void __iomem *)(scmi_info->shmem) + size - 8);
>> +#endif
> The 32 bit case is defined as a u64 in two places above.

That is done to make sure the size of the structure in memory is not 
architecture dependent. This was recommended in one of the previous 
version of this patch.


>
>> +
>> +		/* The func-id & capability-id are kept in last 16 bytes of shmem.
>> +		 *     +-------+
>> +		 *     |       |
>> +		 *     | shmem |
>> +		 *     |       |
>> +		 *     |       |
>> +		 *     +-------+ <-- (size - 16)
>> +		 *     | funcId|
>> +		 *     +-------+ <-- (size - 8)
>> +		 *     | capId |
>> +		 *     +-------+ <-- size
>> +		 */
> Personally I'd add one more space to the right side of the table after
> funcId.

I could do that but then in 32bit case, you would want one more space 
right after cap-id since it is 32 bit on 32 bit platform. If it helps, I 
can have two lay out one for 32bit and one for 64 bit.


>> -	arm_smccc_1_1_invoke(scmi_info->func_id, page, offset, 0, 0, 0, 0, 0,
>> -			     &res);
>> +	if (scmi_info->qcom_xport)
>> +		arm_smccc_1_1_hvc(scmi_info->func_id, cap_id, 0, 0, 0, 0, 0, 0,
>> +				  &res);
>> +	else
>> +		arm_smccc_1_1_invoke(scmi_info->func_id, page, offset, 0, 0, 0,
>> +				     0, 0, &res);
> Does it make sense to call this variable qcom_xport? Would hvc_xport be
> a more appropriate name?
>
> Brian

Cap-id is QCOM specific ABI parameter not HVC.

>
Nikunj Kela Oct. 2, 2023, 6:45 p.m. UTC | #4
On 10/2/2023 11:39 AM, Brian Masney wrote:
> On Mon, Oct 02, 2023 at 02:34:06PM -0400, Brian Masney wrote:
>> On Mon, Sep 11, 2023 at 12:43:59PM -0700, Nikunj Kela wrote:
>>> +		func_id = readl((void __iomem *)(scmi_info->shmem) + size - 16);
>>> +#ifdef CONFIG_ARM64
>>> +		cap_id = readq((void __iomem *)(scmi_info->shmem) + size - 8);
>>> +#else
>>> +		/* capability-id is 32 bit wide on 32bit machines */
>>> +		cap_id = readl((void __iomem *)(scmi_info->shmem) + size - 8);
>>> +#endif
>> The 32 bit case is defined as a u64 in two places above.
> Also should the 32 bit case be 'size - 4' instead of 'size - 8'? Sorry
> I just noticed that as soon as I pressed send.
>
> Brian

I already addressed this in one of your previous comments. We are 
keeping last 16 bytes reserved for these two parameters regardless of 
the architecture.
Sudeep Holla Oct. 3, 2023, 10:48 a.m. UTC | #5
On Mon, Oct 02, 2023 at 11:42:22AM -0700, Nikunj Kela wrote:
> 
> On 10/2/2023 11:34 AM, Brian Masney wrote:
> > On Mon, Sep 11, 2023 at 12:43:59PM -0700, Nikunj Kela wrote:
> > > This change adds the support for SCMI message exchange on Qualcomm
> > > virtual platforms.
> > > 
> > > The hypervisor associates an object-id also known as capability-id
> > > with each hvc doorbell object. The capability-id is used to identify the
> > > doorbell from the VM's capability namespace, similar to a file-descriptor.
> > > 
> > > The hypervisor, in addition to the function-id, expects the capability-id
> > > to be passed in x1 register when HVC call is invoked.
> > > 
> > > The function-id & capability-id are allocated by the hypervisor on bootup
> > > and are stored in the shmem region by the firmware before starting Linux.
> > > 
> > > Signed-off-by: Nikunj Kela <quic_nkela@quicinc.com>
> > > ---
> > >   drivers/firmware/arm_scmi/driver.c |  1 +
> > >   drivers/firmware/arm_scmi/smc.c    | 47 ++++++++++++++++++++++++++----
> > >   2 files changed, 43 insertions(+), 5 deletions(-)
> > > 
> > > diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
> > > index 87383c05424b..ea344bc6ae49 100644
> > > --- a/drivers/firmware/arm_scmi/driver.c
> > > +++ b/drivers/firmware/arm_scmi/driver.c
> > > @@ -2915,6 +2915,7 @@ static const struct of_device_id scmi_of_match[] = {
> > >   #ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC
> > >   	{ .compatible = "arm,scmi-smc", .data = &scmi_smc_desc},
> > >   	{ .compatible = "arm,scmi-smc-param", .data = &scmi_smc_desc},
> > > +	{ .compatible = "qcom,scmi-hvc-shmem", .data = &scmi_smc_desc},
> > >   #endif
> > >   #ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO
> > >   	{ .compatible = "arm,scmi-virtio", .data = &scmi_virtio_desc},
> > > diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c
> > > index 0a0b7e401159..94ec07fdc14a 100644
> > > --- a/drivers/firmware/arm_scmi/smc.c
> > > +++ b/drivers/firmware/arm_scmi/smc.c
> > > @@ -50,6 +50,9 @@
> > >    * @func_id: smc/hvc call function id
> > >    * @param_page: 4K page number of the shmem channel
> > >    * @param_offset: Offset within the 4K page of the shmem channel
> > > + * @cap_id: hvc doorbell's capability id to be used on Qualcomm virtual
> > > + *	    platforms
> > > + * @qcom_xport: Flag to indicate the transport on Qualcomm virtual platforms
> > >    */
> > >   struct scmi_smc {
> > > @@ -63,6 +66,8 @@ struct scmi_smc {
> > >   	u32 func_id;
> > >   	u32 param_page;
> > >   	u32 param_offset;
> > > +	u64 cap_id;
> > > +	bool qcom_xport;
> > >   };
> > [snip]
> > 
> > >   static irqreturn_t smc_msg_done_isr(int irq, void *data)
> > > @@ -129,6 +134,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
> > >   	struct resource res;
> > >   	struct device_node *np;
> > >   	u32 func_id;
> > > +	u64 cap_id;
> > >   	int ret;
> > [snip]
> > 
> > > +		func_id = readl((void __iomem *)(scmi_info->shmem) + size - 16);
> > > +#ifdef CONFIG_ARM64
> > > +		cap_id = readq((void __iomem *)(scmi_info->shmem) + size - 8);
> > > +#else
> > > +		/* capability-id is 32 bit wide on 32bit machines */
> > > +		cap_id = readl((void __iomem *)(scmi_info->shmem) + size - 8);
> > > +#endif
> > The 32 bit case is defined as a u64 in two places above.
> 
> That is done to make sure the size of the structure in memory is not
> architecture dependent. This was recommended in one of the previous version
> of this patch.
> 
> 
> > 
> > > +
> > > +		/* The func-id & capability-id are kept in last 16 bytes of shmem.
> > > +		 *     +-------+
> > > +		 *     |       |
> > > +		 *     | shmem |
> > > +		 *     |       |
> > > +		 *     |       |
> > > +		 *     +-------+ <-- (size - 16)
> > > +		 *     | funcId|
> > > +		 *     +-------+ <-- (size - 8)
> > > +		 *     | capId |
> > > +		 *     +-------+ <-- size
> > > +		 */
> > Personally I'd add one more space to the right side of the table after
> > funcId.
> 
> I could do that but then in 32bit case, you would want one more space right
> after cap-id since it is 32 bit on 32 bit platform. If it helps, I can have
> two lay out one for 32bit and one for 64 bit.
>

IIUC, it was just a cosmetic change requested. Instead of this,

		+-------+ <-- (size - 16)
		| funcId|
		+-------+ <-- (size - 8)

something like this, just a extra space after 'funcId' text.

		+--------+ <-- (size - 16)
		| funcId |
		+--------+ <-- (size - 8)
Sudeep Holla Oct. 3, 2023, 11:19 a.m. UTC | #6
On Mon, Sep 11, 2023 at 12:43:59PM -0700, Nikunj Kela wrote:
> This change adds the support for SCMI message exchange on Qualcomm
> virtual platforms.
> 
> The hypervisor associates an object-id also known as capability-id
> with each hvc doorbell object. The capability-id is used to identify the
> doorbell from the VM's capability namespace, similar to a file-descriptor.
> 
> The hypervisor, in addition to the function-id, expects the capability-id
> to be passed in x1 register when HVC call is invoked.
> 
> The function-id & capability-id are allocated by the hypervisor on bootup
> and are stored in the shmem region by the firmware before starting Linux.
> 
> Signed-off-by: Nikunj Kela <quic_nkela@quicinc.com>
> ---
>  drivers/firmware/arm_scmi/driver.c |  1 +
>  drivers/firmware/arm_scmi/smc.c    | 47 ++++++++++++++++++++++++++----
>  2 files changed, 43 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
> index 87383c05424b..ea344bc6ae49 100644
> --- a/drivers/firmware/arm_scmi/driver.c
> +++ b/drivers/firmware/arm_scmi/driver.c
> @@ -2915,6 +2915,7 @@ static const struct of_device_id scmi_of_match[] = {
>  #ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC
>  	{ .compatible = "arm,scmi-smc", .data = &scmi_smc_desc},
>  	{ .compatible = "arm,scmi-smc-param", .data = &scmi_smc_desc},
> +	{ .compatible = "qcom,scmi-hvc-shmem", .data = &scmi_smc_desc},
>  #endif
>  #ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO
>  	{ .compatible = "arm,scmi-virtio", .data = &scmi_virtio_desc},
> diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c
> index 0a0b7e401159..94ec07fdc14a 100644
> --- a/drivers/firmware/arm_scmi/smc.c
> +++ b/drivers/firmware/arm_scmi/smc.c
> @@ -50,6 +50,9 @@
>   * @func_id: smc/hvc call function id
>   * @param_page: 4K page number of the shmem channel
>   * @param_offset: Offset within the 4K page of the shmem channel
> + * @cap_id: hvc doorbell's capability id to be used on Qualcomm virtual
> + *	    platforms
> + * @qcom_xport: Flag to indicate the transport on Qualcomm virtual platforms
>   */
>  
>  struct scmi_smc {
> @@ -63,6 +66,8 @@ struct scmi_smc {
>  	u32 func_id;
>  	u32 param_page;
>  	u32 param_offset;
> +	u64 cap_id;

Can it be unsigned long instead so that it just works for both 32 and 64 bit.

> +	bool qcom_xport;

Do we really need this ?

>  };
>  
>  static irqreturn_t smc_msg_done_isr(int irq, void *data)
> @@ -129,6 +134,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
>  	struct resource res;
>  	struct device_node *np;
>  	u32 func_id;
> +	u64 cap_id;

Ditto..

>  	int ret;
>  
>  	if (!tx)
> @@ -158,9 +164,34 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
>  		return -EADDRNOTAVAIL;
>  	}
>  
> -	ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id);
> -	if (ret < 0)
> -		return ret;
> +	if (of_device_is_compatible(dev->of_node, "qcom,scmi-hvc-shmem")) {
> +		scmi_info->qcom_xport = true;
> +
> +		/* The func-id & capability-id are kept in last 16 bytes of shmem.
> +		 *     +-------+
> +		 *     |       |
> +		 *     | shmem |
> +		 *     |       |
> +		 *     |       |
> +		 *     +-------+ <-- (size - 16)
> +		 *     | funcId|
> +		 *     +-------+ <-- (size - 8)
> +		 *     | capId |
> +		 *     +-------+ <-- size
> +		 */
> +
> +		func_id = readl((void __iomem *)(scmi_info->shmem) + size - 16);

So unlike 'arm,scmi-smc', you don't want 'arm,smc-id' in the DT ? Any
particular reason ? Just to get both FID and cap ID from shmem ?

> +#ifdef CONFIG_ARM64

I would rather make this arch agnostic using CONFIG_64BIT

> +		cap_id = readq((void __iomem *)(scmi_info->shmem) + size - 8);

Do you need __iomem typecast here ? Is scmi_info->shmem not already __iomem ?
Also scmi_info->shmem is ioremapped just few steps above and you are using
read* here, is that safe ?

> +#else
> +		/* capability-id is 32 bit wide on 32bit machines */
> +		cap_id = rieadl((void __iomem *)(scmi_info->shmem) + size - 8);

Other thought once you move for u64 to unsigned long you need not have
#ifdeffery, just do copy of sizeof(unsigned long)

> +#endif
> +	} else {
> +		ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id);
> +		if (ret < 0)
> +			return ret;
> +	}
>  
>  	if (of_device_is_compatible(dev->of_node, "arm,scmi-smc-param")) {
>  		scmi_info->param_page = SHMEM_PAGE(res.start);
> @@ -184,6 +215,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
>  	}
>  
>  	scmi_info->func_id = func_id;
> +	scmi_info->cap_id = cap_id;
>  	scmi_info->cinfo = cinfo;
>  	smc_channel_lock_init(scmi_info);
>  	cinfo->transport_info = scmi_info;
> @@ -213,6 +245,7 @@ static int smc_send_message(struct scmi_chan_info *cinfo,
>  	struct arm_smccc_res res;
>  	unsigned long page = scmi_info->param_page;
>  	unsigned long offset = scmi_info->param_offset;
> +	unsigned long cap_id = (unsigned long)scmi_info->cap_id;
>  
>  	/*
>  	 * Channel will be released only once response has been
> @@ -222,8 +255,12 @@ static int smc_send_message(struct scmi_chan_info *cinfo,
>  
>  	shmem_tx_prepare(scmi_info->shmem, xfer, cinfo);
>  
> -	arm_smccc_1_1_invoke(scmi_info->func_id, page, offset, 0, 0, 0, 0, 0,
> -			     &res);
> +	if (scmi_info->qcom_xport)

Just make sure cap_id is set only for qcom and just use that as your flag.
No point in setting always true scmi_info->qcom_xport and using it here.

> +		arm_smccc_1_1_hvc(scmi_info->func_id, cap_id, 0, 0, 0, 0, 0, 0,
> +				  &res);
> +	else
> +		arm_smccc_1_1_invoke(scmi_info->func_id, page, offset, 0, 0, 0,
> +				     0, 0, &res);
>  
>  	/* Only SMCCC_RET_NOT_SUPPORTED is valid error code */
>  	if (res.a0) {
> -- 
> 2.17.1
>
Nikunj Kela Oct. 3, 2023, 4:16 p.m. UTC | #7
On 10/3/2023 4:19 AM, Sudeep Holla wrote:
> On Mon, Sep 11, 2023 at 12:43:59PM -0700, Nikunj Kela wrote:
>> This change adds the support for SCMI message exchange on Qualcomm
>> virtual platforms.
>>
>> The hypervisor associates an object-id also known as capability-id
>> with each hvc doorbell object. The capability-id is used to identify the
>> doorbell from the VM's capability namespace, similar to a file-descriptor.
>>
>> The hypervisor, in addition to the function-id, expects the capability-id
>> to be passed in x1 register when HVC call is invoked.
>>
>> The function-id & capability-id are allocated by the hypervisor on bootup
>> and are stored in the shmem region by the firmware before starting Linux.
>>
>> Signed-off-by: Nikunj Kela <quic_nkela@quicinc.com>
>> ---
>>   drivers/firmware/arm_scmi/driver.c |  1 +
>>   drivers/firmware/arm_scmi/smc.c    | 47 ++++++++++++++++++++++++++----
>>   2 files changed, 43 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
>> index 87383c05424b..ea344bc6ae49 100644
>> --- a/drivers/firmware/arm_scmi/driver.c
>> +++ b/drivers/firmware/arm_scmi/driver.c
>> @@ -2915,6 +2915,7 @@ static const struct of_device_id scmi_of_match[] = {
>>   #ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC
>>   	{ .compatible = "arm,scmi-smc", .data = &scmi_smc_desc},
>>   	{ .compatible = "arm,scmi-smc-param", .data = &scmi_smc_desc},
>> +	{ .compatible = "qcom,scmi-hvc-shmem", .data = &scmi_smc_desc},
>>   #endif
>>   #ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO
>>   	{ .compatible = "arm,scmi-virtio", .data = &scmi_virtio_desc},
>> diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c
>> index 0a0b7e401159..94ec07fdc14a 100644
>> --- a/drivers/firmware/arm_scmi/smc.c
>> +++ b/drivers/firmware/arm_scmi/smc.c
>> @@ -50,6 +50,9 @@
>>    * @func_id: smc/hvc call function id
>>    * @param_page: 4K page number of the shmem channel
>>    * @param_offset: Offset within the 4K page of the shmem channel
>> + * @cap_id: hvc doorbell's capability id to be used on Qualcomm virtual
>> + *	    platforms
>> + * @qcom_xport: Flag to indicate the transport on Qualcomm virtual platforms
>>    */
>>   
>>   struct scmi_smc {
>> @@ -63,6 +66,8 @@ struct scmi_smc {
>>   	u32 func_id;
>>   	u32 param_page;
>>   	u32 param_offset;
>> +	u64 cap_id;
> Can it be unsigned long instead so that it just works for both 32 and 64 bit.

My first version of this patch was ulong but Bjorn suggested to make 
this structure size fixed i.e. architecture independent. Hence changed 
it to u64. If you are ok with ulong, I can change it back to ulong.


>
>> +	bool qcom_xport;
> Do we really need this ?

Not if we initialize it with a negative value since 0 is a valid value 
for cap-id.


>
>>   };
>>   
>>   static irqreturn_t smc_msg_done_isr(int irq, void *data)
>> @@ -129,6 +134,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
>>   	struct resource res;
>>   	struct device_node *np;
>>   	u32 func_id;
>> +	u64 cap_id;
> Ditto..

Answered in earlier comment.


>>   	int ret;
>>   
>>   	if (!tx)
>> @@ -158,9 +164,34 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
>>   		return -EADDRNOTAVAIL;
>>   	}
>>   
>> -	ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id);
>> -	if (ret < 0)
>> -		return ret;
>> +	if (of_device_is_compatible(dev->of_node, "qcom,scmi-hvc-shmem")) {
>> +		scmi_info->qcom_xport = true;
>> +
>> +		/* The func-id & capability-id are kept in last 16 bytes of shmem.
>> +		 *     +-------+
>> +		 *     |       |
>> +		 *     | shmem |
>> +		 *     |       |
>> +		 *     |       |
>> +		 *     +-------+ <-- (size - 16)
>> +		 *     | funcId|
>> +		 *     +-------+ <-- (size - 8)
>> +		 *     | capId |
>> +		 *     +-------+ <-- size
>> +		 */
>> +
>> +		func_id = readl((void __iomem *)(scmi_info->shmem) + size - 16);
> So unlike 'arm,scmi-smc', you don't want 'arm,smc-id' in the DT ? Any
> particular reason ? Just to get both FID and cap ID from shmem ?

I could use smc-id binding for func-id, it's just two parameters will 
come from two different places so thought of keeping everything at one 
place to maintain consistency.  Since DT can't take cap-id, I decided to 
move func-id. I am fine if you want me to use smc-id binding.


>> +#ifdef CONFIG_ARM64
> I would rather make this arch agnostic using CONFIG_64BIT
ok.
>
>> +		cap_id = readq((void __iomem *)(scmi_info->shmem) + size - 8);
> Do you need __iomem typecast here ? Is scmi_info->shmem not already __iomem ?
> Also scmi_info->shmem is ioremapped just few steps above and you are using
> read* here, is that safe ?

I saw some compilation warnings without __iomem. I will use ioread* API 
instead of read*.


>
>> +#else
>> +		/* capability-id is 32 bit wide on 32bit machines */
>> +		cap_id = rieadl((void __iomem *)(scmi_info->shmem) + size - 8);
> Other thought once you move for u64 to unsigned long you need not have
> #ifdeffery, just do copy of sizeof(unsigned long)
Right, my first version was like that only.
>
>> +#endif
>> +	} else {
>> +		ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id);
>> +		if (ret < 0)
>> +			return ret;
>> +	}
>>   
>>   	if (of_device_is_compatible(dev->of_node, "arm,scmi-smc-param")) {
>>   		scmi_info->param_page = SHMEM_PAGE(res.start);
>> @@ -184,6 +215,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
>>   	}
>>   
>>   	scmi_info->func_id = func_id;
>> +	scmi_info->cap_id = cap_id;
>>   	scmi_info->cinfo = cinfo;
>>   	smc_channel_lock_init(scmi_info);
>>   	cinfo->transport_info = scmi_info;
>> @@ -213,6 +245,7 @@ static int smc_send_message(struct scmi_chan_info *cinfo,
>>   	struct arm_smccc_res res;
>>   	unsigned long page = scmi_info->param_page;
>>   	unsigned long offset = scmi_info->param_offset;
>> +	unsigned long cap_id = (unsigned long)scmi_info->cap_id;
>>   
>>   	/*
>>   	 * Channel will be released only once response has been
>> @@ -222,8 +255,12 @@ static int smc_send_message(struct scmi_chan_info *cinfo,
>>   
>>   	shmem_tx_prepare(scmi_info->shmem, xfer, cinfo);
>>   
>> -	arm_smccc_1_1_invoke(scmi_info->func_id, page, offset, 0, 0, 0, 0, 0,
>> -			     &res);
>> +	if (scmi_info->qcom_xport)
> Just make sure cap_id is set only for qcom and just use that as your flag.
> No point in setting always true scmi_info->qcom_xport and using it here.
ok, I can remove that. Though 0 is a valid value for cap-id so will have 
to init cap-id with a negative value.
>
>> +		arm_smccc_1_1_hvc(scmi_info->func_id, cap_id, 0, 0, 0, 0, 0, 0,
>> +				  &res);
>> +	else
>> +		arm_smccc_1_1_invoke(scmi_info->func_id, page, offset, 0, 0, 0,
>> +				     0, 0, &res);
>>   
>>   	/* Only SMCCC_RET_NOT_SUPPORTED is valid error code */
>>   	if (res.a0) {
>> -- 
>> 2.17.1
>>
Sudeep Holla Oct. 4, 2023, 4:06 p.m. UTC | #8
On Tue, Oct 03, 2023 at 09:16:27AM -0700, Nikunj Kela wrote:
> 
> On 10/3/2023 4:19 AM, Sudeep Holla wrote:
> > On Mon, Sep 11, 2023 at 12:43:59PM -0700, Nikunj Kela wrote:
> > > This change adds the support for SCMI message exchange on Qualcomm
> > > virtual platforms.
> > > 
> > > The hypervisor associates an object-id also known as capability-id
> > > with each hvc doorbell object. The capability-id is used to identify the
> > > doorbell from the VM's capability namespace, similar to a file-descriptor.
> > > 
> > > The hypervisor, in addition to the function-id, expects the capability-id
> > > to be passed in x1 register when HVC call is invoked.
> > > 
> > > The function-id & capability-id are allocated by the hypervisor on bootup
> > > and are stored in the shmem region by the firmware before starting Linux.
> > > 
> > > Signed-off-by: Nikunj Kela <quic_nkela@quicinc.com>
> > > ---
> > >   drivers/firmware/arm_scmi/driver.c |  1 +
> > >   drivers/firmware/arm_scmi/smc.c    | 47 ++++++++++++++++++++++++++----
> > >   2 files changed, 43 insertions(+), 5 deletions(-)
> > > 
> > > diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
> > > index 87383c05424b..ea344bc6ae49 100644
> > > --- a/drivers/firmware/arm_scmi/driver.c
> > > +++ b/drivers/firmware/arm_scmi/driver.c
> > > @@ -2915,6 +2915,7 @@ static const struct of_device_id scmi_of_match[] = {
> > >   #ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC
> > >   	{ .compatible = "arm,scmi-smc", .data = &scmi_smc_desc},
> > >   	{ .compatible = "arm,scmi-smc-param", .data = &scmi_smc_desc},
> > > +	{ .compatible = "qcom,scmi-hvc-shmem", .data = &scmi_smc_desc},
> > >   #endif
> > >   #ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO
> > >   	{ .compatible = "arm,scmi-virtio", .data = &scmi_virtio_desc},
> > > diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c
> > > index 0a0b7e401159..94ec07fdc14a 100644
> > > --- a/drivers/firmware/arm_scmi/smc.c
> > > +++ b/drivers/firmware/arm_scmi/smc.c
> > > @@ -50,6 +50,9 @@
> > >    * @func_id: smc/hvc call function id
> > >    * @param_page: 4K page number of the shmem channel
> > >    * @param_offset: Offset within the 4K page of the shmem channel
> > > + * @cap_id: hvc doorbell's capability id to be used on Qualcomm virtual
> > > + *	    platforms
> > > + * @qcom_xport: Flag to indicate the transport on Qualcomm virtual platforms
> > >    */
> > >   struct scmi_smc {
> > > @@ -63,6 +66,8 @@ struct scmi_smc {
> > >   	u32 func_id;
> > >   	u32 param_page;
> > >   	u32 param_offset;
> > > +	u64 cap_id;
> > Can it be unsigned long instead so that it just works for both 32 and 64 bit.
> 
> My first version of this patch was ulong but Bjorn suggested to make this
> structure size fixed i.e. architecture independent. Hence changed it to u64.
> If you are ok with ulong, I can change it back to ulong.
>

SMCCC pre-v1.2 used the common structure in that way. I don't see any issue
with that. I haven't followed Bjorn suggestions/comments though.

> 
> > 
> > > +	bool qcom_xport;
> > Do we really need this ?
> 
> Not if we initialize it with a negative value since 0 is a valid value for
> cap-id.
>

Fine with negative value(-EINVAL may be).

> > >   	int ret;
> > >   	if (!tx)
> > > @@ -158,9 +164,34 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
> > >   		return -EADDRNOTAVAIL;
> > >   	}
> > > -	ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id);
> > > -	if (ret < 0)
> > > -		return ret;
> > > +	if (of_device_is_compatible(dev->of_node, "qcom,scmi-hvc-shmem")) {
> > > +		scmi_info->qcom_xport = true;
> > > +
> > > +		/* The func-id & capability-id are kept in last 16 bytes of shmem.
> > > +		 *     +-------+
> > > +		 *     |       |
> > > +		 *     | shmem |
> > > +		 *     |       |
> > > +		 *     |       |
> > > +		 *     +-------+ <-- (size - 16)
> > > +		 *     | funcId|
> > > +		 *     +-------+ <-- (size - 8)
> > > +		 *     | capId |
> > > +		 *     +-------+ <-- size
> > > +		 */
> > > +
> > > +		func_id = readl((void __iomem *)(scmi_info->shmem) + size - 16);
> > So unlike 'arm,scmi-smc', you don't want 'arm,smc-id' in the DT ? Any
> > particular reason ? Just to get both FID and cap ID from shmem ?
>

I am fine either way. If you use from DT(via arm,smc-id), then "qcom,scmi"
can be just addition compatible that expects you to read cap-id from the
shmem. May need adjustment in the binding as you allow both
"qcom,scmi-smc", "arm,scmi-smc". I will leave the details to you.

> I could use smc-id binding for func-id, it's just two parameters will come
> from two different places so thought of keeping everything at one place to
> maintain consistency.  Since DT can't take cap-id, I decided to move
> func-id. I am fine if you want me to use smc-id binding.
>

Up to you. If you want to make "qcom,scmi-smc" and "arm,scmi-smc"
compatible in way in that way or you can keep it incompatible as you have
proposed in this patch set.

> 
> > > +#ifdef CONFIG_ARM64
> > I would rather make this arch agnostic using CONFIG_64BIT
> ok.
> > 
> > > +		cap_id = readq((void __iomem *)(scmi_info->shmem) + size - 8);
> > Do you need __iomem typecast here ? Is scmi_info->shmem not already __iomem ?
> > Also scmi_info->shmem is ioremapped just few steps above and you are using
> > read* here, is that safe ?
> 
> I saw some compilation warnings without __iomem. I will use ioread* API
> instead of read*.
>

That was the clue that you were using __iomem with read* calls IMO.

> 
> > 
> > > +#else
> > > +		/* capability-id is 32 bit wide on 32bit machines */
> > > +		cap_id = rieadl((void __iomem *)(scmi_info->shmem) + size - 8);
> > Other thought once you move for u64 to unsigned long you need not have
> > #ifdeffery, just do copy of sizeof(unsigned long)
> Right, my first version was like that only.

OK

> > 
> > > +#endif
> > > +	} else {
> > > +		ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id);
> > > +		if (ret < 0)
> > > +			return ret;
> > > +	}
> > >   	if (of_device_is_compatible(dev->of_node, "arm,scmi-smc-param")) {
> > >   		scmi_info->param_page = SHMEM_PAGE(res.start);
> > > @@ -184,6 +215,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
> > >   	}
> > >   	scmi_info->func_id = func_id;
> > > +	scmi_info->cap_id = cap_id;
> > >   	scmi_info->cinfo = cinfo;
> > >   	smc_channel_lock_init(scmi_info);
> > >   	cinfo->transport_info = scmi_info;
> > > @@ -213,6 +245,7 @@ static int smc_send_message(struct scmi_chan_info *cinfo,
> > >   	struct arm_smccc_res res;
> > >   	unsigned long page = scmi_info->param_page;
> > >   	unsigned long offset = scmi_info->param_offset;
> > > +	unsigned long cap_id = (unsigned long)scmi_info->cap_id;
> > >   	/*
> > >   	 * Channel will be released only once response has been
> > > @@ -222,8 +255,12 @@ static int smc_send_message(struct scmi_chan_info *cinfo,
> > >   	shmem_tx_prepare(scmi_info->shmem, xfer, cinfo);
> > > -	arm_smccc_1_1_invoke(scmi_info->func_id, page, offset, 0, 0, 0, 0, 0,
> > > -			     &res);
> > > +	if (scmi_info->qcom_xport)
> > Just make sure cap_id is set only for qcom and just use that as your flag.
> > No point in setting always true scmi_info->qcom_xport and using it here.
> ok, I can remove that. Though 0 is a valid value for cap-id so will have to
> init cap-id with a negative value.

Yes as mentioned above.
Nikunj Kela Oct. 4, 2023, 5:48 p.m. UTC | #9
On 10/4/2023 9:06 AM, Sudeep Holla wrote:
> On Tue, Oct 03, 2023 at 09:16:27AM -0700, Nikunj Kela wrote:
>> On 10/3/2023 4:19 AM, Sudeep Holla wrote:
>>> On Mon, Sep 11, 2023 at 12:43:59PM -0700, Nikunj Kela wrote:
>>>> This change adds the support for SCMI message exchange on Qualcomm
>>>> virtual platforms.
>>>>
>>>> The hypervisor associates an object-id also known as capability-id
>>>> with each hvc doorbell object. The capability-id is used to identify the
>>>> doorbell from the VM's capability namespace, similar to a file-descriptor.
>>>>
>>>> The hypervisor, in addition to the function-id, expects the capability-id
>>>> to be passed in x1 register when HVC call is invoked.
>>>>
>>>> The function-id & capability-id are allocated by the hypervisor on bootup
>>>> and are stored in the shmem region by the firmware before starting Linux.
>>>>
>>>> Signed-off-by: Nikunj Kela <quic_nkela@quicinc.com>
>>>> ---
>>>>    drivers/firmware/arm_scmi/driver.c |  1 +
>>>>    drivers/firmware/arm_scmi/smc.c    | 47 ++++++++++++++++++++++++++----
>>>>    2 files changed, 43 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
>>>> index 87383c05424b..ea344bc6ae49 100644
>>>> --- a/drivers/firmware/arm_scmi/driver.c
>>>> +++ b/drivers/firmware/arm_scmi/driver.c
>>>> @@ -2915,6 +2915,7 @@ static const struct of_device_id scmi_of_match[] = {
>>>>    #ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC
>>>>    	{ .compatible = "arm,scmi-smc", .data = &scmi_smc_desc},
>>>>    	{ .compatible = "arm,scmi-smc-param", .data = &scmi_smc_desc},
>>>> +	{ .compatible = "qcom,scmi-hvc-shmem", .data = &scmi_smc_desc},
>>>>    #endif
>>>>    #ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO
>>>>    	{ .compatible = "arm,scmi-virtio", .data = &scmi_virtio_desc},
>>>> diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c
>>>> index 0a0b7e401159..94ec07fdc14a 100644
>>>> --- a/drivers/firmware/arm_scmi/smc.c
>>>> +++ b/drivers/firmware/arm_scmi/smc.c
>>>> @@ -50,6 +50,9 @@
>>>>     * @func_id: smc/hvc call function id
>>>>     * @param_page: 4K page number of the shmem channel
>>>>     * @param_offset: Offset within the 4K page of the shmem channel
>>>> + * @cap_id: hvc doorbell's capability id to be used on Qualcomm virtual
>>>> + *	    platforms
>>>> + * @qcom_xport: Flag to indicate the transport on Qualcomm virtual platforms
>>>>     */
>>>>    struct scmi_smc {
>>>> @@ -63,6 +66,8 @@ struct scmi_smc {
>>>>    	u32 func_id;
>>>>    	u32 param_page;
>>>>    	u32 param_offset;
>>>> +	u64 cap_id;
>>> Can it be unsigned long instead so that it just works for both 32 and 64 bit.
>> My first version of this patch was ulong but Bjorn suggested to make this
>> structure size fixed i.e. architecture independent. Hence changed it to u64.
>> If you are ok with ulong, I can change it back to ulong.
>>
> SMCCC pre-v1.2 used the common structure in that way. I don't see any issue
> with that. I haven't followed Bjorn suggestions/comments though.
Ok.
>>>> +	bool qcom_xport;
>>> Do we really need this ?
>> Not if we initialize it with a negative value since 0 is a valid value for
>> cap-id.
>>
> Fine with negative value(-EINVAL may be).
Ok.
>>>>    	int ret;
>>>>    	if (!tx)
>>>> @@ -158,9 +164,34 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
>>>>    		return -EADDRNOTAVAIL;
>>>>    	}
>>>> -	ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id);
>>>> -	if (ret < 0)
>>>> -		return ret;
>>>> +	if (of_device_is_compatible(dev->of_node, "qcom,scmi-hvc-shmem")) {
>>>> +		scmi_info->qcom_xport = true;
>>>> +
>>>> +		/* The func-id & capability-id are kept in last 16 bytes of shmem.
>>>> +		 *     +-------+
>>>> +		 *     |       |
>>>> +		 *     | shmem |
>>>> +		 *     |       |
>>>> +		 *     |       |
>>>> +		 *     +-------+ <-- (size - 16)
>>>> +		 *     | funcId|
>>>> +		 *     +-------+ <-- (size - 8)
>>>> +		 *     | capId |
>>>> +		 *     +-------+ <-- size
>>>> +		 */
>>>> +
>>>> +		func_id = readl((void __iomem *)(scmi_info->shmem) + size - 16);
>>> So unlike 'arm,scmi-smc', you don't want 'arm,smc-id' in the DT ? Any
>>> particular reason ? Just to get both FID and cap ID from shmem ?
> I am fine either way. If you use from DT(via arm,smc-id), then "qcom,scmi"
> can be just addition compatible that expects you to read cap-id from the
> shmem. May need adjustment in the binding as you allow both
> "qcom,scmi-smc", "arm,scmi-smc". I will leave the details to you.
Ok.
>> I could use smc-id binding for func-id, it's just two parameters will come
>> from two different places so thought of keeping everything at one place to
>> maintain consistency.  Since DT can't take cap-id, I decided to move
>> func-id. I am fine if you want me to use smc-id binding.
>>
> Up to you. If you want to make "qcom,scmi-smc" and "arm,scmi-smc"
> compatible in way in that way or you can keep it incompatible as you have
> proposed in this patch set.
Ok.
>>>> +#ifdef CONFIG_ARM64
>>> I would rather make this arch agnostic using CONFIG_64BIT
>> ok.
>>>> +		cap_id = readq((void __iomem *)(scmi_info->shmem) + size - 8);
>>> Do you need __iomem typecast here ? Is scmi_info->shmem not already __iomem ?
>>> Also scmi_info->shmem is ioremapped just few steps above and you are using
>>> read* here, is that safe ?
>> I saw some compilation warnings without __iomem. I will use ioread* API
>> instead of read*.
>>
> That was the clue that you were using __iomem with read* calls IMO.
Ok.
>>>> +#else
>>>> +		/* capability-id is 32 bit wide on 32bit machines */
>>>> +		cap_id = rieadl((void __iomem *)(scmi_info->shmem) + size - 8);
>>> Other thought once you move for u64 to unsigned long you need not have
>>> #ifdeffery, just do copy of sizeof(unsigned long)
>> Right, my first version was like that only.
> OK
>
>>>> +#endif
>>>> +	} else {
>>>> +		ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id);
>>>> +		if (ret < 0)
>>>> +			return ret;
>>>> +	}
>>>>    	if (of_device_is_compatible(dev->of_node, "arm,scmi-smc-param")) {
>>>>    		scmi_info->param_page = SHMEM_PAGE(res.start);
>>>> @@ -184,6 +215,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
>>>>    	}
>>>>    	scmi_info->func_id = func_id;
>>>> +	scmi_info->cap_id = cap_id;
>>>>    	scmi_info->cinfo = cinfo;
>>>>    	smc_channel_lock_init(scmi_info);
>>>>    	cinfo->transport_info = scmi_info;
>>>> @@ -213,6 +245,7 @@ static int smc_send_message(struct scmi_chan_info *cinfo,
>>>>    	struct arm_smccc_res res;
>>>>    	unsigned long page = scmi_info->param_page;
>>>>    	unsigned long offset = scmi_info->param_offset;
>>>> +	unsigned long cap_id = (unsigned long)scmi_info->cap_id;
>>>>    	/*
>>>>    	 * Channel will be released only once response has been
>>>> @@ -222,8 +255,12 @@ static int smc_send_message(struct scmi_chan_info *cinfo,
>>>>    	shmem_tx_prepare(scmi_info->shmem, xfer, cinfo);
>>>> -	arm_smccc_1_1_invoke(scmi_info->func_id, page, offset, 0, 0, 0, 0, 0,
>>>> -			     &res);
>>>> +	if (scmi_info->qcom_xport)
>>> Just make sure cap_id is set only for qcom and just use that as your flag.
>>> No point in setting always true scmi_info->qcom_xport and using it here.
>> ok, I can remove that. Though 0 is a valid value for cap-id so will have to
>> init cap-id with a negative value.
> Yes as mentioned above.
Ok.
>
Bjorn Andersson Oct. 5, 2023, 10:20 p.m. UTC | #10
On Wed, Oct 04, 2023 at 05:06:30PM +0100, Sudeep Holla wrote:
> On Tue, Oct 03, 2023 at 09:16:27AM -0700, Nikunj Kela wrote:
> > On 10/3/2023 4:19 AM, Sudeep Holla wrote:
> > > On Mon, Sep 11, 2023 at 12:43:59PM -0700, Nikunj Kela wrote:
> > > > diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c
[..]
> > > > @@ -63,6 +66,8 @@ struct scmi_smc {
> > > >   	u32 func_id;
> > > >   	u32 param_page;
> > > >   	u32 param_offset;
> > > > +	u64 cap_id;
> > > Can it be unsigned long instead so that it just works for both 32 and 64 bit.
> > 
> > My first version of this patch was ulong but Bjorn suggested to make this
> > structure size fixed i.e. architecture independent. Hence changed it to u64.
> > If you are ok with ulong, I can change it back to ulong.
> >
> 
> SMCCC pre-v1.2 used the common structure in that way. I don't see any issue
> with that. I haven't followed Bjorn suggestions/comments though.
> 

My request was that funcId and capId is an ABI between the firmware and
the OS, so I'd like for that to use well defined, fixed sized, data
types - if nothing else just for documentation purpose.

These values will be truncated when passed to arm_smccc_1_1_invoke()
anyways, so I don't have any opinion against using unsigned long here...


PS. I understand why func_id is u32, but why are param_page and
param_offset u32?

Regards,
Bjorn
Nikunj Kela Oct. 5, 2023, 10:33 p.m. UTC | #11
On 10/5/2023 3:20 PM, Bjorn Andersson wrote:
> On Wed, Oct 04, 2023 at 05:06:30PM +0100, Sudeep Holla wrote:
>> On Tue, Oct 03, 2023 at 09:16:27AM -0700, Nikunj Kela wrote:
>>> On 10/3/2023 4:19 AM, Sudeep Holla wrote:
>>>> On Mon, Sep 11, 2023 at 12:43:59PM -0700, Nikunj Kela wrote:
>>>>> diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c
> [..]
>>>>> @@ -63,6 +66,8 @@ struct scmi_smc {
>>>>>    	u32 func_id;
>>>>>    	u32 param_page;
>>>>>    	u32 param_offset;
>>>>> +	u64 cap_id;
>>>> Can it be unsigned long instead so that it just works for both 32 and 64 bit.
>>> My first version of this patch was ulong but Bjorn suggested to make this
>>> structure size fixed i.e. architecture independent. Hence changed it to u64.
>>> If you are ok with ulong, I can change it back to ulong.
>>>
>> SMCCC pre-v1.2 used the common structure in that way. I don't see any issue
>> with that. I haven't followed Bjorn suggestions/comments though.
>>
> My request was that funcId and capId is an ABI between the firmware and
> the OS, so I'd like for that to use well defined, fixed sized, data
> types - if nothing else just for documentation purpose.
>
> These values will be truncated when passed to arm_smccc_1_1_invoke()
> anyways, so I don't have any opinion against using unsigned long here...
>
>
> PS. I understand why func_id is u32, but why are param_page and
> param_offset u32?

That was done to keep it uniform across smc32/smc64 conventions.

>
> Regards,
> Bjorn
Sudeep Holla Oct. 6, 2023, 7:26 a.m. UTC | #12
On Thu, Oct 05, 2023 at 03:20:16PM -0700, Bjorn Andersson wrote:
> On Wed, Oct 04, 2023 at 05:06:30PM +0100, Sudeep Holla wrote:
> > On Tue, Oct 03, 2023 at 09:16:27AM -0700, Nikunj Kela wrote:
> > > On 10/3/2023 4:19 AM, Sudeep Holla wrote:
> > > > On Mon, Sep 11, 2023 at 12:43:59PM -0700, Nikunj Kela wrote:
> > > > > diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c
> [..]
> > > > > @@ -63,6 +66,8 @@ struct scmi_smc {
> > > > >   	u32 func_id;
> > > > >   	u32 param_page;
> > > > >   	u32 param_offset;
> > > > > +	u64 cap_id;
> > > > Can it be unsigned long instead so that it just works for both 32 and 64 bit.
> > > 
> > > My first version of this patch was ulong but Bjorn suggested to make this
> > > structure size fixed i.e. architecture independent. Hence changed it to u64.
> > > If you are ok with ulong, I can change it back to ulong.
> > >
> > 
> > SMCCC pre-v1.2 used the common structure in that way. I don't see any issue
> > with that. I haven't followed Bjorn suggestions/comments though.
> > 
> 
> My request was that funcId and capId is an ABI between the firmware and
> the OS, so I'd like for that to use well defined, fixed sized, data
> types - if nothing else just for documentation purpose.
> 
> These values will be truncated when passed to arm_smccc_1_1_invoke()
> anyways, so I don't have any opinion against using unsigned long here...
> 
> 
> PS. I understand why func_id is u32, but why are param_page and
> param_offset u32?
> 

Good point. Sorry I somehow missed your original comment, my bad.
Yes, it is good to be consistent. Sorry if I added any confusion by
missing o read your comment and understanding it before I responded.

--
Regards,
Sudeep
diff mbox series

Patch

diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 87383c05424b..ea344bc6ae49 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -2915,6 +2915,7 @@  static const struct of_device_id scmi_of_match[] = {
 #ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC
 	{ .compatible = "arm,scmi-smc", .data = &scmi_smc_desc},
 	{ .compatible = "arm,scmi-smc-param", .data = &scmi_smc_desc},
+	{ .compatible = "qcom,scmi-hvc-shmem", .data = &scmi_smc_desc},
 #endif
 #ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO
 	{ .compatible = "arm,scmi-virtio", .data = &scmi_virtio_desc},
diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c
index 0a0b7e401159..94ec07fdc14a 100644
--- a/drivers/firmware/arm_scmi/smc.c
+++ b/drivers/firmware/arm_scmi/smc.c
@@ -50,6 +50,9 @@ 
  * @func_id: smc/hvc call function id
  * @param_page: 4K page number of the shmem channel
  * @param_offset: Offset within the 4K page of the shmem channel
+ * @cap_id: hvc doorbell's capability id to be used on Qualcomm virtual
+ *	    platforms
+ * @qcom_xport: Flag to indicate the transport on Qualcomm virtual platforms
  */
 
 struct scmi_smc {
@@ -63,6 +66,8 @@  struct scmi_smc {
 	u32 func_id;
 	u32 param_page;
 	u32 param_offset;
+	u64 cap_id;
+	bool qcom_xport;
 };
 
 static irqreturn_t smc_msg_done_isr(int irq, void *data)
@@ -129,6 +134,7 @@  static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
 	struct resource res;
 	struct device_node *np;
 	u32 func_id;
+	u64 cap_id;
 	int ret;
 
 	if (!tx)
@@ -158,9 +164,34 @@  static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
 		return -EADDRNOTAVAIL;
 	}
 
-	ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id);
-	if (ret < 0)
-		return ret;
+	if (of_device_is_compatible(dev->of_node, "qcom,scmi-hvc-shmem")) {
+		scmi_info->qcom_xport = true;
+
+		/* The func-id & capability-id are kept in last 16 bytes of shmem.
+		 *     +-------+
+		 *     |       |
+		 *     | shmem |
+		 *     |       |
+		 *     |       |
+		 *     +-------+ <-- (size - 16)
+		 *     | funcId|
+		 *     +-------+ <-- (size - 8)
+		 *     | capId |
+		 *     +-------+ <-- size
+		 */
+
+		func_id = readl((void __iomem *)(scmi_info->shmem) + size - 16);
+#ifdef CONFIG_ARM64
+		cap_id = readq((void __iomem *)(scmi_info->shmem) + size - 8);
+#else
+		/* capability-id is 32 bit wide on 32bit machines */
+		cap_id = readl((void __iomem *)(scmi_info->shmem) + size - 8);
+#endif
+	} else {
+		ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id);
+		if (ret < 0)
+			return ret;
+	}
 
 	if (of_device_is_compatible(dev->of_node, "arm,scmi-smc-param")) {
 		scmi_info->param_page = SHMEM_PAGE(res.start);
@@ -184,6 +215,7 @@  static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
 	}
 
 	scmi_info->func_id = func_id;
+	scmi_info->cap_id = cap_id;
 	scmi_info->cinfo = cinfo;
 	smc_channel_lock_init(scmi_info);
 	cinfo->transport_info = scmi_info;
@@ -213,6 +245,7 @@  static int smc_send_message(struct scmi_chan_info *cinfo,
 	struct arm_smccc_res res;
 	unsigned long page = scmi_info->param_page;
 	unsigned long offset = scmi_info->param_offset;
+	unsigned long cap_id = (unsigned long)scmi_info->cap_id;
 
 	/*
 	 * Channel will be released only once response has been
@@ -222,8 +255,12 @@  static int smc_send_message(struct scmi_chan_info *cinfo,
 
 	shmem_tx_prepare(scmi_info->shmem, xfer, cinfo);
 
-	arm_smccc_1_1_invoke(scmi_info->func_id, page, offset, 0, 0, 0, 0, 0,
-			     &res);
+	if (scmi_info->qcom_xport)
+		arm_smccc_1_1_hvc(scmi_info->func_id, cap_id, 0, 0, 0, 0, 0, 0,
+				  &res);
+	else
+		arm_smccc_1_1_invoke(scmi_info->func_id, page, offset, 0, 0, 0,
+				     0, 0, &res);
 
 	/* Only SMCCC_RET_NOT_SUPPORTED is valid error code */
 	if (res.a0) {