[PATCH for drm-misc-fixes v3 2/2] drm/hisilicon/hibmc: Add a flag to indicate whether the OS-side driver has been loaded

From: Yongbang Shi

Date: Thu Sep 24 2026 - 04:22:42 EST


From: Lin He <helin52@xxxxxxxxxx>

Add a flag to indicate whether the OS-side driver has been loaded to
prevent the BMC from enabling DP if the driver is not loaded, which could
lead to system failure in handling interrupts and generate error messages
like:

irq xx: nobody cared (try booting with the "irqpoll" option)
...
Call Trace:
<TRQ>
...

Fixes: 0ab6ea261c1f ("drm/hisilicon/hibmc: add dp module in hibmc")
Signed-off-by: Lin He <helin52@xxxxxxxxxx>
Signed-off-by: Yongbang Shi <shiyongbang@xxxxxxxxxx>
---
ChangeLog:
v2 -> v3:
- Move hibmc_set_enable_flag() before drm_dev_register() and
hibmc_set_disable_flag() after drm_dev_unregister() to narrow the
race window. (sashiko-bot)
- Add spinlock_t gpio_lock to hibmc_drm_private to protect all
operations on 0x0802A4. (sashiko-bot)
v1 -> v2:
- The call to `hibmc_set_enable_flag()` has been moved before
`drm_client_setup()`, specifically before the connector detection
triggers the I2C bit operation. (sashiko-bot)
- A read-modify-write operation has been implemented instead of directly
writing to prevent clearing the I2C mask bits. (sashiko-bot)
---
.../gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 30 +++++++++++++++++++
.../gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h | 2 ++
.../gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c | 19 ++++++++++--
.../gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h | 3 ++
4 files changed, 51 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 4ab0e565cb13..9859492da5fa 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -167,6 +167,8 @@ static int hibmc_kms_init(struct hibmc_drm_private *priv)
if (ret)
return ret;

+ spin_lock_init(&priv->gpio_lock);
+
dev->mode_config.min_width = 0;
dev->mode_config.min_height = 0;
dev->mode_config.max_width = 1920;
@@ -423,6 +425,30 @@ static int hibmc_load(struct drm_device *dev)
return ret;
}

+static inline void hibmc_set_enable_flag(struct hibmc_drm_private *priv)
+{
+ unsigned long flags;
+ u32 value;
+
+ spin_lock_irqsave(&priv->gpio_lock, flags);
+ value = readl(priv->mmio + HIBMC_ENABLE_FLAG);
+ value |= HIBMC_ENABLE_STATE;
+ writel(value, priv->mmio + HIBMC_ENABLE_FLAG);
+ spin_unlock_irqrestore(&priv->gpio_lock, flags);
+}
+
+static inline void hibmc_set_disable_flag(struct hibmc_drm_private *priv)
+{
+ unsigned long flags;
+ u32 value;
+
+ spin_lock_irqsave(&priv->gpio_lock, flags);
+ value = readl(priv->mmio + HIBMC_ENABLE_FLAG);
+ value &= ~HIBMC_ENABLE_STATE;
+ writel(value, priv->mmio + HIBMC_ENABLE_FLAG);
+ spin_unlock_irqrestore(&priv->gpio_lock, flags);
+}
+
static int hibmc_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -458,6 +484,8 @@ static int hibmc_pci_probe(struct pci_dev *pdev,
goto err_return;
}

+ hibmc_set_enable_flag(priv);
+
ret = drm_dev_register(dev, 0);
if (ret) {
drm_err(dev, "failed to register drv for userspace access: %d\n",
@@ -470,6 +498,7 @@ static int hibmc_pci_probe(struct pci_dev *pdev,
return 0;

err_unload:
+ hibmc_set_disable_flag(to_hibmc_drm_private(dev));
hibmc_unload(dev);
err_return:
return ret;
@@ -480,6 +509,7 @@ static void hibmc_pci_remove(struct pci_dev *pdev)
struct drm_device *dev = pci_get_drvdata(pdev);

drm_dev_unregister(dev);
+ hibmc_set_disable_flag(to_hibmc_drm_private(dev));
hibmc_unload(dev);
}

diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index dce8572bf63e..c2a82000ea7f 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -49,6 +49,8 @@ struct hibmc_drm_private {
struct drm_crtc crtc;
struct hibmc_vdac vdac;
struct hibmc_dp dp;
+
+ spinlock_t gpio_lock; /* protects RMW on I2C/ENABLE_FLAG (0x0802A4) */
};

static inline struct hibmc_vdac *to_hibmc_vdac(struct drm_connector *connector)
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c
index 44860011855e..4ceb87efec05 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c
@@ -27,7 +27,11 @@ static void hibmc_set_i2c_signal(void *data, u32 mask, int value)
{
struct hibmc_vdac *vdac = data;
struct hibmc_drm_private *priv = to_hibmc_drm_private(vdac->connector.dev);
- u32 tmp_dir = readl(priv->mmio + GPIO_DATA_DIRECTION);
+ unsigned long flags;
+ u32 tmp_dir;
+
+ spin_lock_irqsave(&priv->gpio_lock, flags);
+ tmp_dir = readl(priv->mmio + GPIO_DATA_DIRECTION);

if (value) {
tmp_dir &= ~mask;
@@ -41,20 +45,29 @@ static void hibmc_set_i2c_signal(void *data, u32 mask, int value)
tmp_dir |= mask;
writel(tmp_dir, priv->mmio + GPIO_DATA_DIRECTION);
}
+ spin_unlock_irqrestore(&priv->gpio_lock, flags);
}

static int hibmc_get_i2c_signal(void *data, u32 mask)
{
struct hibmc_vdac *vdac = data;
struct hibmc_drm_private *priv = to_hibmc_drm_private(vdac->connector.dev);
- u32 tmp_dir = readl(priv->mmio + GPIO_DATA_DIRECTION);
+ unsigned long flags;
+ u32 tmp_dir;
+ int ret;
+
+ spin_lock_irqsave(&priv->gpio_lock, flags);
+ tmp_dir = readl(priv->mmio + GPIO_DATA_DIRECTION);

if ((tmp_dir & mask) != mask) {
tmp_dir &= ~mask;
writel(tmp_dir, priv->mmio + GPIO_DATA_DIRECTION);
}

- return (readl(priv->mmio + GPIO_DATA) & mask) ? 1 : 0;
+ ret = (readl(priv->mmio + GPIO_DATA) & mask) ? 1 : 0;
+ spin_unlock_irqrestore(&priv->gpio_lock, flags);
+
+ return ret;
}

static void hibmc_ddc_setsda(void *data, int state)
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
index 17b30c393b10..b95add5b253c 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
@@ -200,5 +200,8 @@

#define HIBMC_CRT_PALETTE 0x80C00

+#define HIBMC_ENABLE_FLAG 0x802A4
+#define HIBMC_ENABLE_STATE BIT(2)
+
#define HIBMC_FIELD(field, value) (field(value) & field##_MASK)
#endif
--
2.43.0