All of lore.kernel.org
 help / color / mirror / Atom feed
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 8/8] i3c: mipi-i3c-hci: Add Hot-Join support
Date: Tue, 12 May 2026 15:17:32 +0300	[thread overview]
Message-ID: <20260512121732.406009-9-adrian.hunter@intel.com> (raw)
In-Reply-To: <20260512121732.406009-1-adrian.hunter@intel.com>

Wire the MIPI I3C HCI driver into the I3C core Hot-Join framework to
allow targets to dynamically join the bus after initial DAA.

HCI hardware ACKs or NACKs Hot-Join requests based on
HC_CONTROL.HOT_JOIN_CTRL.  This was previously left in the
NACK-and-DISEC state, effectively preventing Hot-Join.  Implement
the ->enable_hotjoin() and ->disable_hotjoin() master operations
so the core and user space can control this policy at runtime.

Also issue broadcast ENEC HJ when enabling Hot-Join.  This is required
because the controller may have previously DISEC'ed the Hot-Join
event, causing targets that were NACKed once to never retry.

Acknowledged Hot-Join requests are delivered as IBIs on the reserved
address 0x02.  Update both the DMA and PIO IBI paths to recognise this
address and forward the event to i3c_master_queue_hotjoin().

To make Hot-Join usable by default, enable it once after the initial
DAA.  This is gated by rpm_ibi_allowed, since otherwise keeping Hot-Join
enabled prevents runtime suspend.  A new hj_init_done flag ensures this
one-time enablement is not repeated on subsequent DAAs.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/i3c/master/mipi-i3c-hci/core.c | 50 ++++++++++++++++++++++++--
 drivers/i3c/master/mipi-i3c-hci/dma.c  |  5 +++
 drivers/i3c/master/mipi-i3c-hci/hci.h  |  1 +
 drivers/i3c/master/mipi-i3c-hci/pio.c  |  5 +++
 4 files changed, 58 insertions(+), 3 deletions(-)

diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
index 2866d599612a..f8b399d16598 100644
--- a/drivers/i3c/master/mipi-i3c-hci/core.c
+++ b/drivers/i3c/master/mipi-i3c-hci/core.c
@@ -392,11 +392,52 @@ static int i3c_hci_send_ccc_cmd(struct i3c_master_controller *m,
 	return ret;
 }
 
+static int i3c_hci_enable_hotjoin(struct i3c_master_controller *m)
+{
+	struct i3c_hci *hci = to_i3c_hci(m);
+	int ret;
+
+	reg_clear(HC_CONTROL, HC_CONTROL_HOT_JOIN_CTRL);
+
+	/*
+	 * Broadcast Hot_join enable, so that an I3C device that has previously
+	 * had its Hot-Join request NACK'ed knows to try again.
+	 */
+	ret = i3c_master_enec_disec_locked(m, I3C_BROADCAST_ADDR, true, I3C_CCC_EVENT_HJ, true);
+	if (ret) {
+		reg_set(HC_CONTROL, HC_CONTROL_HOT_JOIN_CTRL);
+		dev_err(&hci->master.dev, "Hot-Join ENEC CCC failed\n");
+	}
+
+	return ret;
+}
+
+static int i3c_hci_disable_hotjoin(struct i3c_master_controller *m)
+{
+	struct i3c_hci *hci = to_i3c_hci(m);
+
+	reg_set(HC_CONTROL, HC_CONTROL_HOT_JOIN_CTRL);
+	return 0;
+}
+
 static int i3c_hci_daa(struct i3c_master_controller *m)
 {
 	struct i3c_hci *hci = to_i3c_hci(m);
+	int ret;
 
-	return hci->cmd->perform_daa(hci);
+	ret = hci->cmd->perform_daa(hci);
+
+	if (!hci->hj_init_done) {
+		hci->hj_init_done = true;
+		/*
+		 * Enable Hot-Join by default after initial DAA if it does not
+		 * prevent runtime suspend.
+		 */
+		if (m->rpm_ibi_allowed && !ret)
+			m->hotjoin = !i3c_hci_enable_hotjoin(m);
+	}
+
+	return ret;
 }
 
 static int i3c_hci_i3c_xfers(struct i3c_dev_desc *dev,
@@ -652,6 +693,8 @@ static const struct i3c_master_controller_ops i3c_hci_ops = {
 	.enable_ibi		= i3c_hci_enable_ibi,
 	.disable_ibi		= i3c_hci_disable_ibi,
 	.recycle_ibi_slot	= i3c_hci_recycle_ibi_slot,
+	.enable_hotjoin		= i3c_hci_enable_hotjoin,
+	.disable_hotjoin	= i3c_hci_disable_hotjoin,
 };
 
 static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id)
@@ -833,8 +876,9 @@ static int i3c_hci_do_reset_and_restore(struct i3c_hci *hci)
 	scoped_guard(spinlock_irqsave, &hci->lock)
 		hci->irq_inactive = false;
 
-	/* Enable bus with Hot-Join disabled */
-	reg_set(HC_CONTROL, HC_CONTROL_BUS_ENABLE | HC_CONTROL_HOT_JOIN_CTRL);
+	/* Enable bus, restoring hot-join state */
+	reg_set(HC_CONTROL,
+		HC_CONTROL_BUS_ENABLE | (hci->master.hotjoin ? 0 : HC_CONTROL_HOT_JOIN_CTRL));
 
 	return 0;
 }
diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c
index e5deeba0aa4e..34129ac039dc 100644
--- a/drivers/i3c/master/mipi-i3c-hci/dma.c
+++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
@@ -971,6 +971,11 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh)
 	}
 
 	/* determine who this is for */
+	if (ibi_addr == I3C_HOT_JOIN_ADDR) {
+		i3c_master_queue_hotjoin(&hci->master);
+		goto done;
+	}
+
 	dev = i3c_hci_addr_to_dev(hci, ibi_addr);
 	if (!dev) {
 		dev_err(&hci->master.dev,
diff --git a/drivers/i3c/master/mipi-i3c-hci/hci.h b/drivers/i3c/master/mipi-i3c-hci/hci.h
index 243d7a67f6f6..591eea040b01 100644
--- a/drivers/i3c/master/mipi-i3c-hci/hci.h
+++ b/drivers/i3c/master/mipi-i3c-hci/hci.h
@@ -57,6 +57,7 @@ struct i3c_hci {
 	bool irq_inactive;
 	bool enqueue_blocked;
 	bool recovery_needed;
+	bool hj_init_done;
 	wait_queue_head_t enqueue_wait_queue;
 	u32 caps;
 	unsigned int quirks;
diff --git a/drivers/i3c/master/mipi-i3c-hci/pio.c b/drivers/i3c/master/mipi-i3c-hci/pio.c
index 6b8cc5f2b4d2..b5ae1cfaa9e0 100644
--- a/drivers/i3c/master/mipi-i3c-hci/pio.c
+++ b/drivers/i3c/master/mipi-i3c-hci/pio.c
@@ -862,6 +862,11 @@ static bool hci_pio_prep_new_ibi(struct i3c_hci *hci, struct hci_pio_data *pio)
 	ibi->seg_len = FIELD_GET(IBI_DATA_LENGTH, ibi_status);
 	ibi->seg_cnt = ibi->seg_len;
 
+	if (ibi->addr == I3C_HOT_JOIN_ADDR) {
+		i3c_master_queue_hotjoin(&hci->master);
+		return true;
+	}
+
 	dev = i3c_hci_addr_to_dev(hci, ibi->addr);
 	if (!dev) {
 		dev_err(&hci->master.dev,
-- 
2.51.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

WARNING: multiple messages have this Message-ID (diff)
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 8/8] i3c: mipi-i3c-hci: Add Hot-Join support
Date: Tue, 12 May 2026 15:17:32 +0300	[thread overview]
Message-ID: <20260512121732.406009-9-adrian.hunter@intel.com> (raw)
In-Reply-To: <20260512121732.406009-1-adrian.hunter@intel.com>

Wire the MIPI I3C HCI driver into the I3C core Hot-Join framework to
allow targets to dynamically join the bus after initial DAA.

HCI hardware ACKs or NACKs Hot-Join requests based on
HC_CONTROL.HOT_JOIN_CTRL.  This was previously left in the
NACK-and-DISEC state, effectively preventing Hot-Join.  Implement
the ->enable_hotjoin() and ->disable_hotjoin() master operations
so the core and user space can control this policy at runtime.

Also issue broadcast ENEC HJ when enabling Hot-Join.  This is required
because the controller may have previously DISEC'ed the Hot-Join
event, causing targets that were NACKed once to never retry.

Acknowledged Hot-Join requests are delivered as IBIs on the reserved
address 0x02.  Update both the DMA and PIO IBI paths to recognise this
address and forward the event to i3c_master_queue_hotjoin().

To make Hot-Join usable by default, enable it once after the initial
DAA.  This is gated by rpm_ibi_allowed, since otherwise keeping Hot-Join
enabled prevents runtime suspend.  A new hj_init_done flag ensures this
one-time enablement is not repeated on subsequent DAAs.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/i3c/master/mipi-i3c-hci/core.c | 50 ++++++++++++++++++++++++--
 drivers/i3c/master/mipi-i3c-hci/dma.c  |  5 +++
 drivers/i3c/master/mipi-i3c-hci/hci.h  |  1 +
 drivers/i3c/master/mipi-i3c-hci/pio.c  |  5 +++
 4 files changed, 58 insertions(+), 3 deletions(-)

diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
index 2866d599612a..f8b399d16598 100644
--- a/drivers/i3c/master/mipi-i3c-hci/core.c
+++ b/drivers/i3c/master/mipi-i3c-hci/core.c
@@ -392,11 +392,52 @@ static int i3c_hci_send_ccc_cmd(struct i3c_master_controller *m,
 	return ret;
 }
 
+static int i3c_hci_enable_hotjoin(struct i3c_master_controller *m)
+{
+	struct i3c_hci *hci = to_i3c_hci(m);
+	int ret;
+
+	reg_clear(HC_CONTROL, HC_CONTROL_HOT_JOIN_CTRL);
+
+	/*
+	 * Broadcast Hot_join enable, so that an I3C device that has previously
+	 * had its Hot-Join request NACK'ed knows to try again.
+	 */
+	ret = i3c_master_enec_disec_locked(m, I3C_BROADCAST_ADDR, true, I3C_CCC_EVENT_HJ, true);
+	if (ret) {
+		reg_set(HC_CONTROL, HC_CONTROL_HOT_JOIN_CTRL);
+		dev_err(&hci->master.dev, "Hot-Join ENEC CCC failed\n");
+	}
+
+	return ret;
+}
+
+static int i3c_hci_disable_hotjoin(struct i3c_master_controller *m)
+{
+	struct i3c_hci *hci = to_i3c_hci(m);
+
+	reg_set(HC_CONTROL, HC_CONTROL_HOT_JOIN_CTRL);
+	return 0;
+}
+
 static int i3c_hci_daa(struct i3c_master_controller *m)
 {
 	struct i3c_hci *hci = to_i3c_hci(m);
+	int ret;
 
-	return hci->cmd->perform_daa(hci);
+	ret = hci->cmd->perform_daa(hci);
+
+	if (!hci->hj_init_done) {
+		hci->hj_init_done = true;
+		/*
+		 * Enable Hot-Join by default after initial DAA if it does not
+		 * prevent runtime suspend.
+		 */
+		if (m->rpm_ibi_allowed && !ret)
+			m->hotjoin = !i3c_hci_enable_hotjoin(m);
+	}
+
+	return ret;
 }
 
 static int i3c_hci_i3c_xfers(struct i3c_dev_desc *dev,
@@ -652,6 +693,8 @@ static const struct i3c_master_controller_ops i3c_hci_ops = {
 	.enable_ibi		= i3c_hci_enable_ibi,
 	.disable_ibi		= i3c_hci_disable_ibi,
 	.recycle_ibi_slot	= i3c_hci_recycle_ibi_slot,
+	.enable_hotjoin		= i3c_hci_enable_hotjoin,
+	.disable_hotjoin	= i3c_hci_disable_hotjoin,
 };
 
 static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id)
@@ -833,8 +876,9 @@ static int i3c_hci_do_reset_and_restore(struct i3c_hci *hci)
 	scoped_guard(spinlock_irqsave, &hci->lock)
 		hci->irq_inactive = false;
 
-	/* Enable bus with Hot-Join disabled */
-	reg_set(HC_CONTROL, HC_CONTROL_BUS_ENABLE | HC_CONTROL_HOT_JOIN_CTRL);
+	/* Enable bus, restoring hot-join state */
+	reg_set(HC_CONTROL,
+		HC_CONTROL_BUS_ENABLE | (hci->master.hotjoin ? 0 : HC_CONTROL_HOT_JOIN_CTRL));
 
 	return 0;
 }
diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c
index e5deeba0aa4e..34129ac039dc 100644
--- a/drivers/i3c/master/mipi-i3c-hci/dma.c
+++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
@@ -971,6 +971,11 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh)
 	}
 
 	/* determine who this is for */
+	if (ibi_addr == I3C_HOT_JOIN_ADDR) {
+		i3c_master_queue_hotjoin(&hci->master);
+		goto done;
+	}
+
 	dev = i3c_hci_addr_to_dev(hci, ibi_addr);
 	if (!dev) {
 		dev_err(&hci->master.dev,
diff --git a/drivers/i3c/master/mipi-i3c-hci/hci.h b/drivers/i3c/master/mipi-i3c-hci/hci.h
index 243d7a67f6f6..591eea040b01 100644
--- a/drivers/i3c/master/mipi-i3c-hci/hci.h
+++ b/drivers/i3c/master/mipi-i3c-hci/hci.h
@@ -57,6 +57,7 @@ struct i3c_hci {
 	bool irq_inactive;
 	bool enqueue_blocked;
 	bool recovery_needed;
+	bool hj_init_done;
 	wait_queue_head_t enqueue_wait_queue;
 	u32 caps;
 	unsigned int quirks;
diff --git a/drivers/i3c/master/mipi-i3c-hci/pio.c b/drivers/i3c/master/mipi-i3c-hci/pio.c
index 6b8cc5f2b4d2..b5ae1cfaa9e0 100644
--- a/drivers/i3c/master/mipi-i3c-hci/pio.c
+++ b/drivers/i3c/master/mipi-i3c-hci/pio.c
@@ -862,6 +862,11 @@ static bool hci_pio_prep_new_ibi(struct i3c_hci *hci, struct hci_pio_data *pio)
 	ibi->seg_len = FIELD_GET(IBI_DATA_LENGTH, ibi_status);
 	ibi->seg_cnt = ibi->seg_len;
 
+	if (ibi->addr == I3C_HOT_JOIN_ADDR) {
+		i3c_master_queue_hotjoin(&hci->master);
+		return true;
+	}
+
 	dev = i3c_hci_addr_to_dev(hci, ibi->addr);
 	if (!dev) {
 		dev_err(&hci->master.dev,
-- 
2.51.0


  parent reply	other threads:[~2026-05-12 12:18 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-12 12:17 [PATCH 0/8] i3c: Hot-Join improvements and MIPI HCI Hot-Join support Adrian Hunter
2026-05-12 12:17 ` Adrian Hunter
2026-05-12 12:17 ` [PATCH 1/8] i3c: master: Make hot-join workqueue freezable to block hot-join during suspend Adrian Hunter
2026-05-12 12:17   ` Adrian Hunter
2026-05-12 16:09   ` Frank Li
2026-05-12 16:09     ` Frank Li
2026-05-12 12:17 ` [PATCH 2/8] i3c: master: Serialize i3c_set_hotjoin() with the maintenance lock Adrian Hunter
2026-05-12 12:17   ` Adrian Hunter
2026-05-12 16:11   ` Frank Li
2026-05-12 16:11     ` Frank Li
2026-05-12 19:42     ` David Nyström
2026-05-12 19:42       ` David Nyström
2026-05-13  5:01       ` Adrian Hunter
2026-05-13  5:01         ` Adrian Hunter
2026-05-13 10:21         ` David Nyström
2026-05-13 10:21           ` David Nyström
2026-05-13  5:09     ` Adrian Hunter
2026-05-13  5:09       ` Adrian Hunter
2026-05-12 12:17 ` [PATCH 3/8] i3c: master: Consolidate Hot-Join DAA work in the core Adrian Hunter
2026-05-12 12:17   ` Adrian Hunter
2026-05-12 16:16   ` Frank Li
2026-05-12 16:16     ` Frank Li
2026-05-12 12:17 ` [PATCH 4/8] i3c: master: Ensure Hot-Join operations are stopped on shutdown Adrian Hunter
2026-05-12 12:17   ` Adrian Hunter
2026-05-12 16:27   ` Frank Li
2026-05-12 16:27     ` Frank Li
2026-05-13  5:31     ` Adrian Hunter
2026-05-13  5:31       ` Adrian Hunter
2026-05-13 19:04       ` Frank Li
2026-05-13 19:04         ` Frank Li
2026-05-12 12:17 ` [PATCH 5/8] i3c: dw: Drop redundant Hot-Join cancel_work_sync() in shutdown Adrian Hunter
2026-05-12 12:17   ` Adrian Hunter
2026-05-12 16:30   ` Frank Li
2026-05-12 16:30     ` Frank Li
2026-05-12 12:17 ` [PATCH 6/8] i3c: master: Defer new-device registration out of DAA caller context Adrian Hunter
2026-05-12 12:17   ` Adrian Hunter
2026-05-12 16:39   ` Frank Li
2026-05-12 16:39     ` Frank Li
2026-05-13  5:45     ` Adrian Hunter
2026-05-13  5:45       ` Adrian Hunter
2026-05-13 10:20       ` David Nyström
2026-05-13 10:20         ` David Nyström
2026-05-13 19:03       ` Frank Li
2026-05-13 19:03         ` Frank Li
2026-05-15 16:42         ` Adrian Hunter
2026-05-15 16:42           ` Adrian Hunter
2026-05-12 12:17 ` [PATCH 7/8] i3c: master: Export i3c_master_enec_disec_locked() Adrian Hunter
2026-05-12 12:17   ` Adrian Hunter
2026-05-12 16:31   ` Frank Li
2026-05-12 16:31     ` Frank Li
2026-05-12 12:17 ` Adrian Hunter [this message]
2026-05-12 12:17   ` [PATCH 8/8] i3c: mipi-i3c-hci: Add Hot-Join support Adrian Hunter
2026-05-12 16:34   ` Frank Li
2026-05-12 16:34     ` Frank Li

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=20260512121732.406009-9-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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.