From: Adrian Hunter <adrian.hunter@intel.com>
To: alexandre.belloni@bootlin.com
Cc: Frank.Li@nxp.com, linux-i3c@lists.infradead.org,
linux-kernel@vger.kernel.org
Subject: [PATCH 1/7] i3c: mipi-i3c-hci: Fix race in i3c_hci_addr_to_dev()
Date: Wed, 27 May 2026 14:27:52 +0300 [thread overview]
Message-ID: <20260527112758.38530-2-adrian.hunter@intel.com> (raw)
In-Reply-To: <20260527112758.38530-1-adrian.hunter@intel.com>
i3c_hci_addr_to_dev() walks bus->devs.i3c, which is protected by
bus.lock (rwsem). However, it is invoked from the MIPI I3C HCI IRQ
handler, which cannot take bus.lock. This allows concurrent device
addition/removal in the I3C core to modify the list while it is being
traversed, potentially leading to use-after-free or crashes.
Remove the dependency on the bus device list and introduce a dedicated
lookup table. Add an ibi_devs[] array indexed by DAT entry, maintained
under hci->lock. Update the array when IBIs are enabled or disabled,
so that it always reflects the set of devices allowed to generate IBIs.
Move i3c_hci_addr_to_dev() into core.c, reimplement it using the new
array, and add a lockdep assertion to enforce that hci->lock is held
by callers.
Fixes: 9ad9a52cce282 ("i3c/master: introduce the mipi-i3c-hci driver")
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/i3c/master/mipi-i3c-hci/core.c | 25 +++++++++++++++++++++++++
drivers/i3c/master/mipi-i3c-hci/hci.h | 1 +
drivers/i3c/master/mipi-i3c-hci/ibi.h | 13 +------------
3 files changed, 27 insertions(+), 12 deletions(-)
diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
index 53797841b63f..b19bdff5c5e2 100644
--- a/drivers/i3c/master/mipi-i3c-hci/core.c
+++ b/drivers/i3c/master/mipi-i3c-hci/core.c
@@ -22,6 +22,7 @@
#include "ext_caps.h"
#include "cmd.h"
#include "dat.h"
+#include "ibi.h"
/*
* Host Controller Capabilities and Operation Registers
@@ -124,6 +125,7 @@ static void i3c_hci_set_master_dyn_addr(struct i3c_hci *hci)
static int i3c_hci_bus_init(struct i3c_master_controller *m)
{
struct i3c_hci *hci = to_i3c_hci(m);
+ struct device *dev = hci->master.dev.parent;
struct i3c_device_info info;
int ret;
@@ -144,6 +146,10 @@ static int i3c_hci_bus_init(struct i3c_master_controller *m)
if (ret)
return ret;
+ hci->ibi_devs = devm_kcalloc(dev, hci->DAT_entries, sizeof(*hci->ibi_devs), GFP_KERNEL);
+ if (!hci->ibi_devs)
+ return -ENOMEM;
+
ret = hci->io->init(hci);
if (ret)
return ret;
@@ -647,6 +653,21 @@ static void i3c_hci_free_ibi(struct i3c_dev_desc *dev)
hci->io->free_ibi(hci, dev);
}
+struct i3c_dev_desc *i3c_hci_addr_to_dev(struct i3c_hci *hci, unsigned int addr)
+{
+ int dat_idx;
+
+ lockdep_assert_held(&hci->lock);
+
+ for (dat_idx = 0; dat_idx < hci->DAT_entries; dat_idx++) {
+ struct i3c_dev_desc *dev = hci->ibi_devs[dat_idx];
+
+ if (dev && dev->info.dyn_addr == addr)
+ return dev;
+ }
+ return NULL;
+}
+
static int i3c_hci_enable_ibi(struct i3c_dev_desc *dev)
{
struct i3c_master_controller *m = i3c_dev_get_master(dev);
@@ -654,6 +675,8 @@ static int i3c_hci_enable_ibi(struct i3c_dev_desc *dev)
struct i3c_hci_dev_data *dev_data = i3c_dev_get_master_data(dev);
mipi_i3c_hci_dat_v1.clear_flags(hci, dev_data->dat_idx, DAT_0_SIR_REJECT, 0);
+ scoped_guard(spinlock_irqsave, &hci->lock)
+ hci->ibi_devs[dev_data->dat_idx] = dev;
return i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
}
@@ -664,6 +687,8 @@ static int i3c_hci_disable_ibi(struct i3c_dev_desc *dev)
struct i3c_hci_dev_data *dev_data = i3c_dev_get_master_data(dev);
mipi_i3c_hci_dat_v1.set_flags(hci, dev_data->dat_idx, DAT_0_SIR_REJECT, 0);
+ scoped_guard(spinlock_irqsave, &hci->lock)
+ hci->ibi_devs[dev_data->dat_idx] = NULL;
return i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
}
diff --git a/drivers/i3c/master/mipi-i3c-hci/hci.h b/drivers/i3c/master/mipi-i3c-hci/hci.h
index 41d31a53abd3..b3d9803b1968 100644
--- a/drivers/i3c/master/mipi-i3c-hci/hci.h
+++ b/drivers/i3c/master/mipi-i3c-hci/hci.h
@@ -65,6 +65,7 @@ struct i3c_hci {
unsigned int DAT_entry_size;
void *DAT_data;
struct dat_words *DAT;
+ struct i3c_dev_desc **ibi_devs;
unsigned int DCT_entries;
unsigned int DCT_entry_size;
u8 version_major;
diff --git a/drivers/i3c/master/mipi-i3c-hci/ibi.h b/drivers/i3c/master/mipi-i3c-hci/ibi.h
index e1f98e264da0..073ca67b7d04 100644
--- a/drivers/i3c/master/mipi-i3c-hci/ibi.h
+++ b/drivers/i3c/master/mipi-i3c-hci/ibi.h
@@ -26,17 +26,6 @@
#define IBI_DATA_LENGTH GENMASK(7, 0)
/* handy helpers */
-static inline struct i3c_dev_desc *
-i3c_hci_addr_to_dev(struct i3c_hci *hci, unsigned int addr)
-{
- struct i3c_bus *bus = i3c_master_get_bus(&hci->master);
- struct i3c_dev_desc *dev;
-
- i3c_bus_for_each_i3cdev(bus, dev) {
- if (dev->info.dyn_addr == addr)
- return dev;
- }
- return NULL;
-}
+struct i3c_dev_desc *i3c_hci_addr_to_dev(struct i3c_hci *hci, unsigned int addr);
#endif
--
2.51.0
--
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c
next prev parent reply other threads:[~2026-05-27 11:28 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-27 11:27 [PATCH 0/7] i3c: Fix IBI race, address handling, and reconcile DAA Adrian Hunter
2026-05-27 11:27 ` Adrian Hunter [this message]
2026-05-27 11:27 ` [PATCH 2/7] i3c: mipi-i3c-hci: Ignore DISEC failures when disabling IBIs Adrian Hunter
2026-05-27 11:27 ` [PATCH 3/7] i3c: master: Prevent reuse of dynamic address on device add failure Adrian Hunter
2026-05-27 11:27 ` [PATCH 4/7] i3c: mipi-i3c-hci: Tolerate i3c_master_add_i3c_dev_locked() failures in DAA Adrian Hunter
2026-05-27 11:27 ` [PATCH 5/7] i3c: master: Make i3c_master_add_i3c_dev_locked() return void Adrian Hunter
2026-05-27 11:27 ` [PATCH 6/7] i3c: master: Move DAA API functions after i3c_master_add_i3c_dev_locked() Adrian Hunter
2026-05-27 11:27 ` [PATCH 7/7] i3c: master: Reconcile dynamic addresses after DAA Adrian Hunter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260527112758.38530-2-adrian.hunter@intel.com \
--to=adrian.hunter@intel.com \
--cc=Frank.Li@nxp.com \
--cc=alexandre.belloni@bootlin.com \
--cc=linux-i3c@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox