From nobody Mon May 25 05:12:13 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DD5EC3F86ED for ; Mon, 18 May 2026 11:55:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779105341; cv=none; b=RxnayF8TbqUlcjlQYsaHFxC991aSattA/kEwmZN16st0QFvFByL1NQ+JQIFIxdoXiSI6ZMiqr3rTeB7zSlSjMG6kT6DToTf+/xHh+lSYWqsr4DR4jTVeIuYS22xucRgcxNmL4it+mUmYM2rjX4iocNtLdRAn7ewzmMAJe8XFAWw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779105341; c=relaxed/simple; bh=RdMb05f8g6qUnk2QWuCC2x0h1RsjtSC/GCFb+mBaJ9k=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=EkuhaTjU4gXHpDtUICVrRx58qL4oPiign+0tY0kg+QXoZ1b9wBvoe+AkaJtmcEJ8WZ7v/ePk2J0Tm2oEbLCcFbbvsNucyYY6vDh6MyduxcFGxHAHpkQALD+vjauxsCybcolbgFCdj3lFPkU2gR24aj1PBeXpWcscGKdwqBA7/1A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=kIb/S9Uc; arc=none smtp.client-ip=192.198.163.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="kIb/S9Uc" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1779105339; x=1810641339; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=RdMb05f8g6qUnk2QWuCC2x0h1RsjtSC/GCFb+mBaJ9k=; b=kIb/S9UcMp1C78vO1oUpGp7doB9BWMoAPSOzadJp8zWkgMlDjFzRvcOe CN3QyoRKbJjZczjxsZ7iOmdirKuKmuHZLguKDak1NsoGfx7zHpWOproKV 04I2TIcx/E3qUL29nMrSIvWwFKZZv7/Z7noT7FBPNrxiMmOEi6cA/chht qkB5kwViI/e8Rn2RGDlXU3IkmzIQrtsl5vwbIwdpdgWEB1+6r+prlyQSJ kI50g41CGAoHRv0G++UaCKO9jW4zrMgNRuKz13wasor9dSIDOA0OTwzXs sywxW1IweNKsTmq9XmhAt0Fd2NzM1SeT8oL3X54RGkvCs/CiR8vmWxZat g==; X-CSE-ConnectionGUID: LiDuUYfER5iVWDD2KalEIQ== X-CSE-MsgGUID: xcs7w51ZRqW0h2Ky3bnwZw== X-IronPort-AV: E=McAfee;i="6800,10657,11789"; a="91347033" X-IronPort-AV: E=Sophos;i="6.23,241,1770624000"; d="scan'208";a="91347033" Received: from orviesa007.jf.intel.com ([10.64.159.147]) by fmvoesa104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 May 2026 04:55:38 -0700 X-CSE-ConnectionGUID: vcQ/X60GRLSRbhWc3FVr/g== X-CSE-MsgGUID: EPyR1eKkTaGUxJllwyj+dg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,241,1770624000"; d="scan'208";a="239663398" Received: from egrumbac-mobl6.ger.corp.intel.com (HELO ahunter6-desk) ([10.245.245.220]) by orviesa007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 May 2026 04:55:37 -0700 From: Adrian Hunter To: alexandre.belloni@bootlin.com Cc: Frank.Li@nxp.com, david.nystrom@est.tech, linux-i3c@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH V2 1/8] i3c: master: Make hot-join workqueue freezable to block hot-join during suspend Date: Mon, 18 May 2026 14:55:12 +0300 Message-ID: <20260518115520.98335-2-adrian.hunter@intel.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260518115520.98335-1-adrian.hunter@intel.com> References: <20260518115520.98335-1-adrian.hunter@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Organization: Intel Finland Oy, Registered Address: c/o Alberga Business Park, 6 krs, Bertel Jungin Aukio 5, 02600 Espoo, Business Identity Code: 0357606 - 4, Domiciled in Helsinki Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The I3C master workqueue (master->wq) is used to defer work that needs thread context and the bus maintenance lock, most notably Hot Join processing (which calls i3c_master_do_daa() to assign dynamic addresses to newly joined devices). Currently the workqueue keeps running across system suspend, which can race with the suspend path: - do_daa() may execute after the controller has been suspended, issuing bus transactions on a powered-down or otherwise unusable controller. - New I3C devices can be enumerated and added to the bus mid-suspend, registering driver model objects at a point where the I3C subsystem and its consumers are not prepared to handle them. Mark the workqueue WQ_FREEZABLE so its workers are frozen for the duration of system suspend/hibernate and resumed afterwards. This naturally defers any pending or newly queued Hot Join work until the system (and the controller) is fully resumed, closing both races without adding explicit suspend/resume synchronization in the master drivers. Update the kerneldoc for struct i3c_master_controller::wq to reflect that the workqueue is freezable. Fixes: 3a379bbcea0af ("i3c: Add core I3C infrastructure") Signed-off-by: Adrian Hunter Reviewed-by: Frank Li --- Changes in V2: Add Fixes tag Add Frank's Rev'd by drivers/i3c/master.c | 2 +- include/linux/i3c/master.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 5cd4e5da2233..ab11e2d79aab 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -3079,7 +3079,7 @@ int i3c_master_register(struct i3c_master_controller = *master, if (ret) goto err_put_dev; =20 - master->wq =3D alloc_workqueue("%s", WQ_PERCPU, 0, dev_name(parent)); + master->wq =3D alloc_workqueue("%s", WQ_PERCPU | WQ_FREEZABLE, 0, dev_nam= e(parent)); if (!master->wq) { ret =3D -ENOMEM; goto err_put_dev; diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h index 592b646f6134..e6112e5f6608 100644 --- a/include/linux/i3c/master.h +++ b/include/linux/i3c/master.h @@ -515,7 +515,7 @@ struct i3c_master_controller_ops { * @boardinfo.i2c: list of I2C boardinfo objects * @boardinfo: board-level information attached to devices connected on th= e bus * @bus: I3C bus exposed by this master - * @wq: workqueue which can be used by master + * @wq: freezable workqueue which can be used by master * drivers if they need to postpone operations that need to take place * in a thread context. Typical examples are Hot Join processing which * requires taking the bus lock in maintenance, which in turn, can only --=20 2.51.0 From nobody Mon May 25 05:12:13 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8BE1C3F889A for ; Mon, 18 May 2026 11:55:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779105343; cv=none; b=kQHgfforvYUBkfyW7efgbzll03KIb3PqraT8Ka8Vn+cE/ODltbYypyPQY6lvka1HtIEYttL9gSPMshJ3/e74wEnAVRXHsJKIh8MdIsr6KAPiO5QG6e6faUukzTEExyvxPfrrrWzPjAH56GREL2xKpplsz8wH7noW9jZXTVYGW4I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779105343; c=relaxed/simple; bh=lTtMuVrJNw2IoPW2wMITq46V6MAlulkuO/DcRnZTqTU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UG0kT7m2afoFU4qDWu3KeTOqJldP1uxn5TimuMm6LQdwprAMN5jAxXzFEwDRmS0fJFyOSb9kiVelwSrF/wwI8XWoRnvs82GKzsxlIf5SBJAm56g3GF7WGpsa2ttQq0LOA1ePUhbLdolz5TPeW711zyAb0Le5qoaihxry5p6/A8c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=J8rhRh1/; arc=none smtp.client-ip=192.198.163.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="J8rhRh1/" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1779105341; x=1810641341; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=lTtMuVrJNw2IoPW2wMITq46V6MAlulkuO/DcRnZTqTU=; b=J8rhRh1/TGWz6ZpfCSD+jPqFY3wPDwTEG98Abs/JwfwwoHQIkfQVXpBo pqRLof2qFYmfxzl4pYzAlOcrm4p2o3atS3pBExyfe1jgUBgc/Oc0NfgLr xSeGWyUiBhHefIVc6RKcOIxcYMcqLNLrTc/B3HTvxYZVOLQ5jlHtL7n1F DfUs3cCGvo4DSSnjB1mzAaBDkJl4+vJ7JpW5Okl+Q5jYBF6WqtEd+5tUt 89uQqLj52geyWJXnI1PjCaGmn/CzfXZPm/JJbG3GZHaAMGDBa1z0CiqHn ZuvmlIzPpMpo625ziTnnaiq2TznABMV/ai8reeGs3hLJFv1pIKDrY66RD g==; X-CSE-ConnectionGUID: iA1ToCKzRgeuGAmok9Hs9A== X-CSE-MsgGUID: b1i/P8oGSg6rbJqfaxdWgw== X-IronPort-AV: E=McAfee;i="6800,10657,11789"; a="91347044" X-IronPort-AV: E=Sophos;i="6.23,241,1770624000"; d="scan'208";a="91347044" Received: from orviesa007.jf.intel.com ([10.64.159.147]) by fmvoesa104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 May 2026 04:55:41 -0700 X-CSE-ConnectionGUID: +ESJhtAKT1yllq8VseiOpA== X-CSE-MsgGUID: uH47qRaRQZaaVgNVei7lzg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,241,1770624000"; d="scan'208";a="239663404" Received: from egrumbac-mobl6.ger.corp.intel.com (HELO ahunter6-desk) ([10.245.245.220]) by orviesa007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 May 2026 04:55:39 -0700 From: Adrian Hunter To: alexandre.belloni@bootlin.com Cc: Frank.Li@nxp.com, david.nystrom@est.tech, linux-i3c@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH V2 2/8] i3c: master: Serialize i3c_set_hotjoin() with the maintenance lock Date: Mon, 18 May 2026 14:55:13 +0300 Message-ID: <20260518115520.98335-3-adrian.hunter@intel.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260518115520.98335-1-adrian.hunter@intel.com> References: <20260518115520.98335-1-adrian.hunter@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Organization: Intel Finland Oy, Registered Address: c/o Alberga Business Park, 6 krs, Bertel Jungin Aukio 5, 02600 Espoo, Business Identity Code: 0357606 - 4, Domiciled in Helsinki Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" i3c_set_hotjoin() dispatches the controller's enable_hotjoin() or disable_hotjoin() op and updates master->hotjoin under i3c_bus_normaluse_lock(). That lock is a read-side acquisition of bus->lock (down_read()), so it does not exclude concurrent callers. The hotjoin sysfs attribute can be opened multiple times, and writes through different opens are not serialized. Two concurrent writers to "hotjoin" can therefore race in i3c_set_hotjoin(), with the controller op and the master->hotjoin store from one call interleaving with the other. The hardware enable/disable state and the value reported by hotjoin_show() can end up out of sync. Take i3c_bus_maintenance_lock() instead. Toggling Hot Join enable changes bus state and is conceptually a maintenance operation, so the write-side acquisition of bus->lock is the appropriate lock and serializes concurrent callers against each other and against other maintenance operations. Fixes: 317bacf960a48 ("i3c: master: add enable(disable) hot join in sys ent= ry") Signed-off-by: Adrian Hunter --- Changes in V2: Add Fixes tag drivers/i3c/master.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index ab11e2d79aab..38ffc8713167 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -649,7 +649,7 @@ static int i3c_set_hotjoin(struct i3c_master_controller= *master, bool enable) return ret; } =20 - i3c_bus_normaluse_lock(&master->bus); + i3c_bus_maintenance_lock(&master->bus); =20 if (enable) ret =3D master->ops->enable_hotjoin(master); @@ -659,7 +659,7 @@ static int i3c_set_hotjoin(struct i3c_master_controller= *master, bool enable) if (!ret) master->hotjoin =3D enable; =20 - i3c_bus_normaluse_unlock(&master->bus); + i3c_bus_maintenance_unlock(&master->bus); =20 if ((enable && ret) || (!enable && !ret) || master->rpm_ibi_allowed) i3c_master_rpm_put(master); --=20 2.51.0 From nobody Mon May 25 05:12:13 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5796A3F88B0 for ; Mon, 18 May 2026 11:55:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779105346; cv=none; b=pYnhU9g9qb56XqBYEu51hIJiaAmJjX66j6jADlWXXYBy5HssNDPXPy8LBtkAFPBANV+aKIhuave3Ex2pRvXNltR3rVy7L9NX/AsTh29ef/HH7xtzSNXeYDQZ11VMUV0mf5M4ezbQL+m1VPfg7HX0par2h4Qy8QNTkAQw53TvHZo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779105346; c=relaxed/simple; bh=jqb52z3FD1EpiSlyrjjyS6KqUaUoTKx1LHGW291bxws=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=GSjRQkrpvrgP1JwXemN4nsc95FELbCwqUUGtnquBsoDFiscqfNLgHduWqvhAAri6KYpdr4qs8PWYUL61SmPZlk+bpZ+W1mQwZQOoxjvAApQ2Uq8uiCC81Dnm2xurPek2CU4WekptxdcVQXWg1BDEbTSDMPX76vDPl0umrGUoH00= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=JG5axSc1; arc=none smtp.client-ip=192.198.163.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="JG5axSc1" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1779105344; x=1810641344; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=jqb52z3FD1EpiSlyrjjyS6KqUaUoTKx1LHGW291bxws=; b=JG5axSc1H9OfN4bWvKCC2Y3Ku7bd9KWGrcc53WHIOKuLp7VslYIenPy+ srgtWqBLeALG/E+gn0hBsNN0OlFZ/RlDHWJ+fNnostmtraqZ4n7qFLuVI yaQhjB4F2+pZgaywoj4g+c602197IS8r1Den+xL/LvPjnfnxeH3YO/c/O zUHxPqfQXl40SMPODPbHLfxEEf2rMbymDSW1lBozv2LXMs02TrRgPbFhE pAokM5oPiSRg0+sGEyEI0eYurk+hXBrphqt+7f9Znn4z+DGfyg2MsMx+P +O4zjkQOOzsHGqVmyYvTVIWC16nZB3b0sNUX/QW6j765Ydh8LXd1HILP8 A==; X-CSE-ConnectionGUID: rDLL2erQSI+GeGuGPr0CLg== X-CSE-MsgGUID: LgpoEdp/QhmFPxXRD9ClXA== X-IronPort-AV: E=McAfee;i="6800,10657,11789"; a="91347055" X-IronPort-AV: E=Sophos;i="6.23,241,1770624000"; d="scan'208";a="91347055" Received: from orviesa007.jf.intel.com ([10.64.159.147]) by fmvoesa104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 May 2026 04:55:43 -0700 X-CSE-ConnectionGUID: XycV79rjTWC8wpak60NcyA== X-CSE-MsgGUID: k5sjuCopQxia+aGuEk7XZg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,241,1770624000"; d="scan'208";a="239663410" Received: from egrumbac-mobl6.ger.corp.intel.com (HELO ahunter6-desk) ([10.245.245.220]) by orviesa007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 May 2026 04:55:42 -0700 From: Adrian Hunter To: alexandre.belloni@bootlin.com Cc: Frank.Li@nxp.com, david.nystrom@est.tech, linux-i3c@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH V2 3/8] i3c: master: Consolidate Hot-Join DAA work in the core Date: Mon, 18 May 2026 14:55:14 +0300 Message-ID: <20260518115520.98335-4-adrian.hunter@intel.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260518115520.98335-1-adrian.hunter@intel.com> References: <20260518115520.98335-1-adrian.hunter@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Organization: Intel Finland Oy, Registered Address: c/o Alberga Business Park, 6 krs, Bertel Jungin Aukio 5, 02600 Espoo, Business Identity Code: 0357606 - 4, Domiciled in Helsinki Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Three master drivers (dw-i3c-master, i3c-master-cdns, svc-i3c-master) each carry an essentially identical Hot-Join handler: a struct work_struct embedded in their private state, a work function that just calls i3c_master_do_daa() on the embedded i3c_master_controller, plus matching INIT_WORK()/cancel_work_sync() boilerplate in probe/remove (and shutdown for dw-i3c). The IBI/ISR paths then queue that work onto master->wq, which already lives in the core. Move this pattern into the I3C core: - Add struct work_struct hj_work to struct i3c_master_controller and initialise it in i3c_master_register() with a core-provided handler i3c_master_hj_work_fn() that performs i3c_master_do_daa(). - Cancel the work in i3c_master_unregister() so all controllers get correct teardown ordering against the workqueue for free. - Export i3c_master_queue_hotjoin() as the single entry point drivers call from their Hot-Join IBI handler. Convert the three existing users to the new API: drop their private hj_work fields, work functions, INIT_WORK() and cancel_work_sync() calls, and replace the queue_work(master->wq, &drv->hj_work) call sites with i3c_master_queue_hotjoin(&drv->base). The dw-i3c shutdown path still needs to flush pending Hot-Join work before tearing down the hardware, so it is updated to cancel master->base.hj_work directly. No functional change intended: the work is still queued on the same master->wq, runs the same i3c_master_do_daa(), and is cancelled at controller teardown. Future Hot-Join improvements now only need to be made in one place. Signed-off-by: Adrian Hunter Reviewed-by: Frank Li --- Changes in V2: Add Frank's Rev'd by drivers/i3c/master.c | 21 +++++++++++++++++++++ drivers/i3c/master/dw-i3c-master.c | 15 ++------------- drivers/i3c/master/dw-i3c-master.h | 2 -- drivers/i3c/master/i3c-master-cdns.c | 14 +------------- drivers/i3c/master/svc-i3c-master.c | 14 +------------- include/linux/i3c/master.h | 4 ++++ 6 files changed, 29 insertions(+), 41 deletions(-) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 38ffc8713167..cdb5cb2aa65d 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -633,6 +633,13 @@ static ssize_t i2c_scl_frequency_show(struct device *d= ev, } static DEVICE_ATTR_RO(i2c_scl_frequency); =20 +static void i3c_master_hj_work_fn(struct work_struct *work) +{ + struct i3c_master_controller *master =3D container_of(work, typeof(*maste= r), hj_work); + + i3c_master_do_daa(master); +} + static int i3c_set_hotjoin(struct i3c_master_controller *master, bool enab= le) { int ret; @@ -711,6 +718,18 @@ int i3c_master_disable_hotjoin(struct i3c_master_contr= oller *master) } EXPORT_SYMBOL_GPL(i3c_master_disable_hotjoin); =20 +/** + * i3c_master_queue_hotjoin - Queue DAA processing after a Hot-Join event + * @master: I3C master object + * + * Queue the hot-join worker on the master's workqueue. + */ +void i3c_master_queue_hotjoin(struct i3c_master_controller *master) +{ + queue_work(master->wq, &master->hj_work); +} +EXPORT_SYMBOL_GPL(i3c_master_queue_hotjoin); + static ssize_t hotjoin_show(struct device *dev, struct device_attribute *d= a, char *buf) { struct i3c_bus *i3cbus =3D dev_to_i3cbus(dev); @@ -3084,6 +3103,7 @@ int i3c_master_register(struct i3c_master_controller = *master, ret =3D -ENOMEM; goto err_put_dev; } + INIT_WORK(&master->hj_work, i3c_master_hj_work_fn); =20 ret =3D i3c_master_bus_init(master); if (ret) @@ -3146,6 +3166,7 @@ EXPORT_SYMBOL_GPL(i3c_master_register); void i3c_master_unregister(struct i3c_master_controller *master) { i3c_bus_notify(&master->bus, I3C_NOTIFY_BUS_REMOVE); + cancel_work_sync(&master->hj_work); =20 if (master->ops->set_dev_nack_retry) device_remove_file(&master->dev, &dev_attr_dev_nack_retry_count); diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c= -master.c index 655693a2187e..eb9a13a73684 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -1445,7 +1445,7 @@ static void dw_i3c_master_irq_handle_ibis(struct dw_i= 3c_master *master) if (IBI_TYPE_SIRQ(reg)) { dw_i3c_master_handle_ibi_sir(master, reg); } else if (IBI_TYPE_HJ(reg)) { - queue_work(master->base.wq, &master->hj_work); + i3c_master_queue_hotjoin(&master->base); } else { len =3D IBI_QUEUE_STATUS_DATA_LEN(reg); dev_info(&master->base.dev, @@ -1554,14 +1554,6 @@ static const struct dw_i3c_platform_ops dw_i3c_platf= orm_ops_default =3D { .set_dat_ibi =3D dw_i3c_platform_set_dat_ibi_nop, }; =20 -static void dw_i3c_hj_work(struct work_struct *work) -{ - struct dw_i3c_master *master =3D - container_of(work, typeof(*master), hj_work); - - i3c_master_do_daa(&master->base); -} - int dw_i3c_common_probe(struct dw_i3c_master *master, struct platform_device *pdev) { @@ -1636,8 +1628,6 @@ int dw_i3c_common_probe(struct dw_i3c_master *master, if (master->quirks & DW_I3C_DISABLE_RUNTIME_PM_QUIRK) pm_runtime_get_noresume(&pdev->dev); =20 - INIT_WORK(&master->hj_work, dw_i3c_hj_work); - device_set_of_node_from_dev(&master->base.i2c.dev, &pdev->dev); ret =3D i3c_master_register(&master->base, &pdev->dev, &dw_mipi_i3c_ops, false); @@ -1659,7 +1649,6 @@ EXPORT_SYMBOL_GPL(dw_i3c_common_probe); =20 void dw_i3c_common_remove(struct dw_i3c_master *master) { - cancel_work_sync(&master->hj_work); i3c_master_unregister(&master->base); =20 /* Balance pm_runtime_get_noresume() from probe() */ @@ -1804,7 +1793,7 @@ static void dw_i3c_shutdown(struct platform_device *p= dev) return; } =20 - cancel_work_sync(&master->hj_work); + cancel_work_sync(&master->base.hj_work); =20 /* Disable interrupts */ writel((u32)~INTR_ALL, master->regs + INTR_STATUS_EN); diff --git a/drivers/i3c/master/dw-i3c-master.h b/drivers/i3c/master/dw-i3c= -master.h index c5cb695c16ab..2f029bd36232 100644 --- a/drivers/i3c/master/dw-i3c-master.h +++ b/drivers/i3c/master/dw-i3c-master.h @@ -68,8 +68,6 @@ struct dw_i3c_master { =20 /* platform-specific data */ const struct dw_i3c_platform_ops *platform_ops; - - struct work_struct hj_work; }; =20 struct dw_i3c_platform_ops { diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-= master-cdns.c index 5cfec6761494..6d221596ea35 100644 --- a/drivers/i3c/master/i3c-master-cdns.c +++ b/drivers/i3c/master/i3c-master-cdns.c @@ -398,7 +398,6 @@ struct cdns_i3c_data { }; =20 struct cdns_i3c_master { - struct work_struct hj_work; struct i3c_master_controller base; u32 free_rr_slots; unsigned int maxdevs; @@ -1357,7 +1356,7 @@ static void cnds_i3c_master_demux_ibis(struct cdns_i3= c_master *master) =20 case IBIR_TYPE_HJ: WARN_ON(IBIR_XFER_BYTES(ibir) || (ibir & IBIR_ERROR)); - queue_work(master->base.wq, &master->hj_work); + i3c_master_queue_hotjoin(&master->base); break; =20 case IBIR_TYPE_MR: @@ -1528,15 +1527,6 @@ static const struct i3c_master_controller_ops cdns_i= 3c_master_ops =3D { .recycle_ibi_slot =3D cdns_i3c_master_recycle_ibi_slot, }; =20 -static void cdns_i3c_master_hj(struct work_struct *work) -{ - struct cdns_i3c_master *master =3D container_of(work, - struct cdns_i3c_master, - hj_work); - - i3c_master_do_daa(&master->base); -} - static struct cdns_i3c_data cdns_i3c_devdata =3D { .thd_delay_ns =3D 10, }; @@ -1584,7 +1574,6 @@ static int cdns_i3c_master_probe(struct platform_devi= ce *pdev) spin_lock_init(&master->xferqueue.lock); INIT_LIST_HEAD(&master->xferqueue.list); =20 - INIT_WORK(&master->hj_work, cdns_i3c_master_hj); writel(0xffffffff, master->regs + MST_IDR); writel(0xffffffff, master->regs + SLV_IDR); ret =3D devm_request_irq(&pdev->dev, irq, cdns_i3c_master_interrupt, 0, @@ -1627,7 +1616,6 @@ static void cdns_i3c_master_remove(struct platform_de= vice *pdev) { struct cdns_i3c_master *master =3D platform_get_drvdata(pdev); =20 - cancel_work_sync(&master->hj_work); i3c_master_unregister(&master->base); } =20 diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i= 3c-master.c index e2d99a3ac07d..62e5666798c8 100644 --- a/drivers/i3c/master/svc-i3c-master.c +++ b/drivers/i3c/master/svc-i3c-master.c @@ -208,7 +208,6 @@ struct svc_i3c_drvdata { * @free_slots: Bit array of available slots * @addrs: Array containing the dynamic addresses of each attached device * @descs: Array of descriptors, one per attached device - * @hj_work: Hot-join work * @irq: Main interrupt * @num_clks: I3C clock number * @fclk: Fast clock (bus) @@ -235,7 +234,6 @@ struct svc_i3c_master { u32 free_slots; u8 addrs[SVC_I3C_MAX_DEVS]; struct i3c_dev_desc *descs[SVC_I3C_MAX_DEVS]; - struct work_struct hj_work; int irq; int num_clks; struct clk *fclk; @@ -366,14 +364,6 @@ to_svc_i3c_master(struct i3c_master_controller *master) return container_of(master, struct svc_i3c_master, base); } =20 -static void svc_i3c_master_hj_work(struct work_struct *work) -{ - struct svc_i3c_master *master; - - master =3D container_of(work, struct svc_i3c_master, hj_work); - i3c_master_do_daa(&master->base); -} - static struct i3c_dev_desc * svc_i3c_master_dev_from_addr(struct svc_i3c_master *master, unsigned int ibiaddr) @@ -651,7 +641,7 @@ static void svc_i3c_master_ibi_isr(struct svc_i3c_maste= r *master) case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN: svc_i3c_master_emit_stop(master); if (is_events_enabled(master, SVC_I3C_EVENT_HOTJOIN)) - queue_work(master->base.wq, &master->hj_work); + i3c_master_queue_hotjoin(&master->base); break; case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST: svc_i3c_master_emit_stop(master); @@ -2022,7 +2012,6 @@ static int svc_i3c_master_probe(struct platform_devic= e *pdev) if (ret) return dev_err_probe(dev, ret, "can't enable I3C clocks\n"); =20 - INIT_WORK(&master->hj_work, svc_i3c_master_hj_work); mutex_init(&master->lock); =20 ret =3D devm_request_irq(dev, master->irq, svc_i3c_master_irq_handler, @@ -2081,7 +2070,6 @@ static void svc_i3c_master_remove(struct platform_dev= ice *pdev) { struct svc_i3c_master *master =3D platform_get_drvdata(pdev); =20 - cancel_work_sync(&master->hj_work); i3c_master_unregister(&master->base); =20 pm_runtime_dont_use_autosuspend(&pdev->dev); diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h index e6112e5f6608..eb5c51608bd7 100644 --- a/include/linux/i3c/master.h +++ b/include/linux/i3c/master.h @@ -520,6 +520,8 @@ struct i3c_master_controller_ops { * in a thread context. Typical examples are Hot Join processing which * requires taking the bus lock in maintenance, which in turn, can only * be done from a sleep-able context + * @hj_work: work item used to run DAA after a Hot-Join event is detected. + * Queued to @wq by i3c_master_queue_hotjoin() * @dev_nack_retry_count: retry count when slave device nack * * A &struct i3c_master_controller has to be registered to the I3C subsyst= em @@ -543,6 +545,7 @@ struct i3c_master_controller { } boardinfo; struct i3c_bus bus; struct workqueue_struct *wq; + struct work_struct hj_work; unsigned int dev_nack_retry_count; }; =20 @@ -623,6 +626,7 @@ int i3c_master_register(struct i3c_master_controller *m= aster, void i3c_master_unregister(struct i3c_master_controller *master); int i3c_master_enable_hotjoin(struct i3c_master_controller *master); int i3c_master_disable_hotjoin(struct i3c_master_controller *master); +void i3c_master_queue_hotjoin(struct i3c_master_controller *master); =20 /** * i3c_dev_get_master_data() - get master private data attached to an I3C --=20 2.51.0 From nobody Mon May 25 05:12:13 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4CEAA3F889B for ; Mon, 18 May 2026 11:55:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779105348; cv=none; b=VH5xnoZRLId8MdmK/F4mmmUeDK+NAx3398vfJTzlnPZPEDcEESMwTFbn+COsqKLEOhrGqeZJNWppGegr8Vv2eON+vEwrzxLrj13jUMKQn3vM8rH+WsjdmZIuKyhKTeTkPjRaRUlHNY5GzHR9E4SoirMMkbQO5KFepCD7Yx1fXpI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779105348; c=relaxed/simple; bh=UTjhVCrREM53e4OcVoixACuB519wxeFJxJJPGmIx5OE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Hc64YuK5DfU8mFf1Pr+SGchMY9mklQKbrYOCE1fc90wVKs/lXRka9NFTmDDXYe6tiZAuzFVsoZFNc7nlfYxCXqY9VVswXtA3zy4Vxybsx/E/e//kv5yx+/TveYRp4afpvm0GzpS2MS41Wi+aS1xR+IM0L54e+ufYDIG/e323Wok= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=XJIdwv29; arc=none smtp.client-ip=192.198.163.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="XJIdwv29" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1779105346; x=1810641346; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=UTjhVCrREM53e4OcVoixACuB519wxeFJxJJPGmIx5OE=; b=XJIdwv29NDtEIFZguEESpZmVKF77TC5gP84FohJhyC4x3T36VA+wtZnp eMoLQL+SYSprdqaPDX/uzgrMxmyEetyYgaoMuPtrhSTwMTOPXwYhmYNbz PgWKGXBahLG+59DOsfsXd1J25RenfFjiISOl/4Z7e95Fy+v52lOU8kTQo Vpix6fOVuPUH8jYeOdeg3K0WOtrnW+Qu+JnJ9lNCZiLZoDuiMNSo9a45m ilKO5GfptAtGV08Y7GkT4KoY8kgLQ5+rvIQdY2aiBCsqqAqPSsZ4a+Tco 6G5keYpRxEPhG0cyjO+PjLKHxluK7IABu7cP/fR874R87aKp13N/vs1oH w==; X-CSE-ConnectionGUID: DPuJLbnLSNKeq4de2wtl3Q== X-CSE-MsgGUID: XENlBtEYTDGi4VEC41EkCQ== X-IronPort-AV: E=McAfee;i="6800,10657,11789"; a="91347064" X-IronPort-AV: E=Sophos;i="6.23,241,1770624000"; d="scan'208";a="91347064" Received: from orviesa007.jf.intel.com ([10.64.159.147]) by fmvoesa104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 May 2026 04:55:46 -0700 X-CSE-ConnectionGUID: REZAZ45mQsCFhhPG85/kTA== X-CSE-MsgGUID: irb79U/BRzao2jfXMVdFzA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,241,1770624000"; d="scan'208";a="239663415" Received: from egrumbac-mobl6.ger.corp.intel.com (HELO ahunter6-desk) ([10.245.245.220]) by orviesa007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 May 2026 04:55:44 -0700 From: Adrian Hunter To: alexandre.belloni@bootlin.com Cc: Frank.Li@nxp.com, david.nystrom@est.tech, linux-i3c@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH V2 4/8] i3c: master: Ensure Hot-Join operations are stopped on shutdown Date: Mon, 18 May 2026 14:55:15 +0300 Message-ID: <20260518115520.98335-5-adrian.hunter@intel.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260518115520.98335-1-adrian.hunter@intel.com> References: <20260518115520.98335-1-adrian.hunter@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Organization: Intel Finland Oy, Registered Address: c/o Alberga Business Park, 6 krs, Bertel Jungin Aukio 5, 02600 Espoo, Business Identity Code: 0357606 - 4, Domiciled in Helsinki Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" System shutdown invokes each device's bus shutdown callback to quiesce hardware, but the I3C bus type does not currently implement one. As a result, on shutdown the controller's Hot-Join work and any in-flight i3c_master_do_daa() can keep running (or be newly triggered) while the rest of the system is being torn down. A similar window exists at i3c_master_unregister() time: cancel_work_sync() on hj_work prevents queued work from completing, but does not stop a fresh Hot-Join IBI from re-queueing the worker, nor a concurrent sysfs writer from toggling Hot-Join via i3c_set_hotjoin(). Introduce a single "shutting down" gate in the I3C core, set under the bus maintenance lock so it is observed by any in-progress DAA path before pending work is cancelled. Install an i3c_bus_type shutdown callback that engages this gate for master devices during system shutdown, and use the same gate in i3c_master_unregister() so both paths get identical guarantees. Once the gate is engaged, the Hot-Join worker, i3c_master_do_daa_ext() and i3c_set_hotjoin() all bail out cleanly, so Hot-Join IBIs that race with shutdown become no-ops, direct DAA callers see -ENODEV, and sysfs writers can no longer re-enable Hot-Join through ops->enable_hotjoin() while the controller is going away. No functional change for the steady-state runtime path; the new checks only take effect once the controller has been marked as shutting down. Note, this patch depends on patch "i3c: master: Consolidate Hot-Join DAA work in the core". Fixes: 3a379bbcea0af ("i3c: Add core I3C infrastructure") Signed-off-by: Adrian Hunter Reviewed-by: Frank Li --- Changes in V2: Add dependency note to commit message Add Fixes tag Add Frank's Rev'd by drivers/i3c/master.c | 52 +++++++++++++++++++++++++++----------- include/linux/i3c/master.h | 2 ++ 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index cdb5cb2aa65d..a59c4b744b36 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -368,14 +368,6 @@ static void i3c_device_remove(struct device *dev) driver->remove(i3cdev); } =20 -const struct bus_type i3c_bus_type =3D { - .name =3D "i3c", - .match =3D i3c_device_match, - .probe =3D i3c_device_probe, - .remove =3D i3c_device_remove, -}; -EXPORT_SYMBOL_GPL(i3c_bus_type); - static enum i3c_addr_slot_status i3c_bus_get_addr_slot_status_mask(struct i3c_bus *bus, u16 addr, u32 mask) { @@ -637,7 +629,8 @@ static void i3c_master_hj_work_fn(struct work_struct *w= ork) { struct i3c_master_controller *master =3D container_of(work, typeof(*maste= r), hj_work); =20 - i3c_master_do_daa(master); + if (!master->shutting_down) + i3c_master_do_daa(master); } =20 static int i3c_set_hotjoin(struct i3c_master_controller *master, bool enab= le) @@ -658,7 +651,9 @@ static int i3c_set_hotjoin(struct i3c_master_controller= *master, bool enable) =20 i3c_bus_maintenance_lock(&master->bus); =20 - if (enable) + if (master->shutting_down) + ret =3D -ENODEV; + else if (enable) ret =3D master->ops->enable_hotjoin(master); else ret =3D master->ops->disable_hotjoin(master); @@ -837,6 +832,30 @@ static const struct device_type i3c_masterdev_type =3D= { .groups =3D i3c_masterdev_groups, }; =20 +static void i3c_master_shutdown(struct i3c_master_controller *master) +{ + i3c_bus_maintenance_lock(&master->bus); + master->shutting_down =3D true; + i3c_bus_maintenance_unlock(&master->bus); + + cancel_work_sync(&master->hj_work); +} + +static void i3c_device_shutdown(struct device *dev) +{ + if (dev->type =3D=3D &i3c_masterdev_type) + i3c_master_shutdown(dev_to_i3cmaster(dev)); +} + +const struct bus_type i3c_bus_type =3D { + .name =3D "i3c", + .match =3D i3c_device_match, + .probe =3D i3c_device_probe, + .remove =3D i3c_device_remove, + .shutdown =3D i3c_device_shutdown, +}; +EXPORT_SYMBOL_GPL(i3c_bus_type); + static int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode, unsigned long max_i2c_scl_rate) { @@ -1846,10 +1865,13 @@ int i3c_master_do_daa_ext(struct i3c_master_control= ler *master, bool rstdaa) =20 i3c_bus_maintenance_lock(&master->bus); =20 - if (rstdaa) - rstret =3D i3c_master_rstdaa_locked(master, I3C_BROADCAST_ADDR); - - ret =3D master->ops->do_daa(master); + if (master->shutting_down) { + ret =3D -ENODEV; + } else { + if (rstdaa) + rstret =3D i3c_master_rstdaa_locked(master, I3C_BROADCAST_ADDR); + ret =3D master->ops->do_daa(master); + } =20 i3c_bus_maintenance_unlock(&master->bus); =20 @@ -3166,7 +3188,7 @@ EXPORT_SYMBOL_GPL(i3c_master_register); void i3c_master_unregister(struct i3c_master_controller *master) { i3c_bus_notify(&master->bus, I3C_NOTIFY_BUS_REMOVE); - cancel_work_sync(&master->hj_work); + i3c_master_shutdown(master); =20 if (master->ops->set_dev_nack_retry) device_remove_file(&master->dev, &dev_attr_dev_nack_retry_count); diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h index eb5c51608bd7..77e63082b06e 100644 --- a/include/linux/i3c/master.h +++ b/include/linux/i3c/master.h @@ -511,6 +511,7 @@ struct i3c_master_controller_ops { * @hotjoin: true if the master support hotjoin * @rpm_allowed: true if Runtime PM allowed * @rpm_ibi_allowed: true if IBI and Hot-Join allowed while runtime suspen= ded + * @shutting_down: set to true when master begins shutdown or unregister * @boardinfo.i3c: list of I3C boardinfo objects * @boardinfo.i2c: list of I2C boardinfo objects * @boardinfo: board-level information attached to devices connected on th= e bus @@ -539,6 +540,7 @@ struct i3c_master_controller { unsigned int hotjoin: 1; unsigned int rpm_allowed: 1; unsigned int rpm_ibi_allowed: 1; + bool shutting_down; struct { struct list_head i3c; struct list_head i2c; --=20 2.51.0 From nobody Mon May 25 05:12:13 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A36B03F88AC for ; Mon, 18 May 2026 11:55:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779105350; cv=none; b=TPuSaPVEaL+CwBqy3+8eP2P8Z/MrQOEyT+eHQpDcjB7E7Puuipe9TiCYRCCqqD6vpoj51tzrt1axDu5IWVI3NpdxhygCzwyewMdntMVgq81hJL3JcY1K0yDEHEJJGmpO3lZiSz9knMWy8xEhgZOC4vm6oablNT4ZwhYUZGsRGoQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779105350; c=relaxed/simple; bh=x9wINvGzkhXWZhz0LHxePidlKWHibKXGhzDQTSxC8h4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gLO/Zw099dvFCEhZxiTN+d+CICj1VlvNP8BdK2NCpEg0fzXkMUNCl51ps7tTjT2DL0yjhk7MMR4w+e/kplz/DJVeXA1FKe/bfULZB27T2T7QkPCvAwj/iodbUoGwsAPgnFDoSUgleefoxxUovl0bjgD/XYz6YYjnXJ0/JfZs9to= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=eJwjxDIp; arc=none smtp.client-ip=192.198.163.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="eJwjxDIp" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1779105348; x=1810641348; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=x9wINvGzkhXWZhz0LHxePidlKWHibKXGhzDQTSxC8h4=; b=eJwjxDIp88C6l8u4nv/Z9aFjf6iRgXFD+mijEgXQ5pucdDeOV4KJ2Jim a92V1Y/9KoSLudROMJFwwWI0ZGkF7qHTwabURzS1LTGJFtwibThDB0lHx I6dUm6Qudo9CrlGDtXvxqdksKNaRtLvnqC+glfJe48tYUVoqdGXDsJ0ak 8NA+sfdzx+IkuEVTODiwl5k9boNBFHq1f6UbgW4JdonTCcDKHk5WoMVwh oWhn7J8Q/gVoSKBMlSPLhNt5HiX6D3arA05RNxCFrpePPOdsU08V6iTlr 4s8tp9NXgNLD47pMZoHpggqfpIvhKNTuNzQZFizhla5rj72z3FGEXaZ7R Q==; X-CSE-ConnectionGUID: 090HqDIDSMiN7TTL711Rpw== X-CSE-MsgGUID: YvHBjn9JQ/i+GAIigvdesg== X-IronPort-AV: E=McAfee;i="6800,10657,11789"; a="91347074" X-IronPort-AV: E=Sophos;i="6.23,241,1770624000"; d="scan'208";a="91347074" Received: from orviesa007.jf.intel.com ([10.64.159.147]) by fmvoesa104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 May 2026 04:55:48 -0700 X-CSE-ConnectionGUID: fCE30K8ORbC8nt6KjVq5fA== X-CSE-MsgGUID: 1PTJVs2iTxyFrz5Kn1lP5w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,241,1770624000"; d="scan'208";a="239663423" Received: from egrumbac-mobl6.ger.corp.intel.com (HELO ahunter6-desk) ([10.245.245.220]) by orviesa007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 May 2026 04:55:46 -0700 From: Adrian Hunter To: alexandre.belloni@bootlin.com Cc: Frank.Li@nxp.com, david.nystrom@est.tech, linux-i3c@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH V2 5/8] i3c: dw: Drop redundant Hot-Join cancel_work_sync() in shutdown Date: Mon, 18 May 2026 14:55:16 +0300 Message-ID: <20260518115520.98335-6-adrian.hunter@intel.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260518115520.98335-1-adrian.hunter@intel.com> References: <20260518115520.98335-1-adrian.hunter@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Organization: Intel Finland Oy, Registered Address: c/o Alberga Business Park, 6 krs, Bertel Jungin Aukio 5, 02600 Espoo, Business Identity Code: 0357606 - 4, Domiciled in Helsinki Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The I3C core now installs an i3c_bus_type shutdown callback that flushes master->hj_work (via i3c_master_shutdown()) before any driver's platform shutdown hook runs. The explicit cancel_work_sync() in dw_i3c_shutdown() is therefore redundant: by the time it executes, the Hot-Join worker has already been cancelled, and the shutting_down gate makes a new worker a no-op. Remove the now-unneeded call. No functional change. Signed-off-by: Adrian Hunter Reviewed-by: Frank Li --- Changes in V2: Add Frank's Rev'd by drivers/i3c/master/dw-i3c-master.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c= -master.c index eb9a13a73684..c7030d0cd8a6 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -1793,8 +1793,6 @@ static void dw_i3c_shutdown(struct platform_device *p= dev) return; } =20 - cancel_work_sync(&master->base.hj_work); - /* Disable interrupts */ writel((u32)~INTR_ALL, master->regs + INTR_STATUS_EN); writel((u32)~INTR_ALL, master->regs + INTR_SIGNAL_EN); --=20 2.51.0 From nobody Mon May 25 05:12:13 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 02B203F8EB5 for ; Mon, 18 May 2026 11:55:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779105352; cv=none; b=Seu0aQ81FDjgtKWBluhTn07AHLxDqam/qAXNAFqcZm+t9YzT1koI648CHqajCCCAMjGxQOedRd51LHfIPXdCfk3C3IWTNIi0FAsFZBlC5OGyJppuizf1WM5Q7fWDv6y2EzKN4fpd8yZWX4iJmtUpgu6+82o9REZ6zRSqSwsBR5M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779105352; c=relaxed/simple; bh=2vsiy47C7qcBq0tX7O+HypLJJG5GMicj6eDvi7v12sU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JVhY156xV8WF5Z0F4Q8Pp+W+1Lq9LSxbY3JDi91n2Lh5kFsIVueTbj3+tzMZ+U8MULwpk3irHTzQskyisO27VAdRj2/9+PL23OnFvcqReKXAvdfAWbB2XOiUapYH96LGZuKNSEFK5GcWy1rzV7l2M9fwprQEP+eb4h01WTTHggE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=YD2XXYBe; arc=none smtp.client-ip=192.198.163.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="YD2XXYBe" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1779105351; x=1810641351; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=2vsiy47C7qcBq0tX7O+HypLJJG5GMicj6eDvi7v12sU=; b=YD2XXYBeG0RDIAy69bf4n/KzIgl6UopCtg74/nYUa/Bhh/J6k87FoEJz 9V2mWwr+ik52K6RhSxCL/z2fA/yc6Kze/+zOM9Kgoh9b2l/p7MHFCGX/g Mvotdz46GpfqMBZ0dyTnJBdUZBmpPDacO7cwWPuLtf5zqrpe2kjl31W3Q BekecnkW+3gmePCTVxns1d0JW5h3ZfXQYF6yAp8sD5GHseRC/w80VvysO HueYykD/CsFMKWcyjiM2sr68LPyVft5bB/2U9rIg6XGvsDfyeaZbQcx2I 9TsBCeIFHTyN2Mu+2BhK2pZwxOhzdXz/xvY93tKOQsMSJK7mBl3JmGenI g==; X-CSE-ConnectionGUID: kRoKaq8zQUyRWv+nRH0K5A== X-CSE-MsgGUID: gHEgYyaUQLSvKcEScqRScA== X-IronPort-AV: E=McAfee;i="6800,10657,11789"; a="91347087" X-IronPort-AV: E=Sophos;i="6.23,241,1770624000"; d="scan'208";a="91347087" Received: from orviesa007.jf.intel.com ([10.64.159.147]) by fmvoesa104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 May 2026 04:55:50 -0700 X-CSE-ConnectionGUID: mPLrqjjWSOifS3jfa7uclw== X-CSE-MsgGUID: FDjmsVkYTeKJBcZzLZR/Jw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,241,1770624000"; d="scan'208";a="239663426" Received: from egrumbac-mobl6.ger.corp.intel.com (HELO ahunter6-desk) ([10.245.245.220]) by orviesa007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 May 2026 04:55:49 -0700 From: Adrian Hunter To: alexandre.belloni@bootlin.com Cc: Frank.Li@nxp.com, david.nystrom@est.tech, linux-i3c@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH V2 6/8] i3c: master: Defer new-device registration out of DAA caller context Date: Mon, 18 May 2026 14:55:17 +0300 Message-ID: <20260518115520.98335-7-adrian.hunter@intel.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260518115520.98335-1-adrian.hunter@intel.com> References: <20260518115520.98335-1-adrian.hunter@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Organization: Intel Finland Oy, Registered Address: c/o Alberga Business Park, 6 krs, Bertel Jungin Aukio 5, 02600 Espoo, Business Identity Code: 0357606 - 4, Domiciled in Helsinki Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Master drivers may invoke i3c_master_do_daa_ext() during resume to re-run Dynamic Address Assignment. As well as assigning addresses to any newly arrived devices, this restores the dynamic address of devices that lost it across system suspend, so it has to run as part of the controller's resume path. A side effect of i3c_master_do_daa_ext() today is that it also registers any newly discovered I3C devices with the driver model inline, via i3c_master_register_new_i3c_devs(). Doing that from the resume path is problematic: a hot-join-capable device may join the bus during this same DAA, and registering it immediately would push driver model work (probing, sysfs, etc.) into the controller's resume context, where the rest of the system is not yet fully resumed and the controller driver is still partway through its own resume sequence. Decouple discovery from registration: add a reg_work work item to struct i3c_master_controller and have i3c_master_do_daa_ext() queue it on master->wq (the freezable workqueue) instead of calling i3c_master_register_new_i3c_devs() directly. The worker performs the registration only when the controller is not shutting_down, and is cancelled alongside hj_work in i3c_master_shutdown(). Because wq is freezable, any newly observed devices end up being registered after the system has finished resuming. i3c_master_register() also routes its initial post-bus-init registration through reg_work, using flush_work() to keep probe-time behavior synchronous. This keeps a single registration code path and ensures the worker is the only writer of desc->dev. Fixes: 3a379bbcea0af ("i3c: Add core I3C infrastructure") Signed-off-by: Adrian Hunter --- Changes in V2: Add comment about reg_work use Add Fixes tag drivers/i3c/master.c | 27 ++++++++++++++++++++------- include/linux/i3c/master.h | 6 ++++++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index a59c4b744b36..c9685379e868 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -839,6 +839,7 @@ static void i3c_master_shutdown(struct i3c_master_contr= oller *master) i3c_bus_maintenance_unlock(&master->bus); =20 cancel_work_sync(&master->hj_work); + cancel_work_sync(&master->reg_work); } =20 static void i3c_device_shutdown(struct device *dev) @@ -1838,6 +1839,16 @@ i3c_master_register_new_i3c_devs(struct i3c_master_c= ontroller *master) } } =20 +static void i3c_master_reg_work_fn(struct work_struct *work) +{ + struct i3c_master_controller *master =3D container_of(work, typeof(*maste= r), reg_work); + + i3c_bus_normaluse_lock(&master->bus); + if (!master->shutting_down) + i3c_master_register_new_i3c_devs(master); + i3c_bus_normaluse_unlock(&master->bus); +} + /** * i3c_master_do_daa_ext() - Dynamic Address Assignment (extended version) * @master: controller @@ -1878,9 +1889,7 @@ int i3c_master_do_daa_ext(struct i3c_master_controlle= r *master, bool rstdaa) if (ret) goto out; =20 - i3c_bus_normaluse_lock(&master->bus); - i3c_master_register_new_i3c_devs(master); - i3c_bus_normaluse_unlock(&master->bus); + queue_work(master->wq, &master->reg_work); out: i3c_master_rpm_put(master); =20 @@ -3126,6 +3135,7 @@ int i3c_master_register(struct i3c_master_controller = *master, goto err_put_dev; } INIT_WORK(&master->hj_work, i3c_master_hj_work_fn); + INIT_WORK(&master->reg_work, i3c_master_reg_work_fn); =20 ret =3D i3c_master_bus_init(master); if (ret) @@ -3151,12 +3161,15 @@ int i3c_master_register(struct i3c_master_controlle= r *master, =20 /* * We're done initializing the bus and the controller, we can now - * register I3C devices discovered during the initial DAA. + * register I3C devices discovered during the initial DAA. Device + * registration is done via reg_work because that keeps a single + * registration code path and ensures the worker is the only writer + * of desc->dev. Flush the work to preserve synchronous probe-time + * behavior. */ master->init_done =3D true; - i3c_bus_normaluse_lock(&master->bus); - i3c_master_register_new_i3c_devs(master); - i3c_bus_normaluse_unlock(&master->bus); + queue_work(master->wq, &master->reg_work); + flush_work(&master->reg_work); =20 if (master->ops->set_dev_nack_retry) device_create_file(&master->dev, &dev_attr_dev_nack_retry_count); diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h index 77e63082b06e..8cdd7be505d3 100644 --- a/include/linux/i3c/master.h +++ b/include/linux/i3c/master.h @@ -523,6 +523,11 @@ struct i3c_master_controller_ops { * be done from a sleep-able context * @hj_work: work item used to run DAA after a Hot-Join event is detected. * Queued to @wq by i3c_master_queue_hotjoin() + * @reg_work: work item used to register newly discovered I3C devices with + * the driver model. Queued to @wq by i3c_master_do_daa_ext() so + * that device registration is deferred out of the DAA caller's + * context (notably the resume path), and is skipped if the + * controller is shutting down * @dev_nack_retry_count: retry count when slave device nack * * A &struct i3c_master_controller has to be registered to the I3C subsyst= em @@ -548,6 +553,7 @@ struct i3c_master_controller { struct i3c_bus bus; struct workqueue_struct *wq; struct work_struct hj_work; + struct work_struct reg_work; unsigned int dev_nack_retry_count; }; =20 --=20 2.51.0 From nobody Mon May 25 05:12:13 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4BA663F8EC5 for ; Mon, 18 May 2026 11:55:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779105355; cv=none; b=CG/WWKHAvr+9twUTuIXydyHCUpAHPVUJRVO06UQNwBa/RNT7sY6SnqIzK7M+1STKEPm/U20JJs6OhExMTmcmjF8M+dZvKpzIwlcVZFmbz/I6/NSYVWihMrJ/0wLuBHI/vmN8nGh5vqjBCucXde5jGIcE7/Ejov632y5yG6apQ1g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779105355; c=relaxed/simple; bh=ZyQJlmK5assxX/8AYeFVFyJBlXNiV3507wFGzmjI2t4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=KghTfnxV4aOiYou7iHkfIk59enxUn1EkXXMxnOVTBfBZWpFCQnFhPjdwsdDCCFp573yjS4ToarQf21bOf33GXRFHyNXe46jDk8LirOhpi1vDj06xCOnXaAVTnqD8n8bhFw8UgLCahURfMY9AiUF0ZQgX/HLYoZDkPwujtK+H3VI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=ie8czLk6; arc=none smtp.client-ip=192.198.163.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="ie8czLk6" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1779105353; x=1810641353; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ZyQJlmK5assxX/8AYeFVFyJBlXNiV3507wFGzmjI2t4=; b=ie8czLk6lA0Vnjouxc3ZJhBNlBH0yHFujCUd3mX2ETH9h/jxG4ZJSsTJ p3h1jfvcvQW+13fNGmNv3ArYGKbzgulm/M/QYpCyoGnXCs6IJV0L5TLPN 5Z/dH66ZkdxPjmo+9oCzzz1QNC2R5JPyYrXboX3p617GZJYo+fiPZ33EK sTSrT7A6s8Bq7VJgJ6/2UAl5+GBFwG002BxbWoycV8/OY64voe9O3q1ZS JSt7OpDd+oJrju+PXtsHXVcsoWpfCl63wloYeU4cZoZfGbCJ1dydyOI5X gJ25RaUDWAF98s29ibZy1at7md8LPUtcgc35pjpBGzzi8+Okq6uHDD5Kt w==; X-CSE-ConnectionGUID: 3jyUssz9S8etQu4GQHCBYg== X-CSE-MsgGUID: +AFdM0jsRpO9F4vDG53Tug== X-IronPort-AV: E=McAfee;i="6800,10657,11789"; a="91347095" X-IronPort-AV: E=Sophos;i="6.23,241,1770624000"; d="scan'208";a="91347095" Received: from orviesa007.jf.intel.com ([10.64.159.147]) by fmvoesa104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 May 2026 04:55:53 -0700 X-CSE-ConnectionGUID: StcHyrc1QJG/zb1ZagwHEw== X-CSE-MsgGUID: eQ8AlNQJQd2uAtzjJooy4w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,241,1770624000"; d="scan'208";a="239663434" Received: from egrumbac-mobl6.ger.corp.intel.com (HELO ahunter6-desk) ([10.245.245.220]) by orviesa007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 May 2026 04:55:51 -0700 From: Adrian Hunter To: alexandre.belloni@bootlin.com Cc: Frank.Li@nxp.com, david.nystrom@est.tech, linux-i3c@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH V2 7/8] i3c: master: Export i3c_master_enec_disec_locked() Date: Mon, 18 May 2026 14:55:18 +0300 Message-ID: <20260518115520.98335-8-adrian.hunter@intel.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260518115520.98335-1-adrian.hunter@intel.com> References: <20260518115520.98335-1-adrian.hunter@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Organization: Intel Finland Oy, Registered Address: c/o Alberga Business Park, 6 krs, Bertel Jungin Aukio 5, 02600 Espoo, Business Identity Code: 0357606 - 4, Domiciled in Helsinki Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The existing i3c_master_enec_locked() wrapper always treats a NACKed ENEC CCC as a failure (M2 error). However, broadcasting ENEC to enable Hot-Join is legitimately useful even when no I3C devices are currently present on the bus, in which case the broadcast will be NACKed and should not be reported as an error. The underlying helper i3c_master_enec_disec_locked() already accepts a suppress_m2 flag that lets callers ignore such NACKs. Expose it so that a subsequent patch enabling Hot-Join events can issue ENEC with M2 suppression. Signed-off-by: Adrian Hunter Reviewed-by: Frank Li --- Changes in V2: Add Frank's Rev'd by drivers/i3c/master.c | 27 ++++++++++++++++++++++++--- include/linux/i3c/master.h | 2 ++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index c9685379e868..f87bf0099d3c 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -1121,9 +1121,29 @@ int i3c_master_entdaa_locked(struct i3c_master_contr= oller *master) } EXPORT_SYMBOL_GPL(i3c_master_entdaa_locked); =20 -static int i3c_master_enec_disec_locked(struct i3c_master_controller *mast= er, - u8 addr, bool enable, u8 evts, - bool suppress_m2) +/** + * i3c_master_enec_disec_locked() - send an ENEC or DISEC CCC command + * @master: master used to send frames on the bus + * @addr: a valid I3C slave address or %I3C_BROADCAST_ADDR + * @enable: true to send ENEC, false to send DISEC + * @evts: events to enable or disable + * @suppress_m2: if true, treat an M2 (NACK) error from the CCC as success + * + * Send an ENEC or DISEC CCC command to enable or disable some or all even= ts + * coming from a specific slave, or all devices if @addr is + * %I3C_BROADCAST_ADDR. + * + * When @suppress_m2 is true, a NACK of the broadcast (which can happen wh= en + * no devices are present on the bus) is not reported as an error. This is + * useful for callers that want to configure event reporting unconditional= ly, + * regardless of whether any devices are currently on the bus. + * + * This function must be called with the bus lock held in write mode. + * + * Return: 0 in case of success, or a negative error code otherwise. + */ +int i3c_master_enec_disec_locked(struct i3c_master_controller *master, u8 = addr, + bool enable, u8 evts, bool suppress_m2) { struct i3c_ccc_events *events; struct i3c_ccc_cmd_dest dest; @@ -1148,6 +1168,7 @@ static int i3c_master_enec_disec_locked(struct i3c_ma= ster_controller *master, =20 return ret; } +EXPORT_SYMBOL_GPL(i3c_master_enec_disec_locked); =20 /** * i3c_master_disec_locked() - send a DISEC CCC command diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h index 8cdd7be505d3..e2c831fb5354 100644 --- a/include/linux/i3c/master.h +++ b/include/linux/i3c/master.h @@ -607,6 +607,8 @@ int i3c_master_disec_locked(struct i3c_master_controlle= r *master, u8 addr, u8 evts); int i3c_master_enec_locked(struct i3c_master_controller *master, u8 addr, u8 evts); +int i3c_master_enec_disec_locked(struct i3c_master_controller *master, u8 = addr, + bool enable, u8 evts, bool suppress_m2); int i3c_master_entdaa_locked(struct i3c_master_controller *master); int i3c_master_defslvs_locked(struct i3c_master_controller *master); =20 --=20 2.51.0 From nobody Mon May 25 05:12:13 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DFD5C3F8ED0 for ; Mon, 18 May 2026 11:55:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779105358; cv=none; b=HHWfZL/++6a7BL/82svnl5TmrG3pS2k1tlSRVO/rhE3BgJmkE5q/wgk0w/VUbOQyAUFvsZOVawXNCYFejfofRVns2JjXhjycn25R2AMoAcbl0e2EEoGiO7SHUvadpCbBTIv2FtsU530RkVGR8PUevEUNUhJgqJ9gK0qNmcgMRb0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779105358; c=relaxed/simple; bh=0bL8ulieysntLRvRnDmRzhbLwv2zaHH4mGscI66FhyI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ts5LzeuzbVXeQVurarm/6jhAP96Fsv6Ul61ZWDPM8oNiLo5XW2z7JfcRS32e3Dq3ji628iRP+sBc2nuYfsPyF8csgRShPmvErp5RvXwemVeB5SWUxQU4PFZg504CVjnHQZyHom251Eh805/+pF2rBqSIQ2p3oZ44NtC62x2+J8U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=BZFjzIhv; arc=none smtp.client-ip=192.198.163.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="BZFjzIhv" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1779105356; x=1810641356; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=0bL8ulieysntLRvRnDmRzhbLwv2zaHH4mGscI66FhyI=; b=BZFjzIhvMJhXJfW/PdB1eYie95VrIQPErjStyd3FEmDjRZ5NdebdFG7/ JST+cSxffB/yp/w+cqpodatP+e6+dOZPG7OSbbb7MK20uelMLj20g02Ex LNSd9rXX7c1kMQwezzmMQnqdDESz8SWQkokFAgPGEIEbXkfQcg4mA4BD+ LBa+o1kdqAtDM/CT6nlJdTedffWkO2wjlSV+RrkOm7iuxyFEj7HqPVFNS w65FWJXsNWl/7GnYhr9gImzMPtIwNIvDdzPSVQjXTqCMji9kfUAbM39Br sGSXMJ/SuQ64U9mRHXoL0y9R4T2dOkOC1OjbOxHzjsg7oWvv/dEdOVOvA A==; X-CSE-ConnectionGUID: Ns3qTichRcSEO7/IDAn+tA== X-CSE-MsgGUID: IHZjKHgSTfOIKLIg+kHf8g== X-IronPort-AV: E=McAfee;i="6800,10657,11789"; a="91347101" X-IronPort-AV: E=Sophos;i="6.23,241,1770624000"; d="scan'208";a="91347101" Received: from orviesa007.jf.intel.com ([10.64.159.147]) by fmvoesa104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 May 2026 04:55:55 -0700 X-CSE-ConnectionGUID: fiMkYgZ1TxSjmm6Iat4Qtg== X-CSE-MsgGUID: C1HPnQMJRTyz+XZRsEOfkw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,241,1770624000"; d="scan'208";a="239663437" Received: from egrumbac-mobl6.ger.corp.intel.com (HELO ahunter6-desk) ([10.245.245.220]) by orviesa007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 May 2026 04:55:53 -0700 From: Adrian Hunter To: alexandre.belloni@bootlin.com Cc: Frank.Li@nxp.com, david.nystrom@est.tech, linux-i3c@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH V2 8/8] i3c: mipi-i3c-hci: Add Hot-Join support Date: Mon, 18 May 2026 14:55:19 +0300 Message-ID: <20260518115520.98335-9-adrian.hunter@intel.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260518115520.98335-1-adrian.hunter@intel.com> References: <20260518115520.98335-1-adrian.hunter@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Organization: Intel Finland Oy, Registered Address: c/o Alberga Business Park, 6 krs, Bertel Jungin Aukio 5, 02600 Espoo, Business Identity Code: 0357606 - 4, Domiciled in Helsinki Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 Reviewed-by: Frank Li --- Changes in V2: Add Frank's Rev'd by 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/mi= pi-i3c-hci/core.c index c6edbbedfdd7..53797841b63f 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_con= troller *m, return ret; } =20 +static int i3c_hci_enable_hotjoin(struct i3c_master_controller *m) +{ + struct i3c_hci *hci =3D 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 =3D 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 =3D 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 =3D to_i3c_hci(m); + int ret; =20 - return hci->cmd->perform_daa(hci); + ret =3D hci->cmd->perform_daa(hci); + + if (!hci->hj_init_done) { + hci->hj_init_done =3D true; + /* + * Enable Hot-Join by default after initial DAA if it does not + * prevent runtime suspend. + */ + if (m->rpm_ibi_allowed && !ret) + m->hotjoin =3D !i3c_hci_enable_hotjoin(m); + } + + return ret; } =20 static int i3c_hci_i3c_xfers(struct i3c_dev_desc *dev, @@ -652,6 +693,8 @@ static const struct i3c_master_controller_ops i3c_hci_o= ps =3D { .enable_ibi =3D i3c_hci_enable_ibi, .disable_ibi =3D i3c_hci_disable_ibi, .recycle_ibi_slot =3D i3c_hci_recycle_ibi_slot, + .enable_hotjoin =3D i3c_hci_enable_hotjoin, + .disable_hotjoin =3D i3c_hci_disable_hotjoin, }; =20 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 =3D false; =20 - /* 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_C= TRL)); =20 return 0; } diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mip= i-i3c-hci/dma.c index 5c6ae2055618..87622d6f817e 100644 --- a/drivers/i3c/master/mipi-i3c-hci/dma.c +++ b/drivers/i3c/master/mipi-i3c-hci/dma.c @@ -960,6 +960,11 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, s= truct hci_rh_data *rh) } =20 /* determine who this is for */ + if (ibi_addr =3D=3D I3C_HOT_JOIN_ADDR) { + i3c_master_queue_hotjoin(&hci->master); + goto done; + } + dev =3D 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/mip= i-i3c-hci/hci.h index 30297823ca85..41d31a53abd3 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/mip= i-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 =3D FIELD_GET(IBI_DATA_LENGTH, ibi_status); ibi->seg_cnt =3D ibi->seg_len; =20 + if (ibi->addr =3D=3D I3C_HOT_JOIN_ADDR) { + i3c_master_queue_hotjoin(&hci->master); + return true; + } + dev =3D i3c_hci_addr_to_dev(hci, ibi->addr); if (!dev) { dev_err(&hci->master.dev, --=20 2.51.0