From nobody Sat Sep 26 08:38:28 2026 Received: from esa2.hc555-34.eu.iphmx.com (esa2.hc555-34.eu.iphmx.com [23.90.104.147]) (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 D20CF37756F; Thu, 3 Sep 2026 05:39:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=23.90.104.147 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788413994; cv=none; b=dNw9YIaajrXxCIo/GNLEoQby+cpYseAapGRXCEl6cgy7SgtXUW+nDDpzOAU4rP0cXDIDyPkecdGDUxk3tp+meAZXmBhL0nn42VYc2vRMiqR+SkWM63ulub9l/ziJ4q3rO6XMrKgOd2YQVTsyIeHvwS5eVd7I5tt3FrFq2SzdQ6Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788413994; c=relaxed/simple; bh=NvoHc7BvTEE/RZGWswkzTFr6zwn/U3qMkl0QQIYUGTY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=VNo6zDiXZbRmYTvkVg5Gtk/XNecsgbhBjeOzizk7z0+oFCG2bXUNB/0R847QXVFMY/FXAlHMPhhbUoSPugU+s83EX48+fnbaVHp1BUUdEfpTfkkjEQ5j5qQfl51Tjir15da/vFzbnPSR8dcD1vhfqJSSuf0JVpOx530wY2HHrng= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com; spf=pass smtp.mailfrom=mobileye.com; dkim=fail (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b=fT18CuNn reason="key not found in DNS"; arc=none smtp.client-ip=23.90.104.147 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mobileye.com Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b="fT18CuNn" DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=mobileye.com; i=@mobileye.com; q=dns/txt; s=MoEyIP; t=1788413991; x=1819949991; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=NvoHc7BvTEE/RZGWswkzTFr6zwn/U3qMkl0QQIYUGTY=; b=fT18CuNnbN2SPeEUtBKbixgPNp9sHscuxkC2Tf42u16ywG4Y2yx5dvNK xSjJ/OqapBkUNYgYDc6bL99xjmFWZF1KQej5879RMvPI31VkEz0GoShtX ZyLw7Lde6yxRd1VkkLaozp0nc8V91PZk7RqwAUpxJMWRfmS3UJ7VF4KvL LWYp1VrCMCsDrNhY/k6/JwJhd5y09xnIexBesbX8pXlUiHeNyWPrN1QBA VRlBVTIqWZX0xpaBafbykZdYs/9F+3nOH0xSd3ETOu8Wk0UreGZ/aIikf h/aumVmOSGwkVxz6WdaMBvNh6RteGhEroCeczZ06aYwuq4JHA3WmNRR3E w==; X-CSE-ConnectionGUID: MJIvZQ4jREWN4K9ZXQPPZQ== X-CSE-MsgGUID: sMarhDh5T72cs2MEZlOByg== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from unknown (HELO ces01_data.me-corp.lan) ([146.255.191.134]) by esa2.hc555-34.eu.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Sep 2026 08:38:38 +0300 X-CSE-ConnectionGUID: OI9FCmEwT+KWdJxqtVH9XQ== X-CSE-MsgGUID: TUobGhXHSFSsp3sF4n/Iqg== Received: from unknown (HELO epgd056.me-corp.lan) ([10.154.54.3]) by ces01_data.me-corp.lan with SMTP; 03 Sep 2026 08:45:18 +0300 Received: by epgd056.me-corp.lan (sSMTP sendmail emulation); Thu, 03 Sep 2026 08:38:36 +0300 From: Dmitry Guzman Date: Thu, 03 Sep 2026 08:38:08 +0300 Subject: [PATCH v2 01/12] i2c: core: add I2C_XFER_V2 - support for detailed transfer reporting Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-i2c-fault-reporting-v2-1-fedeb91792e6@mobileye.com> References: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> In-Reply-To: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> To: Andi Shyti , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Linus Walleij , Mika Westerberg , Andy Shevchenko Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?Beno=C3=AEt_Monin?= , Dmitry Guzman X-Mailer: b4 0.14.2 In I2C subsystem there is API that allows sending/receiving a number of messages in a single call. I2C_RDWR ioctl, as well as i2c_transfer kernel API function, returns only a single error code. In case of a fault, there is no way to know which message in the series caused a fault, and how many bytes have been sent or received before the fault. This commit introduces i2c_transfer_v2 kernel API function and I2C_RDWR_V2 ioctl. They provide the same functionality as the old ones, but also accept additional pointer to `i2c_transfer_report` structure and fill it with detailed fault report: number of messages transferred successfully, index of message that caused fault, number of bytes transferred (if a fault occurred in the middle of the last message). I2C bus controller driver may implement either both callbacks or any one of them. The implementation of both callbacks may make sense if the precise detection of the fault position requires different handling with the hardware that causes to extra CPU load or other consequences that may be unwanted if the precise fault report is not required. If the precise fault detection is free, the driver may implement only `xfer_v2` callback - the infrastructure will provide pointer to a dummy fault report that will be dropped if the client uses old API. Signed-off-by: Dmitry Guzman --- Documentation/i2c/dev-interface.rst | 46 ++++++++++++++++ drivers/i2c/i2c-core-base.c | 107 +++++++++++++++++++++++++-------= ---- drivers/i2c/i2c-dev.c | 79 ++++++++++++++++++++++---- include/linux/i2c.h | 12 ++++ include/trace/events/i2c.h | 6 +- include/uapi/linux/i2c-dev.h | 9 +++ include/uapi/linux/i2c.h | 21 +++++++ 7 files changed, 232 insertions(+), 48 deletions(-) diff --git a/Documentation/i2c/dev-interface.rst b/Documentation/i2c/dev-in= terface.rst index c277a8e1202b51403a8d00d6c92fca13da1afc58..45a8b94f585b57889c153fbb110= a5826879484f6 100644 --- a/Documentation/i2c/dev-interface.rst +++ b/Documentation/i2c/dev-interface.rst @@ -140,6 +140,52 @@ The following IOCTLs are defined: The slave address and whether to use ten bit address mode has to be set in each message, overriding the values set with the above ioctl's. =20 +``ioctl(file, I2C_RDWR_V2, struct i2c_rdwr_v2_ioctl_data *msgset)`` + Does the same combined read/write transaction as I2C_RDWR, but also + provides detailed fault report. The argument is a pointer to a:: + + struct i2c_rdwr_v2_ioctl_data { + struct i2c_rdwr_ioctl_data rdwr_data; + struct i2c_transfer_report report; + }; + + The rdwr_data is the same structure as the argument for I2C_RDWR ioctl. + The report is the structure that the transfer report is written to:: + + struct i2c_transfer_report { + __s32 fault_msg_idx; + __s32 msgs_cplt; + __s32 bytes_cplt; + }; + + msgs_cplt is the number of messages that has been sent or received + successfully. If there are read messages within this range, the returned + data is guaranteed to be valid. If a message has been read from the + device but the read data is lost (for example, FIFO is flushed before + CPU read it), this message must not be counted. If the controller cannot + determine the number of completed messages, the value is -EOPNOTSUPP. + + fault_msg_idx is the number of message that caused a fault. In case of a + fault, it is not necessary equal to msgs_cplt. For example, if the driver + validates the whole batch before starting transmission, detects that it + cannot send it, it returns -EOPNOTSUPP error immediately, so msgs_cplt i= s 0, + while fault_msg_idx points to the message that cannot be sent. Another + example when these two value may be different is I2C controller that + flushes RX FIFO when an error is detected before CPU reads data from it. + + If there is no fault, the fault_msg_idx value is equal to msgs_cplt. + + bytes_cplt indicates the number of bytes sent/received in the message at + index msgs_cplt. If this is a read message, it is guaranteed that these + bytes in the message data buffer are valid. If the controller cannot + determine the byte number, the value should be -EOPNOTSUPP. If there was + no fault, the value should be 0. + + To discover if the device supports detailed fault reporting, use I2C_RDW= R_V2 + ioctl with nmsgs =3D 0. If the driver supports it, the return value shal= l be 0. + If the driver supports only legacy I2C_RDWR, the return value shall be + -EOPNOTSUPP. In any case, nothing is done on the bus. + ``ioctl(file, I2C_SMBUS, struct i2c_smbus_ioctl_data *args)`` If possible, use the provided ``i2c_smbus_*`` methods described below in= stead of issuing direct ioctls. diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index ddaacf876dada92c1ffafd2d5d1e4b83c8f0101f..a6515868f97baeacb4fffa3bdad= 2f1365a00dffe 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -2177,15 +2177,17 @@ module_exit(i2c_exit); /* Check if val is exceeding the quirk IFF quirk is non 0 */ #define i2c_quirk_exceeded(val, quirk) ((quirk) && ((val) > (quirk))) =20 -static int i2c_quirk_error(struct i2c_adapter *adap, struct i2c_msg *msg, = char *err_msg) +static struct i2c_msg *i2c_quirk_error(struct i2c_adapter *adap, + struct i2c_msg *msg, char *err_msg) { dev_err_ratelimited(&adap->dev, "adapter quirk: %s (addr 0x%04x, size %u,= %s)\n", err_msg, msg->addr, msg->len, str_read_write(msg->flags & I2C_M_RD)); - return -EOPNOTSUPP; + return msg; } =20 -static int i2c_check_for_quirks(struct i2c_adapter *adap, struct i2c_msg *= msgs, int num) +static struct i2c_msg *i2c_check_for_quirks(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) { const struct i2c_adapter_quirks *q =3D adap->quirks; int max_num =3D q->max_num_msgs, i; @@ -2236,31 +2238,51 @@ static int i2c_check_for_quirks(struct i2c_adapter = *adap, struct i2c_msg *msgs, } } =20 - return 0; + return NULL; } =20 /** - * __i2c_transfer - unlocked flavor of i2c_transfer + * __i2c_transfer_v2 - unlocked flavor of i2c_transfer_v2 * @adap: Handle to I2C bus * @msgs: One or more messages to execute before STOP is issued to * terminate the operation; each message begins with a START. * @num: Number of messages to be executed. + * @report: The buffer for detailed transfer report (may be NULL if not re= quired) * * Returns negative errno, else the number of messages executed. + * Writes the detailed transfer report to the structure pointed by 'report= '. * * Adapter lock must be held when calling this function. No debug logging * takes place. */ -int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +int __i2c_transfer_v2(struct i2c_adapter *adap, struct i2c_msg *msgs, int = num, + struct i2c_transfer_report *report) { + struct i2c_transfer_report dummy_report; unsigned long orig_jiffies; int ret, try; =20 - if (!adap->algo->master_xfer) { + if (report) { + report->msgs_cplt =3D -EOPNOTSUPP; + report->bytes_cplt =3D -EOPNOTSUPP; + report->fault_msg_idx =3D -EOPNOTSUPP; + + if (!adap->algo->xfer_v2) + return -EOPNOTSUPP; + } + + if (!adap->algo->master_xfer && !adap->algo->xfer_v2) { dev_dbg(&adap->dev, "I2C level transfers not supported\n"); return -EOPNOTSUPP; } =20 + /* + * If the controller only supports "v2" callback and the report is not re= quested, + * provide pointer to a dummy report. + */ + if (!(adap->algo->master_xfer) && (!report)) + report =3D &dummy_report; + if (WARN_ON(!msgs || num < 1)) return -EINVAL; =20 @@ -2268,8 +2290,18 @@ int __i2c_transfer(struct i2c_adapter *adap, struct = i2c_msg *msgs, int num) if (ret) return ret; =20 - if (adap->quirks && i2c_check_for_quirks(adap, msgs, num)) - return -EOPNOTSUPP; + if (adap->quirks) { + struct i2c_msg *bad_msg =3D i2c_check_for_quirks(adap, msgs, num); + + if (bad_msg) { + if (report) { + report->msgs_cplt =3D 0; + report->bytes_cplt =3D 0; + report->fault_msg_idx =3D bad_msg - msgs; + } + return -EOPNOTSUPP; + } + } =20 /* * i2c_trace_msg_key gets enabled when tracepoint i2c_transfer gets @@ -2290,8 +2322,12 @@ int __i2c_transfer(struct i2c_adapter *adap, struct = i2c_msg *msgs, int num) for (ret =3D 0, try =3D 0; try <=3D adap->retries; try++) { if (i2c_in_atomic_xfer_mode() && adap->algo->master_xfer_atomic) ret =3D adap->algo->master_xfer_atomic(adap, msgs, num); - else - ret =3D adap->algo->master_xfer(adap, msgs, num); + else { + if (report) + ret =3D adap->algo->xfer_v2(adap, msgs, num, report); + else + ret =3D adap->algo->master_xfer(adap, msgs, num); + } =20 if (ret !=3D -EAGAIN) break; @@ -2300,58 +2336,63 @@ int __i2c_transfer(struct i2c_adapter *adap, struct= i2c_msg *msgs, int num) } =20 if (static_branch_unlikely(&i2c_trace_msg_key)) { - int i; - for (i =3D 0; i < ret; i++) + int n; + + if (report) + n =3D report->msgs_cplt; + else + n =3D ret; + for (int i =3D 0; i < n; i++) if (msgs[i].flags & I2C_M_RD) - trace_i2c_reply(adap, &msgs[i], i); + trace_i2c_reply(adap, &msgs[i], msgs[i].len, i); + if (report && report->bytes_cplt > 0 && msgs[n].flags & I2C_M_RD) + trace_i2c_reply(adap, &msgs[n], report->bytes_cplt, n); trace_i2c_result(adap, num, ret); } =20 return ret; } +EXPORT_SYMBOL(__i2c_transfer_v2); + +int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + return __i2c_transfer_v2(adap, msgs, num, NULL); +} EXPORT_SYMBOL(__i2c_transfer); =20 /** - * i2c_transfer - execute a single or combined I2C message + * i2c_transfer_v2 - execute a single or combined I2C message * @adap: Handle to I2C bus * @msgs: One or more messages to execute before STOP is issued to * terminate the operation; each message begins with a START. * @num: Number of messages to be executed. + * @report: Pointer for transmission fault report. * * Returns negative errno, else the number of messages executed. * * Note that there is no requirement that each message be sent to * the same slave address, although that is the most common model. */ -int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +int i2c_transfer_v2(struct i2c_adapter *adap, struct i2c_msg *msgs, int nu= m, + struct i2c_transfer_report *report) { int ret; =20 - /* REVISIT the fault reporting model here is weak: - * - * - When we get an error after receiving N bytes from a slave, - * there is no way to report "N". - * - * - When we get a NAK after transmitting N bytes to a slave, - * there is no way to report "N" ... or to let the master - * continue executing the rest of this combined message, if - * that's the appropriate response. - * - * - When for example "num" is two and we successfully complete - * the first message but get an error part way through the - * second, it's unclear whether that should be reported as - * one (discarding status on the second message) or errno - * (discarding status on the first one). - */ ret =3D __i2c_lock_bus_helper(adap); if (ret) return ret; =20 - ret =3D __i2c_transfer(adap, msgs, num); + ret =3D __i2c_transfer_v2(adap, msgs, num, report); i2c_unlock_bus(adap, I2C_LOCK_SEGMENT); =20 return ret; } +EXPORT_SYMBOL(i2c_transfer_v2); + +int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + return i2c_transfer_v2(adap, msgs, num, NULL); +} EXPORT_SYMBOL(i2c_transfer); =20 /** diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index ccaac5e29f906bec0bf3b0e4a259391053469c2f..90456e6c04b4131dde9a9c2a5bd= 2075dd32b4baf 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -240,12 +240,18 @@ static int i2cdev_check_addr(struct i2c_adapter *adap= ter, unsigned int addr) return result; } =20 -static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, - unsigned nmsgs, struct i2c_msg *msgs) +static noinline int i2cdev_ioctl_rdwr_v2(struct i2c_client *client, + unsigned int nmsgs, struct i2c_msg *msgs, + struct i2c_transfer_report __user *user_report) { + struct i2c_transfer_report report; u8 __user **data_ptrs; int i, res; =20 + report.msgs_cplt =3D -EOPNOTSUPP; + report.fault_msg_idx =3D -EOPNOTSUPP; + report.bytes_cplt =3D -EOPNOTSUPP; + /* Adapter must support I2C transfers */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -EOPNOTSUPP; @@ -259,6 +265,7 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client= *client, /* Limit the size of the message to a sane amount */ if (msgs[i].len > 8192) { res =3D -EINVAL; + report.fault_msg_idx =3D i; break; } =20 @@ -266,6 +273,7 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client= *client, msgs[i].buf =3D memdup_user(data_ptrs[i], msgs[i].len); if (IS_ERR(msgs[i].buf)) { res =3D PTR_ERR(msgs[i].buf); + report.fault_msg_idx =3D i; break; } /* memdup_user allocates with GFP_KERNEL, so DMA is ok */ @@ -289,6 +297,7 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client= *client, I2C_SMBUS_BLOCK_MAX) { i++; res =3D -EINVAL; + report.fault_msg_idx =3D i; break; } =20 @@ -303,9 +312,34 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_clien= t *client, return res; } =20 - res =3D i2c_transfer(client->adapter, msgs, nmsgs); + if (user_report) { + res =3D i2c_transfer_v2(client->adapter, msgs, nmsgs, &report); + i =3D report.msgs_cplt; + } else { + res =3D i2c_transfer(client->adapter, msgs, nmsgs); + if (res < 0) + i =3D 0; + else + i =3D nmsgs; + } + + if (user_report && copy_to_user(user_report, &report, sizeof(report))) + res =3D -EFAULT; + + /* Number of messages transferred completely or partially */ + if (report.bytes_cplt > 0) { + i++; + msgs[i].len =3D report.bytes_cplt; + } + + if (i > (int)nmsgs) { + pr_err("Bad i2c_transfer_report: msgs_cplt =3D %i, bytes_cplt =3D %i, nm= sgs =3D %i\n", + report.msgs_cplt, report.bytes_cplt, nmsgs); + i =3D nmsgs; + } + while (i-- > 0) { - if (res >=3D 0 && (msgs[i].flags & I2C_M_RD)) { + if (msgs[i].flags & I2C_M_RD) { if (copy_to_user(data_ptrs[i], msgs[i].buf, msgs[i].len)) res =3D -EFAULT; @@ -439,18 +473,39 @@ static long i2cdev_ioctl(struct file *file, unsigned = int cmd, unsigned long arg) funcs =3D i2c_get_functionality(client->adapter); return put_user(funcs, (unsigned long __user *)arg); =20 - case I2C_RDWR: { + case I2C_RDWR: + case I2C_RDWR_V2: + { + struct i2c_rdwr_ioctl_data __user *user_arg; + struct i2c_transfer_report __user *user_rep; struct i2c_rdwr_ioctl_data rdwr_arg; struct i2c_msg *rdwr_pa; int res; =20 - if (copy_from_user(&rdwr_arg, - (struct i2c_rdwr_ioctl_data __user *)arg, - sizeof(rdwr_arg))) + if (cmd =3D=3D I2C_RDWR_V2) { + user_arg =3D &((struct i2c_rdwr_v2_ioctl_data __user *)arg)->rdwr_data; + user_rep =3D &((struct i2c_rdwr_v2_ioctl_data __user *)arg)->report; + } else { + user_arg =3D (struct i2c_rdwr_ioctl_data __user *)arg; + user_rep =3D NULL; + } + + if (copy_from_user(&rdwr_arg, user_arg, sizeof(rdwr_arg))) return -EFAULT; =20 - if (!rdwr_arg.msgs || rdwr_arg.nmsgs =3D=3D 0) - return -EINVAL; + if (!rdwr_arg.msgs || rdwr_arg.nmsgs =3D=3D 0) { + /* + * I2C_RDWR_V2 ioctl with nmsgs =3D=3D 0 is used for + * discovering of the controller capability to return + * detailed fault reports. + */ + if (cmd =3D=3D I2C_RDWR) + return -EINVAL; + if (client->adapter->algo->xfer_v2) + return 0; + else + return -EOPNOTSUPP; + } =20 /* * Put an arbitrary limit on the number of messages that can @@ -464,7 +519,7 @@ static long i2cdev_ioctl(struct file *file, unsigned in= t cmd, unsigned long arg) if (IS_ERR(rdwr_pa)) return PTR_ERR(rdwr_pa); =20 - res =3D i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa); + res =3D i2cdev_ioctl_rdwr_v2(client, rdwr_arg.nmsgs, rdwr_pa, user_rep); kfree(rdwr_pa); return res; } @@ -572,7 +627,7 @@ static long compat_i2cdev_ioctl(struct file *file, unsi= gned int cmd, unsigned lo }; } =20 - res =3D i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa); + res =3D i2cdev_ioctl_rdwr_v2(client, rdwr_arg.nmsgs, rdwr_pa, NULL); kfree(rdwr_pa); return res; } diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 14ab4d3055aff624cdb3fccb1dc39ae738164fb7..8ef14b326d84723850d552fbefd= 75df8062f5cd8 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -131,6 +131,14 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_= msg *msgs, int num); /* Unlocked flavor */ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num= ); =20 +/* Transfer with detailed transfer reporting. + */ +int i2c_transfer_v2(struct i2c_adapter *adap, struct i2c_msg *msgs, int nu= m, + struct i2c_transfer_report *report); +/* Unlocked flavor */ +int __i2c_transfer_v2(struct i2c_adapter *adap, struct i2c_msg *msgs, int = num, + struct i2c_transfer_report *report); + /* This is the very generalized SMBus access routine. You probably do not want to use this, though; one of the functions below may be much easier, and probably just as fast. @@ -567,6 +575,10 @@ struct i2c_algorithm { unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data); =20 + /* Same as xfer with detailed reporting */ + int (*xfer_v2)(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num, struct i2c_transfer_report *report); + /* To determine what the adapter supports */ u32 (*functionality)(struct i2c_adapter *adap); =20 diff --git a/include/trace/events/i2c.h b/include/trace/events/i2c.h index 142a23c6593c611de9abc2a89a146b95550b23cd..2ea8e9805edf591d63dcb589340= b0704fd6d38f7 100644 --- a/include/trace/events/i2c.h +++ b/include/trace/events/i2c.h @@ -88,8 +88,8 @@ TRACE_EVENT_FN(i2c_read, */ TRACE_EVENT_FN(i2c_reply, TP_PROTO(const struct i2c_adapter *adap, const struct i2c_msg *msg, - int num), - TP_ARGS(adap, msg, num), + int data_len, int num), + TP_ARGS(adap, msg, data_len, num), TP_STRUCT__entry( __field(int, adapter_nr ) __field(__u16, msg_nr ) @@ -102,7 +102,7 @@ TRACE_EVENT_FN(i2c_reply, __entry->msg_nr =3D num; __entry->addr =3D msg->addr; __entry->flags =3D msg->flags; - __entry->len =3D msg->len; + __entry->len =3D data_len; memcpy(__get_dynamic_array(buf), msg->buf, msg->len); ), TP_printk("i2c-%d #%u a=3D%03x f=3D%04x l=3D%u [%*phD]", diff --git a/include/uapi/linux/i2c-dev.h b/include/uapi/linux/i2c-dev.h index 1c4cec4ddd84d739193b234d33cae7860856738e..5097568a31490e2c9c2036a7d94= ab47588413beb 100644 --- a/include/uapi/linux/i2c-dev.h +++ b/include/uapi/linux/i2c-dev.h @@ -11,11 +11,13 @@ =20 #include #include +#include =20 /* /dev/i2c-X ioctl commands. The ioctl's parameter is always an * unsigned long, except for: * - I2C_FUNCS, takes pointer to an unsigned long * - I2C_RDWR, takes pointer to struct i2c_rdwr_ioctl_data + * - I2C_RDWR_V2, takes pointer to struct i2c_rdwr_v2_ioctl_data * - I2C_SMBUS, takes pointer to struct i2c_smbus_ioctl_data */ #define I2C_RETRIES 0x0701 /* number of times a device address should @@ -33,6 +35,7 @@ #define I2C_FUNCS 0x0705 /* Get the adapter functionality mask */ =20 #define I2C_RDWR 0x0707 /* Combined R/W transfer (one STOP only) */ +#define I2C_RDWR_V2 0x0709 /* I2C_RDWR with detailed fault reporting */ =20 #define I2C_PEC 0x0708 /* !=3D 0 to use PEC with SMBus */ #define I2C_SMBUS 0x0720 /* SMBus transfer */ @@ -52,6 +55,12 @@ struct i2c_rdwr_ioctl_data { __u32 nmsgs; /* number of i2c_msgs */ }; =20 +/* This is the structure as used in the I2C_RDWR_V2 ioctl call */ +struct i2c_rdwr_v2_ioctl_data { + struct i2c_rdwr_ioctl_data rdwr_data; + struct i2c_transfer_report report; +}; + #define I2C_RDWR_IOCTL_MAX_MSGS 42 /* Originally defined with a typo, keep it for compatibility */ #define I2C_RDRW_IOCTL_MAX_MSGS I2C_RDWR_IOCTL_MAX_MSGS diff --git a/include/uapi/linux/i2c.h b/include/uapi/linux/i2c.h index 2a226657d9f8238365453121321fd70dc11dac02..5e8e7d3536c85f2fe604a285258= b070f2efffbb2 100644 --- a/include/uapi/linux/i2c.h +++ b/include/uapi/linux/i2c.h @@ -135,6 +135,27 @@ struct i2c_msg { I2C_FUNC_SMBUS_READ_BLOCK_DATA | \ I2C_FUNC_SMBUS_BLOCK_PROC_CALL) =20 +/* Detailed transfer report */ + +struct i2c_transfer_report { + __s32 fault_msg_idx; /* In case of a fault, index of the message that ca= used + * the fault. If the bus driver cannot determine it, it + * puts a negative error code. If there is no fault, the + * value is equal to number of messages transferred. + */ + __s32 msgs_cplt; /* Number of messages that are known to be transferred + * successfully. If the bus driver cannot determine it, it + * puts a negative error code. If there is no fault, the + * value is equal to number of messages transferred. + */ + __s32 bytes_cplt; /* In case of a fault, number of bytes in the message = at + * index `msgs_cplt` that are known to be transferred + * successfully. If the bus driver cannot determine the + * number of bytes, it puts a negative error value. + * If there is no fault, the value is 0. + */ +}; + /* * Data for SMBus Messages */ --=20 2.43.0 From nobody Sat Sep 26 08:38:28 2026 Received: from esa2.hc555-34.eu.iphmx.com (esa2.hc555-34.eu.iphmx.com [23.90.104.147]) (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 D16093911A8; Thu, 3 Sep 2026 05:39:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=23.90.104.147 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788413995; cv=none; b=jPtf9kCw8g3F18qC9Zx+9jQabLXR0zh7tIuv8pMIkwsjMxnH2JbaHKpnfapnbmjs/Yd4HGtKof1t38X+Ds42vH2IlgULDwuXftnl0D2adcqcQtm0VJxQvUFGfbcOBR2ma5zy3aNLy+wgMj2Ui44N4xyqexphBeXU4l5s8EU3T8M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788413995; c=relaxed/simple; bh=laNov46rEhoHC/594iUdtbtLJH8byqqzWUsDYSOQ0MQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=SQd/Rf/KdL4kbAiEn7y2CxiZIQDPBGeJ/KiObCP6bUE6EyS1z2v2zqbukjWQKrpbhMGbb+NHo2YJcYkOqtvko0LtNBiBMVFVE8JDD8up1Jxr4SGf0BnCAtlIzLXRtiKCSOy0bFVyP0BthqPcPtxQTAjWDUdc+CsfD78R31+cGPM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com; spf=pass smtp.mailfrom=mobileye.com; dkim=fail (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b=KgGP0UVS reason="key not found in DNS"; arc=none smtp.client-ip=23.90.104.147 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mobileye.com Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b="KgGP0UVS" DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=mobileye.com; i=@mobileye.com; q=dns/txt; s=MoEyIP; t=1788413992; x=1819949992; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=laNov46rEhoHC/594iUdtbtLJH8byqqzWUsDYSOQ0MQ=; b=KgGP0UVSlNncCVEY4DvDKRH2T/WiLcx6NYJd0U3hdIr9z1tT2Qv9nLVZ uXcCgRTzOgNW4jlbmjEJCRqQ0uZM0J4UvG7XQHkp6sW+FUPGYePWo/jNQ bnD+4jmpRcK5zfoIf//mGFwulZkANNmNLl0t1lwtSem5pAiZCQ9LUVy8T Ukhd+I+1S6d/sJmMfJ0wyKtcDCZThjipCFDQZwcXyOT+fMR1/s8qqeVis dez783p53hNd1iTxSa3Ulx+YOZHXuCnSVTshGFAp1vWsSnG5an+10+3G+ 11dh8THeDna5pHxy97x3aDuEcyS9uKqqHrLW6naBdAvFKaw7kNJPuYQNz A==; X-CSE-ConnectionGUID: WLsDcoMiRqeta1S+3AaaXA== X-CSE-MsgGUID: TAJc5vCoREOTFPUhgZxbUg== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from unknown (HELO ces03_data.me-corp.lan) ([146.255.191.134]) by esa2.hc555-34.eu.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Sep 2026 08:38:38 +0300 X-CSE-ConnectionGUID: KLgcRyVFTouh6uKzqEEf/Q== X-CSE-MsgGUID: WQqKPgDaTeGS1ta5vi3O2w== Received: from unknown (HELO epgd056.me-corp.lan) ([10.154.54.2]) by ces03_data.me-corp.lan with SMTP; 03 Sep 2026 08:45:06 +0300 Received: by epgd056.me-corp.lan (sSMTP sendmail emulation); Thu, 03 Sep 2026 08:38:37 +0300 From: Dmitry Guzman Date: Thu, 03 Sep 2026 08:38:09 +0300 Subject: [PATCH v2 02/12] i2c: nomadik: optimize struct layout, change unsigned char into u8 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-i2c-fault-reporting-v2-2-fedeb91792e6@mobileye.com> References: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> In-Reply-To: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> To: Andi Shyti , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Linus Walleij , Mika Westerberg , Andy Shevchenko Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?Beno=C3=AEt_Monin?= , Dmitry Guzman X-Mailer: b4 0.14.2 Change type of `tft` and `rft` fields of `nmk_i2c_dev` structure from `unsigned char` to `u8` and `buffer` field of `i2c_nmk_client` structure from `unsigned char *` to `u8 *`. Put two bool variables `xfer_done` and `has_32b_bus` and two u8 variables `tft` and `rft` together in order to reduce struct size wasted for padding. Signed-off-by: Dmitry Guzman Reviewed-by: Linus Walleij --- drivers/i2c/busses/i2c-nomadik.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-noma= dik.c index c3878670da9cfa462b66919ddc58b55cc78db6e5..45b4815b094524d9a8de69376e2= 933171541611a 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -170,7 +170,7 @@ enum i2c_operating_mode { struct i2c_nmk_client { unsigned short slave_adr; unsigned long count; - unsigned char *buffer; + u8 *buffer; unsigned long xfer_bytes; enum i2c_operation operation; }; @@ -187,13 +187,13 @@ struct i2c_nmk_client { * @clk_freq: clock frequency for the operation mode * @tft: Tx FIFO Threshold in bytes * @rft: Rx FIFO Threshold in bytes + * @xfer_done: xfer done boolean. + * @has_32b_bus: controller is on a bus that only supports 32-bit accesses. * @timeout_usecs: Slave response timeout * @sm: speed mode * @stop: stop condition. * @xfer_wq: xfer done wait queue. - * @xfer_done: xfer done boolean. * @result: controller propogated result. - * @has_32b_bus: controller is on a bus that only supports 32-bit accesses. */ struct nmk_i2c_dev { struct i2c_vendor_data *vendor; @@ -204,15 +204,15 @@ struct nmk_i2c_dev { struct clk *clk; struct i2c_nmk_client cli; u32 clk_freq; - unsigned char tft; - unsigned char rft; + u8 tft; + u8 rft; + bool xfer_done; + bool has_32b_bus; u32 timeout_usecs; enum i2c_freq_mode sm; int stop; struct wait_queue_head xfer_wq; - bool xfer_done; int result; - bool has_32b_bus; }; =20 /* controller's abort causes */ --=20 2.43.0 From nobody Sat Sep 26 08:38:28 2026 Received: from esa1.hc555-34.eu.iphmx.com (esa1.hc555-34.eu.iphmx.com [23.90.104.144]) (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 75F353921CE; Thu, 3 Sep 2026 05:39:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=23.90.104.144 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788413995; cv=none; b=MEWyTTN0I3ba5c9pwSLUL/N71A52wI9fmLHa0hzAhK53YNeeXjGnXPAgBBk4axI8xe2wr6JMNpmgPAAnSgcAXqd7D3UQGZz3dlpLFhmkB7o559pWGh9J8Gth5/QAJSbwQu2zAa7b2PzUk5Tf1Kd1xh5fQgbPikeQFAxufJSaxmI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788413995; c=relaxed/simple; bh=L1VT8VFHal4ll3cgXxcUxpNo9geScucAPiMQYju1t00=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=kQhNKl1UnYU1X365sMTttGZyFqvlKsHABrqVSE1BPmurhA43JW3JAnOmc+3us7LmC7JeruGJksQ5PFTNtE1GGulKulcxiItc029t+M6ULyKiv2KscWmIPWm8X3slwPxSsauSturQb1UvDk2XBFSED84fYUNeUYtS42+YSvd1IHo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com; spf=pass smtp.mailfrom=mobileye.com; dkim=fail (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b=Wb1TkKqr reason="key not found in DNS"; arc=none smtp.client-ip=23.90.104.144 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mobileye.com Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b="Wb1TkKqr" DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=mobileye.com; i=@mobileye.com; q=dns/txt; s=MoEyIP; t=1788413992; x=1819949992; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=L1VT8VFHal4ll3cgXxcUxpNo9geScucAPiMQYju1t00=; b=Wb1TkKqrafptV2gcl0ooV9tktX9QjK6IGiS+A1j4PDwyG8c9tARkrADp /HDEUs/O+zL17HzQrAa5ZsQ80NupJPprPG04wD5w9KFp7idlnvrqDYJee ZslOdCWtIa7nx0emAxUrbeGManNKUAGNyVVkuIJWkA/o8/qEbnJpZeBP5 ZUcyAiG0jY2CT9AW06pxxFhIro7ET0XBaDrY8m10BH8Cy4XfY8OfXUqxb 9TaefUUwjcXXAL+9DoknpzLrKg3Pp61psMWl5xSJXq1tHPccLQ99lhv8s 8szW8qYLvPoQYSuMDbuYWfc5Il+UpaUiuqgekOcoa3oSREGun/+8TLWfe Q==; X-CSE-ConnectionGUID: BKzXfXlOS5uYZ2kKHy4/sw== X-CSE-MsgGUID: EAf+4oaGRMC/m1xt+OCdKw== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from unknown (HELO ces04_data.me-crop.lan) ([146.255.191.134]) by esa1.hc555-34.eu.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Sep 2026 08:38:40 +0300 X-CSE-ConnectionGUID: uHjNl9sHS3GOyxfMXxEu2Q== X-CSE-MsgGUID: OSj80QBdQDyXPUG5vZ1qzA== Received: from unknown (HELO epgd056.me-corp.lan) ([10.154.54.3]) by ces04_data.me-crop.lan with SMTP; 03 Sep 2026 08:45:15 +0300 Received: by epgd056.me-corp.lan (sSMTP sendmail emulation); Thu, 03 Sep 2026 08:38:38 +0300 From: Dmitry Guzman Date: Thu, 03 Sep 2026 08:38:10 +0300 Subject: [PATCH v2 03/12] i2c: nomadik: do not try to retransmit I2C message series on errors Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-i2c-fault-reporting-v2-3-fedeb91792e6@mobileye.com> References: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> In-Reply-To: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> To: Andi Shyti , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Linus Walleij , Mika Westerberg , Andy Shevchenko Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?Beno=C3=AEt_Monin?= , Dmitry Guzman X-Mailer: b4 0.14.2 i2c-nomadik driver of I2C bus controller in `xfer` callback retransmits the whole message series in cause of any fault, and returns fault only after third failed attempt. This behavior contradicts with API because not only it hides hardware faults, but also re-sends messages, while they are not guaranteed to be idempotent. Remove the triple attempt to send messages in `xfer` callback. Reviewed-by: Linus Walleij Signed-off-by: Dmitry Guzman --- drivers/i2c/busses/i2c-nomadik.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-noma= dik.c index 45b4815b094524d9a8de69376e2933171541611a..ca9366e09e7125b9c86dd0f9951= 62018df56634d 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -716,27 +716,21 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, int status =3D 0; int i; struct nmk_i2c_dev *priv =3D i2c_get_adapdata(i2c_adap); - int j; =20 pm_runtime_get_sync(&priv->adev->dev); =20 - /* Attempt three times to send the message queue */ - for (j =3D 0; j < 3; j++) { - /* setup the i2c controller */ - setup_i2c_controller(priv); - - for (i =3D 0; i < num_msgs; i++) { - priv->cli.slave_adr =3D msgs[i].addr; - priv->cli.buffer =3D msgs[i].buf; - priv->cli.count =3D msgs[i].len; - priv->stop =3D (i < (num_msgs - 1)) ? 0 : 1; - priv->result =3D 0; - - status =3D nmk_i2c_xfer_one(priv, msgs[i].flags); - if (status !=3D 0) - break; - } - if (status =3D=3D 0) + /* setup the i2c controller */ + setup_i2c_controller(priv); + + for (i =3D 0; i < num_msgs; i++) { + priv->cli.slave_adr =3D msgs[i].addr; + priv->cli.buffer =3D msgs[i].buf; + priv->cli.count =3D msgs[i].len; + priv->stop =3D (i < (num_msgs - 1)) ? 0 : 1; + priv->result =3D 0; + + status =3D nmk_i2c_xfer_one(priv, msgs[i].flags); + if (status !=3D 0) break; } =20 --=20 2.43.0 From nobody Sat Sep 26 08:38:28 2026 Received: from esa2.hc555-34.eu.iphmx.com (esa2.hc555-34.eu.iphmx.com [23.90.104.147]) (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 320F3391E77; Thu, 3 Sep 2026 05:39:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=23.90.104.147 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788413997; cv=none; b=cAQR2BUD9PQ0ON5RsSaLYuU12U3AtmsW/HAkv8KNon/9s6+zXZ0dyb7rM+wlUiOvbJQYaBuVuaYcE7UplqaVUTbnMZ4a9iBUMcrP0uUOPSAsyUe8pI1OZdFThmzExq/k29geQdb8HaWt0WHaBbFQDYJrxS6ko1ACOhdQgn5R4FU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788413997; c=relaxed/simple; bh=yEoKYkqAzY02mykJ1us0DXeoBWZGGZzvI9Pqcx6SKBY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=pKTjSg+dgNTy1Ue5ZwbisQLxC+X8sNVeIrD1mN0pDahjXI4Ux/jmKsRisDapkB+3sy5jwWANZNJ9IpQPfQT1QidT3EiTY9rIRs3qnlVf1BAIZSwzOMAseqthGJwr11hTVCkkR1RwdJSV2E9qbI2ovQVO+eza4+ZFQYV8uyGm6hE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com; spf=pass smtp.mailfrom=mobileye.com; dkim=fail (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b=B5rxsC/3 reason="key not found in DNS"; arc=none smtp.client-ip=23.90.104.147 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mobileye.com Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b="B5rxsC/3" DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=mobileye.com; i=@mobileye.com; q=dns/txt; s=MoEyIP; t=1788413995; x=1819949995; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=yEoKYkqAzY02mykJ1us0DXeoBWZGGZzvI9Pqcx6SKBY=; b=B5rxsC/3F7ON86K7jKX1GCO7xV3VstzgYwgTt6go69jNd4wUDTUr01rA W5UKk2DBiNbAXgV5zXodzmoHHCdJy2Ik8ZoPz9z2waGXGG5u5nxDh8RW2 m9OV7txG6244kjwRh9mGN0qJPZCtWoLBa7mnfY35+RGEN+wUO5KtvPgCM gOL11XrhQ/CfkDiru2ktlW48QKjXVgSni6GNHeAk2VYPxT4FDegl0rZeq P4GAcjSdJ3fGFIz406cE5a8q/zeXwvp51Y33RIqJoDpuvmRNW8v59IyL9 zc9WesuroYPOaMAOprQoXxT5yo2BMAEmwv561ZkcBXM6Qi8vtG3+a+9mp A==; X-CSE-ConnectionGUID: WLsDcoMiRqeta1S+3AaaXA== X-CSE-MsgGUID: uTwTKCDYSrSG2+vTWAA4vw== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from unknown (HELO ces03_data.me-corp.lan) ([146.255.191.134]) by esa2.hc555-34.eu.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Sep 2026 08:38:41 +0300 X-CSE-ConnectionGUID: iDBMjCADQDiUsQoKA31dWg== X-CSE-MsgGUID: pmROrQ4KQ02cYRqFDneMXg== Received: from unknown (HELO epgd056.me-corp.lan) ([10.154.54.3]) by ces03_data.me-corp.lan with SMTP; 03 Sep 2026 08:45:08 +0300 Received: by epgd056.me-corp.lan (sSMTP sendmail emulation); Thu, 03 Sep 2026 08:38:40 +0300 From: Dmitry Guzman Date: Thu, 03 Sep 2026 08:38:11 +0300 Subject: [PATCH v2 04/12] i2c: nomadik: return proper fault codes Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-i2c-fault-reporting-v2-4-fedeb91792e6@mobileye.com> References: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> In-Reply-To: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> To: Andi Shyti , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Linus Walleij , Mika Westerberg , Andy Shevchenko Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?Beno=C3=AEt_Monin?= , Dmitry Guzman X-Mailer: b4 0.14.2 I2C documentation Documentation/i2c/fault-codes.rst defines fault codes for different negative results in I2C transmittion. Previously, i2c-nomadik driver didn't implement them properly - it returned ETIMEDOUT on most errors and EIO on master arbitration lost. To comply with the documentation, return the proper fault codes for different conditions, namely: - EAGAIN if arbitration lost - EOVERFLOW if message is too long (>2047 bytes) - ENXIO if target address is not acknowledged - EIO on other errors detected by controller (for example, NACK on data) - ETIMEDOUT if driver gets timeout waiting for message completion without any fault condition detected by the controller (for example, too long message, or SDA/SCL line stuck on 0). Reviewed-by: Linus Walleij Signed-off-by: Dmitry Guzman --- drivers/i2c/busses/i2c-nomadik.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-noma= dik.c index ca9366e09e7125b9c86dd0f995162018df56634d..a3cef4b66190a9e45898e25867a= 3ceefce5d3d0a 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -226,6 +226,18 @@ static const char *abort_causes[] =3D { "overflow, maxsize is 2047 bytes", }; =20 +/* Linux fault codes for controller abort causes */ +static int fault_codes[] =3D { + ENXIO, + EIO, + EIO, + EAGAIN, + EIO, + EIO, + EOVERFLOW, + EIO +}; + static inline void i2c_set_bit(void __iomem *reg, u32 mask) { writel(readl(reg) | mask, reg); @@ -653,6 +665,8 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *priv, u= 16 flags) cause >=3D ARRAY_SIZE(abort_causes) ? "unknown reason" : abort_causes[cause]); + priv->result =3D -fault_codes[cause]; + status =3D priv->result; } =20 init_hw(priv); @@ -865,7 +879,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) =20 /* Master Arbitration lost interrupt */ case I2C_IT_MAL: - priv->result =3D -EIO; + priv->result =3D -EAGAIN; init_hw(priv); =20 i2c_set_bit(priv->virtbase + I2C_ICR, I2C_IT_MAL); --=20 2.43.0 From nobody Sat Sep 26 08:38:28 2026 Received: from esa2.hc555-34.eu.iphmx.com (esa2.hc555-34.eu.iphmx.com [23.90.104.147]) (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 D7B753446CE; Thu, 3 Sep 2026 05:38:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=23.90.104.147 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788413933; cv=none; b=ALCUEAzI1CUF8zxAw6SRaKQ1a7W2GdE50jFF1NSWgQ/lLqGqWOb+FQV5D52Fujd+h30i8mTZPSETLQjVRJ7M29OcDZxKdXyDQx788JI86X5b2HyGbs3IsdsWW74yU9CjaQEJWeGXUYx0jwAu2lt+1FyVwCXM5jwI+TPAX95pVjg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788413933; c=relaxed/simple; bh=nlZNbwIyTEpADUlhze0eaVgSfFmoT/5b05U10+WjG/M=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UOU6eq5JL9FMbEu4jNCKQef50bvvGXMEQTNN2FpX8FGlvfJCr/tnDsoCfopQu09JAYQwyAPEXgjivpAi4Quw9gKkiKnygjoBkc9z5bJMZnbp13sWNl9YXHVirjpfvobFJirUgI93IwN49tcdAeVarvcB5zhhoI1c1IFqetFaf50= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com; spf=pass smtp.mailfrom=mobileye.com; dkim=fail (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b=PngKJ1Vv reason="key not found in DNS"; arc=none smtp.client-ip=23.90.104.147 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mobileye.com Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b="PngKJ1Vv" DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=mobileye.com; i=@mobileye.com; q=dns/txt; s=MoEyIP; t=1788413929; x=1819949929; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=nlZNbwIyTEpADUlhze0eaVgSfFmoT/5b05U10+WjG/M=; b=PngKJ1Vv61tC69Ymm2HzSHKL+qI/uFA7l7VZo7VvSFnRnwcpwy+8lpJ9 5zdGOHQJxe610zFdy7vvT8/abzyq938Ss7UVNTNtlU2U21ekxk8X5592p pC17+JrYjTxob3fUABgGzZoywm8QQKCYP2Fm+Ar/QZ+EhjwQ+5likzACJ 8A7/2eCvG8OB/p9Zy6PO3un+zFqGJxGXLtJmz1s0PsDQwdNiiOoCk7CdN hwBwxT+lmGVCZ+75Or0u+UW2R6xyjPm5TtmZvHMq8/sQt44j89nXpjaOf nJW0/T+ztsQSrwod1gFIaKcsTfSTk0j06S1/A8H7JKuv0RtaFa5/CDz3U g==; X-CSE-ConnectionGUID: WLsDcoMiRqeta1S+3AaaXA== X-CSE-MsgGUID: qPMyAe9NRcqGeLolwasNGw== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from unknown (HELO ces03_data.me-corp.lan) ([146.255.191.134]) by esa2.hc555-34.eu.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Sep 2026 08:38:42 +0300 X-CSE-ConnectionGUID: abxc5S9CQ2SBHX1Nd2NPmw== X-CSE-MsgGUID: ZuKQV8clSlyTOQVNKYtjJA== Received: from unknown (HELO epgd056.me-corp.lan) ([10.154.54.3]) by ces03_data.me-corp.lan with SMTP; 03 Sep 2026 08:45:09 +0300 Received: by epgd056.me-corp.lan (sSMTP sendmail emulation); Thu, 03 Sep 2026 08:38:41 +0300 From: Dmitry Guzman Date: Thu, 03 Sep 2026 08:38:12 +0300 Subject: [PATCH v2 05/12] i2c: nomadik: change print level for fault messages to debug Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-i2c-fault-reporting-v2-5-fedeb91792e6@mobileye.com> References: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> In-Reply-To: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> To: Andi Shyti , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Linus Walleij , Mika Westerberg , Andy Shevchenko Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?Beno=C3=AEt_Monin?= , Dmitry Guzman X-Mailer: b4 0.14.2 i2c-nomadik driver prints error message on every faulted message. This is not a good practice, because in I2C a fault not always is an error, sometimes it is the expected result. For example, scanning bus with `i2cdetects` prints over 100 messages in dmesg (two messages per each target address). To avoid excessive prints in the log, change the print level from err to debug. Reviewed-by: Linus Walleij Signed-off-by: Dmitry Guzman --- drivers/i2c/busses/i2c-nomadik.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-noma= dik.c index a3cef4b66190a9e45898e25867a3ceefce5d3d0a..9c7658148bd45ecdaef1f998558= 315580233555d 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -627,7 +627,7 @@ static int write_i2c(struct nmk_i2c_dev *priv, u16 flag= s) =20 if (!xfer_done) { /* Controller timed out */ - dev_err(&priv->adev->dev, "write to slave 0x%x timed out\n", + dev_dbg(&priv->adev->dev, "write to slave 0x%x timed out\n", priv->cli.slave_adr); status =3D -ETIMEDOUT; } @@ -661,7 +661,7 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *priv, u= 16 flags) i2c_sr =3D readl(priv->virtbase + I2C_SR); if (FIELD_GET(I2C_SR_STATUS, i2c_sr) =3D=3D I2C_ABORT) { cause =3D FIELD_GET(I2C_SR_CAUSE, i2c_sr); - dev_err(&priv->adev->dev, "%s\n", + dev_dbg(&priv->adev->dev, "%s\n", cause >=3D ARRAY_SIZE(abort_causes) ? "unknown reason" : abort_causes[cause]); --=20 2.43.0 From nobody Sat Sep 26 08:38:28 2026 Received: from esa1.hc555-34.eu.iphmx.com (esa1.hc555-34.eu.iphmx.com [23.90.104.144]) (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 DF8753446CE; Thu, 3 Sep 2026 05:39:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=23.90.104.144 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788414003; cv=none; b=PsXwtfbKGiK6+vhuyQj7ckaj4utMPgEhfpF/uT2NRw/zR3yxe1aQP7vlSXPfxQxvGIP3+X8g1NqyjcdyZSZNbvJyeySVjUtYuJ3MWW1yp3BWbWjzqRsl89OG0TrMK5hUtwLkQqC4mp8hMV/zhLrtBTlNgujwHrbfVjqFwbINrRM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788414003; c=relaxed/simple; bh=ngGDtfpm/5mhvpzqlcomRG1s4PNkluY8gIbRm8fwLA8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=grwvgnrXPMaikzLsNfk1BBVpA+Bf/B6F2EG8V+/o8P8UTN2nzyZnzJPOf78MVrFc0DtjlMZfEPy4KpQBMan2jCGs3KXMqRCYM2QJB0UPGWwzuSv8rEQd+lW+Fx9cUixsrJod2u3Lc2KhPZ20Om4H92V4zXTKfy+foZ0B4ma6vGY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com; spf=pass smtp.mailfrom=mobileye.com; dkim=fail (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b=oqrKNgh5 reason="key not found in DNS"; arc=none smtp.client-ip=23.90.104.144 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mobileye.com Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b="oqrKNgh5" DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=mobileye.com; i=@mobileye.com; q=dns/txt; s=MoEyIP; t=1788413996; x=1819949996; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=ngGDtfpm/5mhvpzqlcomRG1s4PNkluY8gIbRm8fwLA8=; b=oqrKNgh5U38X2Cu/PPhPNRSCezyLWLiqKh5JB7kLcH/coTw7NtDppDBS pY4Iq4F+BTTC2gI5zV9DVgPPQoFdV5+dbJ0/LTigeBXn2z47QjI3wo0wd Yl/uPgIUyaM2a/jejsA/aq/uvQLnG6nWpKW7ML4w4ZIYpj06j0IT6W1iB 92r9tj0ZTveN/sWGxjy6pX5olrS4HTYOcHzmrSPY3XjXv+gc119LT03dt ycmpVa0BjN1sFM8iSqbbL7YXYtv3ge1YORt1AUsrHSJIobrA3hGaUbyVu i7LBP/tI7lzz6fROk2cVZXWd4DD7Yj/8qJrOkhHv8chzO3VnBtfPm0E18 A==; X-CSE-ConnectionGUID: BKzXfXlOS5uYZ2kKHy4/sw== X-CSE-MsgGUID: mk5qw241RI6HyVpvebXJUA== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from unknown (HELO ces04_data.me-crop.lan) ([146.255.191.134]) by esa1.hc555-34.eu.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Sep 2026 08:38:42 +0300 X-CSE-ConnectionGUID: NsHN44qGTJiJHqU79igiIA== X-CSE-MsgGUID: AHHKGvs0QmqFFmKhMvwnVg== Received: from unknown (HELO epgd056.me-corp.lan) ([10.154.54.2]) by ces04_data.me-crop.lan with SMTP; 03 Sep 2026 08:45:18 +0300 Received: by epgd056.me-corp.lan (sSMTP sendmail emulation); Thu, 03 Sep 2026 08:38:42 +0300 From: Dmitry Guzman Date: Thu, 03 Sep 2026 08:38:13 +0300 Subject: [PATCH v2 06/12] i2c: nomadik: add quirks max_len=2047 and no_zero_len_read Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-i2c-fault-reporting-v2-6-fedeb91792e6@mobileye.com> References: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> In-Reply-To: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> To: Andi Shyti , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Linus Walleij , Mika Westerberg , Andy Shevchenko Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?Beno=C3=AEt_Monin?= , Dmitry Guzman X-Mailer: b4 0.14.2 In Nomadik I2c controller, register I2C_MCR has 11-bit wide LENGTH field. Its maximum value is 2047, so this is the maximum length of a single message. It is less than the common maximum I2C message length in I2C subsystem (8192), so define a quirk in order to report the unsupported message without any attempt to transfer it. Zero length reading doesn't work properly on this controller, so add `I2C_AQ_NO_ZERO_LEN_READ` quirk flag. Reviewed-by: Linus Walleij Signed-off-by: Dmitry Guzman --- drivers/i2c/busses/i2c-nomadik.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-noma= dik.c index 9c7658148bd45ecdaef1f998558315580233555d..c36e9961e0a39e76386a6e20f6e= 0b6fec3d5b5a9 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -79,6 +79,9 @@ #define I2C_MCR_STOP BIT(14) /* Stop condition */ #define I2C_MCR_LENGTH GENMASK(25, 15) /* Transaction length */ =20 +/* Controller hardware limitation of the message length */ +#define I2C_MAX_MSG_LENGTH (I2C_MCR_LENGTH >> 15) + /* Status register (SR) */ #define I2C_SR_OP GENMASK(1, 0) /* Operation */ #define I2C_SR_STATUS GENMASK(3, 2) /* controller status */ @@ -238,6 +241,12 @@ static int fault_codes[] =3D { EIO }; =20 +static const struct i2c_adapter_quirks nmk_i2c_quirks =3D { + .flags =3D I2C_AQ_NO_ZERO_LEN_READ, + .max_read_len =3D I2C_MAX_MSG_LENGTH, + .max_write_len =3D I2C_MAX_MSG_LENGTH, +}; + static inline void i2c_set_bit(void __iomem *reg, u32 mask) { writel(readl(reg) | mask, reg); @@ -1161,6 +1170,7 @@ static int nmk_i2c_probe(struct amba_device *adev, co= nst struct amba_id *id) adap->class =3D I2C_CLASS_DEPRECATED; adap->algo =3D &nmk_i2c_algo; adap->timeout =3D usecs_to_jiffies(priv->timeout_usecs); + adap->quirks =3D &nmk_i2c_quirks; snprintf(adap->name, sizeof(adap->name), "Nomadik I2C at %pR", &adev->res); =20 --=20 2.43.0 From nobody Sat Sep 26 08:38:28 2026 Received: from esa4.hc555-34.eu.iphmx.com (esa4.hc555-34.eu.iphmx.com [207.54.77.171]) (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 467353921E9; Thu, 3 Sep 2026 05:39:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=207.54.77.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788414006; cv=none; b=Fqip8HeieSYAeDGhFmMik0tpJPHX76p30Oll4sCRM7yZl2Z25wEXkVhYXWdEG8og4dQxNYdbROVitLm5sq5RrlD+d1pUR9QrTETlR51G7XZyvZN7IfzpniD+igKi9pigEh63GnEPs4x8Ssr2u65uNlj1DuPx06nd9xUXgyvbqV0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788414006; c=relaxed/simple; bh=ItnzHs4CMTfZZuAr1WQ3jV2V8snov5mwV0y2o0zOF2g=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=kn6U6iKsEWk5wk8fsYfGkzZwzd/Wz+RBERcW8mpywbD6RCQY00u8Bzis6BF/tdSkJ/H1cb7g3xKw9rfbvIGxMlsbzTHo687qcWIo1Vpvx4KHwlj56JM2DTSmFhOV+wqa1WJk2TQKPR9jOeGWg8XXUyobXyMpRGEqiQK7pNFOVOI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com; spf=pass smtp.mailfrom=mobileye.com; dkim=fail (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b=XLwle03L reason="key not found in DNS"; arc=none smtp.client-ip=207.54.77.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mobileye.com Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b="XLwle03L" DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=mobileye.com; i=@mobileye.com; q=dns/txt; s=MoEyIP; t=1788413996; x=1819949996; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=ItnzHs4CMTfZZuAr1WQ3jV2V8snov5mwV0y2o0zOF2g=; b=XLwle03LEXq3ibRNo/30ryteQMV6Hy9CvYApIlbOClQZzpGRzqIfgnCo o4hKWaYbTlK2uO5v8vRg3h/FLj20Uw+03IFc1mbqnDBeb7YBFtdTn1KPV BXoVCZOG1ZQUaZtsaPdnlrd6Bmnk+gjU2bxisTTCkEdw+Z7yOW5MK1P26 aX4AgeNqwXVlM06lADy+F27zGRyD5L2T5pbhEu8SOGtxHokusipriBkKv HUqeD8SYc9JgMU8f8kRDRFEgrNlhqGjGBUs6mhVsIIOCotoTNtTkpCbYs QRIypUoGeI5wEPyfBWkjN3RmC41cXyWa28wBjFei0eA/qEwSKTRBS4l1H Q==; X-CSE-ConnectionGUID: gmrDEKMWTtS7tr5NnoYm1Q== X-CSE-MsgGUID: aSDCu6A7SASemtRNvPFdUg== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from unknown (HELO ces02_data.me-corp.lan) ([146.255.191.134]) by esa4.hc555-34.eu.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Sep 2026 08:38:44 +0300 X-CSE-ConnectionGUID: 0bgttk3bQ+aWaisyrwKAlA== X-CSE-MsgGUID: WeSs7CFaRlWuEIIEcXulAQ== Received: from unknown (HELO epgd056.me-corp.lan) ([10.154.54.3]) by ces02_data.me-corp.lan with SMTP; 03 Sep 2026 08:45:22 +0300 Received: by epgd056.me-corp.lan (sSMTP sendmail emulation); Thu, 03 Sep 2026 08:38:43 +0300 From: Dmitry Guzman Date: Thu, 03 Sep 2026 08:38:14 +0300 Subject: [PATCH v2 07/12] i2c: nomadik: add support for I2C_XFER_V2 - detailed fault reporting Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-i2c-fault-reporting-v2-7-fedeb91792e6@mobileye.com> References: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> In-Reply-To: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> To: Andi Shyti , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Linus Walleij , Mika Westerberg , Andy Shevchenko Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?Beno=C3=AEt_Monin?= , Dmitry Guzman X-Mailer: b4 0.14.2 I2C_XFER_V2 is a new API that allows I2C clients to get the detailed report in case of transmission failure. Previously, the only information returned by I2C bus controller was the error code; there was no way to find out how many messages or bytes in a certain message have been sent or received until the fault condition occurred. This commit introduces support of this feature in i2c-nomadik driver. Acked-by: Linus Walleij Signed-off-by: Dmitry Guzman --- drivers/i2c/busses/i2c-nomadik.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-noma= dik.c index c36e9961e0a39e76386a6e20f6e0b6fec3d5b5a9..8b0ab191f7c1fc120f81319c1b1= 689193e2b9ea2 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -197,6 +197,7 @@ struct i2c_nmk_client { * @stop: stop condition. * @xfer_wq: xfer done wait queue. * @result: controller propogated result. + * @bytes_cplt: number of bytes completed in the message that caused a fau= lt. */ struct nmk_i2c_dev { struct i2c_vendor_data *vendor; @@ -216,6 +217,7 @@ struct nmk_i2c_dev { int stop; struct wait_queue_head xfer_wq; int result; + int bytes_cplt; }; =20 /* controller's abort causes */ @@ -529,6 +531,8 @@ static int read_i2c(struct nmk_i2c_dev *priv, u16 flags) int status =3D 0; bool xfer_done; =20 + priv->cli.xfer_bytes =3D 0; + mcr =3D load_i2c_mcr_reg(priv, flags); writel(mcr, priv->virtbase + I2C_MCR); =20 @@ -653,6 +657,7 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *priv, u= 16 flags) { int status; =20 + priv->bytes_cplt =3D 0; if (flags & I2C_M_RD) { /* read operation */ priv->cli.operation =3D I2C_READ; @@ -678,6 +683,16 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *priv, = u16 flags) status =3D priv->result; } =20 + if (flags & I2C_M_RD) { + /* For READ messages, return the number of bytes read from FIFO */ + priv->bytes_cplt =3D priv->cli.xfer_bytes; + } else { + /* For WRITE messages, return the number of bytes sent on bus */ + priv->bytes_cplt =3D FIELD_GET(I2C_SR_LENGTH, i2c_sr); + /* LENGTH value includes the last byte that has not been sent or ACKed = */ + if (priv->bytes_cplt > 0) + priv->bytes_cplt--; + } init_hw(priv); =20 status =3D status ? status : priv->result; @@ -687,10 +702,11 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *priv,= u16 flags) } =20 /** - * nmk_i2c_xfer() - I2C transfer function used by kernel framework + * nmk_i2c_xfer_v2() - I2C transfer function used by kernel framework * @i2c_adap: Adapter pointer to the controller * @msgs: Pointer to data to be written. * @num_msgs: Number of messages to be executed + * @report: Pointer to transfer report to be written. * * This is the function called by the generic kernel i2c_transfer() * or i2c_smbus...() API calls. Note that this code is protected by the @@ -733,14 +749,16 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *priv,= u16 flags) * please use the i2c_smbus_read_i2c_block_data() * or i2c_smbus_write_i2c_block_data() API */ -static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], int num_msgs) +static int nmk_i2c_xfer_v2(struct i2c_adapter *i2c_adap, + struct i2c_msg msgs[], int num_msgs, + struct i2c_transfer_report *report) { int status =3D 0; int i; struct nmk_i2c_dev *priv =3D i2c_get_adapdata(i2c_adap); =20 pm_runtime_get_sync(&priv->adev->dev); + priv->bytes_cplt =3D 0; =20 /* setup the i2c controller */ setup_i2c_controller(priv); @@ -760,10 +778,17 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, pm_runtime_put_sync(&priv->adev->dev); =20 /* return the no. messages processed */ - if (status) + if (status) { + report->msgs_cplt =3D i; + report->bytes_cplt =3D priv->bytes_cplt; + report->fault_msg_idx =3D i; return status; - else + } else { + report->msgs_cplt =3D num_msgs; + report->bytes_cplt =3D 0; + report->fault_msg_idx =3D num_msgs; return num_msgs; + } } =20 /** @@ -1014,7 +1039,7 @@ static unsigned int nmk_i2c_functionality(struct i2c_= adapter *adap) } =20 static const struct i2c_algorithm nmk_i2c_algo =3D { - .xfer =3D nmk_i2c_xfer, + .xfer_v2 =3D nmk_i2c_xfer_v2, .functionality =3D nmk_i2c_functionality }; =20 --=20 2.43.0 From nobody Sat Sep 26 08:38:28 2026 Received: from esa2.hc555-34.eu.iphmx.com (esa2.hc555-34.eu.iphmx.com [23.90.104.147]) (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 64CA137702C; Thu, 3 Sep 2026 05:38:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=23.90.104.147 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788413934; cv=none; b=S7D+8400pYPBI2eKPU63huKa/51yq7y5GyhygJmJbPriins62Ds5Y2P3aGCWuLLPIzlVLkS4KHXyldT+ClXT9HDBw21XF2t6xGeddkx/0f4lAHai7BuQtzWUMpgnWuqIZBlYUVVfLUZuNHVUFpBMBAmfP58Kjct1ge8sd4AEkSQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788413934; c=relaxed/simple; bh=PNI7MueqC5h/YY2PhbaG1O/1pTebA97FxujwfRwmfw0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=QKpd+yARxAZjonk20l6SDj5UrlBkw3tAOxeQIYlgkHByFDmnG8/+JET4xy139tV3bhe4Ef+dS/pSVBZf0um28gL/yXrnb5DDuNlWq3ZWKjdp7j2fYtML5i0hUtsLh0VLAddqVAPwxA8ltEh8uNfFGc1ynoq76b0iblJxSiPeqMs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com; spf=pass smtp.mailfrom=mobileye.com; dkim=fail (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b=CyU9ZQJy reason="key not found in DNS"; arc=none smtp.client-ip=23.90.104.147 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mobileye.com Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b="CyU9ZQJy" DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=mobileye.com; i=@mobileye.com; q=dns/txt; s=MoEyIP; t=1788413929; x=1819949929; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=PNI7MueqC5h/YY2PhbaG1O/1pTebA97FxujwfRwmfw0=; b=CyU9ZQJytgq1yNnRsywUfdJUbQiYZEi1SN8YKx6itJtISJKGxNAHZjv5 0NToH4DIbxEUrFP8dhnIXta6sc4hdP3juhumEcRXcJeZFhfqafJpPFziT 0t2kRmieu3cNN4FIVzgEv8LPwmdtAzsc6pAYHyyh9C7WSqe/BHFzwklLN ZD0l/1DVz8I+NDHDKh/6JNfxuTzJ3l40CBr4CCD6wE7ARaIfev2tUT9Aq wPhyL912rj0BJBrkeasVbefsFUW5Qj1OszR7ZkvKzBiuFn9iptB1mNxsS ITcQGZTRBQqFibFkkdNBtRNG0YiyGwwqTpu3Yo7/fRwJJLHIQxUX2G2dM g==; X-CSE-ConnectionGUID: cXTfemmQQHW5DE+hyRYMiQ== X-CSE-MsgGUID: U4v0nJcpRyW0gwHdYcGigA== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from unknown (HELO ces01_data.me-corp.lan) ([146.255.191.134]) by esa2.hc555-34.eu.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Sep 2026 08:38:45 +0300 X-CSE-ConnectionGUID: +5PfWTSgRT+W4mKBZF2RYg== X-CSE-MsgGUID: VzPzu2k/TLmp0Oeb2pFa8w== Received: from unknown (HELO epgd056.me-corp.lan) ([10.154.54.3]) by ces01_data.me-corp.lan with SMTP; 03 Sep 2026 08:45:25 +0300 Received: by epgd056.me-corp.lan (sSMTP sendmail emulation); Thu, 03 Sep 2026 08:38:44 +0300 From: Dmitry Guzman Date: Thu, 03 Sep 2026 08:38:15 +0300 Subject: [PATCH v2 08/12] i2c: designware: return proper fault codes Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-i2c-fault-reporting-v2-8-fedeb91792e6@mobileye.com> References: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> In-Reply-To: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> To: Andi Shyti , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Linus Walleij , Mika Westerberg , Andy Shevchenko Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?Beno=C3=AEt_Monin?= , Dmitry Guzman X-Mailer: b4 0.14.2 I2C documentation Documentation/i2c/fault-codes.rst defines fault codes for different negative results in I2C transmittion. Previously, i2c-designware driver didn't implement them properly - it returned EREMOTEIO on NACK either on address or data phase instead of ENXIO and EIO respectively, and EINVAL instead of EOPNOTSUPP if a message cannot be sent due to controller hardware limitations. To comply with the documentation, return the proper fault codes for different conditions, namely: - EOPNOTSUPP if the controller cannot transfer the message sequence requested (for example, target address change without STOP condition) - ENXIO if target address is not acknowledged - EIO on other faults detected by controller (for example, NACK on data) Signed-off-by: Dmitry Guzman --- drivers/i2c/busses/i2c-designware-common.c | 8 ++++++-- drivers/i2c/busses/i2c-designware-core.h | 3 +-- drivers/i2c/busses/i2c-designware-master.c | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busse= s/i2c-designware-common.c index a1eca6cd4b75e9a76f2fc10afba8877d2b45417d..e934bcbe766042483874b3e43d1= 0ffff30c59e04 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -776,11 +776,15 @@ int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev) unsigned long abort_source =3D dev->abort_source; int i; =20 - if (abort_source & DW_IC_TX_ABRT_NOACK) { + if (abort_source & (DW_IC_TX_ABRT_ADDR_NOACK | DW_IC_TX_ABRT_TXDATA_NOACK= )) { for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources)) dev_dbg(dev->dev, "%s: %s\n", __func__, abort_sources[i]); - return -EREMOTEIO; + + if (abort_source & DW_IC_TX_ABRT_TXDATA_NOACK) + return -EIO; + else + return -ENXIO; } =20 for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources)) diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/= i2c-designware-core.h index 2c929a6e8da2a35b3b2d8ad886e326e2df285927..025311c8662c612aaaf772fb223= af38278217c90 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -112,10 +112,9 @@ #define DW_IC_RX_ABRT_SLAVE_ARBLOST BIT(ABRT_SLAVE_ARBLOST) #define DW_IC_RX_ABRT_SLAVE_FLUSH_TXFIFO BIT(ABRT_SLAVE_FLUSH_TXFIFO) =20 -#define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \ +#define DW_IC_TX_ABRT_ADDR_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \ DW_IC_TX_ABRT_10ADDR1_NOACK | \ DW_IC_TX_ABRT_10ADDR2_NOACK | \ - DW_IC_TX_ABRT_TXDATA_NOACK | \ DW_IC_TX_ABRT_GCALL_NOACK) =20 struct clk; diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busse= s/i2c-designware-master.c index a1bcc3797e4ffef0edb9d3e978eab20a3c09d6aa..d10f46cf4aa44344fa1c53b9b87= 98a8b0f0c193c 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -894,7 +894,7 @@ i2c_dw_xfer_common(struct dw_i2c_dev *dev, struct i2c_m= sg msgs[], int num) */ for (cnt =3D 1; ; cnt++) { if (!i2c_dw_msg_is_valid(dev, msgs_part, cnt - 1)) { - ret =3D -EINVAL; + ret =3D -EOPNOTSUPP; break; } =20 --=20 2.43.0 From nobody Sat Sep 26 08:38:28 2026 Received: from esa4.hc555-34.eu.iphmx.com (esa4.hc555-34.eu.iphmx.com [207.54.77.171]) (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 F2FB9393DE2; Thu, 3 Sep 2026 05:40:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=207.54.77.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788414009; cv=none; b=W6mdj+SC8BrIPlCcJ3mhtHayZ8/SAuc1Aqru5P8/KgvevoQ9w0w1iHnv1mAeMZSO0nypf1U5X9BN1FYNR+D4X/Ak4BZiL/Kq3gkfrm8sNVMQ3E9p90ktD7qgD6HRBYq+d6pBiVs1ZLIzJm/GWx98ncF1wV1oK+EM063HYOIaCH0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788414009; c=relaxed/simple; bh=8TUN+9eI/Nacj8ClflcM6JdSTv4X8U6aMr/gCQEocVA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ixb+DuqZqMkgQiugV58G3sCEb5zrmzQtsxba3wMP4ehnujw+jAEzCSzSKgD3FpyiU21c2uaTEYPzj3fQUQQsjqMXRA65YWC+i0E4qWBuIiM8wUPy83Jz0ldpcgMsPRHok9x7X96rcsrSQo5SUsN7vpslDg0cbTOkiRfv97CWn+U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com; spf=pass smtp.mailfrom=mobileye.com; dkim=fail (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b=NB03eIlK reason="key not found in DNS"; arc=none smtp.client-ip=207.54.77.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mobileye.com Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b="NB03eIlK" DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=mobileye.com; i=@mobileye.com; q=dns/txt; s=MoEyIP; t=1788414007; x=1819950007; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=8TUN+9eI/Nacj8ClflcM6JdSTv4X8U6aMr/gCQEocVA=; b=NB03eIlKkXM3QCHrn3fr9I1crrc6KlyUIZspk/PtWeL5S583U3AusNYM CQratuxvojyO9ixpPSFnrhvvKlPkRzvIQy/dPYnoalctpoXUhgjaEDWHR 4ItrODVhju4/7Z3Y2+z6Xsi5epXRskJ7629N7SdyJ0zGYCqWSmauUT9v/ la6607AsnzWWAgZOVefq0hNkA1km43qvtQ+VDvfxY7pUDCEqnSdqXIHL3 kt6gqTCAFfxAS9rpny/qjCSiuHYYRmbwp7+kYdgA3XZWCt1JaR0lmZrjC nAFTYKAF7PUJPnKb9HoTUbIPNH4arZK1rPAr1OvwZEu8qplmbjZgvVTy8 w==; X-CSE-ConnectionGUID: gmrDEKMWTtS7tr5NnoYm1Q== X-CSE-MsgGUID: DFSa6K3vTVeVRSxPvcEieg== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from unknown (HELO ces02_data.me-corp.lan) ([146.255.191.134]) by esa4.hc555-34.eu.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Sep 2026 08:38:46 +0300 X-CSE-ConnectionGUID: BmP7FnTISB6uneerkrPTuw== X-CSE-MsgGUID: 1ZenchvwTdGQwojcUCQLPg== Received: from unknown (HELO epgd056.me-corp.lan) ([10.154.54.3]) by ces02_data.me-corp.lan with SMTP; 03 Sep 2026 08:45:24 +0300 Received: by epgd056.me-corp.lan (sSMTP sendmail emulation); Thu, 03 Sep 2026 08:38:45 +0300 From: Dmitry Guzman Date: Thu, 03 Sep 2026 08:38:16 +0300 Subject: [PATCH v2 09/12] i2c: designware: no SMBUS_READ_BLOCK_DATA without EMPTYFIFO_HOLD_MASTER Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-i2c-fault-reporting-v2-9-fedeb91792e6@mobileye.com> References: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> In-Reply-To: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> To: Andi Shyti , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Linus Walleij , Mika Westerberg , Andy Shevchenko Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?Beno=C3=AEt_Monin?= , Dmitry Guzman X-Mailer: b4 0.14.2 Controllers without EMPTYFIFO_HOLD_MASTER feature cannot hold bus with empty FIFO. This makes impossible to issue SMBUS block read command: it is not known how many bytes must be read until it reads the first byte indicates the data length is read. Without EMPTYFIFO_HOLD_MASTER, when the first byte is read, TX FIFO gets empty, this causes STOP condition and the transfer is terminated. Reset SMBUS_READ_BLOCK_DATA bit in functionality mask on such controllers. Signed-off-by: Dmitry Guzman --- drivers/i2c/busses/i2c-designware-master.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busse= s/i2c-designware-master.c index d10f46cf4aa44344fa1c53b9b8798a8b0f0c193c..76f28e1696bdc81326cf149dfe8= 8c52dd2f0731f 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -940,6 +940,13 @@ void i2c_dw_configure_master(struct dw_i2c_dev *dev) if ((dev->flags & MODEL_MASK) !=3D MODEL_AMD_NAVI_GPU) dev->functionality |=3D I2C_FUNC_PROTOCOL_MANGLING; =20 + /* Controllers without EMPTYFIFO_HOLD_MASTER feature cannot issue SMBUS + * block read because after reading the data length FIFO gets empty and + * STOP is generated automatically + */ + if (!dev->emptyfifo_hold_master) + dev->functionality &=3D ~I2C_FUNC_SMBUS_READ_BLOCK_DATA; + dev->master_cfg =3D DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | DW_IC_CON_RESTART_EN; =20 --=20 2.43.0 From nobody Sat Sep 26 08:38:28 2026 Received: from esa2.hc555-34.eu.iphmx.com (esa2.hc555-34.eu.iphmx.com [23.90.104.147]) (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 6F4B7392C39; Thu, 3 Sep 2026 05:39:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=23.90.104.147 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788414002; cv=none; b=eoBK5QLiTWWWefGMgiwYEJRdRsOL3ZfRWw+X6DSAg3ttq6wr44qG8pl0N/WPyiGAgTTF7JEJogLQl/za8vojXavUzMxbyvKX6TDsSKmFqRpK3PobxG35lkavhhI14c4GdT6tLnXllRmJK7uiKV/Qh0WVqe0zLDLoJX/WuyFeml8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788414002; c=relaxed/simple; bh=HlYAVuM9vZLFTesP9pfThfI3jTZfqm2p6kxvhhe8OIs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=HwmdpPRUkUJtWnkrEkevI6lmAmweUQj55uAZcxS/5RYVBIWU0wmz+ZB9VLhvGCQ686WrQh7EhJNZTyDgTjpMqtGNd+zcYnlyUDfkny3iBxuW9CXANzTRJbSIjZRVWwnd7SN6EX4G3SJHGoxIfYrF1c32L4c56IWyrQ01PNNisJA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com; spf=pass smtp.mailfrom=mobileye.com; dkim=fail (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b=n3vV20OP reason="key not found in DNS"; arc=none smtp.client-ip=23.90.104.147 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mobileye.com Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b="n3vV20OP" DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=mobileye.com; i=@mobileye.com; q=dns/txt; s=MoEyIP; t=1788413996; x=1819949996; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=HlYAVuM9vZLFTesP9pfThfI3jTZfqm2p6kxvhhe8OIs=; b=n3vV20OP8CVa5vqGCifBFPYj/I+skQ4A8O3ywxZeyiwjI2RECktvNtGB r4PYYEVQPb/XZmkUHPpVcSXm63l7kdhokHVkHuimB6aqeyYy1XkMquNjY 0cbfm4IZLjdLexlszkEM8ozuRhN+Jf4gq/czLbllFPEdDJceudRhp1WZK EkSZ0tmMB9TKmX6R2PsLkZUsbpL28eKt37w9cA9K6hasGvpso02hRlcAO K473eDLH3O/jZNURFDMpT4dIEIOw5hMVY5hRDZEd4TM/io/RtiKcVLGc6 GePTlvG6nYc7cfR539GJLf1T21HW+yDEkmvm3tPTgKBXcRFkqybJCAy9z A==; X-CSE-ConnectionGUID: WLsDcoMiRqeta1S+3AaaXA== X-CSE-MsgGUID: pfpTQci7RAi4ym1F4MPsvw== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from unknown (HELO ces03_data.me-corp.lan) ([146.255.191.134]) by esa2.hc555-34.eu.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Sep 2026 08:38:47 +0300 X-CSE-ConnectionGUID: DGlRIx87RHqxRAx0DKNZDQ== X-CSE-MsgGUID: /Qj9nrTdRMmiTWGdE7nxiw== Received: from unknown (HELO epgd056.me-corp.lan) ([10.154.54.3]) by ces03_data.me-corp.lan with SMTP; 03 Sep 2026 08:45:15 +0300 Received: by epgd056.me-corp.lan (sSMTP sendmail emulation); Thu, 03 Sep 2026 08:38:46 +0300 From: Dmitry Guzman Date: Thu, 03 Sep 2026 08:38:17 +0300 Subject: [PATCH v2 10/12] i2c: designware: stop transfer if spurious STOP is detected Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-i2c-fault-reporting-v2-10-fedeb91792e6@mobileye.com> References: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> In-Reply-To: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> To: Andi Shyti , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Linus Walleij , Mika Westerberg , Andy Shevchenko Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?Beno=C3=AEt_Monin?= , Dmitry Guzman X-Mailer: b4 0.14.2 In `i2c_dw_process_transfer()`, if STOP_DET flag is set while read or write is in progress, the transfer should be aborted. If this flag is handled the same interrupt as TX_EMPTY flag, the driver first handles TX_EMPTY flag and transmits the following messages, and only afterwards checks STOP_DET flag. Also, if STOP_DET flag is set, interrupts are not masked, so if TX_EMPTY interrupts arrives later, the driver will also send further messages. To abort transmitting data after spurious STOP, check STOP_DET flag before TX_EMPTY flag, and if STOP_DET flag is set while transfer is in progress, disable interrupts as it is done in case of TX_ABRT flag set. Signed-off-by: Dmitry Guzman --- drivers/i2c/busses/i2c-designware-master.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busse= s/i2c-designware-master.c index 76f28e1696bdc81326cf149dfe88c52dd2f0731f..936b9150754e85a1bac2d17a0fa= 65f6963e4ef3e 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -651,17 +651,19 @@ static void i2c_dw_process_transfer(struct dw_i2c_dev= *dev, unsigned int stat) if (stat & DW_IC_INTR_RX_FULL) i2c_dw_read(dev); =20 - if (stat & DW_IC_INTR_TX_EMPTY) - i2c_dw_xfer_msg(dev); - /* Abort if we detect a STOP in the middle of a read or a write */ if ((stat & DW_IC_INTR_STOP_DET) && (dev->status & (STATUS_READ_IN_PROGRESS | STATUS_WRITE_IN_PROGRESS)))= { dev_err(dev->dev, "spurious STOP detected\n"); dev->rx_outstanding =3D 0; dev->msg_err =3D -EIO; + __i2c_dw_write_intr_mask(dev, 0); + goto tx_aborted; } =20 + if (stat & DW_IC_INTR_TX_EMPTY) + i2c_dw_xfer_msg(dev); + /* * No need to modify or disable the interrupt mask here. * i2c_dw_xfer_msg() will take care of it according to --=20 2.43.0 From nobody Sat Sep 26 08:38:28 2026 Received: from esa2.hc555-34.eu.iphmx.com (esa2.hc555-34.eu.iphmx.com [23.90.104.147]) (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 ECA384CCDC6; Thu, 3 Sep 2026 05:38:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=23.90.104.147 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788413936; cv=none; b=g+yOSKqZKxnC05kRkNyEOpV0q1S708J4Fs36vcYXcazSLCLYVuOCM7vhcgqF5QA6QqK8+5S3l1w7OgHH6ojn2bZedtIK5PjGYykFDQxzyAkAFzCBCpRD1NhjYU1D46GR1POYZ0GcxHcNJKghu4vvEmlbXPxJQoEkoOskUAdU0AE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788413936; c=relaxed/simple; bh=eHmFtsWU5LjiwnO3niytJNP8sUYds/84ZFFIoQLM9gk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Hl+e/AW2Czxo7fKtiuKNrhawtsonPk+5bijFsjCdkx+yZ8FM6wzBOeddO1+h6/ySCfzfA6rz0cRXtJISnkvXhnMR7a1WQFXZ9/As1/JA1KkvptsutF+NHPrvQg68Blc6M1e0CyJShOLtFLqhBSuSOS4yGba+FN7ynoB8PyTsIkU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com; spf=pass smtp.mailfrom=mobileye.com; dkim=fail (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b=SabPrrm7 reason="key not found in DNS"; arc=none smtp.client-ip=23.90.104.147 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mobileye.com Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b="SabPrrm7" DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=mobileye.com; i=@mobileye.com; q=dns/txt; s=MoEyIP; t=1788413934; x=1819949934; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=eHmFtsWU5LjiwnO3niytJNP8sUYds/84ZFFIoQLM9gk=; b=SabPrrm7km3DMvlwkSM5tPQhXRXkkcN0xrGvJBLnXSL+gwESb/g+sn2B qcZgeZv9UAn9XFgBGv4FWC5a9Xzwl3oYVmAU33iSalCvdJ8aokr7qR64C avYinIxW2i07pQjnupi+1so08BWm2TfwvQ4SXdpo1whpfgQz5m2OADqHn qeRBSmSvwNVs3UjcpN2nwXWHM9qWA1wiRDXBgl80igvlQpELkDh4DryjN GrHxoe19TXa0HrypYoBY3y72wjxkv3furM+PPoOKVj+M29QDGxjkoHv5p 4om6oXhSD0ZVE/XI6GKtyhZ2SI8zeaxFhtu3X6h5Q7CoUZ4xv3oyNbqG0 A==; X-CSE-ConnectionGUID: cXTfemmQQHW5DE+hyRYMiQ== X-CSE-MsgGUID: lO8lWGNRSHmUZbba1rI0gA== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from unknown (HELO ces01_data.me-corp.lan) ([146.255.191.134]) by esa2.hc555-34.eu.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Sep 2026 08:38:48 +0300 X-CSE-ConnectionGUID: 5S1lyqeURkuJKJFGaAW5FQ== X-CSE-MsgGUID: IQLGvVf4RLesE2UPXjvhPA== Received: from unknown (HELO epgd056.me-corp.lan) ([10.154.54.3]) by ces01_data.me-corp.lan with SMTP; 03 Sep 2026 08:45:29 +0300 Received: by epgd056.me-corp.lan (sSMTP sendmail emulation); Thu, 03 Sep 2026 08:38:47 +0300 From: Dmitry Guzman Date: Thu, 03 Sep 2026 08:38:18 +0300 Subject: [PATCH v2 11/12] i2c: designware: use separate `i2c_algorithm` for AMD_NAVI_GPU Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-i2c-fault-reporting-v2-11-fedeb91792e6@mobileye.com> References: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> In-Reply-To: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> To: Andi Shyti , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Linus Walleij , Mika Westerberg , Andy Shevchenko Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?Beno=C3=AEt_Monin?= , Dmitry Guzman X-Mailer: b4 0.14.2 AMD_NAVI_GPU variant of designware I2C controller uses its own implementation of `xfer` method. Instead of checking flags in runtime, create a separate `i2c_algorithm` structure and put pointer to `amd_i2c_dw_xfer_quirk` directly into it. Signed-off-by: Dmitry Guzman --- drivers/i2c/busses/i2c-designware-common.c | 14 +++++++++++++- drivers/i2c/busses/i2c-designware-core.h | 1 + drivers/i2c/busses/i2c-designware-master.c | 6 ++---- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busse= s/i2c-designware-common.c index e934bcbe766042483874b3e43d10ffff30c59e04..4274bf809b3f4bff90139d18644= 7256b01317951 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -886,6 +886,15 @@ static const struct i2c_algorithm i2c_dw_algo =3D { #endif }; =20 +static const struct i2c_algorithm i2c_dw_amd_navi_gpu_algo =3D { + .xfer =3D amd_i2c_dw_xfer_quirk, + .functionality =3D i2c_dw_func, +#if IS_ENABLED(CONFIG_I2C_SLAVE) + .reg_slave =3D i2c_dw_reg_slave, + .unreg_slave =3D i2c_dw_unreg_slave, +#endif +}; + static const struct i2c_adapter_quirks i2c_dw_quirks =3D { .flags =3D I2C_AQ_NO_ZERO_LEN, }; @@ -922,7 +931,10 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) strscpy(adap->name, "Synopsys DesignWare I2C adapter"); =20 adap->retries =3D 3; - adap->algo =3D &i2c_dw_algo; + if ((dev->flags & MODEL_MASK) =3D=3D MODEL_AMD_NAVI_GPU) + adap->algo =3D &i2c_dw_amd_navi_gpu_algo; + else + adap->algo =3D &i2c_dw_algo; adap->quirks =3D &i2c_dw_quirks; adap->dev.parent =3D dev->dev; i2c_set_adapdata(adap, dev); diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/= i2c-designware-core.h index 025311c8662c612aaaf772fb223af38278217c90..9f3492717e18fe104d307cfc652= 93ae4b41251f0 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -316,6 +316,7 @@ extern void i2c_dw_configure_master(struct dw_i2c_dev *= dev); extern int i2c_dw_probe_master(struct dw_i2c_dev *dev); =20 int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); +int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs, = int num_msgs); =20 #if IS_ENABLED(CONFIG_I2C_SLAVE) extern void i2c_dw_configure_slave(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busse= s/i2c-designware-master.c index 936b9150754e85a1bac2d17a0fa65f6963e4ef3e..f029aa1eadbf83d304fc73b038e= 92f258e2148a1 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -291,8 +291,9 @@ static int i2c_dw_status(struct dw_i2c_dev *dev) * Initiate and continue master read/write transaction with polling * based transfer routine afterward write messages into the Tx buffer. */ -static int amd_i2c_dw_xfer_quirk(struct dw_i2c_dev *dev, struct i2c_msg *m= sgs, int num_msgs) +int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs, = int num_msgs) { + struct dw_i2c_dev *dev =3D i2c_get_adapdata(adap); int msg_wrt_idx, msg_itr_lmt, buf_len, data_idx; int cmd =3D 0, status; u8 *tx_buf; @@ -926,9 +927,6 @@ int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_ms= g *msgs, int num) { struct dw_i2c_dev *dev =3D i2c_get_adapdata(adap); =20 - if ((dev->flags & MODEL_MASK) =3D=3D MODEL_AMD_NAVI_GPU) - return amd_i2c_dw_xfer_quirk(dev, msgs, num); - return i2c_dw_xfer_common(dev, msgs, num); } =20 --=20 2.43.0 From nobody Sat Sep 26 08:38:28 2026 Received: from esa4.hc555-34.eu.iphmx.com (esa4.hc555-34.eu.iphmx.com [207.54.77.171]) (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 7117B394EB7; Thu, 3 Sep 2026 05:40:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=207.54.77.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788414011; cv=none; b=QNdyMu+i61PzmHfo9Soamk0mzulWMbxs7vfLE/WfYoUjC/GhKqB6c4ik2Jn0E57NCBeL8GqhWjmd8yOx0qqOfNUJCAd0Wyz9IzHVclq8Nv+s/nvbnYl3XsDCpsBcfF0IA27zmBKd7LDipkDEdbhyA2hV4IafIuw9bMQEmGXc97Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788414011; c=relaxed/simple; bh=tXlRbGYQCwCA4tGfxwjozAwepNU3isVDrniH+0t54+o=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=U7J6Pbm5hP/RL+fQ+62uzupuILQPbk6pFRkFqla5LNls6WzK5VpM1248xs0vdQYejv11WcKVywk6AD6TN3I6X6lSvFTt4WNCpF05tY78uU76/yBmrzetFDk4J3cWpPwUlT22pZxviZgpbqQSUrfloUUcX3r3QyyiIF/RClvWaFI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com; spf=pass smtp.mailfrom=mobileye.com; dkim=fail (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b=s/KtWBUH reason="key not found in DNS"; arc=none smtp.client-ip=207.54.77.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mobileye.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mobileye.com Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=mobileye.com header.i=@mobileye.com header.b="s/KtWBUH" DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=mobileye.com; i=@mobileye.com; q=dns/txt; s=MoEyIP; t=1788414009; x=1819950009; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=tXlRbGYQCwCA4tGfxwjozAwepNU3isVDrniH+0t54+o=; b=s/KtWBUH/zNi4v+hu0BnpUGx5yKhC9IZQhcqotZEsQNxVRNQL7Mee/bh nFRsD/YKRzI0B9mswzb+7LJOsv43aaBsF8T/wUeHrhLP6We63DLeQZ14I HgGWz+rfm7gnzYDV4hNSS05cmWWTf6lRyZIeEjj6d88OAc5llGWi1M5LY fmgEe9MP9g7mACwGtDsA2N9NdKaApmPAF2YhyFQG8qNolDtoTFpY5eEpp BGqhDkbi2HWghp+X6NUrWK3lZr6sesrqqsSXZ+yf85+PFff3thtmEJC8d F2ZFw+F6vLRf1r+BUs8ePrVcUIASoGov4FxjDa4su+3EL4dDep1sH47Lc g==; X-CSE-ConnectionGUID: LeSvuKNkTvCHYJTaVILy1w== X-CSE-MsgGUID: x46MnQXlRn+HJ/pnMlD2PQ== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from unknown (HELO ces04_data.me-crop.lan) ([146.255.191.134]) by esa4.hc555-34.eu.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Sep 2026 08:38:50 +0300 X-CSE-ConnectionGUID: Uo2BT8XQTdyTw2Hv0XhF0w== X-CSE-MsgGUID: SzSF1Hd3QDCPUsxPczmgbw== Received: from unknown (HELO epgd056.me-corp.lan) ([10.154.54.2]) by ces04_data.me-crop.lan with SMTP; 03 Sep 2026 08:45:25 +0300 Received: by epgd056.me-corp.lan (sSMTP sendmail emulation); Thu, 03 Sep 2026 08:38:48 +0300 From: Dmitry Guzman Date: Thu, 03 Sep 2026 08:38:19 +0300 Subject: [PATCH v2 12/12] i2c: designware: add support for I2C_XFER_V2 - detailed fault reporting Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-i2c-fault-reporting-v2-12-fedeb91792e6@mobileye.com> References: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> In-Reply-To: <20260903-i2c-fault-reporting-v2-0-fedeb91792e6@mobileye.com> To: Andi Shyti , Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers , Linus Walleij , Mika Westerberg , Andy Shevchenko Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?Beno=C3=AEt_Monin?= , Dmitry Guzman X-Mailer: b4 0.14.2 I2C_XFER_V2 is a new API that allows I2C clients to get the detailed report in case of transmission failure. Previously, the only information returned by I2C bus controller was the error code; there was no way to find out how many messages or bytes in a certain message have been sent or received until the fault condition occurred, or to receive the data read before the fault. This patch introduces support for this feature in i2c-designware driver. For AMD_NAVI_GPU model that has its own `xfer` callback function, this feature is currently not implemented. The driver uses FLUSH_CNT field of ABORT_SOURCE register to detect how many command/data bytes written to FIFO were not actually sent. Also, if the detailed fault report is required, the driver checks status after each read/write from/to FIFO. If ABORT flag is set, the driver cannot detect what happened first - FIFO read/write or communication abort, so it assumes that abort happened first, otherwise it either falsely reports one extra byte sent or returns the byte read from FIFO flushed after abort as a valid read byte. So, in unfortunate conditions, the fault report may be too pessimistic by one byte. This check increases amount of time spent in interrupt handler, so if client doesn't need detailed fault report, this check should be avoided. Because of this, both `xfer` and `xfer_v2` callbacks are implemented in struct i2c_algorithm: the former does not generate detailed fault report, while the latter does. Signed-off-by: Dmitry Guzman --- drivers/i2c/busses/i2c-designware-common.c | 1 + drivers/i2c/busses/i2c-designware-core.h | 10 +++ drivers/i2c/busses/i2c-designware-master.c | 139 +++++++++++++++++++++++++= ++-- 3 files changed, 145 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busse= s/i2c-designware-common.c index 4274bf809b3f4bff90139d186447256b01317951..42fc5989c917686a89802d7ef02= 7a6d89aea6213 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -879,6 +879,7 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_i= d) =20 static const struct i2c_algorithm i2c_dw_algo =3D { .xfer =3D i2c_dw_xfer, + .xfer_v2 =3D i2c_dw_xfer_v2, .functionality =3D i2c_dw_func, #if IS_ENABLED(CONFIG_I2C_SLAVE) .reg_slave =3D i2c_dw_reg_slave, diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/= i2c-designware-core.h index 9f3492717e18fe104d307cfc65293ae4b41251f0..108fc1d1132c0aa91723de83198= 204a0dde42484 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -117,6 +117,8 @@ DW_IC_TX_ABRT_10ADDR2_NOACK | \ DW_IC_TX_ABRT_GCALL_NOACK) =20 +#define DW_IC_TX_ABRT_SOURCE_FLUSH_CNT_MASK GENMASK(31, 23) + struct clk; struct device; struct reset_control; @@ -180,6 +182,9 @@ struct reset_control; * to generate the high period and low period of SCL line. * @emptyfifo_hold_master: true if the controller acting as master holds * the clock when the Tx FIFO is empty instead of emitting a stop. + * @need_precise_report: true if client needs precise fault report + * @bytes_written: number of bytes written to FIFO. Used only for precise + fault report. * * HCNT and LCNT parameters can be used if the platform knows more accurate * values than the one computed based only on the input clock frequency. @@ -239,6 +244,8 @@ struct dw_i2c_dev { u32 bus_capacitance_pF; bool clk_freq_optimized; bool emptyfifo_hold_master; + bool need_precise_report; + u32 bytes_written; }; =20 #define ACCESS_INTR_MASK BIT(0) @@ -318,6 +325,9 @@ extern int i2c_dw_probe_master(struct dw_i2c_dev *dev); int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs, = int num_msgs); =20 +int i2c_dw_xfer_v2(struct i2c_adapter *adap, struct i2c_msg *msgs, int num, + struct i2c_transfer_report *report); + #if IS_ENABLED(CONFIG_I2C_SLAVE) extern void i2c_dw_configure_slave(struct dw_i2c_dev *dev); irqreturn_t i2c_dw_isr_slave(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busse= s/i2c-designware-master.c index f029aa1eadbf83d304fc73b038e92f258e2148a1..bc23c3fdaaf2e0629e02016aef4= 28cc9f8bffda2 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -11,6 +11,7 @@ =20 #define DEFAULT_SYMBOL_NAMESPACE "I2C_DW" =20 +#include #include #include #include @@ -33,6 +34,16 @@ #define AMD_TIMEOUT_MAX_US 250 #define AMD_MASTERCFG_MASK GENMASK(15, 0) =20 +static int i2c_dw_fault_report(struct dw_i2c_dev *dev, struct i2c_transfer= _report *report); + +static inline bool i2c_dw_check_abort_flag(struct dw_i2c_dev *dev) +{ + u32 stat; + + regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat); + return (!!(stat & DW_IC_INTR_TX_ABRT)); +} + static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) { unsigned int comp_param1; @@ -198,6 +209,8 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) =20 i2c_dw_set_mode(dev, DW_IC_MASTER); =20 + dev->rx_buf_len =3D 0; + /* If the slave address is ten bit address, enable 10BITADDR */ if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) { ic_con =3D DW_IC_CON_10BITADDR_MASTER; @@ -451,6 +464,21 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) cmd | *buf++); } tx_limit--; buf_len--; + + /* If precise fault reporting is required, check if the transfer + * is aborted after writing each byte. + * Otherwise, if it is aborted during filling FIFO, there is no way + * to know how many bytes was written to FIFO after transfer abort + * and thus are not counted in FLUSH_CNT. + * If we are checking abort flag after each byte, we can lose only 1 by= te. + */ + if (dev->need_precise_report) { + if (i2c_dw_check_abort_flag(dev)) { + dev_warn_ratelimited(dev->dev, "Transfer aborted during FIFO writing.= Report may be imprecise."); + break; + } + dev->bytes_written++; + } } =20 dev->tx_buf =3D buf; @@ -542,6 +570,13 @@ i2c_dw_read(struct dw_i2c_dev *dev) =20 for (; len > 0 && rx_valid > 0; len--, rx_valid--) { regmap_read(dev->map, DW_IC_DATA_CMD, &tmp); + if (dev->need_precise_report) { + if (i2c_dw_check_abort_flag(dev)) { + dev_warn_ratelimited(dev->dev, "Transfer aborted during FIFO reading.= Data byte may be lost"); + /* It is unknown if the read byte is valid. Drop it. */ + break; + } + } tmp &=3D DW_IC_DATA_CMD_DAT; /* Ensure length byte is a valid value */ if (flags & I2C_M_RECV_LEN) { @@ -568,8 +603,10 @@ i2c_dw_read(struct dw_i2c_dev *dev) dev->rx_buf_len =3D len; dev->rx_buf =3D buf; return; - } else + } else { dev->status &=3D ~STATUS_READ_IN_PROGRESS; + dev->rx_buf_len =3D 0; + } } } =20 @@ -765,6 +802,7 @@ __i2c_dw_xfer_one_part(struct dw_i2c_dev *dev, struct i= 2c_msg *msgs, size_t num) dev->status =3D 0; dev->abort_source =3D 0; dev->rx_outstanding =3D 0; + dev->bytes_written =3D 0; =20 ret =3D i2c_dw_wait_bus_not_busy(dev); if (ret < 0) @@ -868,12 +906,25 @@ i2c_dw_msg_is_valid(struct dw_i2c_dev *dev, const str= uct i2c_msg *msgs, size_t i } =20 static int -i2c_dw_xfer_common(struct dw_i2c_dev *dev, struct i2c_msg msgs[], int num) +i2c_dw_xfer_common_v2(struct dw_i2c_dev *dev, struct i2c_msg *msgs, int nu= m, + struct i2c_transfer_report *report) { struct i2c_msg *msgs_part; - size_t cnt; + int msgs_in_prev_parts =3D 0; + size_t cnt =3D 0; int ret; =20 + if (!report) { + dev->need_precise_report =3D false; + } else { + dev->need_precise_report =3D true; + report->msgs_cplt =3D -EOPNOTSUPP; + report->bytes_cplt =3D -EOPNOTSUPP; + report->fault_msg_idx =3D -EOPNOTSUPP; + } + + dev->msg_read_idx =3D 0; + dev_dbg(dev->dev, "msgs: %d\n", num); =20 PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev->dev, pm); @@ -889,6 +940,8 @@ i2c_dw_xfer_common(struct dw_i2c_dev *dev, struct i2c_m= sg msgs[], int num) * we do one transaction for each part up to the STOP. */ for (msgs_part =3D msgs; msgs_part < msgs + num; msgs_part +=3D cnt) { + /* Count previously transferred messages*/ + msgs_in_prev_parts +=3D cnt; /* * Count the messages in a transaction, up to a STOP or * the end of the msgs. The last if below guarantees that @@ -897,6 +950,15 @@ i2c_dw_xfer_common(struct dw_i2c_dev *dev, struct i2c_= msg msgs[], int num) */ for (cnt =3D 1; ; cnt++) { if (!i2c_dw_msg_is_valid(dev, msgs_part, cnt - 1)) { + if (report) { + report->fault_msg_idx =3D msgs_in_prev_parts + cnt - 1; + report->msgs_cplt =3D msgs_in_prev_parts; + report->bytes_cplt =3D 0; + /* Reset report pointer to avoid + * calling i2c_dw_fault_report later + */ + report =3D NULL; + } ret =3D -EOPNOTSUPP; break; } @@ -918,16 +980,83 @@ i2c_dw_xfer_common(struct dw_i2c_dev *dev, struct i2c= _msg msgs[], int num) =20 i2c_dw_release_lock(dev); =20 - if (ret < 0) + if (ret < 0) { + if (report) { + i2c_dw_fault_report(dev, report); + report->msgs_cplt +=3D msgs_in_prev_parts; + report->fault_msg_idx +=3D msgs_in_prev_parts; + } return ret; + } + if (report) { + report->msgs_cplt =3D num; + report->fault_msg_idx =3D num; + report->bytes_cplt =3D 0; + } + return num; } =20 +int i2c_dw_xfer_v2(struct i2c_adapter *adap, struct i2c_msg *msgs, int num, + struct i2c_transfer_report *report) +{ + struct dw_i2c_dev *dev =3D i2c_get_adapdata(adap); + + return i2c_dw_xfer_common_v2(dev, msgs, num, report); +} + int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct dw_i2c_dev *dev =3D i2c_get_adapdata(adap); =20 - return i2c_dw_xfer_common(dev, msgs, num); + return i2c_dw_xfer_common_v2(dev, msgs, num, NULL); +} + +static int i2c_dw_fault_report(struct dw_i2c_dev *dev, struct i2c_transfer= _report *report) +{ + int idx; + int n_flushed =3D FIELD_GET(DW_IC_TX_ABRT_SOURCE_FLUSH_CNT_MASK, dev->abo= rt_source); + + report->msgs_cplt =3D -1; + + if (n_flushed <=3D dev->bytes_written) + dev->bytes_written -=3D n_flushed; + else + dev->bytes_written =3D 0; + + /* The last byte that the transmission was interrupted on is not counted = as "flushed". + * We should not reported it as transferred successfully, so decrement th= e counter. + */ + if (dev->bytes_written) + dev->bytes_written--; + + for (idx =3D 0; idx < dev->msg_write_idx; idx++) { + if (dev->msgs[idx].len <=3D dev->bytes_written) + dev->bytes_written -=3D dev->msgs[idx].len; + else + break; + } + + report->fault_msg_idx =3D idx; + for (int i =3D dev->msg_read_idx; i <=3D idx && i < dev->msgs_num; i++) { + if (dev->msgs[i].flags & I2C_M_RD) { + report->msgs_cplt =3D i; + if (!(dev->rx_buf_len)) + report->bytes_cplt =3D 0; + else + report->bytes_cplt =3D dev->rx_buf - dev->msgs[i].buf; + if ((i < idx) || (report->bytes_cplt < dev->bytes_written)) + dev_warn_ratelimited(dev->dev, "Read data lost due to FIFO flush"); + break; + } + } + + if (report->msgs_cplt < 0) { + report->msgs_cplt =3D idx; + report->bytes_cplt =3D dev->bytes_written; + } + + return idx; } =20 void i2c_dw_configure_master(struct dw_i2c_dev *dev) --=20 2.43.0