1
0
mirror of https://git.yoctoproject.org/meta-arm synced 2026-06-04 14:10:01 +00:00

arm: update Android common kernel

Update ACK to 5.10 and remove the 5.4 recipe

Change-Id: I7a0cc0bc95d02bed965530d36aedaf544045fee4
Signed-off-by: Anders Dellien <anders.dellien@arm.com>
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Signed-off-by: Jon Mason <jon.mason@arm.com>
This commit is contained in:
Anders Dellien
2021-07-22 12:32:45 +01:00
committed by Jon Mason
parent 2f5216c45f
commit 7612faf780
32 changed files with 1802 additions and 7495 deletions
+1 -1
View File
@@ -30,7 +30,7 @@ PREFERRED_PROVIDER_virtual/trusted-firmware-a ?= "trusted-firmware-a"
PREFERRED_VERSION_trusted-firmware-a ?= "2.5%"
PREFERRED_PROVIDER_virtual/kernel ?= "linux-arm64-ack"
PREFERRED_VERSION_linux-arm64-ack ?= "5.4"
PREFERRED_VERSION_linux-arm64-ack ?= "5.10"
# Cannot use the default zImage on arm64
KERNEL_IMAGETYPE = "Image"
@@ -79,19 +79,12 @@ SRC_URI_append_tc0 = " \
file://defconfig \
file://0001-drm-Add-component-aware-simple-encoder.patch \
file://0002-drm-arm-komeda-add-RENDER-capability-to-the-device-n.patch \
file://0003-mailbox-arm_mhuv2-add-device-tree-binding-documentat.patch \
file://0004-mailbox-arm_mhuv2-add-arm-mhuv2-driver.patch \
file://0005-mailbox-arm_mhuv2-add-doorbell-transport-protocol-op.patch \
file://0006-mailbox-arm_mhuv2-add-multi-word-transport-protocol-.patch \
file://0007-firmware-arm_scmi-Add-fast_switch_possible-api.patch \
file://0008-cpufreq-arm_scmi-Set-fast_switch_possible-conditiona.patch \
file://0009-driver-firmware-Initial-version-of-ffa-driver-based-.patch \
file://0010-tee-add-support-for-session-s-client-UUID-generation.patch \
file://0011-tee-optee-Add-support-for-session-login-client-UUID-.patch \
file://0012-driver-optee-Support-for-ffa-transport.patch \
file://0013-tee-optee-fix-mem-handle-removal-in-ffa_shm_unregist.patch \
file://0014-arm64-Add-support-for-asymmetric-AArch32-EL0-configu.patch \
file://0015-arm64-smp-Prevent-hotplugging-the-last-AArch32-able-.patch \
file://0003-Adapt-ION-interface-to-match-Android.patch \
file://0004-dt-bindings-mailbox-arm-mhuv2-Add-bindings.patch \
file://0005-mailbox-arm_mhuv2-Add-driver.patch \
file://0006-mailbox-arm_mhuv2-Fix-sparse-warnings.patch \
file://0007-mailbox-arm_mhuv2-make-remove-callback-return-void.patch \
file://0008-mailbox-arm_mhuv2-Skip-calling-kfree-with-invalid-po.patch \
"
#
@@ -1,7 +1,7 @@
From 7863ac1515009547bae3a66e0808e72b3bdcf8c8 Mon Sep 17 00:00:00 2001
From 9080fb7fc011445d4d6ee164d02d86ff6df0822a Mon Sep 17 00:00:00 2001
From: Tushar Khandelwal <tushar.khandelwal@arm.com>
Date: Tue, 16 Jun 2020 12:39:06 +0000
Subject: [PATCH 1/9] drm: Add component-aware simple encoder
Subject: [PATCH 01/10] drm: Add component-aware simple encoder
This is a simple DRM encoder that gets its connector timings information
from a OF subnode in the device tree and exposes that as a "discovered"
@@ -12,6 +12,7 @@ and the display output is configured outside the kernel.
Signed-off-by: Tushar Khandelwal <tushar.khandelwal@arm.com>
Upstream-Status: Backport [https://git.linaro.org/landing-teams/working/arm/kernel-release.git/commit/?h=latest-armlt&id=15283f7be4b1e586702551e85b4caf06531ac2fc]
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
---
drivers/gpu/drm/Kconfig | 11 +
drivers/gpu/drm/Makefile | 2 +
@@ -20,10 +21,10 @@ Upstream-Status: Backport [https://git.linaro.org/landing-teams/working/arm/kern
create mode 100644 drivers/gpu/drm/drm_virtual_encoder.c
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index e67c194c2aca..c95279cd9341 100644
index ca868271f4c4..6ae8ba3ca7b3 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -265,6 +265,17 @@ config DRM_VKMS
@@ -300,6 +300,17 @@ config DRM_VKMS
If M is selected the module will be called vkms.
@@ -38,14 +39,14 @@ index e67c194c2aca..c95279cd9341 100644
+ drm_vencoder.
+
+
config DRM_ATI_PCIGART
bool
source "drivers/gpu/drm/exynos/Kconfig"
source "drivers/gpu/drm/rockchip/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 82ff826b33cc..d2ab6fc64932 100644
index 81569009f884..a3429152c613 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -53,6 +53,8 @@ drm_kms_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o
@@ -56,6 +56,8 @@ drm_kms_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o
obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/
@@ -56,7 +57,7 @@ index 82ff826b33cc..d2ab6fc64932 100644
obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o
diff --git a/drivers/gpu/drm/drm_virtual_encoder.c b/drivers/gpu/drm/drm_virtual_encoder.c
new file mode 100644
index 000000000000..4fd2098df286
index 000000000000..2f65c6b47d00
--- /dev/null
+++ b/drivers/gpu/drm/drm_virtual_encoder.c
@@ -0,0 +1,299 @@
@@ -250,7 +251,7 @@ index 000000000000..4fd2098df286
+ crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+ bridge = of_drm_find_bridge(dev->of_node);
+ if (bridge) {
+ ret = drm_bridge_attach(encoder, bridge, NULL);
+ ret = drm_bridge_attach(encoder, bridge, NULL, 0);
+ if (ret) {
+ DRM_ERROR("Failed to initialize bridge\n");
+ return ret;
@@ -1,7 +1,7 @@
From 190c6354a0d80c31214550553cfbee25571e1942 Mon Sep 17 00:00:00 2001
From 7a0e6189c7b104a679bc7b91465425e2de909456 Mon Sep 17 00:00:00 2001
From: Tushar Khandelwal <tushar.khandelwal@arm.com>
Date: Wed, 17 Jun 2020 10:49:26 +0000
Subject: [PATCH 2/9] drm: arm: komeda: add RENDER capability to the device
Subject: [PATCH 02/10] drm: arm: komeda: add RENDER capability to the device
node
this is required to make this driver work with android framework
@@ -9,23 +9,24 @@ this is required to make this driver work with android framework
Signed-off-by: Tushar Khandelwal <tushar.khandelwal@arm.com>
Upstream-Status: Inappropriate [Product specific configuration]
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
---
drivers/gpu/drm/arm/display/komeda/komeda_kms.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
index ae274902ff92..238bd8466206 100644
index 1f6682032ca4..9d1a1942e673 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
@@ -56,7 +56,7 @@ static irqreturn_t komeda_kms_irq_handler(int irq, void *data)
@@ -59,7 +59,7 @@ static irqreturn_t komeda_kms_irq_handler(int irq, void *data)
}
static struct drm_driver komeda_kms_driver = {
- .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
+ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_RENDER,
.lastclose = drm_fb_helper_lastclose,
.gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(komeda_gem_cma_dumb_create),
.fops = &komeda_cma_fops,
--
2.17.1
@@ -0,0 +1,33 @@
From b98c6070320ad31318a028482f026d6a5eddce5b Mon Sep 17 00:00:00 2001
From: Anders Dellien <anders.dellien@arm.com>
Date: Fri, 29 Jan 2021 09:44:38 +0000
Subject: [PATCH 03/10] Adapt ION interface to match Android
Change-Id: I62b69cc357868f725170899c862530b8f3069666
Signed-off-by: Anders Dellien <anders.dellien@arm.com>
Upstream-Status: Inappropriate [Product specific configuration]
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
---
include/uapi/linux/ion.h | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/include/uapi/linux/ion.h b/include/uapi/linux/ion.h
index 371e44662755..7022ea223736 100644
--- a/include/uapi/linux/ion.h
+++ b/include/uapi/linux/ion.h
@@ -24,7 +24,10 @@
*/
enum ion_heap_type {
ION_HEAP_TYPE_SYSTEM = 0,
- ION_HEAP_TYPE_DMA = 2,
+ ION_HEAP_TYPE_SYSTEM_CONTIG = 1,
+ ION_HEAP_TYPE_CARVEOUT = 2,
+ ION_HEAP_TYPE_CHUNK = 3,
+ ION_HEAP_TYPE_DMA = 4,
/* reserved range for future standard heap types */
ION_HEAP_TYPE_CUSTOM = 16,
ION_HEAP_TYPE_MAX = 31,
--
2.17.1
@@ -0,0 +1,241 @@
From 4cafac5cd54c7f5069a4d6e17bdbd8f94cd5fa0b Mon Sep 17 00:00:00 2001
From: Viresh Kumar <viresh.kumar@linaro.org>
Date: Tue, 17 Nov 2020 15:32:05 +0530
Subject: [PATCH 04/10] dt-bindings: mailbox : arm,mhuv2: Add bindings
This patch adds device tree binding for ARM Message Handling Unit (MHU)
controller version 2.
Based on earlier work by Morten Borup Petersen.
Reviewed-by: Rob Herring <robh@kernel.org>
Co-developed-by: Tushar Khandelwal <tushar.khandelwal@arm.com>
Signed-off-by: Tushar Khandelwal <tushar.khandelwal@arm.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
Upstream-Status: Backport [https://lkml.org/lkml/2020/11/17/234]
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
---
.../bindings/mailbox/arm,mhuv2.yaml | 209 ++++++++++++++++++
1 file changed, 209 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mailbox/arm,mhuv2.yaml
diff --git a/Documentation/devicetree/bindings/mailbox/arm,mhuv2.yaml b/Documentation/devicetree/bindings/mailbox/arm,mhuv2.yaml
new file mode 100644
index 000000000000..6608545ea66f
--- /dev/null
+++ b/Documentation/devicetree/bindings/mailbox/arm,mhuv2.yaml
@@ -0,0 +1,209 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mailbox/arm,mhuv2.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ARM MHUv2 Mailbox Controller
+
+maintainers:
+ - Tushar Khandelwal <tushar.khandelwal@arm.com>
+ - Viresh Kumar <viresh.kumar@linaro.org>
+
+description: |
+ The Arm Message Handling Unit (MHU) Version 2 is a mailbox controller that has
+ between 1 and 124 channel windows (each 32-bit wide) to provide unidirectional
+ communication with remote processor(s), where the number of channel windows
+ are implementation dependent.
+
+ Given the unidirectional nature of the controller, an MHUv2 mailbox may only
+ be written to or read from. If a pair of MHU controllers is implemented
+ between two processing elements to provide bidirectional communication, these
+ must be specified as two separate mailboxes.
+
+ If the interrupts property is present in device tree node, then its treated as
+ a "receiver" mailbox, otherwise a "sender".
+
+ An MHU controller must be specified along with the supported transport
+ protocols. The transport protocols determine the method of data transmission
+ as well as the number of provided mailbox channels.
+
+ Following are the possible transport protocols.
+
+ - Data-transfer: Each transfer is made of one or more words, using one or more
+ channel windows.
+
+ - Doorbell: Each transfer is made up of single bit flag, using any one of the
+ bits in a channel window. A channel window can support up to 32 doorbells
+ and the entire window shall be used in doorbell protocol. Optionally, data
+ may be transmitted through a shared memory region, wherein the MHU is used
+ strictly as an interrupt generation mechanism but that is out of the scope
+ of these bindings.
+
+# We need a select here so we don't match all nodes with 'arm,primecell'
+select:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - arm,mhuv2-tx
+ - arm,mhuv2-rx
+ required:
+ - compatible
+
+properties:
+ compatible:
+ oneOf:
+ - description: Sender mode
+ items:
+ - const: arm,mhuv2-tx
+ - const: arm,primecell
+
+ - description: Receiver-mode
+ items:
+ - const: arm,mhuv2-rx
+ - const: arm,primecell
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ description: |
+ The MHUv2 controller always implements an interrupt in the "receiver"
+ mode, while the interrupt in the "sender" mode was not available in the
+ version MHUv2.0, but the later versions do have it.
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ maxItems: 1
+
+ arm,mhuv2-protocols:
+ $ref: /schemas/types.yaml#/definitions/uint32-matrix
+ description: |
+ The MHUv2 controller may contain up to 124 channel windows (each 32-bit
+ wide). The hardware and the DT bindings allows any combination of those to
+ be used for various transport protocols.
+
+ This property allows a platform to describe how these channel windows are
+ used in various transport protocols. The entries in this property shall be
+ present as an array of tuples, where each tuple describes details about
+ one of the transport protocol being implemented over some channel
+ window(s).
+
+ The first field of a tuple signifies the transfer protocol, 0 is reserved
+ for doorbell protocol, and 1 is reserved for data-transfer protocol.
+ Using any other value in the first field of a tuple makes it invalid.
+
+ The second field of a tuple signifies the number of channel windows where
+ the protocol would be used and should be set to a non zero value. For
+ doorbell protocol this field signifies the number of 32-bit channel
+ windows that implement the doorbell protocol. For data-transfer protocol,
+ this field signifies the number of 32-bit channel windows that implement
+ the data-transfer protocol.
+
+ The total number of channel windows specified here shouldn't be more than
+ the ones implemented by the platform, though one can specify lesser number
+ of windows here than what the platform implements.
+
+ mhu: mailbox@2b1f0000 {
+ ...
+
+ arm,mhuv2-protocols = <0 2>, <1 1>, <1 5>, <1 7>;
+ }
+
+ The above example defines the protocols of an ARM MHUv2 mailbox
+ controller, where a total of 15 channel windows are used. The first two
+ windows are used in doorbell protocol (64 doorbells), followed by 1, 5 and
+ 7 windows (separately) used in data-transfer protocol.
+
+ minItems: 1
+ maxItems: 124
+ items:
+ items:
+ - enum: [ 0, 1 ]
+ - minimum: 0
+ maximum: 124
+
+
+ '#mbox-cells':
+ description: |
+ It is always set to 2. The first argument in the consumers 'mboxes'
+ property represents the channel window group, which may be used in
+ doorbell, or data-transfer protocol, and the second argument (only
+ relevant in doorbell protocol, should be 0 otherwise) represents the
+ doorbell number within the 32 bit wide channel window.
+
+ From the example given above for arm,mhuv2-protocols, here is how a client
+ node can reference them.
+
+ mboxes = <&mhu 0 5>; // Channel Window Group 0, doorbell 5.
+ mboxes = <&mhu 1 7>; // Channel Window Group 1, doorbell 7.
+ mboxes = <&mhu 2 0>; // Channel Window Group 2, data transfer protocol with 1 window.
+ mboxes = <&mhu 3 0>; // Channel Window Group 3, data transfer protocol with 5 windows.
+ mboxes = <&mhu 4 0>; // Channel Window Group 4, data transfer protocol with 7 windows.
+
+ const: 2
+
+if:
+ # Interrupt is compulsory for receiver
+ properties:
+ compatible:
+ contains:
+ const: arm,mhuv2-rx
+then:
+ required:
+ - interrupts
+
+required:
+ - compatible
+ - reg
+ - '#mbox-cells'
+ - arm,mhuv2-protocols
+
+additionalProperties: false
+
+examples:
+ # Multiple transport protocols implemented by the mailbox controllers
+ - |
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ mhu_tx: mailbox@2b1f0000 {
+ #mbox-cells = <2>;
+ compatible = "arm,mhuv2-tx", "arm,primecell";
+ reg = <0 0x2b1f0000 0 0x1000>;
+ clocks = <&clock 0>;
+ clock-names = "apb_pclk";
+ interrupts = <0 45 4>;
+ arm,mhuv2-protocols = <1 5>, <1 2>, <1 5>, <1 7>, <0 2>;
+ };
+
+ mhu_rx: mailbox@2b1f1000 {
+ #mbox-cells = <2>;
+ compatible = "arm,mhuv2-rx", "arm,primecell";
+ reg = <0 0x2b1f1000 0 0x1000>;
+ clocks = <&clock 0>;
+ clock-names = "apb_pclk";
+ interrupts = <0 46 4>;
+ arm,mhuv2-protocols = <1 1>, <1 7>, <0 2>;
+ };
+
+ mhu_client: scb@2e000000 {
+ compatible = "fujitsu,mb86s70-scb-1.0";
+ reg = <0 0x2e000000 0 0x4000>;
+
+ mboxes =
+ //data-transfer protocol with 5 windows, mhu-tx
+ <&mhu_tx 2 0>,
+ //data-transfer protocol with 7 windows, mhu-tx
+ <&mhu_tx 3 0>,
+ //doorbell protocol channel 4, doorbell 27, mhu-tx
+ <&mhu_tx 4 27>,
+ //data-transfer protocol with 1 window, mhu-rx
+ <&mhu_rx 0 0>;
+ };
+ };
--
2.17.1
@@ -0,0 +1,114 @@
From f082677cb35ea843e749e1c9e5a9b9fba44c5d48 Mon Sep 17 00:00:00 2001
From: Viresh Kumar <viresh.kumar@linaro.org>
Date: Wed, 30 Dec 2020 10:12:04 +0530
Subject: [PATCH 06/10] mailbox: arm_mhuv2: Fix sparse warnings
This patch fixes a bunch of sparse warnings in the newly added arm_mhuv2
driver.
drivers/mailbox/arm_mhuv2.c:506:24: warning: incorrect type in argument 1 (different address spaces)
drivers/mailbox/arm_mhuv2.c:506:24: expected void const volatile [noderef] __iomem *addr
drivers/mailbox/arm_mhuv2.c:506:24: got unsigned int [usertype] *
drivers/mailbox/arm_mhuv2.c:547:42: warning: incorrect type in argument 2 (different address spaces)
drivers/mailbox/arm_mhuv2.c:547:42: expected unsigned int [usertype] *reg
drivers/mailbox/arm_mhuv2.c:547:42: got unsigned int [noderef] __iomem *
drivers/mailbox/arm_mhuv2.c:625:42: warning: incorrect type in argument 2 (different address spaces)
drivers/mailbox/arm_mhuv2.c:625:42: expected unsigned int [usertype] *reg
drivers/mailbox/arm_mhuv2.c:625:42: got unsigned int [noderef] __iomem *
drivers/mailbox/arm_mhuv2.c:972:24: warning: dereference of noderef expression
drivers/mailbox/arm_mhuv2.c:973:22: warning: dereference of noderef expression
drivers/mailbox/arm_mhuv2.c:993:25: warning: dereference of noderef expression
drivers/mailbox/arm_mhuv2.c:1026:24: warning: dereference of noderef expression
drivers/mailbox/arm_mhuv2.c:1027:22: warning: dereference of noderef expression
drivers/mailbox/arm_mhuv2.c:1048:17: warning: dereference of noderef expression
Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
Upstream-Status: Backport [https://lkml.org/lkml/2021/2/9/428]
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
---
drivers/mailbox/arm_mhuv2.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/mailbox/arm_mhuv2.c b/drivers/mailbox/arm_mhuv2.c
index 67fb10885bb4..8223c1005254 100644
--- a/drivers/mailbox/arm_mhuv2.c
+++ b/drivers/mailbox/arm_mhuv2.c
@@ -238,19 +238,19 @@ struct mhuv2_mbox_chan_priv {
};
/* Macro for reading a bitfield within a physically mapped packed struct */
-#define readl_relaxed_bitfield(_regptr, _field) \
+#define readl_relaxed_bitfield(_regptr, _type, _field) \
({ \
u32 _regval; \
_regval = readl_relaxed((_regptr)); \
- (*(typeof((_regptr)))(&_regval))._field; \
+ (*(_type *)(&_regval))._field; \
})
/* Macro for writing a bitfield within a physically mapped packed struct */
-#define writel_relaxed_bitfield(_value, _regptr, _field) \
+#define writel_relaxed_bitfield(_value, _regptr, _type, _field) \
({ \
u32 _regval; \
_regval = readl_relaxed(_regptr); \
- (*(typeof(_regptr))(&_regval))._field = _value; \
+ (*(_type *)(&_regval))._field = _value; \
writel_relaxed(_regval, _regptr); \
})
@@ -496,7 +496,7 @@ static const struct mhuv2_protocol_ops mhuv2_data_transfer_ops = {
/* Interrupt handlers */
-static struct mbox_chan *get_irq_chan_comb(struct mhuv2 *mhu, u32 *reg)
+static struct mbox_chan *get_irq_chan_comb(struct mhuv2 *mhu, u32 __iomem *reg)
{
struct mbox_chan *chans = mhu->mbox.chans;
int channel = 0, i, offset = 0, windows, protocol, ch_wn;
@@ -969,8 +969,8 @@ static int mhuv2_tx_init(struct amba_device *adev, struct mhuv2 *mhu,
mhu->mbox.ops = &mhuv2_sender_ops;
mhu->send = reg;
- mhu->windows = readl_relaxed_bitfield(&mhu->send->mhu_cfg, num_ch);
- mhu->minor = readl_relaxed_bitfield(&mhu->send->aidr, arch_minor_rev);
+ mhu->windows = readl_relaxed_bitfield(&mhu->send->mhu_cfg, struct mhu_cfg_t, num_ch);
+ mhu->minor = readl_relaxed_bitfield(&mhu->send->aidr, struct aidr_t, arch_minor_rev);
spin_lock_init(&mhu->doorbell_pending_lock);
@@ -990,7 +990,7 @@ static int mhuv2_tx_init(struct amba_device *adev, struct mhuv2 *mhu,
mhu->mbox.txdone_poll = false;
mhu->irq = adev->irq[0];
- writel_relaxed_bitfield(1, &mhu->send->int_en, chcomb);
+ writel_relaxed_bitfield(1, &mhu->send->int_en, struct int_en_t, chcomb);
/* Disable all channel interrupts */
for (i = 0; i < mhu->windows; i++)
@@ -1023,8 +1023,8 @@ static int mhuv2_rx_init(struct amba_device *adev, struct mhuv2 *mhu,
mhu->mbox.ops = &mhuv2_receiver_ops;
mhu->recv = reg;
- mhu->windows = readl_relaxed_bitfield(&mhu->recv->mhu_cfg, num_ch);
- mhu->minor = readl_relaxed_bitfield(&mhu->recv->aidr, arch_minor_rev);
+ mhu->windows = readl_relaxed_bitfield(&mhu->recv->mhu_cfg, struct mhu_cfg_t, num_ch);
+ mhu->minor = readl_relaxed_bitfield(&mhu->recv->aidr, struct aidr_t, arch_minor_rev);
mhu->irq = adev->irq[0];
if (!mhu->irq) {
@@ -1045,7 +1045,7 @@ static int mhuv2_rx_init(struct amba_device *adev, struct mhuv2 *mhu,
writel_relaxed(0xFFFFFFFF, &mhu->recv->ch_wn[i].mask_set);
if (mhu->minor)
- writel_relaxed_bitfield(1, &mhu->recv->int_en, chcomb);
+ writel_relaxed_bitfield(1, &mhu->recv->int_en, struct int_en_t, chcomb);
return 0;
}
--
2.17.1
@@ -0,0 +1,47 @@
From a0e07a4d72dfe8892ebcfb29c0a1007c35eebd66 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
Date: Tue, 2 Feb 2021 20:43:08 +0100
Subject: [PATCH 07/10] mailbox: arm_mhuv2: make remove callback return void
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
My build tests failed to catch that amba driver that would have needed
adaption in commit 3fd269e74f2f ("amba: Make the remove callback return
void"). Change the remove function to make the driver build again.
Reported-by: kernel test robot <lkp@intel.com>
Fixes: 3fd269e74f2f ("amba: Make the remove callback return void")
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
Upstream-Status: Backport [https://lkml.org/lkml/2021/2/2/1525]
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
---
drivers/mailbox/arm_mhuv2.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/mailbox/arm_mhuv2.c b/drivers/mailbox/arm_mhuv2.c
index 8223c1005254..cdfb1939fabf 100644
--- a/drivers/mailbox/arm_mhuv2.c
+++ b/drivers/mailbox/arm_mhuv2.c
@@ -1095,14 +1095,12 @@ static int mhuv2_probe(struct amba_device *adev, const struct amba_id *id)
return ret;
}
-static int mhuv2_remove(struct amba_device *adev)
+static void mhuv2_remove(struct amba_device *adev)
{
struct mhuv2 *mhu = amba_get_drvdata(adev);
if (mhu->frame == SENDER_FRAME)
writel_relaxed(0x0, &mhu->send->access_request);
-
- return 0;
}
static struct amba_id mhuv2_ids[] = {
--
2.17.1
@@ -0,0 +1,41 @@
From c55091b7738802c503b1ce4276ee85d601604506 Mon Sep 17 00:00:00 2001
From: Viresh Kumar <viresh.kumar@linaro.org>
Date: Mon, 22 Feb 2021 12:48:06 +0530
Subject: [PATCH 08/10] mailbox: arm_mhuv2: Skip calling kfree() with invalid
pointer
It is possible that 'data' passed to kfree() is set to a error value
instead of allocated space. Make sure it doesn't get called with invalid
pointer.
Fixes: 5a6338cce9f4 ("mailbox: arm_mhuv2: Add driver")
Cc: v5.11 <stable@vger.kernel.org> # v5.11
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
Upstream-Status: Backport [https://lkml.org/lkml/2021/2/22/57]
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
---
drivers/mailbox/arm_mhuv2.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/mailbox/arm_mhuv2.c b/drivers/mailbox/arm_mhuv2.c
index cdfb1939fabf..d997f8ebfa98 100644
--- a/drivers/mailbox/arm_mhuv2.c
+++ b/drivers/mailbox/arm_mhuv2.c
@@ -699,7 +699,9 @@ static irqreturn_t mhuv2_receiver_interrupt(int irq, void *arg)
ret = IRQ_HANDLED;
}
- kfree(data);
+ if (!IS_ERR(data))
+ kfree(data);
+
return ret;
}
--
2.17.1
@@ -2,7 +2,6 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_AUDIT=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_ASYMMETRIC_AARCH32=y
CONFIG_PREEMPT=y
CONFIG_IRQ_TIME_ACCOUNTING=y
CONFIG_BSD_PROCESS_ACCT=y
@@ -67,7 +66,6 @@ CONFIG_ARCH_ZYNQMP=y
CONFIG_ARM64_VA_BITS_48=y
CONFIG_SCHED_MC=y
CONFIG_NUMA=y
CONFIG_SECCOMP=y
CONFIG_KEXEC=y
CONFIG_CRASH_DUMP=y
CONFIG_XEN=y
@@ -86,7 +84,6 @@ CONFIG_ARM_CPUIDLE=y
CONFIG_ARM_PSCI_CPUIDLE=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_STAT=y
CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=m
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
@@ -113,10 +110,10 @@ CONFIG_IMX_SCU_PD=y
CONFIG_ACPI=y
CONFIG_ACPI_APEI=y
CONFIG_ACPI_APEI_GHES=y
CONFIG_ACPI_APEI_PCIEAER=y
CONFIG_ACPI_APEI_MEMORY_FAILURE=y
CONFIG_ACPI_APEI_EINJ=y
CONFIG_VIRTUALIZATION=y
CONFIG_KVM=y
CONFIG_ARM64_CRYPTO=y
CONFIG_CRYPTO_SHA1_ARM64_CE=y
CONFIG_CRYPTO_SHA2_ARM64_CE=y
@@ -242,7 +239,6 @@ CONFIG_QRTR_TUN=m
CONFIG_BPF_JIT=y
CONFIG_BT=m
CONFIG_BT_HIDP=m
# CONFIG_BT_HS is not set
# CONFIG_BT_LE is not set
CONFIG_BT_LEDS=y
# CONFIG_BT_DEBUGFS is not set
@@ -278,7 +274,6 @@ CONFIG_PCIE_QCOM=y
CONFIG_PCIE_ARMADA_8K=y
CONFIG_PCIE_KIRIN=y
CONFIG_PCIE_HISI_STB=y
CONFIG_PCIE_TEGRA194=m
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_FW_LOADER_USER_HELPER=y
@@ -287,12 +282,12 @@ CONFIG_HISILICON_LPC=y
CONFIG_SIMPLE_PM_BUS=y
CONFIG_MTD=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_PHRAM=y
CONFIG_MTD_RAW_NAND=y
CONFIG_MTD_NAND_DENALI_DT=y
CONFIG_MTD_NAND_MARVELL=y
CONFIG_MTD_NAND_QCOM=y
CONFIG_MTD_SPI_NOR=y
CONFIG_SPI_CADENCE_QUADSPI=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=y
@@ -367,14 +362,14 @@ CONFIG_SMSC911X=y
CONFIG_SNI_AVE=y
CONFIG_SNI_NETSEC=y
CONFIG_STMMAC_ETH=m
CONFIG_MDIO_BUS_MUX_MMIOREG=y
CONFIG_AT803X_PHY=y
CONFIG_MESON_GXL_PHY=m
CONFIG_MARVELL_PHY=m
CONFIG_MARVELL_10G_PHY=m
CONFIG_MESON_GXL_PHY=m
CONFIG_MICREL_PHY=y
CONFIG_AT803X_PHY=y
CONFIG_REALTEK_PHY=m
CONFIG_ROCKCHIP_PHY=y
CONFIG_MDIO_BUS_MUX_MMIOREG=y
CONFIG_PPP=y
CONFIG_PPP_BSDCOMP=y
CONFIG_PPP_DEFLATE=y
@@ -403,7 +398,6 @@ CONFIG_INPUT_EVDEV=y
CONFIG_KEYBOARD_ADC=m
CONFIG_KEYBOARD_GPIO=y
CONFIG_KEYBOARD_SNVS_PWRKEY=m
CONFIG_KEYBOARD_CROS_EC=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ATMEL_MXT=m
CONFIG_INPUT_MISC=y
@@ -470,11 +464,11 @@ CONFIG_I2C_SH_MOBILE=y
CONFIG_I2C_TEGRA=y
CONFIG_I2C_UNIPHIER_F=y
CONFIG_I2C_RCAR=y
CONFIG_I2C_CROS_EC_TUNNEL=y
CONFIG_SPI=y
CONFIG_SPI_ARMADA_3700=y
CONFIG_SPI_BCM2835=m
CONFIG_SPI_BCM2835AUX=m
CONFIG_SPI_CADENCE_QUADSPI=y
CONFIG_SPI_NXP_FLEXSPI=y
CONFIG_SPI_IMX=m
CONFIG_SPI_MESON_SPICC=m
@@ -498,16 +492,16 @@ CONFIG_PINCTRL_IMX8MM=y
CONFIG_PINCTRL_IMX8MN=y
CONFIG_PINCTRL_IMX8MQ=y
CONFIG_PINCTRL_IMX8QXP=y
CONFIG_PINCTRL_IPQ8074=y
CONFIG_PINCTRL_MSM8916=y
CONFIG_PINCTRL_MSM8994=y
CONFIG_PINCTRL_MSM8996=y
CONFIG_PINCTRL_MSM8998=y
CONFIG_PINCTRL_QCS404=y
CONFIG_PINCTRL_QDF2XXX=y
CONFIG_PINCTRL_IPQ8074=m
CONFIG_PINCTRL_MSM8916=m
CONFIG_PINCTRL_MSM8994=m
CONFIG_PINCTRL_MSM8996=m
CONFIG_PINCTRL_MSM8998=m
CONFIG_PINCTRL_QCS404=m
CONFIG_PINCTRL_QDF2XXX=m
CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_PINCTRL_SDM845=y
CONFIG_PINCTRL_SM8150=y
CONFIG_PINCTRL_SDM845=m
CONFIG_PINCTRL_SM8150=m
CONFIG_GPIO_ALTERA=m
CONFIG_GPIO_DWAPB=y
CONFIG_GPIO_MB86S7X=y
@@ -520,14 +514,13 @@ CONFIG_GPIO_MAX732X=y
CONFIG_GPIO_PCA953X=y
CONFIG_GPIO_PCA953X_IRQ=y
CONFIG_GPIO_MAX77620=y
CONFIG_POWER_AVS=y
CONFIG_ROCKCHIP_IODOMAIN=y
CONFIG_POWER_RESET_MSM=y
CONFIG_POWER_RESET_XGENE=y
CONFIG_POWER_RESET_SYSCON=y
CONFIG_SYSCON_REBOOT_MODE=y
CONFIG_BATTERY_SBS=m
CONFIG_BATTERY_BQ27XXX=y
CONFIG_SENSORS_ARM_SCMI=y
CONFIG_SENSORS_ARM_SCPI=y
CONFIG_SENSORS_LM90=m
CONFIG_SENSORS_PWM_FAN=m
@@ -586,7 +579,7 @@ CONFIG_REGULATOR_MAX77620=y
CONFIG_REGULATOR_MAX8973=y
CONFIG_REGULATOR_PFUZE100=y
CONFIG_REGULATOR_PWM=y
CONFIG_REGULATOR_QCOM_RPMH=y
CONFIG_REGULATOR_QCOM_RPMH=m
CONFIG_REGULATOR_QCOM_SMD_RPM=y
CONFIG_REGULATOR_QCOM_SPMI=y
CONFIG_REGULATOR_RK808=y
@@ -598,11 +591,7 @@ CONFIG_RC_DEVICES=y
CONFIG_IR_MESON=m
CONFIG_IR_SUNXI=m
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CAMERA_SUPPORT=y
CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
# CONFIG_DVB_NET is not set
CONFIG_MEDIA_USB_SUPPORT=y
CONFIG_USB_VIDEO_CLASS=m
@@ -614,7 +603,6 @@ CONFIG_VIDEO_SAMSUNG_S5P_MFC=m
CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m
CONFIG_VIDEO_RENESAS_FCP=m
CONFIG_VIDEO_RENESAS_VSP1=m
CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
CONFIG_DRM=y
CONFIG_DRM_LOAD_EDID_FIRMWARE=y
CONFIG_DRM_I2C_CH7006=m
@@ -657,7 +645,6 @@ CONFIG_DRM_PANFROST=m
CONFIG_DRM_LEGACY=y
CONFIG_FB_MODE_HELPERS=y
CONFIG_FB_EFI=y
CONFIG_BACKLIGHT_GENERIC=m
CONFIG_BACKLIGHT_PWM=m
CONFIG_BACKLIGHT_LP855X=m
CONFIG_FRAMEBUFFER_CONSOLE=y
@@ -699,7 +686,6 @@ CONFIG_HID_REDRAGON=y
CONFIG_HID_MICROSOFT=y
CONFIG_HID_MONTEREY=y
CONFIG_I2C_HID=m
CONFIG_USB_CONN_GPIO=m
CONFIG_USB=y
CONFIG_USB_OTG=y
CONFIG_USB_XHCI_HCD=y
@@ -775,7 +761,6 @@ CONFIG_RTC_DRV_RX8581=m
CONFIG_RTC_DRV_S5M=y
CONFIG_RTC_DRV_DS3232=y
CONFIG_RTC_DRV_EFI=y
CONFIG_RTC_DRV_CROS_EC=y
CONFIG_RTC_DRV_S3C=y
CONFIG_RTC_DRV_PL031=y
CONFIG_RTC_DRV_SUN6I=y
@@ -811,9 +796,7 @@ CONFIG_STAGING=y
CONFIG_ASHMEM=y
CONFIG_ION=y
CONFIG_ION_SYSTEM_HEAP=y
CONFIG_MFD_CROS_EC=y
CONFIG_CROS_EC_I2C=y
CONFIG_CROS_EC_SPI=y
CONFIG_ION_CMA_HEAP=y
CONFIG_COMMON_CLK_RK808=y
CONFIG_COMMON_CLK_SCMI=y
CONFIG_COMMON_CLK_SCPI=y
@@ -831,7 +814,7 @@ CONFIG_COMMON_CLK_QCOM=y
CONFIG_QCOM_A53PLL=y
CONFIG_QCOM_CLK_APCS_MSM8916=y
CONFIG_QCOM_CLK_SMD_RPM=y
CONFIG_QCOM_CLK_RPMH=y
CONFIG_QCOM_CLK_RPMH=m
CONFIG_IPQ_GCC_8074=y
CONFIG_MSM_GCC_8916=y
CONFIG_MSM_GCC_8994=y
@@ -862,26 +845,24 @@ CONFIG_RPMSG_QCOM_GLINK_SMEM=m
CONFIG_RPMSG_QCOM_SMD=y
CONFIG_OWL_PM_DOMAINS=y
CONFIG_RASPBERRYPI_POWER=y
CONFIG_IMX_SCU_SOC=y
CONFIG_QCOM_AOSS_QMP=y
CONFIG_QCOM_GENI_SE=y
CONFIG_QCOM_GLINK_SSR=m
CONFIG_QCOM_RMTFS_MEM=m
CONFIG_QCOM_RPMH=y
CONFIG_QCOM_RPMHPD=y
CONFIG_QCOM_RPMH=m
CONFIG_QCOM_RPMHPD=m
CONFIG_QCOM_SMEM=y
CONFIG_QCOM_SMD_RPM=y
CONFIG_QCOM_SMP2P=y
CONFIG_QCOM_SMSM=y
CONFIG_QCOM_SOCINFO=m
CONFIG_ARCH_R8A774A1=y
CONFIG_ARCH_R8A774C0=y
CONFIG_ARCH_R8A7795=y
CONFIG_ARCH_R8A77965=y
CONFIG_ARCH_R8A77970=y
CONFIG_ARCH_R8A77980=y
CONFIG_ARCH_R8A77990=y
CONFIG_ARCH_R8A77995=y
CONFIG_ARCH_R8A77990=y
CONFIG_ARCH_R8A77965=y
CONFIG_ARCH_R8A77980=y
CONFIG_ARCH_R8A77970=y
CONFIG_ARCH_R8A774C0=y
CONFIG_ARCH_R8A774A1=y
CONFIG_ROCKCHIP_IODOMAIN=y
CONFIG_ROCKCHIP_PM_DOMAINS=y
CONFIG_ARCH_TEGRA_132_SOC=y
CONFIG_ARCH_TEGRA_210_SOC=y
@@ -891,21 +872,15 @@ CONFIG_ARCH_K3_AM6_SOC=y
CONFIG_ARCH_K3_J721E_SOC=y
CONFIG_TI_SCI_PM_DOMAINS=y
CONFIG_EXTCON_USB_GPIO=y
CONFIG_EXTCON_USBC_CROS_EC=y
CONFIG_MEMORY=y
CONFIG_IIO=y
CONFIG_EXYNOS_ADC=y
CONFIG_QCOM_SPMI_ADC5=m
CONFIG_ROCKCHIP_SARADC=m
CONFIG_IIO_CROS_EC_SENSORS_CORE=m
CONFIG_IIO_CROS_EC_SENSORS=m
CONFIG_IIO_CROS_EC_LIGHT_PROX=m
CONFIG_SENSORS_ISL29018=m
CONFIG_IIO_CROS_EC_BARO=m
CONFIG_MPL3115=m
CONFIG_PWM=y
CONFIG_PWM_BCM2835=m
CONFIG_PWM_CROS_EC=m
CONFIG_PWM_MESON=m
CONFIG_PWM_RCAR=m
CONFIG_PWM_ROCKCHIP=y
@@ -937,9 +912,9 @@ CONFIG_PHY_UNIPHIER_USB3=y
CONFIG_PHY_TEGRA_XUSB=y
CONFIG_ARM_SMMU_V3_PMU=m
CONFIG_FSL_IMX8_DDR_PMU=m
CONFIG_HISI_PMU=y
CONFIG_QCOM_L2_PMU=y
CONFIG_QCOM_L3_PMU=y
CONFIG_HISI_PMU=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
CONFIG_NVMEM_IMX_OCOTP=y
@@ -995,8 +970,8 @@ CONFIG_CRYPTO_DEV_HISI_ZIP=m
CONFIG_CMA_SIZE_MBYTES=256
CONFIG_PRINTK_TIME=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_FS=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
# CONFIG_SCHED_DEBUG is not set
# CONFIG_DEBUG_PREEMPT is not set
# CONFIG_FTRACE is not set
@@ -1,134 +0,0 @@
From bca81c4c54765565651634b6de5edb6a191577a3 Mon Sep 17 00:00:00 2001
From: Usama Arif <usama.arif@arm.com>
Date: Thu, 27 Jun 2019 11:16:22 +0100
Subject: [PATCH 3/9] mailbox: arm_mhuv2: add device tree binding documentation
This patch adds device tree binding for Message Handling Unit
controller version 2 from Arm.
Change-Id: I8c46dd7cd1a48450020c33721ea7cce9f8b8e64f
Signed-off-by: Usama Arif <usama.arif@arm.com>
Signed-off-by: Morten Borup Petersen <morten.petersen@arm.com>
Signed-off-by: Tushar Khandelwal <tushar.khandelwal@arm.com>
Cc: robh+dt@kernel.org
Cc: mark.rutland@arm.com
Cc: devicetree@vger.kernel.org
Cc: jassisinghbrar@gmail.com
Upstream-Status: Denied [https://lkml.org/lkml/2019/7/17/615]
---
.../devicetree/bindings/mailbox/arm,mhuv2.txt | 101 ++++++++++++++++++
1 file changed, 101 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mailbox/arm,mhuv2.txt
diff --git a/Documentation/devicetree/bindings/mailbox/arm,mhuv2.txt b/Documentation/devicetree/bindings/mailbox/arm,mhuv2.txt
new file mode 100644
index 000000000000..5b8a2ab21ae0
--- /dev/null
+++ b/Documentation/devicetree/bindings/mailbox/arm,mhuv2.txt
@@ -0,0 +1,101 @@
+Arm MHUv2 Mailbox Driver
+========================
+
+The Arm Message-Handling-Unit (MHU) Version 2 is a mailbox controller that has
+between 1 and 124 channel windows to provide unidirectional communication with
+remote processor(s).
+
+Given the unidirectional nature of the device, an MHUv2 mailbox may only be
+written to or read from. If a pair of MHU devices is implemented between two
+processing elements to provide bidirectional communication, these must be
+specified as two separate mailboxes.
+
+If the interrupts property is present in device tree node, then its treated
+as a receiver frame, otherwise a sender frame.
+
+An MHU device must be specified with a transport protocol. The transport
+protocol of an MHU device determines the method of data transmission as well as
+the number of provided mailboxes.
+Following are the possible transport protocol types:
+- Single-word: An MHU device implements as many mailboxes as it
+ provides channel windows. Data is transmitted through
+ the MHU registers.
+- Multi-word: An MHU device implements a single mailbox. All channel windows
+ will be used during transmission. Data is transmitted through
+ the MHU registers.
+- Doorbell: An MHU device implements as many mailboxes as there are flag
+ bits available in its channel windows. Optionally, data may
+ be transmitted through a shared memory region, wherein the MHU
+ is used strictly as an interrupt generation mechanism.
+
+Mailbox Device Node:
+====================
+
+Required properties:
+--------------------
+- compatible: Shall be "arm,mhuv2" & "arm,primecell"
+- reg: Contains the mailbox register address range (base
+ address and length)
+- #mbox-cells Shall be 1 - the index of the channel needed.
+- mhu-protocol Transport protocol of the device. Shall be one of the
+ following: "single-word", "multi-word", "doorbell"
+
+Required properties (receiver frame):
+-------------------------------------
+- interrupts: Contains the interrupt information for the receiver frame
+
+Example:
+--------
+
+ mbox_mw_tx: mhu@10000000 {
+ compatible = "arm,mhuv2","arm,primecell";
+ reg = <0x10000000 0x1000>;
+ clocks = <&refclk100mhz>;
+ clock-names = "apb_pclk";
+ #mbox-cells = <1>;
+ mhu-protocol = "multi-word";
+ };
+
+ mbox_sw_tx: mhu@10000000 {
+ compatible = "arm,mhuv2","arm,primecell";
+ reg = <0x11000000 0x1000>;
+ clocks = <&refclk100mhz>;
+ clock-names = "apb_pclk";
+ #mbox-cells = <1>;
+ mhu-protocol = "single-word";
+ };
+
+ mbox_db_rx: mhu@10000000 {
+ compatible = "arm,mhuv2","arm,primecell";
+ reg = <0x12000000 0x1000>;
+ clocks = <&refclk100mhz>;
+ clock-names = "apb_pclk";
+ #mbox-cells = <1>;
+ interrupts = <0 45 4>;
+ interrupt-names = "mhu_rx";
+ mhu-protocol = "doorbell";
+ };
+
+ mhu_client: scb@2e000000 {
+ compatible = "fujitsu,mb86s70-scb-1.0";
+ reg = <0 0x2e000000 0x4000>;
+ mboxes =
+ // For multi-word frames, client may only instantiate a single
+ // mailbox for a mailbox controller
+ <&mbox_mw_tx 0>,
+
+ // For single-word frames, client may instantiate as many
+ // mailboxes as there are channel windows in the MHU
+ <&mbox_sw_tx 0>,
+ <&mbox_sw_tx 1>,
+ <&mbox_sw_tx 2>,
+ <&mbox_sw_tx 3>,
+
+ // For doorbell frames, client may instantiate as many mailboxes
+ // as there are bits available in the combined number of channel
+ // windows ((channel windows * 32) mailboxes)
+ <mbox_db_rx 0>,
+ <mbox_db_rx 1>,
+ ...
+ <mbox_db_rx 17>;
+ };
\ No newline at end of file
--
2.17.1
@@ -1,822 +0,0 @@
From 364539028799290814a35aa10d32d850486f0b4a Mon Sep 17 00:00:00 2001
From: Usama Arif <usama.arif@arm.com>
Date: Thu, 27 Jun 2019 11:17:14 +0100
Subject: [PATCH 4/9] mailbox: arm_mhuv2: add arm mhuv2 driver
This commit adds a driver for the ARM MHUv2 (Message Handling Unit).
The driver registers itself as a mailbox controller within the common
mailbox framework.
This commit implements the single-word transport protocol;
In single-word mode, the mailbox controller will provide a mailbox for each
channel window available in the MHU device.
Transmitting and receiving data through the mailbox framework in
single-word mode is done through a struct arm_mbox_msg.
Change-Id: I718253ceb902a2d53f7199a746063a36129b0fa6
Signed-off-by: Usama Arif <usama.arif@arm.com>
Signed-off-by: Morten Borup Petersen <morten.petersen@arm.com>
Signed-off-by: Tushar Khandelwal <tushar.khandelwal@arm.com>
Cc: jassisinghbrar@gmail.com
Cc: devicetree@vger.kernel.org
Upstream-Status: Denied [https://lkml.org/lkml/2019/7/17/615]
---
drivers/mailbox/Kconfig | 7 +
drivers/mailbox/Makefile | 2 +
drivers/mailbox/arm_mhu_v2.c | 707 +++++++++++++++++++++++
include/linux/mailbox/arm-mbox-message.h | 37 ++
4 files changed, 753 insertions(+)
create mode 100644 drivers/mailbox/arm_mhu_v2.c
create mode 100644 include/linux/mailbox/arm-mbox-message.h
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index ab4eb750bbdd..0a0dce01098c 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -22,6 +22,13 @@ config IMX_MBOX
help
Mailbox implementation for i.MX Messaging Unit (MU).
+config ARM_MHU_V2
+ tristate "ARM MHUv2 Mailbox"
+ depends on ARM_AMBA
+ help
+ Say Y here if you want to build the ARM MHUv2 controller driver,
+ which provides unidirectional mailboxes between processing elements.
+
config PLATFORM_MHU
tristate "Platform MHU Mailbox"
depends on OF
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index c22fad6f696b..78377f459421 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -11,6 +11,8 @@ obj-$(CONFIG_IMX_MBOX) += imx-mailbox.o
obj-$(CONFIG_ARMADA_37XX_RWTM_MBOX) += armada-37xx-rwtm-mailbox.o
+obj-$(CONFIG_ARM_MHU_V2) += arm_mhu_v2.o
+
obj-$(CONFIG_PLATFORM_MHU) += platform_mhu.o
obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o
diff --git a/drivers/mailbox/arm_mhu_v2.c b/drivers/mailbox/arm_mhu_v2.c
new file mode 100644
index 000000000000..d809076eb47b
--- /dev/null
+++ b/drivers/mailbox/arm_mhu_v2.c
@@ -0,0 +1,707 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Arm Message Handling Unit Version 2 (MHUv2) driver
+ *
+ * An MHU device may function in one of three transport protocol modes
+ * (single-word, multi-word and doorbell).
+ * This transport protocol should be specified in the device tree entry for the
+ * device. The transport protocol determines how the underlying hardware
+ * resources of the device are utilized when transmitting data.
+ *
+ * The arm MHUv2 driver registers as a mailbox controller with the common
+ * mailbox framework. Each mailbox channel represents a separate virtual
+ * communication channel through the MHU device.
+ * The number of registered mailbox channels is dependent on both the
+ * underlying hardware - mainly the number of channel windows within each MHU
+ * frame, as well as the selected transport protocol.
+ *
+ * Copyright (C) 2019 Arm Ltd.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/amba/bus.h>
+#include <linux/mailbox_controller.h>
+#include <linux/mailbox/arm-mbox-message.h>
+#include <linux/of_address.h>
+#include <linux/interrupt.h>
+
+/* Maximum number of channel windows */
+#define MHUV2_CHANNEL_MAX 124
+/* Number of combined interrupt status registers */
+#define MHUV2_CMB_INT_ST_REG_CNT 4
+#define MHUV2_CH_UNKNOWN -1
+
+/* Channel window status register type */
+typedef u32 mhuv2_stat_reg_t;
+#define MHUV2_STAT_BYTES sizeof(mhuv2_stat_reg_t)
+#define MHUV2_STAT_BITS (MHUV2_STAT_BYTES * __CHAR_BIT__)
+
+#define LSB_MASK(n) ((1 << (n)) - 1)
+
+#ifndef PAD
+#define _PADLINE(line) pad##line
+#define _XSTR(line) _PADLINE(line)
+#define PAD _XSTR(__LINE__)
+#endif
+
+/* ====== Arm MHUv2 register defines ====== */
+
+/* Register Message Handling Unit Configuration fields */
+struct MHU_CFG_t {
+ u32 NUM_CH : 7;
+ u32 PAD : 25;
+} __packed;
+
+/* Register Implementer Identification fields */
+struct IIDR_t {
+ u32 IMPLEMENTER : 12;
+ u32 REVISION : 4;
+ u32 VARIANT : 4;
+ u32 PRODUCT_ID : 12;
+} __packed;
+
+/* Register Architecture Identification Register fields */
+struct AIDR_t {
+ u32 ARCH_MINOR_REV : 4;
+ u32 ARCH_MAJOR_REV : 4;
+ u32 PAD : 24;
+} __packed;
+
+/* register Interrupt Status fields */
+struct INT_ST_t {
+ u32 NR2R : 1;
+ u32 R2NR : 1;
+ u32 PAD : 30;
+} __packed;
+
+/* Register Interrupt Clear fields */
+struct INT_CLR_t {
+ u32 NR2R : 1;
+ u32 R2NR : 1;
+ u32 PAD : 30;
+} __packed;
+
+/* Register Interrupt Enable fields */
+struct INT_EN_t {
+ u32 R2NR : 1;
+ u32 NR2R : 1;
+ u32 CHCOMB : 1;
+ u32 PAD : 29;
+} __packed;
+
+/* Sender Channel Window fields */
+struct mhu2_send_channel_reg {
+ mhuv2_stat_reg_t STAT;
+ u8 PAD[0xC - 0x4];
+ mhuv2_stat_reg_t STAT_SET;
+ u8 PAD[0x20 - 0x10];
+} __packed;
+
+/* Sender frame register fields */
+struct mhu2_send_frame_reg {
+ struct mhu2_send_channel_reg channel[MHUV2_CHANNEL_MAX];
+ struct MHU_CFG_t MHU_CFG;
+ u32 RESP_CFG;
+ u32 ACCESS_REQUEST;
+ u32 ACCESS_READY;
+ struct INT_ST_t INT_ST;
+ struct INT_CLR_t INT_CLR;
+ struct INT_EN_t INT_EN;
+ u32 RESERVED0;
+ u32 CHCOMB_INT_ST[MHUV2_CMB_INT_ST_REG_CNT];
+ u8 PAD[0xFC8 - 0xFB0];
+ struct IIDR_t IIDR;
+ struct AIDR_t AIDR;
+} __packed;
+
+/* Receiver Channel Window fields */
+struct mhu2_recv_channel_reg {
+ mhuv2_stat_reg_t STAT;
+ mhuv2_stat_reg_t STAT_PEND;
+ mhuv2_stat_reg_t STAT_CLEAR;
+ u8 RESERVED0[0x10 - 0x0C];
+ mhuv2_stat_reg_t MASK;
+ mhuv2_stat_reg_t MASK_SET;
+ mhuv2_stat_reg_t MASK_CLEAR;
+ u8 PAD[0x20 - 0x1C];
+} __packed;
+
+/* Receiver frame register fields */
+struct mhu2_recv_frame_reg {
+ struct mhu2_recv_channel_reg channel[MHUV2_CHANNEL_MAX];
+ struct MHU_CFG_t MHU_CFG;
+ u8 RESERVED0[0xF90 - 0xF84];
+ struct INT_ST_t INT_ST;
+ struct INT_CLR_t INT_CLR;
+ struct INT_EN_t INT_EN;
+ u32 PAD;
+ mhuv2_stat_reg_t CHCOMB_INT_ST[MHUV2_CMB_INT_ST_REG_CNT];
+ u8 RESERVED2[0xFC8 - 0xFB0];
+ struct IIDR_t IIDR;
+ struct AIDR_t AIDR;
+} __packed;
+
+/* ====== Arm MHUv2 device tree property identifiers ====== */
+
+static const char *const mhuv2_protocol_dt_identifiers[] = { "single-word",
+ "multi-word",
+ "doorbell" };
+
+static const char *const mhuv2_frame_dt_identifiers[] = { "receiver",
+ "sender" };
+
+/* ====== Arm MHUv2 data structures ====== */
+
+enum mhuv2_transport_protocol { SINGLE_WORD, MULTI_WORD, DOORBELL };
+
+enum mhuv2_frame { RECEIVER_FRAME, SENDER_FRAME };
+
+/**
+ * Arm MHUv2 operations
+ *
+ * Each transport protocol must provide an implementation of the operations
+ * presented in this structure.
+ * Most operations present a struct mbox_chan* as argument. This channel will
+ * correspond to one of the virtual channels within the MHU device. What
+ * constitutes a channel within the MHU device is dependent on the transport
+ * protocol.
+ */
+struct arm_mhuv2;
+struct mhuv2_ops {
+ int (*read_data)(struct arm_mhuv2 *mhuv2, struct mbox_chan *chan,
+ struct arm_mbox_msg *msg);
+ int (*clear_data)(struct arm_mhuv2 *mhuv2, struct mbox_chan *chan,
+ struct arm_mbox_msg *msg);
+ int (*send_data)(struct arm_mhuv2 *mhuv2, struct mbox_chan *chan,
+ const struct arm_mbox_msg *msg);
+ int (*setup)(struct arm_mhuv2 *mhuv2);
+ int (*last_tx_done)(struct arm_mhuv2 *mhuv2, struct mbox_chan *chan);
+ struct mbox_chan *(*get_active_mbox_chan)(struct arm_mhuv2 *mhuv2);
+};
+
+/**
+ * Arm MHUv2 mailbox channel information
+ *
+ * A channel contains a notion of its index within the array of mailbox channels
+ * which a mailbox controller allocates.
+ */
+struct arm_mhuv2_mbox_chan_priv {
+ u32 ch_idx;
+};
+
+#define mhuv2_chan_idx(_chanptr) \
+ (((struct arm_mhuv2_mbox_chan_priv *)(_chanptr)->con_priv)->ch_idx)
+
+/**
+ * Arm MHUv2 mailbox controller data
+ *
+ * @reg: Base address of the register mapping region
+ * @protocol: Transport protocol, derived from device tree
+ * @frame: Frame type, derived from device tree
+ * @irq: Interrupt, only valid for receiver frames
+ * @mbox: Mailbox controller belonging to the MHU frame
+ * @ops: Pointer to transport-protocol specific operations
+ * @dev: Device to which it is attached
+ */
+struct arm_mhuv2 {
+ union {
+ struct mhu2_send_frame_reg __iomem *send;
+ struct mhu2_recv_frame_reg __iomem *recv;
+ } reg;
+ enum mhuv2_frame frame;
+ unsigned int irq;
+ struct mbox_controller mbox;
+ struct mhuv2_ops *ops;
+ struct device *dev;
+};
+
+#define mhu2_from_mbox_ctrl(_mbox) container_of(_mbox, struct arm_mhuv2, mbox)
+#define mhu2_from_mbox_chan(_chan) mhu2_from_mbox_ctrl(_chan->mbox)
+
+/* Macro for reading a bitfield within a physically mapped packed struct */
+#define readl_relaxed_bitfield(_regptr, _field) \
+ ({ \
+ mhuv2_stat_reg_t _regval; \
+ BUILD_BUG_ON(sizeof(*(_regptr)) > sizeof(typeof(_regval))); \
+ _regval = readl_relaxed((_regptr)); \
+ (*(typeof((_regptr)))(&_regval))._field; \
+ })
+
+/* Macro for writing a bitfield within a physically mapped packed struct */
+#define writel_relaxed_bitfield(_value, _regptr, _field) \
+ ({ \
+ mhuv2_stat_reg_t _regval; \
+ BUILD_BUG_ON(sizeof(*_regptr) > sizeof(typeof(_regval))); \
+ _regval = readl_relaxed(_regptr); \
+ (*(typeof(_regptr))(&_regval))._field = _value; \
+ writel_relaxed(_regval, _regptr); \
+ })
+
+static inline int __find_set_bit(uint32_t val)
+{
+ const uint32_t trailing_zeros = __builtin_ctz(val);
+ return trailing_zeros == 32 ? -1 : trailing_zeros;
+}
+
+/**
+ * Get index of a set bit within the combined interrupt status registers
+ *
+ * The function will calculate the index being the offset from the LSB of the
+ * first combined interrupt status register.
+ *
+ */
+static inline int mhuv2_combint_idx(struct arm_mhuv2 *mhuv2)
+{
+ int ch_idx = 0;
+ int set_bit_index, reg_idx;
+
+ for (reg_idx = 0; reg_idx < MHUV2_CMB_INT_ST_REG_CNT; reg_idx++) {
+ mhuv2_stat_reg_t stat_reg;
+
+ stat_reg =
+ readl_relaxed(&mhuv2->reg.recv->CHCOMB_INT_ST[reg_idx]);
+ set_bit_index = __find_set_bit(stat_reg);
+ if (set_bit_index == -1) {
+ ch_idx += MHUV2_STAT_BITS;
+ } else {
+ ch_idx += set_bit_index;
+ break;
+ }
+ }
+ return (ch_idx >= (MHUV2_CMB_INT_ST_REG_CNT * MHUV2_STAT_BITS) ?
+ MHUV2_CH_UNKNOWN :
+ ch_idx);
+}
+
+/* ================ Single word transport protocol operations =============== */
+static inline int mhuv20_get_non_zero_ch_idx(struct arm_mhuv2 *mhuv2)
+{
+ /* Locate a channel window with a non-zero STAT register */
+ int ch_idx;
+ int ch = MHUV2_CH_UNKNOWN;
+
+ for (ch_idx = 0;
+ ch_idx < readl_relaxed_bitfield(&mhuv2->reg.recv->MHU_CFG, NUM_CH);
+ ch_idx++) {
+ if (readl_relaxed(&mhuv2->reg.recv->channel[ch_idx].STAT)) {
+ ch = ch_idx;
+ break;
+ }
+ }
+ return ch;
+}
+
+static inline int mhuv2_get_non_zero_ch_idx(struct arm_mhuv2 *mhuv2)
+{
+ /* Identify index of channel window containing non-zero data */
+ switch (readl_relaxed_bitfield(&mhuv2->reg.recv->AIDR,
+ ARCH_MINOR_REV)) {
+ case 1:
+ return mhuv2_combint_idx(mhuv2);
+ default:
+ return mhuv20_get_non_zero_ch_idx(mhuv2);
+ }
+}
+
+static inline int mhuv2_read_data_single_word(struct arm_mhuv2 *mhuv2,
+ struct mbox_chan *chan,
+ struct arm_mbox_msg *msg)
+{
+ const u32 ch_idx = mhuv2_chan_idx(chan);
+
+ msg->data = kzalloc(MHUV2_STAT_BYTES, GFP_KERNEL);
+ if (!msg->data)
+ return -ENOMEM;
+
+ *(mhuv2_stat_reg_t *)msg->data =
+ readl_relaxed(&mhuv2->reg.recv->channel[ch_idx].STAT);
+ msg->len = MHUV2_STAT_BYTES;
+ return 0;
+}
+
+static inline int mhuv2_clear_data_single_word(struct arm_mhuv2 *mhuv2,
+ struct mbox_chan *chan,
+ struct arm_mbox_msg *msg)
+{
+ const u32 ch_idx = mhuv2_chan_idx(chan);
+
+ writel_relaxed(readl_relaxed(&mhuv2->reg.recv->channel[ch_idx].STAT),
+ &mhuv2->reg.recv->channel[ch_idx].STAT_CLEAR);
+ return 0;
+}
+
+static inline int mhuv2_send_data_single_word(struct arm_mhuv2 *mhuv2,
+ struct mbox_chan *chan,
+ const struct arm_mbox_msg *msg)
+{
+ const u32 ch_idx = mhuv2_chan_idx(chan);
+ int bytes_left = msg->len;
+ char *data = msg->data;
+
+ if (ch_idx >= readl_relaxed_bitfield(&mhuv2->reg.recv->MHU_CFG, NUM_CH))
+ return -ENODEV;
+
+ while (bytes_left > 0) {
+ mhuv2_stat_reg_t word = *(mhuv2_stat_reg_t *)(data);
+
+ if (bytes_left < MHUV2_STAT_BYTES)
+ word &= LSB_MASK(bytes_left * __CHAR_BIT__);
+
+ if (!word) {
+ dev_err(mhuv2->dev,
+ "Data transmitted in single-word mode must be non-zero\n");
+ return -EINVAL;
+ }
+ writel_relaxed(word,
+ &mhuv2->reg.send->channel[ch_idx].STAT_SET);
+ while (readl_relaxed(&mhuv2->reg.send->channel[ch_idx].STAT))
+ continue;
+ bytes_left -= MHUV2_STAT_BYTES;
+ data += MHUV2_STAT_BYTES;
+ }
+
+ return 0;
+}
+
+static inline int mhuv2_last_tx_done_single_word(struct arm_mhuv2 *mhuv2,
+ struct mbox_chan *chan)
+{
+ const u32 ch_idx = mhuv2_chan_idx(chan);
+
+ return readl_relaxed(&mhuv2->reg.send->channel[ch_idx].STAT) == 0;
+}
+
+static inline int mhuv2_setup_single_word(struct arm_mhuv2 *mhuv2)
+{
+ int i;
+ const u32 channel_windows =
+ readl_relaxed_bitfield(mhuv2->frame == RECEIVER_FRAME ?
+ &mhuv2->reg.recv->MHU_CFG :
+ &mhuv2->reg.send->MHU_CFG,
+ NUM_CH);
+
+ mhuv2->mbox.num_chans = channel_windows;
+ mhuv2->mbox.chans =
+ devm_kzalloc(mhuv2->dev,
+ mhuv2->mbox.num_chans * sizeof(struct mbox_chan),
+ GFP_KERNEL);
+
+ for (i = 0; i < mhuv2->mbox.num_chans; i++) {
+ mhuv2->mbox.chans[i].con_priv =
+ devm_kzalloc(mhuv2->dev,
+ sizeof(struct arm_mhuv2_mbox_chan_priv),
+ GFP_KERNEL);
+ mhuv2_chan_idx(&mhuv2->mbox.chans[i]) = i;
+ }
+
+ if (mhuv2->frame == RECEIVER_FRAME) {
+ /* Ensure all status registers are unmasked */
+ for (i = 0; i < channel_windows; i++) {
+ writel_relaxed(0x0,
+ &mhuv2->reg.recv->channel[i].MASK_SET);
+ }
+ }
+
+ return 0;
+}
+
+static inline struct mbox_chan *
+ mhuv2_get_active_mbox_chan_single_word(struct arm_mhuv2 *mhuv2)
+{
+ const u32 ch_idx = mhuv2_get_non_zero_ch_idx(mhuv2);
+
+ if (ch_idx >= mhuv2->mbox.num_chans) {
+ dev_err(mhuv2->dev,
+ "Invalid active channel in single word mode\n");
+ return ERR_PTR(-EINVAL);
+ }
+ return &mhuv2->mbox.chans[ch_idx];
+}
+
+static const struct mhuv2_ops mhuv2_single_word_ops = {
+ .read_data = mhuv2_read_data_single_word,
+ .clear_data = mhuv2_clear_data_single_word,
+ .send_data = mhuv2_send_data_single_word,
+ .setup = mhuv2_setup_single_word,
+ .last_tx_done = mhuv2_last_tx_done_single_word,
+ .get_active_mbox_chan = mhuv2_get_active_mbox_chan_single_word,
+};
+/* ========================================================================== */
+
+/*
+ * MHUv2 receiver interrupt service routine
+ *
+ * This routine will be called whenever a reception interrupt is raised on the
+ * MHU device. Given that an MHU device may manage multiple mailboxes, it is
+ * up to the protocol-specific operations to determine:
+ * - What is the active mailbox channel
+ * - Read the data within the MHU corresponding to the channel
+ * - Clear the data within the MHU corresponding to the channel
+ *
+ * These operations must also ensure to not overwrite any data which may belong
+ * to a different mailbox channel. For instance, if data is received in two
+ * channel windows in single-word mode, the ISR will read and clear the data
+ * from one of these channel windows within a pass. This will result in a status
+ * register being non-zero upon returning from this routine, which in turn
+ * will keep the interrupt asserted for a second round.
+ */
+static irqreturn_t mhuv2_rx_interrupt(int irq, void *data)
+{
+ struct arm_mbox_msg msg;
+ int status;
+ struct arm_mhuv2 *mhuv2 = data;
+ struct mbox_chan *chan = mhuv2->ops->get_active_mbox_chan(mhuv2);
+
+ msg.data = NULL;
+ msg.len = 0;
+
+ status = mhuv2->ops->read_data(mhuv2, chan, &msg);
+ if (status != 0)
+ goto rx_exit;
+
+ if (!chan->cl) {
+ dev_warn(
+ mhuv2->dev,
+ "Warning: Received data on channel not currently attached to "
+ "a mailbox client\n");
+ } else {
+ mbox_chan_received_data(chan, (void *)&msg);
+ }
+
+ status = mhuv2->ops->clear_data(mhuv2, chan, &msg);
+
+rx_exit:
+ kfree(msg.data);
+
+ return status == 0 ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static bool mhuv2_last_tx_done(struct mbox_chan *chan)
+{
+ struct arm_mhuv2 *mhuv2 = mhu2_from_mbox_chan(chan);
+
+ return mhuv2->ops->last_tx_done(mhuv2, chan);
+}
+
+static int mhuv2_send_data(struct mbox_chan *chan, void *data)
+{
+ struct arm_mhuv2 *mhuv2 = mhu2_from_mbox_chan(chan);
+ struct arm_mbox_msg *msg = data;
+ int ret;
+
+ if (!mhuv2->ops->last_tx_done(mhuv2, chan))
+ return -EBUSY;
+
+ ret = mhuv2->ops->send_data(mhuv2, chan, msg);
+ return ret;
+}
+
+static int mhuv2_startup(struct mbox_chan *chan)
+{
+ struct arm_mhuv2 *mhuv2 = mhu2_from_mbox_ctrl(chan->mbox);
+
+ writel_relaxed(0x1, &mhuv2->reg.send->ACCESS_REQUEST);
+ while (!readl_relaxed(&mhuv2->reg.send->ACCESS_READY))
+ continue;
+
+ return 0;
+}
+
+static void mhuv2_shutdown(struct mbox_chan *chan)
+{
+ struct arm_mhuv2 *mhuv2 = mhu2_from_mbox_ctrl(chan->mbox);
+
+ writel_relaxed(0x0, &mhuv2->reg.send->ACCESS_REQUEST);
+}
+
+static int mhuv2_recv_startup(struct mbox_chan *chan)
+{
+ return 0;
+}
+
+static void mhuv2_recv_shutdown(struct mbox_chan *chan)
+{
+}
+
+static int mhuv2_recv_send_data(struct mbox_chan *chan, void *data)
+{
+ dev_err(chan->mbox->dev,
+ "Trying to transmit on a receiver MHU frame\n");
+ return -EIO;
+}
+
+static bool mhuv2_recv_last_tx_done(struct mbox_chan *chan)
+{
+ dev_err(chan->mbox->dev, "Trying to Tx poll on a receiver MHU frame\n");
+ return true;
+}
+
+static const struct mbox_chan_ops mhuv2_receiver_ops = {
+ .send_data = mhuv2_recv_send_data,
+ .startup = mhuv2_recv_startup,
+ .shutdown = mhuv2_recv_shutdown,
+ .last_tx_done = mhuv2_recv_last_tx_done,
+};
+
+static const struct mbox_chan_ops mhuv2_sender_ops = {
+ .send_data = mhuv2_send_data,
+ .startup = mhuv2_startup,
+ .shutdown = mhuv2_shutdown,
+ .last_tx_done = mhuv2_last_tx_done,
+};
+
+static struct mbox_chan *mhuv2_mbox_of_xlate(struct mbox_controller *ctrl,
+ const struct of_phandle_args *pa)
+{
+ struct mbox_chan *chan;
+
+ if (pa->args_count != 1)
+ return ERR_PTR(-EINVAL);
+
+ if (pa->args[0] >= ctrl->num_chans)
+ return ERR_PTR(-ENOENT);
+
+ chan = &ctrl->chans[pa->args[0]];
+ return chan;
+}
+
+static int mhuv2_probe(struct amba_device *adev, const struct amba_id *id)
+{
+ int err;
+ struct device *dev = &adev->dev;
+ const struct device_node *np = dev->of_node;
+ struct arm_mhuv2 *mhuv2;
+ const char *mhuv2_protocol_str;
+
+ /* Allocate memory for device */
+ mhuv2 = devm_kzalloc(dev, sizeof(*mhuv2), GFP_KERNEL);
+ if (!mhuv2)
+ return -ENOMEM;
+
+ mhuv2->dev = dev;
+
+ /* Assign transport protocol-specific operations */
+ err = of_property_read_string(np, "mhu-protocol", &mhuv2_protocol_str);
+
+ if (err) {
+ dev_err(dev,
+ "Probe failed: no transport protocol specified\n");
+ return -ENODEV;
+ } else if (strcmp(mhuv2_protocol_str,
+ mhuv2_protocol_dt_identifiers[SINGLE_WORD]) == 0) {
+ mhuv2->ops = &mhuv2_single_word_ops;
+ } else {
+ dev_err(dev,
+ "Probe failed: '%s' is not a valid transport protocol specifier\n",
+ mhuv2_protocol_str);
+ return -ENODEV;
+ }
+
+ /* Get MHU type specific properties from device tree */
+ if (adev->irq[0]) {
+ mhuv2->frame = RECEIVER_FRAME;
+ mhuv2->reg.recv = (struct mhu2_recv_frame_reg *)of_iomap(
+ (struct device_node *)np, 0);
+ if (!mhuv2->reg.recv)
+ goto io_fail;
+ mhuv2->irq = adev->irq[0];
+ } else {
+ mhuv2->frame = SENDER_FRAME;
+ mhuv2->reg.send = (struct mhu2_send_frame_reg *)of_iomap(
+ (struct device_node *)np, 0);
+ if (!mhuv2->reg.send)
+ goto io_fail;
+ }
+
+ /* Mailbox controller setup */
+ mhuv2->mbox.dev = dev;
+ mhuv2->mbox.txdone_irq = false;
+ mhuv2->mbox.txdone_poll = true;
+ mhuv2->mbox.txpoll_period = 1;
+ mhuv2->mbox.of_xlate = mhuv2_mbox_of_xlate;
+ mhuv2->mbox.ops = mhuv2->frame == SENDER_FRAME ? &mhuv2_sender_ops :
+ &mhuv2_receiver_ops;
+ /*
+ * Transport protocol specific setup
+ * Setup function _must_ allocate mailbox channels according to the
+ * number of channels provided in the given transport protocol mode.
+ */
+ err = mhuv2->ops->setup(mhuv2);
+ if (err)
+ return err;
+
+ /* Request an interrupt if this is a receiver frame */
+ if (mhuv2->frame == RECEIVER_FRAME) {
+ err = devm_request_threaded_irq(dev, adev->irq[0], NULL,
+ mhuv2_rx_interrupt, IRQF_ONESHOT, "mhuv2_link", mhuv2);
+ if (err) {
+ dev_err(dev, "unable to acquire IRQ %d\n", mhuv2->irq);
+ return err;
+ }
+ /*
+ * For minor version 1 and forward, the combined interrupt of
+ * the receiver frame must be explicitly enabled during startup.
+ */
+ if (readl_relaxed_bitfield(&mhuv2->reg.recv->AIDR,
+ ARCH_MINOR_REV) > 0) {
+ writel_relaxed_bitfield(1, &mhuv2->reg.recv->INT_EN,
+ CHCOMB);
+ }
+ }
+
+ amba_set_drvdata(adev, mhuv2);
+
+ err = devm_mbox_controller_register(dev, &mhuv2->mbox);
+ if (err) {
+ dev_err(dev, "failed to register ARM MHUv2 driver %d\n", err);
+ iounmap(mhuv2->frame == RECEIVER_FRAME ? mhuv2->reg.recv :
+ mhuv2->reg.send);
+ return err;
+ }
+
+ dev_info(dev, "ARM MHUv2 %s frame (%s) Mailbox driver registered\n",
+ mhuv2_frame_dt_identifiers[mhuv2->frame],
+ mhuv2_protocol_str);
+
+ return 0;
+
+io_fail:
+ dev_err(dev, "Probe failed: failed to map '%s' frame\n",
+ mhuv2_frame_dt_identifiers[mhuv2->frame]);
+ iounmap(mhuv2->frame == RECEIVER_FRAME ? mhuv2->reg.recv :
+ mhuv2->reg.send);
+ return -ENOMEM;
+}
+
+static int mhuv2_remove(struct amba_device *adev)
+{
+ return 0;
+}
+
+static struct amba_id mhuv2_ids[] = {
+ {
+ .id = 0x4b0d1,
+ .mask = 0xfffff,
+ },
+ {
+ .id = 0xbb0d1,
+ .mask = 0xfffff,
+ },
+ { 0, 0 },
+};
+MODULE_DEVICE_TABLE(amba, mhuv2_ids);
+
+static struct amba_driver arm_mhuv2_driver = {
+ .drv = {
+ .name = "mhuv2",
+ },
+ .id_table = mhuv2_ids,
+ .probe = mhuv2_probe,
+ .remove = mhuv2_remove,
+};
+module_amba_driver(arm_mhuv2_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ARM MHUv2 Driver");
+MODULE_AUTHOR("Morten Borup Petersen <morten.petersen@arm.com>");
diff --git a/include/linux/mailbox/arm-mbox-message.h b/include/linux/mailbox/arm-mbox-message.h
new file mode 100644
index 000000000000..112b4f927c1a
--- /dev/null
+++ b/include/linux/mailbox/arm-mbox-message.h
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Arm Mailbox Message
+ *
+ * The Arm mailbox message structure is used to pass data- and length
+ * information between a mailbox client and mailbox controller, through the
+ * provided void* of the common mailbox frameworks send- and receive APIs.
+ *
+ * This will be utilized when a mailbox controller is able to transmit
+ * more than a single word within a transmission, allowing the controller
+ * to fully utilize its available resources.
+ * No message protocol is enforced through this structure - a utilizing mailbox
+ * client driver shall implement its own message protocol, which may then be
+ * transmitted through an arm_mbox_msg.
+ *
+ * Given a message protocol of size A and an arm_mbox_msg containing data of
+ * length B, a mailbox channel may callback with B < A. In this case, the
+ * message protocol driver must implement a state machine which allows for
+ * multiple callbacks that provides parts of a full message of size A. This
+ * state machine must account for, that the length of the arm_mbox_msg received
+ * may vary between callbacks based on the underlying hardware as well as the
+ * transmitted data.
+ *
+ * Copyright (C) 2019 Arm Ltd.
+ */
+
+#ifndef _LINUX_ARM_MBOX_MESSAGE_H_
+#define _LINUX_ARM_MBOX_MESSAGE_H_
+
+#include <linux/types.h>
+
+struct arm_mbox_msg {
+ void *data;
+ size_t len;
+};
+
+#endif /* _LINUX_ARM_MBOX_MESSAGE_H_ */
--
2.17.1
@@ -1,156 +0,0 @@
From 515a936531a25a0c48a97efe3828962ed8d781dd Mon Sep 17 00:00:00 2001
From: Usama Arif <usama.arif@arm.com>
Date: Wed, 19 Jun 2019 16:55:20 +0100
Subject: [PATCH 5/9] mailbox: arm_mhuv2: add doorbell transport protocol
operations
In doorbell mode, the mailbox controller will provide a mailbox for each
flag bit available in the combined number of channel windows available
within the MHU device.
When in doorbell mode, the MHU should be used solely as an interrupt
generating mechanism. If data is to be transmitted, this must be done
out-band, ie. through shared memory, by a driving utilizing the mailbox
for interrupt generation.
Change-Id: I8410b21471743c0b624c873388f9629ea0863789
Signed-off-by: Usama Arif <usama.arif@arm.com>
Signed-off-by: Morten Borup Petersen <morten.petersen@arm.com>
Signed-off-by: Tushar Khandelwal <tushar.khandelwal@arm.com>
Cc:Jassi Brar <jassisinghbrar@gmail.com
Cc: devicetree@vger.kernel.org
Upstream-Status: Denied [https://lkml.org/lkml/2019/7/17/615]
---
drivers/mailbox/arm_mhu_v2.c | 108 +++++++++++++++++++++++++++++++++++
1 file changed, 108 insertions(+)
diff --git a/drivers/mailbox/arm_mhu_v2.c b/drivers/mailbox/arm_mhu_v2.c
index d809076eb47b..efde7a71a3f7 100644
--- a/drivers/mailbox/arm_mhu_v2.c
+++ b/drivers/mailbox/arm_mhu_v2.c
@@ -429,6 +429,111 @@ static const struct mhuv2_ops mhuv2_single_word_ops = {
};
/* ========================================================================== */
+/* =================== Doorbell transport protocol operations =============== */
+
+static inline int mhuv2_read_data_doorbell(struct arm_mhuv2 *mhuv2,
+ struct mbox_chan *chan,
+ struct arm_mbox_msg *msg)
+{
+ return 0;
+}
+
+static inline int mhuv2_clear_data_doorbell(struct arm_mhuv2 *mhuv2,
+ struct mbox_chan *chan,
+ struct arm_mbox_msg *msg)
+{
+ const u32 ch_mbox_idx = mhuv2_chan_idx(chan);
+ const u32 ch_window_idx = ch_mbox_idx / MHUV2_STAT_BITS;
+ const u32 ch_window_reg_idx = ch_mbox_idx % MHUV2_STAT_BITS;
+
+ writel_relaxed(BIT(ch_window_reg_idx),
+ &mhuv2->reg.recv->channel[ch_window_idx].STAT_CLEAR);
+ return 0;
+}
+
+static inline int mhuv2_send_data_doorbell(struct arm_mhuv2 *mhuv2,
+ struct mbox_chan *chan,
+ const struct arm_mbox_msg *msg)
+{
+ const u32 ch_mbox_idx = mhuv2_chan_idx(chan);
+ const u32 ch_window_idx = ch_mbox_idx / MHUV2_STAT_BITS;
+ const u32 ch_window_reg_idx = ch_mbox_idx % MHUV2_STAT_BITS;
+
+ writel_relaxed(
+ readl_relaxed(&mhuv2->reg.send->channel[ch_window_idx].STAT) |
+ BIT(ch_window_reg_idx),
+ &mhuv2->reg.send->channel[ch_window_idx].STAT_SET);
+ return 0;
+}
+
+static inline int mhuv2_last_tx_done_doorbell(struct arm_mhuv2 *mhuv2,
+ struct mbox_chan *chan)
+{
+ const u32 ch_mbox_idx = mhuv2_chan_idx(chan);
+ const u32 ch_window_idx = ch_mbox_idx / MHUV2_STAT_BITS;
+ const u32 ch_window_reg_idx = ch_mbox_idx % MHUV2_STAT_BITS;
+
+ return (readl_relaxed(&mhuv2->reg.send->channel[ch_window_idx].STAT) &
+ BIT(ch_window_reg_idx)) == 0;
+}
+
+static inline int mhuv2_setup_doorbell(struct arm_mhuv2 *mhuv2)
+{
+ int i;
+ const u32 channel_windows =
+ readl_relaxed_bitfield(mhuv2->frame == RECEIVER_FRAME ?
+ &mhuv2->reg.recv->MHU_CFG :
+ &mhuv2->reg.send->MHU_CFG,
+ NUM_CH);
+
+ mhuv2->mbox.num_chans = MHUV2_STAT_BITS * channel_windows;
+ mhuv2->mbox.chans =
+ devm_kzalloc(mhuv2->dev,
+ mhuv2->mbox.num_chans * sizeof(struct mbox_chan),
+ GFP_KERNEL);
+
+ for (i = 0; i < mhuv2->mbox.num_chans; i++) {
+ mhuv2->mbox.chans[i].con_priv =
+ devm_kzalloc(mhuv2->dev,
+ sizeof(struct arm_mhuv2_mbox_chan_priv),
+ GFP_KERNEL);
+ mhuv2_chan_idx(&mhuv2->mbox.chans[i]) = i;
+ }
+
+ if (mhuv2->frame == RECEIVER_FRAME) {
+ /* Ensure all status registers are unmasked */
+ for (i = 0; i < channel_windows; i++) {
+ writel_relaxed(0x0,
+ &mhuv2->reg.recv->channel[i].MASK_SET);
+ }
+ }
+
+ return 0;
+}
+
+static inline struct mbox_chan *
+ mhuv2_get_active_mbox_chan_doorbell(struct arm_mhuv2 *mhuv2)
+{
+ const u32 ch_window_idx = mhuv2_get_non_zero_ch_idx(mhuv2);
+ const u32 ch_window_reg_idx = __find_set_bit(
+ readl_relaxed(&mhuv2->reg.recv->channel[ch_window_idx].STAT));
+ if (ch_window_reg_idx == -1)
+ return ERR_PTR(-EIO);
+
+ return &mhuv2->mbox.chans[ch_window_reg_idx +
+ ch_window_idx * MHUV2_STAT_BITS];
+}
+
+static const struct mhuv2_ops mhuv2_doorbell_ops = {
+ .read_data = mhuv2_read_data_doorbell,
+ .clear_data = mhuv2_clear_data_doorbell,
+ .send_data = mhuv2_send_data_doorbell,
+ .setup = mhuv2_setup_doorbell,
+ .last_tx_done = mhuv2_last_tx_done_doorbell,
+ .get_active_mbox_chan = mhuv2_get_active_mbox_chan_doorbell,
+};
+/* ========================================================================== */
+
/*
* MHUv2 receiver interrupt service routine
*
@@ -591,6 +696,9 @@ static int mhuv2_probe(struct amba_device *adev, const struct amba_id *id)
} else if (strcmp(mhuv2_protocol_str,
mhuv2_protocol_dt_identifiers[SINGLE_WORD]) == 0) {
mhuv2->ops = &mhuv2_single_word_ops;
+ } else if (strcmp(mhuv2_protocol_str,
+ mhuv2_protocol_dt_identifiers[DOORBELL]) == 0) {
+ mhuv2->ops = &mhuv2_doorbell_ops;
} else {
dev_err(dev,
"Probe failed: '%s' is not a valid transport protocol specifier\n",
--
2.17.1
@@ -1,271 +0,0 @@
From 31140984e2ead5d56b072d0fed0b5f18a1e7e825 Mon Sep 17 00:00:00 2001
From: Usama Arif <usama.arif@arm.com>
Date: Wed, 19 Jun 2019 17:00:31 +0100
Subject: [PATCH 6/9] mailbox: arm_mhuv2: add multi word transport protocol
operations
When in multi-word mode, the mailbox controller will provide a single
mailbox. It is required that the MHU device has at least 2 channel windows
available for the MHU to function in multi-word mode.
Transmitting and receiving data through the mailbox framework in
multi-word mode is done through a struct arm_mbox_msg.
Change-Id: Ibcf352d19ae3908093b20350853b16cf6a7933a2
Signed-off-by: Usama Arif <usama.arif@arm.com>
Signed-off-by: Morten Borup Petersen <morten.petersen@arm.com>
Signed-off-by: Tushar Khandelwal <tushar.khandelwal@arm.com>
Cc: jassisinghbrar@gmail.com
Cc: devicetree@vger.kernel.org
Upstream-Status: Denied [https://lkml.org/lkml/2019/7/17/615]
---
drivers/mailbox/arm_mhu_v2.c | 225 +++++++++++++++++++++++++++++++++++
1 file changed, 225 insertions(+)
diff --git a/drivers/mailbox/arm_mhu_v2.c b/drivers/mailbox/arm_mhu_v2.c
index efde7a71a3f7..e73e829d4f1e 100644
--- a/drivers/mailbox/arm_mhu_v2.c
+++ b/drivers/mailbox/arm_mhu_v2.c
@@ -429,6 +429,228 @@ static const struct mhuv2_ops mhuv2_single_word_ops = {
};
/* ========================================================================== */
+/* ================ Multi word transport protocol operations ================ */
+static inline int mhuv2_read_data_multi_word(struct arm_mhuv2 *mhuv2,
+ struct mbox_chan *chan,
+ struct arm_mbox_msg *msg)
+{
+ int ch;
+ const int channels =
+ readl_relaxed_bitfield(&mhuv2->reg.recv->MHU_CFG, NUM_CH);
+
+ msg->data = kzalloc(MHUV2_STAT_BYTES * channels, GFP_KERNEL);
+
+ for (ch = 0; ch < channels; ch++) {
+ /*
+ * Messages are expected to be received in order of most
+ * significant word to least significant word.
+ * (see mhuv2_send_data_multi_word)
+ */
+ const mhuv2_stat_reg_t word =
+ readl_relaxed(&mhuv2->reg.recv->channel[ch].STAT);
+ ((mhuv2_stat_reg_t *)msg->data)[channels - 1 - ch] = word;
+ }
+
+ msg->len = channels * MHUV2_STAT_BYTES;
+ return 0;
+}
+
+static inline int mhuv2_clear_data_multi_word(struct arm_mhuv2 *mhuv2,
+ struct mbox_chan *chan,
+ struct arm_mbox_msg *msg)
+{
+ int ch;
+ const int channels =
+ readl_relaxed_bitfield(&mhuv2->reg.recv->MHU_CFG, NUM_CH);
+
+ for (ch = 0; ch < channels; ch++) {
+ /*
+ * Last channel window must be cleared as the final operation.
+ * Upon clearing the last channel window register, which is
+ * unmasked in multi-word mode, the interrupt is deasserted.
+ */
+ writel_relaxed(
+ readl_relaxed(&mhuv2->reg.recv->channel[ch].STAT),
+ &mhuv2->reg.recv->channel[ch].STAT_CLEAR);
+ }
+ return 0;
+}
+
+static inline int __mhuv2_mw_bytes_to_send(const int bytes_in_round,
+ const int bytes_left)
+{
+ /*
+ * Bytes to send on the current channel will always be MHUV2_STAT_BYTES
+ * unless in the last round and
+ * msg->len % MHUV2_STAT_BYTES != 0
+ */
+ if (bytes_in_round % MHUV2_STAT_BYTES != 0) {
+ const int bts = bytes_left % MHUV2_STAT_BYTES;
+ return bts == 0 ? MHUV2_STAT_BYTES : bts;
+ } else {
+ return MHUV2_STAT_BYTES;
+ }
+}
+
+static inline int mhuv2_send_data_multi_word(struct arm_mhuv2 *mhuv2,
+ struct mbox_chan *chan,
+ const struct arm_mbox_msg *msg)
+{
+ /*
+ * Message will be transmitted from most significant to least
+ * significant word. This is to allow for messages shorter than
+ * $channels to still trigger the receiver interrupt which gets
+ * activated when the last STAT register is written. As an example, a
+ * 6-word message is to be written on a 4-channel MHU connection:
+ * Registers marked with '*' are masked, and will not generate an
+ * interrupt on the receiver side once written.
+ *
+ * uint32_t *data = [0x00000001],[0x00000002],[0x00000003],[0x00000004],
+ * [0x00000005], [0x00000006]
+ *
+ * ROUND 1:
+ * STAT reg To write Write sequence
+ * [ STAT 3 ] <- [0x00000001] 4 <- triggers interrupt on receiver
+ * *[ STAT 2 ] <- [0x00000002] 3
+ * *[ STAT 1 ] <- [0x00000003] 2
+ * *[ STAT 0 ] <- [0x00000004] 1
+ *
+ * data += 4 // Increment data pointer by number of STAT regs
+ *
+ * ROUND 2:
+ * STAT reg To write Write sequence
+ * [ STAT 3 ] <- [0x00000005] 2 <- triggers interrupt on receiver
+ * *[ STAT 2 ] <- [0x00000006] 1
+ * *[ STAT 1 ] <- [0x00000000]
+ * *[ STAT 0 ] <- [0x00000000]
+ */
+ int bytes_left, bytes_to_send, i, ch_idx;
+ const int ch_windows =
+ readl_relaxed_bitfield(&mhuv2->reg.recv->MHU_CFG, NUM_CH);
+ const size_t round_capacity = ch_windows * MHUV2_STAT_BYTES;
+
+ bytes_left = msg->len;
+ mhuv2_stat_reg_t *data = msg->data;
+
+ while (bytes_left > 0) {
+ /* Note: Each entry of this loop indicates a new ROUND */
+ if (*(u32 *)data == 0) {
+ dev_err(mhuv2->dev,
+ "values in *data aligned on NUM_STAT boundaries must not be zero to ensure that receiver interrupt is triggered\n",
+ ch_windows);
+ return -EINVAL;
+ }
+
+ const int bytes_in_round = bytes_left > round_capacity ?
+ round_capacity :
+ bytes_left;
+
+ for (i = (ch_windows - 1); i >= 0; i--) {
+ ch_idx = ch_windows - 1 - i;
+ /*
+ * Check whether data should be transmitted in register
+ * of index 'ch'.
+ */
+ if (bytes_in_round > (i * MHUV2_STAT_BYTES)) {
+ mhuv2_stat_reg_t word = data[i];
+
+ bytes_to_send = __mhuv2_mw_bytes_to_send(
+ bytes_in_round, bytes_left);
+
+ if (bytes_to_send != MHUV2_STAT_BYTES) {
+ word &= LSB_MASK(bytes_to_send *
+ __CHAR_BIT__);
+ }
+ while (readl_relaxed(
+ &mhuv2->reg.send->channel[ch_idx]
+ .STAT) != 0)
+ continue;
+
+ writel_relaxed(
+ word,
+ &mhuv2->reg.send->channel[ch_idx].STAT_SET);
+ bytes_left -= bytes_to_send;
+ }
+ }
+
+ data += ch_windows;
+
+ for (ch_idx = 0; ch_idx < ch_windows; ch_idx++) {
+ while (readl_relaxed(
+ &mhuv2->reg.send->channel[ch_idx].STAT) != 0)
+ continue;
+ }
+ }
+ return 0;
+}
+
+
+static inline int mhuv2_last_tx_done_multi_word(struct arm_mhuv2 *mhuv2,
+ struct mbox_chan *chan)
+{
+ int ch_idx;
+ bool tx_done = true;
+
+ for (ch_idx = 0;
+ ch_idx < readl_relaxed_bitfield(&mhuv2->reg.send->MHU_CFG, NUM_CH);
+ ch_idx++) {
+ tx_done &= readl_relaxed(
+ &mhuv2->reg.send->channel[ch_idx].STAT) == 0;
+ }
+ return tx_done;
+}
+
+static inline int mhuv2_setup_multi_word(struct arm_mhuv2 *mhuv2)
+{
+ int ret, i;
+
+ const u32 channel_windows =
+ readl_relaxed_bitfield(mhuv2->frame == RECEIVER_FRAME ?
+ &mhuv2->reg.recv->MHU_CFG :
+ &mhuv2->reg.send->MHU_CFG,
+ NUM_CH);
+ if (channel_windows < 2) {
+ dev_err(mhuv2->dev,
+ "Error: at least 2 MHU channel windows are required for using the multi-word transfer protocol");
+ return -ENODEV;
+ }
+
+ if (mhuv2->frame == RECEIVER_FRAME) {
+ /*
+ * The multi-word transport protocol mandates that all but
+ * the last status register must be masked.
+ */
+ for (i = 0; i < (channel_windows - 1); i++) {
+ writel_relaxed(-1,
+ &mhuv2->reg.recv->channel[i].MASK_SET);
+ }
+ }
+
+ mhuv2->mbox.num_chans = 1;
+ mhuv2->mbox.chans =
+ devm_kzalloc(mhuv2->dev,
+ mhuv2->mbox.num_chans * sizeof(struct mbox_chan),
+ GFP_KERNEL);
+
+ return 0;
+}
+
+static inline struct mbox_chan *
+ mhuv2_get_active_mbox_chan_multi_word(struct arm_mhuv2 *mhuv2)
+{
+ return &mhuv2->mbox.chans[0];
+}
+
+static const struct mhuv2_ops mhuv2_multi_word_ops = {
+ .read_data = mhuv2_read_data_multi_word,
+ .clear_data = mhuv2_clear_data_multi_word,
+ .send_data = mhuv2_send_data_multi_word,
+ .setup = mhuv2_setup_multi_word,
+ .last_tx_done = mhuv2_last_tx_done_multi_word,
+ .get_active_mbox_chan = mhuv2_get_active_mbox_chan_multi_word,
+};
+/* ========================================================================== */
+
/* =================== Doorbell transport protocol operations =============== */
static inline int mhuv2_read_data_doorbell(struct arm_mhuv2 *mhuv2,
@@ -696,6 +918,9 @@ static int mhuv2_probe(struct amba_device *adev, const struct amba_id *id)
} else if (strcmp(mhuv2_protocol_str,
mhuv2_protocol_dt_identifiers[SINGLE_WORD]) == 0) {
mhuv2->ops = &mhuv2_single_word_ops;
+ } else if (strcmp(mhuv2_protocol_str,
+ mhuv2_protocol_dt_identifiers[MULTI_WORD]) == 0) {
+ mhuv2->ops = &mhuv2_multi_word_ops;
} else if (strcmp(mhuv2_protocol_str,
mhuv2_protocol_dt_identifiers[DOORBELL]) == 0) {
mhuv2->ops = &mhuv2_doorbell_ops;
--
2.17.1
@@ -1,67 +0,0 @@
From 68ce2dfe4c6f3806001fb8d682d6e99a9580dc2a Mon Sep 17 00:00:00 2001
From: Usama Arif <usama.arif@arm.com>
Date: Wed, 24 Jun 2020 11:16:01 +0100
Subject: [PATCH 7/9] firmware: arm_scmi: Add fast_switch_possible() api
Add a new fast_switch_possible interface to the existing
perf_ops api to export the information of whether or not
fast_switch is possible in this driver.
This can be used by the CPUFreq driver and framework to
choose proper mechanism for frequency change.
Suggested-by: Lukasz Luba <lukasz.luba@arm.com>
Signed-off-by: Nicola Mazzucato <nicola.mazzucato@arm.com>
Upstream-Status: Backport [https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/firmware/arm_scmi?id=1909872ff20fc378ec6a44ea1a2b2966d834e504]
---
drivers/firmware/arm_scmi/perf.c | 12 ++++++++++++
include/linux/scmi_protocol.h | 2 ++
2 files changed, 14 insertions(+)
diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c
index 601af4edad5e..c9350bb2ba1f 100644
--- a/drivers/firmware/arm_scmi/perf.c
+++ b/drivers/firmware/arm_scmi/perf.c
@@ -691,6 +691,17 @@ static int scmi_dvfs_est_power_get(const struct scmi_handle *handle, u32 domain,
return ret;
}
+static bool scmi_fast_switch_possible(const struct scmi_handle *handle,
+ struct device *dev)
+{
+ struct perf_dom_info *dom;
+ struct scmi_perf_info *pi = handle->perf_priv;
+
+ dom = pi->dom_info + scmi_dev_domain_id(dev);
+
+ return (dom->fc_info && dom->fc_info->level_set_addr);
+}
+
static struct scmi_perf_ops perf_ops = {
.limits_set = scmi_perf_limits_set,
.limits_get = scmi_perf_limits_get,
@@ -702,6 +713,7 @@ static struct scmi_perf_ops perf_ops = {
.freq_set = scmi_dvfs_freq_set,
.freq_get = scmi_dvfs_freq_get,
.est_power_get = scmi_dvfs_est_power_get,
+ .fast_switch_possible = scmi_fast_switch_possible,
};
static int scmi_perf_protocol_init(struct scmi_handle *handle)
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 881fea47c83d..b1f4a88219c5 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -114,6 +114,8 @@ struct scmi_perf_ops {
unsigned long *rate, bool poll);
int (*est_power_get)(const struct scmi_handle *handle, u32 domain,
unsigned long *rate, unsigned long *power);
+ bool (*fast_switch_possible)(const struct scmi_handle *handle,
+ struct device *dev);
};
/**
--
2.17.1
@@ -1,42 +0,0 @@
From 47300d8385801913709eda5fd237d54f51477546 Mon Sep 17 00:00:00 2001
From: Usama Arif <usama.arif@arm.com>
Date: Wed, 24 Jun 2020 11:25:02 +0100
Subject: [PATCH 8/9] cpufreq: arm_scmi: Set fast_switch_possible conditionally
Currently the fast_switch_possible flag is set unconditionally
to true. Based on this, schedutil does not create a
thread for frequency switching and would always use the
fast switch path.
However, if the platform does not support frequency
fast switch, this may cause the governor to attempt an
operation that is not supported by the platform.
Fix this by correctly retrieve the fast_switch capability
from the driver which knows if the platform can support
this feature.
Suggested-by: Lukasz Luba <lukasz.luba@arm.com>
Signed-off-by: Nicola Mazzucato <nicola.mazzucato@arm.com>
Upstream-Status: Backport [https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/cpufreq?id=fb3571276b970cbe7b45ecdc762e92f3f305ad6d]
---
drivers/cpufreq/scmi-cpufreq.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c
index e6182c89df79..931fcf0ef221 100644
--- a/drivers/cpufreq/scmi-cpufreq.c
+++ b/drivers/cpufreq/scmi-cpufreq.c
@@ -198,7 +198,8 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = latency;
- policy->fast_switch_possible = true;
+ policy->fast_switch_possible =
+ handle->perf_ops->fast_switch_possible(handle, cpu_dev);
em_register_perf_domain(policy->cpus, nr_opp, &em_cb);
--
2.17.1
@@ -1,252 +0,0 @@
Upstream-Status: Backport [https://github.com/linaro-swg/linux/commit/e33bcbab16d1c0dd85d72bec275308369ad901f5#diff-317c0445401e56bde9d2ee0e0bb2758b0362a4099dca8e535dd20f1f649ecfc8]
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
From 69a50f4234d8fb143d499e92e3f0f67009bae586 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Vesa=20J=C3=A4=C3=A4skel=C3=A4inen?=
<vesa.jaaskelainen@vaisala.com>
Date: Wed, 22 Apr 2020 15:28:07 +0300
Subject: [PATCH] tee: add support for session's client UUID generation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
TEE Client API defines that from user space only information needed for
specified login operations is group identifier for group based logins.
REE kernel is expected to formulate trustworthy client UUID and pass that
to TEE environment. REE kernel is required to verify that provided group
identifier for group based logins matches calling processes group
memberships.
TEE specification only defines that the information passed from REE
environment to TEE environment is encoded into on UUID.
In order to guarantee trustworthiness of client UUID user space is not
allowed to freely pass client UUID.
UUIDv5 form is used encode variable amount of information needed for
different login types.
Signed-off-by: Vesa Jääskeläinen <vesa.jaaskelainen@vaisala.com>
Change-Id: I414f68d7485f95277d292fcb2646cc41bd57e62a
---
drivers/tee/Kconfig | 1 +
drivers/tee/tee_core.c | 143 ++++++++++++++++++++++++++++++++++++++++
include/linux/tee_drv.h | 16 +++++
3 files changed, 160 insertions(+)
diff --git a/drivers/tee/Kconfig b/drivers/tee/Kconfig
index 676ffcb64985..5a56317f3f4e 100644
--- a/drivers/tee/Kconfig
+++ b/drivers/tee/Kconfig
@@ -3,6 +3,7 @@
config TEE
tristate "Trusted Execution Environment support"
depends on HAVE_ARM_SMCCC || COMPILE_TEST
+ select CRYPTO_SHA1
select DMA_SHARED_BUFFER
select GENERIC_ALLOCATOR
help
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index 0f16d9ffd8d1..3d32a2ca48c3 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -6,18 +6,33 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/cdev.h>
+#include <linux/cred.h>
#include <linux/fs.h>
#include <linux/idr.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/tee_drv.h>
#include <linux/uaccess.h>
+#include <crypto/hash.h>
+#include <crypto/sha.h>
#include "tee_private.h"
#define TEE_NUM_DEVICES 32
#define TEE_IOCTL_PARAM_SIZE(x) (sizeof(struct tee_param) * (x))
+#define TEE_UUID_NS_NAME_SIZE 128
+
+/*
+ * TEE Client UUID name space identifier (UUIDv4)
+ *
+ * Value here is random UUID that is allocated as name space identifier for
+ * forming Client UUID's for TEE environment using UUIDv5 scheme.
+ */
+static const uuid_t tee_client_uuid_ns = UUID_INIT(0x58ac9ca0, 0x2086, 0x4683,
+ 0xa1, 0xb8, 0xec, 0x4b,
+ 0xc0, 0x8e, 0x01, 0xb6);
+
/*
* Unprivileged devices in the lower half range and privileged devices in
* the upper half range.
@@ -111,6 +126,134 @@ static int tee_release(struct inode *inode, struct file *filp)
return 0;
}
+/**
+ * uuid_v5() - Calculate UUIDv5
+ * @uuid: Resulting UUID
+ * @ns: Name space ID for UUIDv5 function
+ * @name: Name for UUIDv5 function
+ * @size: Size of name
+ *
+ * UUIDv5 is specific in RFC 4122.
+ *
+ * This implements section (for SHA-1):
+ * 4.3. Algorithm for Creating a Name-Based UUID
+ */
+static int uuid_v5(uuid_t *uuid, const uuid_t *ns, const void *name,
+ size_t size)
+{
+ unsigned char hash[SHA1_DIGEST_SIZE];
+ struct crypto_shash *shash = NULL;
+ struct shash_desc *desc = NULL;
+ int rc;
+
+ shash = crypto_alloc_shash("sha1", 0, 0);
+ if (IS_ERR(shash)) {
+ rc = PTR_ERR(shash);
+ pr_err("shash(sha1) allocation failed\n");
+ return rc;
+ }
+
+ desc = kzalloc(sizeof(*desc) + crypto_shash_descsize(shash),
+ GFP_KERNEL);
+ if (IS_ERR(desc)) {
+ rc = PTR_ERR(desc);
+ goto out;
+ }
+
+ desc->tfm = shash;
+
+ rc = crypto_shash_init(desc);
+ if (rc < 0)
+ goto out2;
+
+ rc = crypto_shash_update(desc, (const u8 *)ns, sizeof(*ns));
+ if (rc < 0)
+ goto out2;
+
+ rc = crypto_shash_update(desc, (const u8 *)name, size);
+ if (rc < 0)
+ goto out2;
+
+ rc = crypto_shash_final(desc, hash);
+ if (rc < 0)
+ goto out2;
+
+ memcpy(uuid->b, hash, UUID_SIZE);
+
+ /* Tag for version 5 */
+ uuid->b[6] = (hash[6] & 0x0F) | 0x50;
+ uuid->b[8] = (hash[8] & 0x3F) | 0x80;
+
+out2:
+ kfree(desc);
+
+out:
+ crypto_free_shash(shash);
+ return rc;
+}
+
+int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method,
+ const u8 connection_data[TEE_IOCTL_UUID_LEN])
+{
+ const char *application_id = NULL;
+ gid_t ns_grp = (gid_t)-1;
+ kgid_t grp = INVALID_GID;
+ char *name = NULL;
+ int rc;
+
+ if (connection_method == TEE_IOCTL_LOGIN_PUBLIC) {
+ /* Nil UUID to be passed to TEE environment */
+ uuid_copy(uuid, &uuid_null);
+ return 0;
+ }
+
+ /*
+ * In Linux environment client UUID is based on UUIDv5.
+ *
+ * Determine client UUID with following semantics for 'name':
+ *
+ * For TEEC_LOGIN_USER:
+ * uid=<uid>
+ *
+ * For TEEC_LOGIN_GROUP:
+ * gid=<gid>
+ *
+ */
+
+ name = kzalloc(TEE_UUID_NS_NAME_SIZE, GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+
+ switch (connection_method) {
+ case TEE_IOCTL_LOGIN_USER:
+ scnprintf(name, TEE_UUID_NS_NAME_SIZE, "uid=%x",
+ current_euid().val);
+ break;
+
+ case TEE_IOCTL_LOGIN_GROUP:
+ memcpy(&ns_grp, connection_data, sizeof(gid_t));
+ grp = make_kgid(current_user_ns(), ns_grp);
+ if (!gid_valid(grp) || !in_egroup_p(grp)) {
+ rc = -EPERM;
+ goto out;
+ }
+
+ scnprintf(name, TEE_UUID_NS_NAME_SIZE, "gid=%x", grp.val);
+ break;
+
+ default:
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = uuid_v5(uuid, &tee_client_uuid_ns, name, strlen(name));
+out:
+ kfree(name);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(tee_session_calc_client_uuid);
+
static int tee_ioctl_version(struct tee_context *ctx,
struct tee_ioctl_version_data __user *uvers)
{
diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
index 7a03f68fb982..545a57f61a5e 100644
--- a/include/linux/tee_drv.h
+++ b/include/linux/tee_drv.h
@@ -166,6 +166,22 @@ int tee_device_register(struct tee_device *teedev);
*/
void tee_device_unregister(struct tee_device *teedev);
+/**
+ * tee_session_calc_client_uuid() - Calculates client UUID for session
+ * @uuid: Resulting UUID
+ * @connection_method: Connection method for session (TEE_IOCTL_LOGIN_*)
+ * @connectuon_data: Connection data for opening session
+ *
+ * Based on connection method calculates UUIDv5 based client UUID.
+ *
+ * For group based logins verifies that calling process has specified
+ * credentials.
+ *
+ * @return < 0 on failure
+ */
+int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method,
+ const u8 connection_data[TEE_IOCTL_UUID_LEN]);
+
/**
* struct tee_shm - shared memory object
* @teedev: device used to allocate the object
--
2.26.2
@@ -1,43 +0,0 @@
Upstream-Status: Backport [https://github.com/linaro-swg/linux/commit/c5b4312bea5d5e5e3d4f0af640e2ef8a1c1bb167#diff-2d83bca4adf0468bdb51b155a5df495e0226f7971f4150cfffbf043fe3b5a279]
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
From c6c4046d8fcd34a4b8da9d844ce592951780ba8c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Vesa=20J=C3=A4=C3=A4skel=C3=A4inen?=
<vesa.jaaskelainen@vaisala.com>
Date: Wed, 22 Apr 2020 15:30:39 +0300
Subject: [PATCH] tee: optee: Add support for session login client UUID
generation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Adds support for client UUID generation for OP-TEE. For group based session
logins membership is verified.
Signed-off-by: Vesa Jääskeläinen <vesa.jaaskelainen@vaisala.com>
---
drivers/tee/optee/call.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c
index cf2367ba08d6..dbed3f480dc0 100644
--- a/drivers/tee/optee/call.c
+++ b/drivers/tee/optee/call.c
@@ -233,9 +233,13 @@ int optee_open_session(struct tee_context *ctx,
msg_arg->params[1].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT |
OPTEE_MSG_ATTR_META;
memcpy(&msg_arg->params[0].u.value, arg->uuid, sizeof(arg->uuid));
- memcpy(&msg_arg->params[1].u.value, arg->uuid, sizeof(arg->clnt_uuid));
msg_arg->params[1].u.value.c = arg->clnt_login;
+ rc = tee_session_calc_client_uuid((uuid_t *)&msg_arg->params[1].u.value,
+ arg->clnt_login, arg->clnt_uuid);
+ if (rc)
+ goto out;
+
rc = optee_to_msg_param(msg_arg->params + 2, arg->num_params, param);
if (rc)
goto out;
--
2.26.2
@@ -1,51 +0,0 @@
From 957e0145899813017a6a2b7f863a4a2b4e4b75aa Mon Sep 17 00:00:00 2001
From: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Date: Tue, 5 Jan 2021 09:27:41 +0000
Subject: [PATCH] tee: optee: fix mem handle removal in ffa_shm_unregister
Remove ffa memory handle before calling mem_reclaim. This enables the
handle to be re-used by another thread once mem_claim for that handle
is completed.
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: I7294bd71f2bbc28514eaa09ae757dd216bc7df45
Upstream-Status: Pending [Not submitted to upstream yet]
---
drivers/tee/optee/call.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c
index ac89ab42a43f..9c9480add0b5 100644
--- a/drivers/tee/optee/call.c
+++ b/drivers/tee/optee/call.c
@@ -843,6 +843,10 @@ int optee_ffa_shm_unregister_supp(struct tee_context *ctx,
{
struct optee *optee = tee_get_drvdata(ctx->teedev);
int rc = 0;
+ u64 handle = shm->sec_world_id;
+
+ optee_shm_rem_ffa_handle(optee, handle);
+ shm->sec_world_id = 0;
/*
* We're skipping the OPTEE_FFA_YIELDING_CALL_UNREGISTER_SHM call
@@ -850,14 +854,10 @@ int optee_ffa_shm_unregister_supp(struct tee_context *ctx,
* this ID.
*/
- rc = optee->ffa.ops->mem_reclaim(shm->sec_world_id, 0);
+ rc = optee->ffa.ops->mem_reclaim(handle, 0);
if (rc)
pr_err("mem_reclain: %d", rc);
- optee_shm_rem_ffa_handle(optee, shm->sec_world_id);
-
- shm->sec_world_id = 0;
-
return rc;
}
#endif /*CONFIG_ARM_FFA_TRANSPORT*/
--
2.26.2
@@ -1,462 +0,0 @@
Upstream-Status: Backport [http://www.linux-arm.org/git?p=linux-power.git;a=commit;h=ce7d6e205568b7949ff26f2b3c65dc4db1c15b96]
Signed-off-by: Usama Arif <usama.arif@arm.com>
From 0316669bc2a0e1279427b7a3ed01313b70544756 Mon Sep 17 00:00:00 2001
From: Catalin Marinas <catalin.marinas@arm.com>
Date: Thu, 20 Jun 2019 17:59:25 +0100
Subject: [PATCH 1/2] arm64: Add support for asymmetric AArch32 EL0
configurations
There is a non-negligible chance that we may see asymmetric big.LITTLE
configurations where only the LITTLE CPUs have AArch32 support at EL0.
While Linux currently handles such configurations by not allowing
AArch32 tasks, there is a strong marketing push to investigate the
possibility of allowing compat applications. This patch is aimed to
facilitate internal testing and NOT FOR UPSTREAM.
When the CONFIG_ASYMMETRIC_AARCH32 option is enabled (EXPERT), the type
of the ARM64_HAS_32BIT_EL0 capability becomes WEAK_LOCAL_CPU_FEATURE.
The kernel will now return true for system_supports_32bit_el0() and
32-bit tasks will be migrated to the capable CPUs during
do_notify_resume(). If the last CPU supporting 32-bit is offlined, the
kernel will SIGKILL any scheduled 32-bit tasks (the alternative is to
prevent offlining through a new .cpu_disable feature entry).
In addition to the relaxation of the ARM64_HAS_32BIT_EL0 capability,
this patch factors out the 32-bit cpuinfo and features setting into
separate functions: __cpuinfo_store_cpu_32bit(),
init_cpu_32bit_features(). The cpuinfo of the booting CPU
(boot_cpu_data) is now updated on the first 32-bit capable CPU even if
it is a secondary one. The ID_AA64PFR0_EL0_64BIT_ONLY feature is relaxed
to FTR_NONSTRICT and FTR_HIGHER_SAFE when the asymmetric AArch32 support
is enabled. The compat_elf_hwcaps are only verified for the
AArch32-capable CPUs to still allow hotplugging AArch64-only CPUs.
Cc: Suzuki K Poulose <Suzuki.Poulose@arm.com>
Cc: Morten Rasmussen <Morten.Rasmussen@arm.com>
Cc: Valentin Schneider <valentin.schneider@arm.com>
Cc: Qais Yousef <qais.yousef@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Qais Yousef <qais.yousef@arm.com>
---
arch/arm64/Kconfig | 13 ++++++
arch/arm64/include/asm/cpu.h | 2 +
arch/arm64/include/asm/cpufeature.h | 3 ++
arch/arm64/include/asm/thread_info.h | 5 ++-
arch/arm64/kernel/cpufeature.c | 64 ++++++++++++++++++----------
arch/arm64/kernel/cpuinfo.c | 61 +++++++++++++++++---------
arch/arm64/kernel/process.c | 17 ++++++++
arch/arm64/kernel/signal.c | 30 ++++++++++++-
8 files changed, 150 insertions(+), 45 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 71d23b5d10d4..068e9e9ffc40 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1680,6 +1680,19 @@ config DMI
endmenu
+config ASYMMETRIC_AARCH32
+ bool "Allow support for asymmetric AArch32 support"
+ depends on COMPAT && EXPERT && !KVM
+ help
+ Enable this option to allow support for asymmetric AArch32 EL0
+ CPU configurations. Once the AArch32 EL0 support is detected
+ on a CPU, the feature is made available to user space to allow
+ the execution of 32-bit (compat) applications by migrating
+ them to the capable CPUs. Offlining such CPUs leads to 32-bit
+ applications being killed.
+
+ If unsure say N.
+
config SYSVIPC_COMPAT
def_bool y
depends on COMPAT && SYSVIPC
diff --git a/arch/arm64/include/asm/cpu.h b/arch/arm64/include/asm/cpu.h
index d72d995b7e25..39dbf5827070 100644
--- a/arch/arm64/include/asm/cpu.h
+++ b/arch/arm64/include/asm/cpu.h
@@ -15,6 +15,7 @@
struct cpuinfo_arm64 {
struct cpu cpu;
struct kobject kobj;
+ bool aarch32_valid;
u32 reg_ctr;
u32 reg_cntfrq;
u32 reg_dczid;
@@ -60,6 +61,7 @@ void cpuinfo_store_cpu(void);
void __init cpuinfo_store_boot_cpu(void);
void __init init_cpu_features(struct cpuinfo_arm64 *info);
+void init_cpu_32bit_features(struct cpuinfo_arm64 *info);
void update_cpu_features(int cpu, struct cpuinfo_arm64 *info,
struct cpuinfo_arm64 *boot);
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 9cde5d2e768f..d00d673d423b 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -17,6 +17,7 @@
#ifndef __ASSEMBLY__
#include <linux/bug.h>
+#include <linux/cpumask.h>
#include <linux/jump_label.h>
#include <linux/kernel.h>
@@ -370,6 +371,8 @@ cpucap_multi_entry_cap_matches(const struct arm64_cpu_capabilities *entry,
return false;
}
+extern cpumask_t aarch32_el0_mask;
+
extern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS];
extern struct static_key_false arm64_const_caps_ready;
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 8c73764b9ed2..54a4c912a7ab 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -66,6 +66,7 @@ void arch_release_task_struct(struct task_struct *tsk);
#define TIF_FOREIGN_FPSTATE 3 /* CPU's FP state is not current's */
#define TIF_UPROBE 4 /* uprobe breakpoint or singlestep */
#define TIF_FSCHECK 5 /* Check FS is USER_DS on return */
+#define TIF_SET_32BIT_AFFINITY 6 /* set thread affinity for asymmetric AArch32 */
#define TIF_NOHZ 7
#define TIF_SYSCALL_TRACE 8 /* syscall trace active */
#define TIF_SYSCALL_AUDIT 9 /* syscall auditing */
@@ -95,11 +96,13 @@ void arch_release_task_struct(struct task_struct *tsk);
#define _TIF_UPROBE (1 << TIF_UPROBE)
#define _TIF_FSCHECK (1 << TIF_FSCHECK)
#define _TIF_32BIT (1 << TIF_32BIT)
+#define _TIF_SET_32BIT_AFFINITY (1 << TIF_SET_32BIT_AFFINITY)
#define _TIF_SVE (1 << TIF_SVE)
#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
_TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \
- _TIF_UPROBE | _TIF_FSCHECK)
+ _TIF_UPROBE | _TIF_FSCHECK | \
+ _TIF_SET_32BIT_AFFINITY)
#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
_TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index da92693b202c..c0d656cfe5b8 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -8,7 +8,6 @@
#define pr_fmt(fmt) "CPU features: " fmt
#include <linux/bsearch.h>
-#include <linux/cpumask.h>
#include <linux/crash_dump.h>
#include <linux/sort.h>
#include <linux/stop_machine.h>
@@ -164,7 +163,11 @@ static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL3_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL2_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_SHIFT, 4, ID_AA64PFR0_EL1_64BIT_ONLY),
+#ifndef CONFIG_ASYMMETRIC_AARCH32
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL0_SHIFT, 4, ID_AA64PFR0_EL0_64BIT_ONLY),
+#else
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_HIGHER_SAFE, ID_AA64PFR0_EL0_SHIFT, 4, ID_AA64PFR0_EL0_64BIT_ONLY),
+#endif
ARM64_FTR_END,
};
@@ -509,7 +512,7 @@ static void __init sort_ftr_regs(void)
* Any bits that are not covered by an arm64_ftr_bits entry are considered
* RES0 for the system-wide value, and must strictly match.
*/
-static void __init init_cpu_ftr_reg(u32 sys_reg, u64 new)
+static void init_cpu_ftr_reg(u32 sys_reg, u64 new)
{
u64 val = 0;
u64 strict_mask = ~0x0ULL;
@@ -590,25 +593,6 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info)
init_cpu_ftr_reg(SYS_ID_AA64PFR1_EL1, info->reg_id_aa64pfr1);
init_cpu_ftr_reg(SYS_ID_AA64ZFR0_EL1, info->reg_id_aa64zfr0);
- if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
- init_cpu_ftr_reg(SYS_ID_DFR0_EL1, info->reg_id_dfr0);
- init_cpu_ftr_reg(SYS_ID_ISAR0_EL1, info->reg_id_isar0);
- init_cpu_ftr_reg(SYS_ID_ISAR1_EL1, info->reg_id_isar1);
- init_cpu_ftr_reg(SYS_ID_ISAR2_EL1, info->reg_id_isar2);
- init_cpu_ftr_reg(SYS_ID_ISAR3_EL1, info->reg_id_isar3);
- init_cpu_ftr_reg(SYS_ID_ISAR4_EL1, info->reg_id_isar4);
- init_cpu_ftr_reg(SYS_ID_ISAR5_EL1, info->reg_id_isar5);
- init_cpu_ftr_reg(SYS_ID_MMFR0_EL1, info->reg_id_mmfr0);
- init_cpu_ftr_reg(SYS_ID_MMFR1_EL1, info->reg_id_mmfr1);
- init_cpu_ftr_reg(SYS_ID_MMFR2_EL1, info->reg_id_mmfr2);
- init_cpu_ftr_reg(SYS_ID_MMFR3_EL1, info->reg_id_mmfr3);
- init_cpu_ftr_reg(SYS_ID_PFR0_EL1, info->reg_id_pfr0);
- init_cpu_ftr_reg(SYS_ID_PFR1_EL1, info->reg_id_pfr1);
- init_cpu_ftr_reg(SYS_MVFR0_EL1, info->reg_mvfr0);
- init_cpu_ftr_reg(SYS_MVFR1_EL1, info->reg_mvfr1);
- init_cpu_ftr_reg(SYS_MVFR2_EL1, info->reg_mvfr2);
- }
-
if (id_aa64pfr0_sve(info->reg_id_aa64pfr0)) {
init_cpu_ftr_reg(SYS_ZCR_EL1, info->reg_zcr);
sve_init_vq_map();
@@ -627,6 +611,26 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info)
setup_boot_cpu_capabilities();
}
+void init_cpu_32bit_features(struct cpuinfo_arm64 *info)
+{
+ init_cpu_ftr_reg(SYS_ID_DFR0_EL1, info->reg_id_dfr0);
+ init_cpu_ftr_reg(SYS_ID_ISAR0_EL1, info->reg_id_isar0);
+ init_cpu_ftr_reg(SYS_ID_ISAR1_EL1, info->reg_id_isar1);
+ init_cpu_ftr_reg(SYS_ID_ISAR2_EL1, info->reg_id_isar2);
+ init_cpu_ftr_reg(SYS_ID_ISAR3_EL1, info->reg_id_isar3);
+ init_cpu_ftr_reg(SYS_ID_ISAR4_EL1, info->reg_id_isar4);
+ init_cpu_ftr_reg(SYS_ID_ISAR5_EL1, info->reg_id_isar5);
+ init_cpu_ftr_reg(SYS_ID_MMFR0_EL1, info->reg_id_mmfr0);
+ init_cpu_ftr_reg(SYS_ID_MMFR1_EL1, info->reg_id_mmfr1);
+ init_cpu_ftr_reg(SYS_ID_MMFR2_EL1, info->reg_id_mmfr2);
+ init_cpu_ftr_reg(SYS_ID_MMFR3_EL1, info->reg_id_mmfr3);
+ init_cpu_ftr_reg(SYS_ID_PFR0_EL1, info->reg_id_pfr0);
+ init_cpu_ftr_reg(SYS_ID_PFR1_EL1, info->reg_id_pfr1);
+ init_cpu_ftr_reg(SYS_MVFR0_EL1, info->reg_mvfr0);
+ init_cpu_ftr_reg(SYS_MVFR1_EL1, info->reg_mvfr1);
+ init_cpu_ftr_reg(SYS_MVFR2_EL1, info->reg_mvfr2);
+}
+
static void update_cpu_ftr_reg(struct arm64_ftr_reg *reg, u64 new)
{
const struct arm64_ftr_bits *ftrp;
@@ -1264,6 +1268,16 @@ static bool can_use_gic_priorities(const struct arm64_cpu_capabilities *entry,
}
#endif
+#ifdef CONFIG_ASYMMETRIC_AARCH32
+cpumask_t aarch32_el0_mask;
+
+static void cpu_enable_aarch32_el0(struct arm64_cpu_capabilities const *cap)
+{
+ if (has_cpuid_feature(cap, SCOPE_LOCAL_CPU))
+ cpumask_set_cpu(smp_processor_id(), &aarch32_el0_mask);
+}
+#endif
+
static const struct arm64_cpu_capabilities arm64_features[] = {
{
.desc = "GIC system register CPU interface",
@@ -1340,7 +1354,12 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
{
.desc = "32-bit EL0 Support",
.capability = ARM64_HAS_32BIT_EL0,
+#ifndef CONFIG_ASYMMETRIC_AARCH32
.type = ARM64_CPUCAP_SYSTEM_FEATURE,
+#else
+ .type = ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE,
+ .cpu_enable = cpu_enable_aarch32_el0,
+#endif
.matches = has_cpuid_feature,
.sys_reg = SYS_ID_AA64PFR0_EL1,
.sign = FTR_UNSIGNED,
@@ -1983,7 +2002,8 @@ static void verify_local_cpu_capabilities(void)
verify_local_elf_hwcaps(arm64_elf_hwcaps);
- if (system_supports_32bit_el0())
+ if (system_supports_32bit_el0() &&
+ this_cpu_has_cap(ARM64_HAS_32BIT_EL0))
verify_local_elf_hwcaps(compat_elf_hwcaps);
if (system_supports_sve())
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
index 05933c065732..bda37687bb66 100644
--- a/arch/arm64/kernel/cpuinfo.c
+++ b/arch/arm64/kernel/cpuinfo.c
@@ -351,27 +351,6 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1);
info->reg_id_aa64zfr0 = read_cpuid(ID_AA64ZFR0_EL1);
- /* Update the 32bit ID registers only if AArch32 is implemented */
- if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
- info->reg_id_dfr0 = read_cpuid(ID_DFR0_EL1);
- info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1);
- info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1);
- info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1);
- info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1);
- info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1);
- info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1);
- info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1);
- info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1);
- info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1);
- info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1);
- info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1);
- info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);
-
- info->reg_mvfr0 = read_cpuid(MVFR0_EL1);
- info->reg_mvfr1 = read_cpuid(MVFR1_EL1);
- info->reg_mvfr2 = read_cpuid(MVFR2_EL1);
- }
-
if (IS_ENABLED(CONFIG_ARM64_SVE) &&
id_aa64pfr0_sve(info->reg_id_aa64pfr0))
info->reg_zcr = read_zcr_features();
@@ -379,10 +358,46 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
cpuinfo_detect_icache_policy(info);
}
+static void __cpuinfo_store_cpu_32bit(struct cpuinfo_arm64 *info)
+{
+ info->aarch32_valid = true;
+
+ info->reg_id_dfr0 = read_cpuid(ID_DFR0_EL1);
+ info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1);
+ info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1);
+ info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1);
+ info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1);
+ info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1);
+ info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1);
+ info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1);
+ info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1);
+ info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1);
+ info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1);
+ info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1);
+ info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);
+
+ info->reg_mvfr0 = read_cpuid(MVFR0_EL1);
+ info->reg_mvfr1 = read_cpuid(MVFR1_EL1);
+ info->reg_mvfr2 = read_cpuid(MVFR2_EL1);
+}
+
void cpuinfo_store_cpu(void)
{
struct cpuinfo_arm64 *info = this_cpu_ptr(&cpu_data);
__cpuinfo_store_cpu(info);
+ if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0))
+ __cpuinfo_store_cpu_32bit(info);
+ /*
+ * With asymmetric AArch32 support, populate the boot CPU information
+ * on the first 32-bit capable secondary CPU if the primary one
+ * skipped this step.
+ */
+ if (IS_ENABLED(CONFIG_ASYMMETRIC_AARCH32) &&
+ !boot_cpu_data.aarch32_valid &&
+ id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
+ __cpuinfo_store_cpu_32bit(&boot_cpu_data);
+ init_cpu_32bit_features(&boot_cpu_data);
+ }
update_cpu_features(smp_processor_id(), info, &boot_cpu_data);
}
@@ -390,9 +405,13 @@ void __init cpuinfo_store_boot_cpu(void)
{
struct cpuinfo_arm64 *info = &per_cpu(cpu_data, 0);
__cpuinfo_store_cpu(info);
+ if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0))
+ __cpuinfo_store_cpu_32bit(info);
boot_cpu_data = *info;
init_cpu_features(&boot_cpu_data);
+ if (id_aa64pfr0_32bit_el0(boot_cpu_data.reg_id_aa64pfr0))
+ init_cpu_32bit_features(&boot_cpu_data);
}
device_initcall(cpuinfo_regs_init);
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index cc1d8b1025b1..35f0c93699ce 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -494,6 +494,15 @@ static void entry_task_switch(struct task_struct *next)
__this_cpu_write(__entry_task, next);
}
+static void aarch32_thread_switch(struct task_struct *next)
+{
+ struct thread_info *ti = task_thread_info(next);
+
+ if (IS_ENABLED(CONFIG_ASYMMETRIC_AARCH32) && is_compat_thread(ti) &&
+ !cpumask_test_cpu(smp_processor_id(), &aarch32_el0_mask))
+ set_ti_thread_flag(ti, TIF_SET_32BIT_AFFINITY);
+}
+
/*
* Thread switching.
*/
@@ -511,6 +520,7 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev,
ptrauth_thread_switch(next);
ssbs_thread_switch(next);
scs_overflow_check(next);
+ aarch32_thread_switch(next);
/*
* Complete any pending TLB or cache maintenance on this CPU in case
@@ -569,6 +579,13 @@ void arch_setup_new_exec(void)
current->mm->context.flags = is_compat_task() ? MMCF_AARCH32 : 0;
ptrauth_thread_init_user(current);
+
+ /*
+ * If exec'ing a 32-bit task, force the asymmetric 32-bit feature
+ * check as the task may not go through a switch_to() call.
+ */
+ if (IS_ENABLED(CONFIG_ASYMMETRIC_AARCH32) && is_compat_task())
+ set_thread_flag(TIF_SET_32BIT_AFFINITY);
}
#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index dd2cdc0d5be2..d8cdd3211d68 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -8,6 +8,7 @@
#include <linux/cache.h>
#include <linux/compat.h>
+#include <linux/cpumask.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/signal.h>
@@ -896,6 +897,29 @@ static void do_signal(struct pt_regs *regs)
restore_saved_sigmask();
}
+static void set_32bit_cpus_allowed(void)
+{
+ int ret;
+
+ /*
+ * Try to honour as best as possible whatever affinity request this
+ * task has. If it spans no compatible CPU, disregard it entirely.
+ */
+ if (cpumask_intersects(current->cpus_ptr, &aarch32_el0_mask)) {
+ cpumask_t cpus_allowed;
+
+ cpumask_and(&cpus_allowed, current->cpus_ptr, &aarch32_el0_mask);
+ ret = set_cpus_allowed_ptr(current, &cpus_allowed);
+ } else {
+ ret = set_cpus_allowed_ptr(current, &aarch32_el0_mask);
+ }
+
+ if (ret) {
+ pr_warn_once("No CPUs capable of running 32-bit tasks\n");
+ force_sig(SIGKILL);
+ }
+}
+
asmlinkage void do_notify_resume(struct pt_regs *regs,
unsigned long thread_flags)
{
@@ -910,7 +934,11 @@ asmlinkage void do_notify_resume(struct pt_regs *regs,
/* Check valid user FS if needed */
addr_limit_user_check();
- if (thread_flags & _TIF_NEED_RESCHED) {
+ if (IS_ENABLED(CONFIG_ASYMMETRIC_AARCH32) &&
+ thread_flags & _TIF_SET_32BIT_AFFINITY) {
+ clear_thread_flag(TIF_SET_32BIT_AFFINITY);
+ set_32bit_cpus_allowed();
+ } else if (thread_flags & _TIF_NEED_RESCHED) {
/* Unmask Debug and SError for the next task */
local_daif_restore(DAIF_PROCCTX_NOIRQ);
--
2.29.2
@@ -1,89 +0,0 @@
Upstream-Status: Backport [http://www.linux-arm.org/git?p=linux-power.git;a=commit;h=e6b567c1cc07dd1690e5d34b6a93ab9819ab2eeb]
Signed-off-by: Usama Arif <usama.arif@arm.com>
From d6acb605de7d40c295ada9b1f4c8336e4db71ae4 Mon Sep 17 00:00:00 2001
From: Valentin Schneider <valentin.schneider@arm.com>
Date: Thu, 5 Sep 2019 17:53:19 +0100
Subject: [PATCH 2/2] arm64: smp: Prevent hotplugging the last AArch32-able CPU
EL0 AArch32 tasks are now sigkilled when they can't run on any
compatible CPU, either because there aren't any left (hotplug) or
because they aren't allowed to run on those left (task affinity).
However, it has been deemed valuable to prevent the loss of
functionality resulting in offlining the last AArch32-compatible CPU.
Add arch-specific hook in _cpu_down() that allows checking whether we
can offline a cpu or not and use that hook to veto offlining the last
AArch32 CPU.
Signed-off-by: Valentin Schneider <valentin.schneider@arm.com>
Signed-off-by: Qais Yousef <qais.yousef@arm.com>
---
arch/arm64/kernel/smp.c | 22 ++++++++++++++++++++++
kernel/cpu.c | 9 +++++++++
2 files changed, 31 insertions(+)
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 038ce6263d1c..c8ab4ee29f32 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -85,6 +85,28 @@ static inline int op_cpu_kill(unsigned int cpu)
}
#endif
+bool arch_allows_cpu_disable(int cpu, int tasks_frozen,
+ enum cpuhp_state target)
+{
+ /*
+ * Don't let the last AArch32-compatible CPU go down unless the request
+ * is related to suspend (!tasks_frozen) then allow it to be offlined
+ * or we'll break suspend-to-ram functionality.
+ */
+ if (IS_ENABLED(CONFIG_ASYMMETRIC_AARCH32) &&
+ !cpumask_empty(&aarch32_el0_mask) &&
+ !tasks_frozen) {
+ cpumask_t online;
+
+ cpumask_and(&online, &aarch32_el0_mask, cpu_online_mask);
+
+ if (cpumask_weight(&online) == 1)
+ return false;
+ }
+
+ return true;
+}
+
/*
* Boot a secondary CPU, and assign it the specified idle task.
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 261b5098f81c..4fae9b61f442 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -134,6 +134,12 @@ static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state)
return cpuhp_hp_states + state;
}
+bool __weak arch_allows_cpu_disable(int cpu, int tasks_frozen,
+ enum cpuhp_state target)
+{
+ return true;
+}
+
/**
* cpuhp_invoke_callback _ Invoke the callbacks for a given state
* @cpu: The cpu for which the callback should be invoked
@@ -985,6 +991,9 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen,
if (!cpu_present(cpu))
return -EINVAL;
+ if (!arch_allows_cpu_disable(cpu, tasks_frozen, target))
+ return -EBUSY;
+
cpus_write_lock();
cpuhp_tasks_frozen = tasks_frozen;
--
2.29.2
@@ -1,12 +1,12 @@
# SPDX-License-Identifier: Apache-2.0
#
# Copyright (c) 2020 Arm Limited
# Copyright (c) 2021 Arm Limited
#
DESCRIPTION = "Linux Android Common Kernel"
SECTION = "kernel"
LICENSE = "GPLv2"
LIC_FILES_CHKSUM = "file://${S}/COPYING;md5=bbea815ee2795b2f4230826c0c6b8814"
LIC_FILES_CHKSUM = "file://${S}/COPYING;md5=6bc538ed5bd9a7fc9398086aedcd7e46"
require recipes-kernel/linux/linux-yocto.inc
@@ -1,69 +0,0 @@
Upstream-Status: Backport
Signed-off-by: Ross Burton <ross.burton@arm.com>
From 28c69b683210b5d5321ceb71e44a77bc31a32c8a Mon Sep 17 00:00:00 2001
From: Leo Yan <leo.yan@linaro.org>
Date: Tue, 5 May 2020 21:36:42 +0800
Subject: [PATCH 1/4] perf cs-etm: Move definition of 'traceid_list' global
variable from header file
The variable 'traceid_list' is defined in the header file cs-etm.h,
if multiple C files include cs-etm.h the compiler might complaint for
multiple definition of 'traceid_list'.
To fix multiple definition error, move the definition of 'traceid_list'
into cs-etm.c.
Fixes: cd8bfd8c973e ("perf tools: Add processing of coresight metadata")
Reported-by: Thomas Backlund <tmb@mageia.org>
Signed-off-by: Leo Yan <leo.yan@linaro.org>
Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Mike Leach <mike.leach@linaro.org>
Tested-by: Mike Leach <mike.leach@linaro.org>
Tested-by: Thomas Backlund <tmb@mageia.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Suzuki Poulouse <suzuki.poulose@arm.com>
Cc: Tor Jeremiassen <tor@ti.com>
Cc: linux-arm-kernel@lists.infradead.org
Link: http://lore.kernel.org/lkml/20200505133642.4756-1-leo.yan@linaro.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/cs-etm.c | 3 +++
tools/perf/util/cs-etm.h | 3 ---
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index f5f855fff412..50de6a1ed0ce 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -94,6 +94,9 @@ struct cs_etm_queue {
struct cs_etm_traceid_queue **traceid_queues;
};
+/* RB tree for quick conversion between traceID and metadata pointers */
+static struct intlist *traceid_list;
+
static int cs_etm__update_queues(struct cs_etm_auxtrace *etm);
static int cs_etm__process_queues(struct cs_etm_auxtrace *etm);
static int cs_etm__process_timeless_queues(struct cs_etm_auxtrace *etm,
diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h
index 650ecc2a6349..4ad925d6d799 100644
--- a/tools/perf/util/cs-etm.h
+++ b/tools/perf/util/cs-etm.h
@@ -114,9 +114,6 @@ enum cs_etm_isa {
CS_ETM_ISA_T32,
};
-/* RB tree for quick conversion between traceID and metadata pointers */
-struct intlist *traceid_list;
-
struct cs_etm_queue;
struct cs_etm_packet {
--
2.25.1
@@ -1,43 +0,0 @@
Upstream-Status: Backport
Signed-off-by: Ross Burton <ross.burton@arm.com>
From b28dc646b4c5cd3844bd591af841494dd1de0a9f Mon Sep 17 00:00:00 2001
From: Arnaldo Carvalho de Melo <acme@redhat.com>
Date: Mon, 2 Mar 2020 11:13:19 -0300
Subject: [PATCH 2/4] perf tests bp_account: Make global variable static
To fix the build with newer gccs, that without this patch exit with:
LD /tmp/build/perf/tests/perf-in.o
ld: /tmp/build/perf/tests/bp_account.o:/git/perf/tools/perf/tests/bp_account.c:22: multiple definition of `the_var'; /tmp/build/perf/tests/bp_signal.o:/git/perf/tools/perf/tests/bp_signal.c:38: first defined here
make[4]: *** [/git/perf/tools/build/Makefile.build:145: /tmp/build/perf/tests/perf-in.o] Error 1
First noticed in fedora:rawhide/32 with:
[perfbuilder@a5ff49d6e6e4 ~]$ gcc --version
gcc (GCC) 10.0.1 20200216 (Red Hat 10.0.1-0.8)
Reported-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/tests/bp_account.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/perf/tests/bp_account.c b/tools/perf/tests/bp_account.c
index 016bba2c142d..55a9de311d7b 100644
--- a/tools/perf/tests/bp_account.c
+++ b/tools/perf/tests/bp_account.c
@@ -23,7 +23,7 @@
#include "../perf-sys.h"
#include "cloexec.h"
-volatile long the_var;
+static volatile long the_var;
static noinline int test_function(void)
{
--
2.25.1
@@ -1,240 +0,0 @@
Upstream-Status: Backport
Signed-off-by: Ross Burton <ross.burton@arm.com>
From e6ae6031755b6781af42af28f11186bb18e94842 Mon Sep 17 00:00:00 2001
From: Arnaldo Carvalho de Melo <acme@redhat.com>
Date: Mon, 2 Mar 2020 12:09:38 -0300
Subject: [PATCH 3/4] perf bench: Share some global variables to fix build with
gcc 10
Noticed with gcc 10 (fedora rawhide) that those variables were not being
declared as static, so end up with:
ld: /tmp/build/perf/bench/epoll-wait.o:/git/perf/tools/perf/bench/epoll-wait.c:93: multiple definition of `end'; /tmp/build/perf/bench/futex-hash.o:/git/perf/tools/perf/bench/futex-hash.c:40: first defined here
ld: /tmp/build/perf/bench/epoll-wait.o:/git/perf/tools/perf/bench/epoll-wait.c:93: multiple definition of `start'; /tmp/build/perf/bench/futex-hash.o:/git/perf/tools/perf/bench/futex-hash.c:40: first defined here
ld: /tmp/build/perf/bench/epoll-wait.o:/git/perf/tools/perf/bench/epoll-wait.c:93: multiple definition of `runtime'; /tmp/build/perf/bench/futex-hash.o:/git/perf/tools/perf/bench/futex-hash.c:40: first defined here
ld: /tmp/build/perf/bench/epoll-ctl.o:/git/perf/tools/perf/bench/epoll-ctl.c:38: multiple definition of `end'; /tmp/build/perf/bench/futex-hash.o:/git/perf/tools/perf/bench/futex-hash.c:40: first defined here
ld: /tmp/build/perf/bench/epoll-ctl.o:/git/perf/tools/perf/bench/epoll-ctl.c:38: multiple definition of `start'; /tmp/build/perf/bench/futex-hash.o:/git/perf/tools/perf/bench/futex-hash.c:40: first defined here
ld: /tmp/build/perf/bench/epoll-ctl.o:/git/perf/tools/perf/bench/epoll-ctl.c:38: multiple definition of `runtime'; /tmp/build/perf/bench/futex-hash.o:/git/perf/tools/perf/bench/futex-hash.c:40: first defined here
make[4]: *** [/git/perf/tools/build/Makefile.build:145: /tmp/build/perf/bench/perf-in.o] Error 1
Prefix those with bench__ and add them to bench/bench.h, so that we can
share those on the tools needing to access those variables from signal
handlers.
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lore.kernel.org/lkml/20200303155811.GD13702@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/bench/bench.h | 4 ++++
tools/perf/bench/epoll-ctl.c | 7 +++----
tools/perf/bench/epoll-wait.c | 11 +++++------
tools/perf/bench/futex-hash.c | 12 ++++++------
tools/perf/bench/futex-lock-pi.c | 11 +++++------
5 files changed, 23 insertions(+), 22 deletions(-)
diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h
index fddb3ced9db6..4aa6de1aa67d 100644
--- a/tools/perf/bench/bench.h
+++ b/tools/perf/bench/bench.h
@@ -2,6 +2,10 @@
#ifndef BENCH_H
#define BENCH_H
+#include <sys/time.h>
+
+extern struct timeval bench__start, bench__end, bench__runtime;
+
/*
* The madvise transparent hugepage constants were added in glibc
* 2.13. For compatibility with older versions of glibc, define these
diff --git a/tools/perf/bench/epoll-ctl.c b/tools/perf/bench/epoll-ctl.c
index bb617e568841..a7526c05df38 100644
--- a/tools/perf/bench/epoll-ctl.c
+++ b/tools/perf/bench/epoll-ctl.c
@@ -35,7 +35,6 @@
static unsigned int nthreads = 0;
static unsigned int nsecs = 8;
-struct timeval start, end, runtime;
static bool done, __verbose, randomize;
/*
@@ -94,8 +93,8 @@ static void toggle_done(int sig __maybe_unused,
{
/* inform all threads that we're done for the day */
done = true;
- gettimeofday(&end, NULL);
- timersub(&end, &start, &runtime);
+ gettimeofday(&bench__end, NULL);
+ timersub(&bench__end, &bench__start, &bench__runtime);
}
static void nest_epollfd(void)
@@ -361,7 +360,7 @@ int bench_epoll_ctl(int argc, const char **argv)
threads_starting = nthreads;
- gettimeofday(&start, NULL);
+ gettimeofday(&bench__start, NULL);
do_threads(worker, cpu);
diff --git a/tools/perf/bench/epoll-wait.c b/tools/perf/bench/epoll-wait.c
index 7af694437f4e..d1c5cb526b9f 100644
--- a/tools/perf/bench/epoll-wait.c
+++ b/tools/perf/bench/epoll-wait.c
@@ -90,7 +90,6 @@
static unsigned int nthreads = 0;
static unsigned int nsecs = 8;
-struct timeval start, end, runtime;
static bool wdone, done, __verbose, randomize, nonblocking;
/*
@@ -276,8 +275,8 @@ static void toggle_done(int sig __maybe_unused,
{
/* inform all threads that we're done for the day */
done = true;
- gettimeofday(&end, NULL);
- timersub(&end, &start, &runtime);
+ gettimeofday(&bench__end, NULL);
+ timersub(&bench__end, &bench__start, &bench__runtime);
}
static void print_summary(void)
@@ -287,7 +286,7 @@ static void print_summary(void)
printf("\nAveraged %ld operations/sec (+- %.2f%%), total secs = %d\n",
avg, rel_stddev_stats(stddev, avg),
- (int) runtime.tv_sec);
+ (int)bench__runtime.tv_sec);
}
static int do_threads(struct worker *worker, struct perf_cpu_map *cpu)
@@ -479,7 +478,7 @@ int bench_epoll_wait(int argc, const char **argv)
threads_starting = nthreads;
- gettimeofday(&start, NULL);
+ gettimeofday(&bench__start, NULL);
do_threads(worker, cpu);
@@ -519,7 +518,7 @@ int bench_epoll_wait(int argc, const char **argv)
qsort(worker, nthreads, sizeof(struct worker), cmpworker);
for (i = 0; i < nthreads; i++) {
- unsigned long t = worker[i].ops/runtime.tv_sec;
+ unsigned long t = worker[i].ops / bench__runtime.tv_sec;
update_stats(&throughput_stats, t);
diff --git a/tools/perf/bench/futex-hash.c b/tools/perf/bench/futex-hash.c
index 8ba0c3330a9a..21776862e940 100644
--- a/tools/perf/bench/futex-hash.c
+++ b/tools/perf/bench/futex-hash.c
@@ -37,7 +37,7 @@ static unsigned int nfutexes = 1024;
static bool fshared = false, done = false, silent = false;
static int futex_flag = 0;
-struct timeval start, end, runtime;
+struct timeval bench__start, bench__end, bench__runtime;
static pthread_mutex_t thread_lock;
static unsigned int threads_starting;
static struct stats throughput_stats;
@@ -103,8 +103,8 @@ static void toggle_done(int sig __maybe_unused,
{
/* inform all threads that we're done for the day */
done = true;
- gettimeofday(&end, NULL);
- timersub(&end, &start, &runtime);
+ gettimeofday(&bench__end, NULL);
+ timersub(&bench__end, &bench__start, &bench__runtime);
}
static void print_summary(void)
@@ -114,7 +114,7 @@ static void print_summary(void)
printf("%sAveraged %ld operations/sec (+- %.2f%%), total secs = %d\n",
!silent ? "\n" : "", avg, rel_stddev_stats(stddev, avg),
- (int) runtime.tv_sec);
+ (int)bench__runtime.tv_sec);
}
int bench_futex_hash(int argc, const char **argv)
@@ -161,7 +161,7 @@ int bench_futex_hash(int argc, const char **argv)
threads_starting = nthreads;
pthread_attr_init(&thread_attr);
- gettimeofday(&start, NULL);
+ gettimeofday(&bench__start, NULL);
for (i = 0; i < nthreads; i++) {
worker[i].tid = i;
worker[i].futex = calloc(nfutexes, sizeof(*worker[i].futex));
@@ -204,7 +204,7 @@ int bench_futex_hash(int argc, const char **argv)
pthread_mutex_destroy(&thread_lock);
for (i = 0; i < nthreads; i++) {
- unsigned long t = worker[i].ops/runtime.tv_sec;
+ unsigned long t = worker[i].ops / bench__runtime.tv_sec;
update_stats(&throughput_stats, t);
if (!silent) {
if (nfutexes == 1)
diff --git a/tools/perf/bench/futex-lock-pi.c b/tools/perf/bench/futex-lock-pi.c
index d0cae8125423..30d97121dc4f 100644
--- a/tools/perf/bench/futex-lock-pi.c
+++ b/tools/perf/bench/futex-lock-pi.c
@@ -37,7 +37,6 @@ static bool silent = false, multi = false;
static bool done = false, fshared = false;
static unsigned int nthreads = 0;
static int futex_flag = 0;
-struct timeval start, end, runtime;
static pthread_mutex_t thread_lock;
static unsigned int threads_starting;
static struct stats throughput_stats;
@@ -64,7 +63,7 @@ static void print_summary(void)
printf("%sAveraged %ld operations/sec (+- %.2f%%), total secs = %d\n",
!silent ? "\n" : "", avg, rel_stddev_stats(stddev, avg),
- (int) runtime.tv_sec);
+ (int)bench__runtime.tv_sec);
}
static void toggle_done(int sig __maybe_unused,
@@ -73,8 +72,8 @@ static void toggle_done(int sig __maybe_unused,
{
/* inform all threads that we're done for the day */
done = true;
- gettimeofday(&end, NULL);
- timersub(&end, &start, &runtime);
+ gettimeofday(&bench__end, NULL);
+ timersub(&bench__end, &bench__start, &bench__runtime);
}
static void *workerfn(void *arg)
@@ -185,7 +184,7 @@ int bench_futex_lock_pi(int argc, const char **argv)
threads_starting = nthreads;
pthread_attr_init(&thread_attr);
- gettimeofday(&start, NULL);
+ gettimeofday(&bench__start, NULL);
create_threads(worker, thread_attr, cpu);
pthread_attr_destroy(&thread_attr);
@@ -211,7 +210,7 @@ int bench_futex_lock_pi(int argc, const char **argv)
pthread_mutex_destroy(&thread_lock);
for (i = 0; i < nthreads; i++) {
- unsigned long t = worker[i].ops/runtime.tv_sec;
+ unsigned long t = worker[i].ops / bench__runtime.tv_sec;
update_stats(&throughput_stats, t);
if (!silent)
--
2.25.1
@@ -1,39 +0,0 @@
Upstream-Status: Backport
Signed-off-by: Ross Burton <ross.burton@arm.com>
From c2c2c58915def6cda401d1782048d23b2b02ed85 Mon Sep 17 00:00:00 2001
From: Ben Hutchings <ben@decadent.org.uk>
Date: Sat, 25 Jul 2020 02:06:23 +0100
Subject: [PATCH 4/4] libtraceevent: Fix build with binutils 2.35
In binutils 2.35, 'nm -D' changed to show symbol versions along with
symbol names, with the usual @@ separator. When generating
libtraceevent-dynamic-list we need just the names, so strip off the
version suffix if present.
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Tested-by: Salvatore Bonaccorso <carnil@debian.org>
Reviewed-by: Steven Rostedt <rostedt@goodmis.org>
Cc: linux-trace-devel@vger.kernel.org
Cc: stable@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/lib/traceevent/plugins/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/lib/traceevent/plugins/Makefile b/tools/lib/traceevent/plugins/Makefile
index f440989fa55e..23c3535bcbd6 100644
--- a/tools/lib/traceevent/plugins/Makefile
+++ b/tools/lib/traceevent/plugins/Makefile
@@ -196,7 +196,7 @@ define do_generate_dynamic_list_file
xargs echo "U w W" | tr 'w ' 'W\n' | sort -u | xargs echo`;\
if [ "$$symbol_type" = "U W" ];then \
(echo '{'; \
- $(NM) -u -D $1 | awk 'NF>1 {print "\t"$$2";"}' | sort -u;\
+ $(NM) -u -D $1 | awk 'NF>1 {sub("@.*", "", $$2); print "\t"$$2";"}' | sort -u;\
echo '};'; \
) > $2; \
else \
--
2.25.1
@@ -0,0 +1,12 @@
# SPDX-License-Identifier: Apache-2.0
#
# Copyright (c) 2021 Arm Limited
#
require linux-arm64-ack.inc
SRC_URI = " \
git://android.googlesource.com/kernel/common.git;protocol=https;branch=android12-5.10-lts \
"
# tag: ASB-2021-06-05_12-5.10
SRCREV = "00dc4c64e6592a2e469f7886a6a927778c4a2806"
@@ -1,16 +0,0 @@
# SPDX-License-Identifier: Apache-2.0
#
# Copyright (c) 2020 Arm Limited
#
require linux-arm64-ack.inc
SRC_URI = " \
git://android.googlesource.com/kernel/common.git;protocol=https;branch=android11-5.4-lts \
file://0001-perf-cs-etm-Move-definition-of-traceid_list-global-v.patch \
file://0002-perf-tests-bp_account-Make-global-variable-static.patch \
file://0003-perf-bench-Share-some-global-variables-to-fix-build-.patch \
file://0004-libtraceevent-Fix-build-with-binutils-2.35.patch \
"
# ASB-2020-07-05_5.4-stable tag commit
SRCREV = "056684c0d252f75c13be4abb7408f692eedab653"