1 | Currently, smc/hvc calls are made with parameters set | 1 | Currently, smc/hvc calls are made with parameters set |
---|---|---|---|
2 | to zeros. We are using multiple scmi instances within | 2 | to zeros. We are using multiple scmi instances within |
3 | a VM and hypervisor associates a tag with each instance | 3 | a VM. We are sharing the same smc-id(func_id) with all |
4 | and expects the tag in smc calls from that instance, while | 4 | scmi instance. The hypervisor needs a way to distinguish |
5 | sharing the same smc-id(func_id) among the instances. | 5 | among hvc calls made from different instances. |
6 | 6 | ||
7 | This patch series introduces new optional dtb bindings which | 7 | This patch series introduces new compatible string which |
8 | can be used to pass parameters to smc/hvc calls. | 8 | can be used to pass shmem channel address as parameters |
9 | to smc/hvc calls. | ||
10 | |||
11 | --- | ||
12 | v5 -> avoid computing page and offset in send function | ||
13 | Link: https://lore.kernel.org/all/20230418185659.29745-1-quic_nkela@quicinc.com/ | ||
14 | |||
15 | v4 -> split shmem address into 4KB-pages and offset | ||
16 | |||
17 | v3 -> pass shmem channel address as parameter | ||
18 | |||
19 | v2 -> fix the compilation erros on 32bit platform(see below) | ||
20 | Reported-by: kernel test robot <lkp@intel.com> | ||
21 | Closes: https://lore.kernel.org/oe-kbuild-all/202304100606.kUjhsRYf-lkp@intel.com/ | ||
22 | |||
23 | v1 -> original patches | ||
9 | 24 | ||
10 | Nikunj Kela (2): | 25 | Nikunj Kela (2): |
11 | dt-bindings: firmware: arm,scmi: support parameter passing in smc/hvc | 26 | dt-bindings: firmware: arm,scmi: support for parameter in smc/hvc call |
12 | firmware: arm_scmi: Augment SMC/HVC to allow optional parameters | 27 | firmware: arm_scmi: Augment SMC/HVC to allow optional parameters |
13 | 28 | ||
14 | .../bindings/firmware/arm,scmi.yaml | 16 +++++ | 29 | .../bindings/firmware/arm,scmi.yaml | 8 ++++- |
15 | drivers/firmware/arm_scmi/smc.c | 66 ++++++++++++++++++- | 30 | drivers/firmware/arm_scmi/driver.c | 1 + |
16 | 2 files changed, 81 insertions(+), 1 deletion(-) | 31 | drivers/firmware/arm_scmi/smc.c | 30 ++++++++++++++++++- |
32 | 3 files changed, 37 insertions(+), 2 deletions(-) | ||
17 | 33 | ||
18 | -- | 34 | -- |
19 | 2.17.1 | 35 | 2.17.1 | diff view generated by jsdifflib |
1 | Currently, smc/hvc calls are made with smc-id only. The parameters are | 1 | Currently, smc/hvc calls are made with smc-id only. The parameters are |
---|---|---|---|
2 | all set to zeros. This patch defines two optional device tree bindings, | 2 | all set to zeros. This change defines a new compatible string that can |
3 | that can be used to pass parameters in smc/hvc calls. | 3 | be used to pass shmem address(4KB-page, offset) as two parameters in |
4 | SMC/HVC doorbell. | ||
4 | 5 | ||
5 | This is useful when multiple scmi instances are used with common smc-id. | 6 | This is useful when multiple scmi instances are used with common smc-id. |
6 | 7 | ||
7 | Signed-off-by: Nikunj Kela <quic_nkela@quicinc.com> | 8 | Signed-off-by: Nikunj Kela <quic_nkela@quicinc.com> |
9 | Reviewed-by: Rob Herring <robh@kernel.org> | ||
8 | --- | 10 | --- |
9 | .../devicetree/bindings/firmware/arm,scmi.yaml | 16 ++++++++++++++++ | 11 | Documentation/devicetree/bindings/firmware/arm,scmi.yaml | 8 +++++++- |
10 | 1 file changed, 16 insertions(+) | 12 | 1 file changed, 7 insertions(+), 1 deletion(-) |
11 | 13 | ||
12 | diff --git a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml | 14 | diff --git a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml |
13 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml | 16 | --- a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml |
15 | +++ b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml | 17 | +++ b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml |
16 | @@ -XXX,XX +XXX,XX @@ properties: | 18 | @@ -XXX,XX +XXX,XX @@ properties: |
17 | description: | 19 | - description: SCMI compliant firmware with ARM SMC/HVC transport |
18 | SMC id required when using smc or hvc transports | 20 | items: |
19 | 21 | - const: arm,scmi-smc | |
20 | + arm,smc32-params: | 22 | + - description: SCMI compliant firmware with ARM SMC/HVC transport |
21 | + $ref: /schemas/types.yaml#/definitions/uint32-array | 23 | + with shmem address(4KB-page, offset) as parameters |
22 | + description: | 24 | + items: |
23 | + An optional parameter list passed in smc32 or hvc32 calls | 25 | + - const: arm,scmi-smc-param |
24 | + default: 0 | 26 | - description: SCMI compliant firmware with SCMI Virtio transport. |
25 | + minItems: 1 | 27 | The virtio transport only supports a single device. |
26 | + maxItems: 6 | 28 | items: |
27 | + | 29 | @@ -XXX,XX +XXX,XX @@ else: |
28 | + arm,smc64-params: | 30 | properties: |
29 | + $ref: /schemas/types.yaml#/definitions/uint64-array | 31 | compatible: |
30 | + description: | 32 | contains: |
31 | + An optional parameter list passed in smc64 or hvc64 calls | 33 | - const: arm,scmi-smc |
32 | + default: 0 | 34 | + enum: |
33 | + minItems: 1 | 35 | + - arm,scmi-smc |
34 | + maxItems: 6 | 36 | + - arm,scmi-smc-param |
35 | + | 37 | then: |
36 | linaro,optee-channel-id: | 38 | required: |
37 | $ref: /schemas/types.yaml#/definitions/uint32 | 39 | - arm,smc-id |
38 | description: | ||
39 | -- | 40 | -- |
40 | 2.17.1 | 41 | 2.17.1 | diff view generated by jsdifflib |
1 | This patch add support for passing parameters to smc/hvc calls. | 1 | This change adds support for passing shmem channel address as parameters |
---|---|---|---|
2 | This patch is useful when multiple scmi instances are using same | 2 | in smc/hvc call. The address is split into 4KB-page and offset. |
3 | smc-id and firmware needs to distiguish among the instances. | 3 | This is useful when multiple scmi instances are using same smc-id |
4 | and firmware needs to distinguish among the instances. | ||
4 | 5 | ||
5 | Signed-off-by: Nikunj Kela <quic_nkela@quicinc.com> | 6 | Signed-off-by: Nikunj Kela <quic_nkela@quicinc.com> |
6 | --- | 7 | --- |
7 | drivers/firmware/arm_scmi/smc.c | 66 ++++++++++++++++++++++++++++++++- | 8 | drivers/firmware/arm_scmi/driver.c | 1 + |
8 | 1 file changed, 65 insertions(+), 1 deletion(-) | 9 | drivers/firmware/arm_scmi/smc.c | 30 +++++++++++++++++++++++++++++- |
10 | 2 files changed, 30 insertions(+), 1 deletion(-) | ||
9 | 11 | ||
12 | diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/drivers/firmware/arm_scmi/driver.c | ||
15 | +++ b/drivers/firmware/arm_scmi/driver.c | ||
16 | @@ -XXX,XX +XXX,XX @@ static const struct of_device_id scmi_of_match[] = { | ||
17 | #endif | ||
18 | #ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC | ||
19 | { .compatible = "arm,scmi-smc", .data = &scmi_smc_desc}, | ||
20 | + { .compatible = "arm,scmi-smc-param", .data = &scmi_smc_desc}, | ||
21 | #endif | ||
22 | #ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO | ||
23 | { .compatible = "arm,scmi-virtio", .data = &scmi_virtio_desc}, | ||
10 | diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c | 24 | diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c |
11 | index XXXXXXX..XXXXXXX 100644 | 25 | index XXXXXXX..XXXXXXX 100644 |
12 | --- a/drivers/firmware/arm_scmi/smc.c | 26 | --- a/drivers/firmware/arm_scmi/smc.c |
13 | +++ b/drivers/firmware/arm_scmi/smc.c | 27 | +++ b/drivers/firmware/arm_scmi/smc.c |
14 | @@ -XXX,XX +XXX,XX @@ | 28 | @@ -XXX,XX +XXX,XX @@ |
15 | 29 | ||
16 | #include "common.h" | 30 | #include "common.h" |
17 | 31 | ||
18 | +#define MAX_PARAM_COUNT 6 | 32 | +/* |
33 | + * The shmem address is split into 4K page and offset. | ||
34 | + * This is to make sure the parameters fit in 32bit arguments of the | ||
35 | + * smc/hvc call to keep it uniform across smc32/smc64 conventions. | ||
36 | + * This however limits the shmem address to 44 bit. | ||
37 | + * | ||
38 | + * These optional parameters can be used to distinguish among multiple | ||
39 | + * scmi instances that are using the same smc-id. | ||
40 | + * The page parameter is passed in r1/x1/w1 register and the offset parameter | ||
41 | + * is passed in r2/x2/w2 register. | ||
42 | + */ | ||
19 | + | 43 | + |
20 | +/** | 44 | +#define SHMEM_SIZE (SZ_4K) |
21 | + * scmi_smc_param_t - parameter type for SCMI smc/hvc call | 45 | +#define SHMEM_SHIFT 12 |
22 | + */ | 46 | +#define SHMEM_PAGE(x) (_UL((x) >> SHMEM_SHIFT)) |
23 | +typedef union { | 47 | +#define SHMEM_OFFSET(x) ((x) & (SHMEM_SIZE - 1)) |
24 | + u64 x; | ||
25 | + u32 w; | ||
26 | +} scmi_smc_param_t; | ||
27 | + | 48 | + |
28 | /** | 49 | /** |
29 | * struct scmi_smc - Structure representing a SCMI smc transport | 50 | * struct scmi_smc - Structure representing a SCMI smc transport |
30 | * | 51 | * |
31 | @@ -XXX,XX +XXX,XX @@ | 52 | @@ -XXX,XX +XXX,XX @@ |
32 | * @inflight: Atomic flag to protect access to Tx/Rx shared memory area. | 53 | * @inflight: Atomic flag to protect access to Tx/Rx shared memory area. |
33 | * Used when operating in atomic mode. | 54 | * Used when operating in atomic mode. |
34 | * @func_id: smc/hvc call function id | 55 | * @func_id: smc/hvc call function id |
35 | + * @is_smc64: A flag, indicating smc64 calling convention. | 56 | + * @param_page: 4K page number of the shmem channel |
36 | + * @params: Optional, smc/hvc call parameters. | 57 | + * @param_offset: Offset within the 4K page of the shmem channel |
37 | */ | 58 | */ |
38 | 59 | ||
39 | struct scmi_smc { | 60 | struct scmi_smc { |
40 | @@ -XXX,XX +XXX,XX @@ struct scmi_smc { | 61 | @@ -XXX,XX +XXX,XX @@ struct scmi_smc { |
41 | #define INFLIGHT_NONE MSG_TOKEN_MAX | 62 | #define INFLIGHT_NONE MSG_TOKEN_MAX |
42 | atomic_t inflight; | 63 | atomic_t inflight; |
43 | u32 func_id; | 64 | u32 func_id; |
44 | + bool is_smc64; | 65 | + u32 param_page; |
45 | + scmi_smc_param_t params[MAX_PARAM_COUNT]; | 66 | + u32 param_offset; |
46 | }; | 67 | }; |
47 | 68 | ||
48 | +static void populate_smc_params(struct device *dev, struct scmi_smc *scmi_info) | 69 | static irqreturn_t smc_msg_done_isr(int irq, void *data) |
49 | +{ | 70 | @@ -XXX,XX +XXX,XX @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, |
50 | + struct device_node *np = dev->of_node; | 71 | if (ret < 0) |
51 | + u64 params64[MAX_PARAM_COUNT] = { 0 }; | 72 | return ret; |
52 | + u32 params32[MAX_PARAM_COUNT] = { 0 }; | 73 | |
53 | + int i, count; | 74 | + if (of_device_is_compatible(dev->of_node, "arm,scmi-smc-param")) { |
54 | + | 75 | + scmi_info->param_page = SHMEM_PAGE(res.start); |
55 | + if (scmi_info->is_smc64) { | 76 | + scmi_info->param_offset = SHMEM_OFFSET(res.start); |
56 | + count = of_property_read_variable_u64_array(np, | ||
57 | + "arm,smc64-params", | ||
58 | + ¶ms64[0], 1, | ||
59 | + MAX_PARAM_COUNT); | ||
60 | + if (count == -EINVAL) /* if property is not defined */ | ||
61 | + return; | ||
62 | + | ||
63 | + if (count > 0) /* populate the parameters */ | ||
64 | + for (i = 0; i < count; i++) | ||
65 | + scmi_info->params[i].x = params64[i]; | ||
66 | + else | ||
67 | + goto param_err; | ||
68 | + } else { | ||
69 | + count = of_property_read_variable_u32_array(np, | ||
70 | + "arm,smc32-params", | ||
71 | + ¶ms32[0], 1, | ||
72 | + MAX_PARAM_COUNT); | ||
73 | + if (count == -EINVAL) /* if property is not defined */ | ||
74 | + return; | ||
75 | + | ||
76 | + if (count > 0) /* populate the parameters */ | ||
77 | + for (i = 0; i < count; i++) | ||
78 | + scmi_info->params[i].w = params32[i]; | ||
79 | + else | ||
80 | + goto param_err; | ||
81 | + } | 77 | + } |
82 | + | 78 | /* |
83 | + return; | 79 | * If there is an interrupt named "a2p", then the service and |
84 | + | 80 | * completion of a message is signaled by an interrupt rather than by |
85 | +param_err: | ||
86 | + dev_warn(dev, "failed to read smc/hvc call parameters\n"); | ||
87 | +} | ||
88 | + | ||
89 | static irqreturn_t smc_msg_done_isr(int irq, void *data) | ||
90 | { | ||
91 | struct scmi_smc *scmi_info = data; | ||
92 | @@ -XXX,XX +XXX,XX @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, | ||
93 | } | ||
94 | |||
95 | scmi_info->func_id = func_id; | ||
96 | + scmi_info->is_smc64 = ARM_SMCCC_IS_64(func_id); | ||
97 | + populate_smc_params(dev, scmi_info); | ||
98 | scmi_info->cinfo = cinfo; | ||
99 | smc_channel_lock_init(scmi_info); | ||
100 | cinfo->transport_info = scmi_info; | ||
101 | @@ -XXX,XX +XXX,XX @@ static int smc_send_message(struct scmi_chan_info *cinfo, | 81 | @@ -XXX,XX +XXX,XX @@ static int smc_send_message(struct scmi_chan_info *cinfo, |
102 | { | 82 | { |
103 | struct scmi_smc *scmi_info = cinfo->transport_info; | 83 | struct scmi_smc *scmi_info = cinfo->transport_info; |
104 | struct arm_smccc_res res; | 84 | struct arm_smccc_res res; |
105 | + scmi_smc_param_t *p = scmi_info->params; | 85 | + unsigned long page = scmi_info->param_page; |
86 | + unsigned long offset = scmi_info->param_offset; | ||
106 | 87 | ||
107 | /* | 88 | /* |
108 | * Channel will be released only once response has been | 89 | * Channel will be released only once response has been |
109 | @@ -XXX,XX +XXX,XX @@ static int smc_send_message(struct scmi_chan_info *cinfo, | 90 | @@ -XXX,XX +XXX,XX @@ static int smc_send_message(struct scmi_chan_info *cinfo, |
110 | 91 | ||
111 | shmem_tx_prepare(scmi_info->shmem, xfer, cinfo); | 92 | shmem_tx_prepare(scmi_info->shmem, xfer, cinfo); |
112 | 93 | ||
113 | - arm_smccc_1_1_invoke(scmi_info->func_id, 0, 0, 0, 0, 0, 0, 0, &res); | 94 | - arm_smccc_1_1_invoke(scmi_info->func_id, 0, 0, 0, 0, 0, 0, 0, &res); |
114 | + if (scmi_info->is_smc64) | 95 | + arm_smccc_1_1_invoke(scmi_info->func_id, page, offset, 0, 0, 0, 0, 0, |
115 | + arm_smccc_1_1_invoke(scmi_info->func_id, p[0].x, p[1].x, p[2].x, | 96 | + &res); |
116 | + p[3].x, p[4].x, p[5].x, 0, &res); | ||
117 | + else | ||
118 | + arm_smccc_1_1_invoke(scmi_info->func_id, p[0].w, p[1].w, p[2].w, | ||
119 | + p[3].w, p[4].w, p[5].w, 0, &res); | ||
120 | + | ||
121 | 97 | ||
122 | /* Only SMCCC_RET_NOT_SUPPORTED is valid error code */ | 98 | /* Only SMCCC_RET_NOT_SUPPORTED is valid error code */ |
123 | if (res.a0) { | 99 | if (res.a0) { |
124 | -- | 100 | -- |
125 | 2.17.1 | 101 | 2.17.1 | diff view generated by jsdifflib |