]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
usb: misc: qcom_eud: Access EUD_MODE_MANAGER2 through secure calls
authorKomal Bajaj <komal.bajaj@oss.qualcomm.com>
Thu, 31 Jul 2025 09:01:32 +0000 (14:31 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 13 Aug 2025 15:13:45 +0000 (17:13 +0200)
EUD_MODE_MANAGER2 register is mapped to a memory region that is marked
as read-only for operating system running at EL1, enforcing access
restrictions that prohibit direct memory-mapped writes via writel().

Attempts to write to this region from HLOS can result in silent failures
or memory access violations, particularly when toggling EUD (Embedded
USB Debugger) state. To ensure secure register access, modify the driver
to use qcom_scm_io_writel(), which routes the write operation to Qualcomm
Secure Channel Monitor (SCM). SCM has the necessary permissions to access
protected memory regions, enabling reliable control over EUD state.

SC7280, the only user of EUD is also affected, indicating that this could
never have worked on a properly fused device.

Fixes: 9a1bf58ccd44 ("usb: misc: eud: Add driver support for Embedded USB Debugger(EUD)")
Signed-off-by: Melody Olvera <quic_molvera@quicinc.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Souradeep Chowdhury <quic_schowdhu@quicinc.com>
Signed-off-by: Komal Bajaj <komal.bajaj@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20250731-eud_mode_manager_secure_access-v8-1-4a5dcbb79f41@oss.qualcomm.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/misc/Kconfig
drivers/usb/misc/qcom_eud.c

index 6497c4e81e951a14201ad965dadc29f9888f8254..9bf8fc6247bacaa2499c6aa04e5acb25c02d0e34 100644 (file)
@@ -147,6 +147,7 @@ config USB_APPLEDISPLAY
 config USB_QCOM_EUD
        tristate "QCOM Embedded USB Debugger(EUD) Driver"
        depends on ARCH_QCOM || COMPILE_TEST
+       select QCOM_SCM
        select USB_ROLE_SWITCH
        help
          This module enables support for Qualcomm Technologies, Inc.
index 67832790acad28183a23b137c3929ec7b06bc0c4..926419ca560fc8611ad958409802b133e6f1e647 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/sysfs.h>
 #include <linux/usb/role.h>
+#include <linux/firmware/qcom/qcom_scm.h>
 
 #define EUD_REG_INT1_EN_MASK   0x0024
 #define EUD_REG_INT_STATUS_1   0x0044
@@ -34,7 +35,7 @@ struct eud_chip {
        struct device                   *dev;
        struct usb_role_switch          *role_sw;
        void __iomem                    *base;
-       void __iomem                    *mode_mgr;
+       phys_addr_t                     mode_mgr;
        unsigned int                    int_status;
        int                             irq;
        bool                            enabled;
@@ -43,18 +44,29 @@ struct eud_chip {
 
 static int enable_eud(struct eud_chip *priv)
 {
+       int ret;
+
+       ret = qcom_scm_io_writel(priv->mode_mgr + EUD_REG_EUD_EN2, 1);
+       if (ret)
+               return ret;
+
        writel(EUD_ENABLE, priv->base + EUD_REG_CSR_EUD_EN);
        writel(EUD_INT_VBUS | EUD_INT_SAFE_MODE,
                        priv->base + EUD_REG_INT1_EN_MASK);
-       writel(1, priv->mode_mgr + EUD_REG_EUD_EN2);
 
        return usb_role_switch_set_role(priv->role_sw, USB_ROLE_DEVICE);
 }
 
-static void disable_eud(struct eud_chip *priv)
+static int disable_eud(struct eud_chip *priv)
 {
+       int ret;
+
+       ret = qcom_scm_io_writel(priv->mode_mgr + EUD_REG_EUD_EN2, 0);
+       if (ret)
+               return ret;
+
        writel(0, priv->base + EUD_REG_CSR_EUD_EN);
-       writel(0, priv->mode_mgr + EUD_REG_EUD_EN2);
+       return 0;
 }
 
 static ssize_t enable_show(struct device *dev,
@@ -82,11 +94,12 @@ static ssize_t enable_store(struct device *dev,
                        chip->enabled = enable;
                else
                        disable_eud(chip);
+
        } else {
-               disable_eud(chip);
+               ret = disable_eud(chip);
        }
 
-       return count;
+       return ret < 0 ? ret : count;
 }
 
 static DEVICE_ATTR_RW(enable);
@@ -178,6 +191,7 @@ static void eud_role_switch_release(void *data)
 static int eud_probe(struct platform_device *pdev)
 {
        struct eud_chip *chip;
+       struct resource *res;
        int ret;
 
        chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
@@ -199,9 +213,10 @@ static int eud_probe(struct platform_device *pdev)
        if (IS_ERR(chip->base))
                return PTR_ERR(chip->base);
 
-       chip->mode_mgr = devm_platform_ioremap_resource(pdev, 1);
-       if (IS_ERR(chip->mode_mgr))
-               return PTR_ERR(chip->mode_mgr);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!res)
+               return -ENODEV;
+       chip->mode_mgr = res->start;
 
        chip->irq = platform_get_irq(pdev, 0);
        if (chip->irq < 0)