From nobody Sat Jun 13 13:02:51 2026 Received: from mail-lj1-f180.google.com (mail-lj1-f180.google.com [209.85.208.180]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A67123C6A43 for ; Thu, 7 May 2026 09:33:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.180 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778146407; cv=none; b=YGIAqsM7SeigjLZOUZ6xf9oiKdqwztin1/1YHKYfzcqHAj+zBRAiOp/nXzk9oTKbC6WRBH2tPxofU+ZnZXKHwpAvTElpf7Frs/BBAprsWpxwjsaVvMT83bGJANn16fY9K4OlaPdQ1k4T7ZtD0Smr+vReVlF+7HJqQYUbaWQh29s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778146407; c=relaxed/simple; bh=XhZrXauAACb4WHe93YLAMRtIyhKDF5L0YIyHXg6C7x8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=oevMgHKy3dxKx8Z26jwN6w6LNDyuCTeXTUigVDrSoGIz3rHkA9jFkpvwOuwWNpx5MZiGnQ5vg8jiaO/96HThzKw6Y5wStcUHO/cq6AEJ3aE8jVXKU2f2mWnphJzz+R/x+ciq6pKwiFQ0o+6hDGgf5HJXGD/P5t3S5xKHJmTnlMM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Y9J7OcNd; arc=none smtp.client-ip=209.85.208.180 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Y9J7OcNd" Received: by mail-lj1-f180.google.com with SMTP id 38308e7fff4ca-39380e79936so7431581fa.2 for ; Thu, 07 May 2026 02:33:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778146402; x=1778751202; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=+AGdFUHDF2nHQALLrNQHKOEqd/fvRy2bQu566xPn6As=; b=Y9J7OcNd8GbH0Rp4yGyFtMZgxMut0pOGsc0BPkyGg40LALT/cGiUPxNdpkTs0bVHrE 8l27GOuHDfOundSaZ5HcWst1gJj4PwMcMbOuR1AhPGMjYRMcgJ4EupI1Uo68oSnu2j62 yXp6fHaznxP06C+X3TUPU4sLNPMoaa9Az+HyqMekzNqx37PBh0RNABsQheEj2DI3KVn5 pQyXliiVj4OTXbwMVSaJyun8Ka3jrdiVJ21kKUcOImvh4cBcmAQ1QIlQ6bQ8Qc8wzL94 zg5x0v9d5bOhXBskwEZ62+Tmk++s4DFTVwmQXmjv48qcYZlCcIpcLl2s5xEMlGoZ4vtg s9uA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778146402; x=1778751202; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=+AGdFUHDF2nHQALLrNQHKOEqd/fvRy2bQu566xPn6As=; b=etuG6dTbc5iTTDR9EFtEkQe7MqxJO8YtLqNPC8vYI7vBkPgr+M2872d3xK3Ve9dj3N 5FGMaF0zYiTkEMENAGC2GmSAh/CBO4Igx9RYu3JLwwZVHEC2waPZub4/1JZDEmv3bZtd o/MejgJCseypOiU0y1hAvVDXpXCxJFmT/VIyOlKh0S3HxgIqIXlccZQ6EMsnsZJYO3Cx zrfuw89T2WuF9oSSnvwxeMZw3XRzkwRWN4j38xhVqxm5vPaxaq3L5mbzh/5f/GucTt2b 5KlU4gs+W8j/mJj58MffiQVK0Yb/+cXvt4Epznob51U1AtypydCUFSyJJUyDbrIhT2KM s2gQ== X-Forwarded-Encrypted: i=1; AFNElJ+XMnzZ7uGXuREu92DSc5Db0954MddWafl2dRhuguLEFdaBiGgP63CW8W4aiKB3GLgDXIiaq2V+sVd4X08=@vger.kernel.org X-Gm-Message-State: AOJu0YyloNRdNDvrrt4W+N/0iAX2AOYqFX0YtIZhWge0yrK7Fq1Qwv2u AaZ/UkQrqKKGpaiSDLJIC6fdhmZfGuG4W36Zp6/dlleqASAr4RVOo2Nl X-Gm-Gg: AeBDieuS8mgJnujDcU1TJG3T9zjwtUdnfbzfM+NtvWyXRlcOCwOp+gYr1Z1M6FSmvgv AecuNqLoIlfLJq5+4eOAEUlNTcnV9/UEHlPZtI1s8AB78y9EonspqBdQrbKiReyP3VAx+9tVcBc 8ADvNR7583llR2QZxSp4yRRewWUOgkfgw8y9sWIJ84mblZ0maMKaQXVVeWzF77fBGn/d9PlOoOv 5XKqwUio6X5121U+dxIwzgnSvbnMRZgDsSfKYTJZPVF75dKgaI2X7Zu7ON5u/xNDlgRnS/3jMQG HrnaS4CDTGDN/Lavq6+J7/+3zdowYsd7xO2VEfm9FwU9eFpdXRu6NvIJNA+Suz+5PDpPfiNZZmo H2XMc47qDT16AjEKRCfwCT3DQ2v1btWmLMAfTEJB7jfqfJq89q4LJjbQJz3cqHcXJLaHiIh5CPI SRjOmQ0CVRurTKltPl5Ti725wYpDaimun6s8AH X-Received: by 2002:a05:6512:318e:b0:5a8:9dc2:8a81 with SMTP id 2adb3069b0e04-5a89dc28d0bmr493127e87.17.1778146401564; Thu, 07 May 2026 02:33:21 -0700 (PDT) Received: from builder ([2001:9e8:f13c:9216:be24:11ff:fe30:5d85]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-5a864c6f16esm4752445e87.15.2026.05.07.02.33.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 May 2026 02:33:21 -0700 (PDT) From: Jonas Jelonek To: Russell King , Andrew Lunn , Heiner Kallweit , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Maxime Chevallier Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, =?UTF-8?q?Bj=C3=B8rn=20Mork?= , Jonas Jelonek Subject: [PATCH net-next v7 1/2] net: sfp: apply I2C adapter quirks to limit block size Date: Thu, 7 May 2026 09:33:00 +0000 Message-ID: <20260507093301.1144740-2-jelonek.jonas@gmail.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260507093301.1144740-1-jelonek.jonas@gmail.com> References: <20260507093301.1144740-1-jelonek.jonas@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The SFP driver assumes all I2C adapters support reading and writing the pre-defined block size SFP_EEPROM_BLOCK_SIZE of 16 bytes. This constant was probably chosen based on good guesses and known limitations of a range of I2C adapters and SFP modules. However, I2C adapters may even support less and usually need to specify this via I2C quirks. Theoretically, such an adapter may provide full functionality but only support a read and write length of e.g. 8 bytes. Currently, the SFP driver doesn't account for that. Add handling for I2C quirks in SFP I2C configuration taking the fields max_read_len and max_write_len in struct i2c_adapter_quirks into account to further limit the maximum block size if needed. Signed-off-by: Jonas Jelonek Reviewed-by: Maxime Chevallier --- drivers/net/phy/sfp.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index bd970f753beb..e58e29a1e8d2 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -807,21 +807,29 @@ static int sfp_smbus_byte_write(struct sfp *sfp, bool= a2, u8 dev_addr, =20 static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c) { + size_t max_block_size; + sfp->i2c =3D i2c; =20 if (i2c_check_functionality(i2c, I2C_FUNC_I2C)) { sfp->read =3D sfp_i2c_read; sfp->write =3D sfp_i2c_write; - sfp->i2c_max_block_size =3D SFP_EEPROM_BLOCK_SIZE; + max_block_size =3D SFP_EEPROM_BLOCK_SIZE; } else if (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_BYTE_DATA)) { sfp->read =3D sfp_smbus_byte_read; sfp->write =3D sfp_smbus_byte_write; - sfp->i2c_max_block_size =3D 1; + max_block_size =3D 1; } else { sfp->i2c =3D NULL; return -EINVAL; } =20 + if (i2c->quirks && i2c->quirks->max_read_len) + max_block_size =3D min(max_block_size, i2c->quirks->max_read_len); + if (i2c->quirks && i2c->quirks->max_write_len) + max_block_size =3D min(max_block_size, i2c->quirks->max_write_len); + + sfp->i2c_max_block_size =3D max_block_size; return 0; } =20 --=20 2.51.0 From nobody Sat Jun 13 13:02:51 2026 Received: from mail-lf1-f53.google.com (mail-lf1-f53.google.com [209.85.167.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A13AB3C3438 for ; Thu, 7 May 2026 09:33:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.167.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778146408; cv=none; b=H9TH3Vr/C1dxwjT54P3N93qsn1IzC39PuDTUHTQzfU/RnD3ht+E7RFNE3Y/AEaoKQXvHcxuOGaByRaOOU/TjYxCcmMWvziEysCS1d+E3NvaZ7pDkRq1N/1/aR5IJuaHj2JCWxOgrUarOvldeRkTCtQL8qtxGR7hUdQZuatoEEjA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778146408; c=relaxed/simple; bh=hwOefSuycVQmiVAMd3uRl8u0JpsRLLcPXRmMrv22KjI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YPOAGCfnx4xZRuFzGgNIxZ6/rk/AvOsB+faeRE7iCm16qm8BjGmgGdCTazXx5x2BBH80Hm+bh/tD+6DQXJSRIqPPKXgiK+LCA8Tm50TdrwOSDfz9Juvmq5736XszzP6VOPVdaQ6A9d2ynrGLKXiF3MgiakwNtXpy484v/niB+IA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=pDiHH4JW; arc=none smtp.client-ip=209.85.167.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="pDiHH4JW" Received: by mail-lf1-f53.google.com with SMTP id 2adb3069b0e04-5a86bfa2a4eso763659e87.1 for ; Thu, 07 May 2026 02:33:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778146403; x=1778751203; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=hhP2G5VzPxePJc3qtDjKU5GQ2mK7j5Q09lX9BYrFj3c=; b=pDiHH4JWQUHAPQk9Q/sI5O8E9a1JmnqBCWdJHPaZ4oCF+JCRHklIN1xHqo/8ARRZXe nf+5mjQePgDoory9NSuPYZEQuU5ThwEqvlk5OW0seZk833JkaqjOgK582lT1XqKbAI8R U4/gFTRJEsDT0icoQfHxkj0igQi3rTdKEF97N+hXKZ0f7yqcGIen74F818WMuKeWglTj ENhbxmX98A3HZLIu+IBXNTc6PHoNZUw12wxOs4RJzmsGKwWTc46iigUf5k0wpJCaknH+ 4UEbCdEbTK3ZhYXnPcnO6PLfAjFxfoJ3PuK8X77L4JG+KFKRvjIiEmYSy2rjV3qViXo5 qtbg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778146403; x=1778751203; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=hhP2G5VzPxePJc3qtDjKU5GQ2mK7j5Q09lX9BYrFj3c=; b=kF9EX/pJW3ZgG+BqB6oCOklq/xsNaFYBt/5P/ma6eXR6rJ34HTV9Ai0ICj7UzrPJrL 67uDkvxOAEDK41+F5Lt9XsvZnC0aPRDuHmx8HC30rTCkO+8FFMFfrpCcCCr4lOWMferJ HiC2zkP6XfjSub2DW9Cobi/F/hdwv76LYYr/YLaJ37UQcICrGYMFTPj52q/31T6jn9CD F951vbxb/TmjK71tzIeh6fc3cXnwWJULO9hW5zkQNSW7H026YkLFUE+rmM1kT0RomSrK ZzcQwmXT3cQBBRISyNL3qvztD2HRUydkZvP20Xl+1eeVQEJaaOvmkbkrne6YZK6PadXw l1+A== X-Forwarded-Encrypted: i=1; AFNElJ8bJk41IipoSWTcpM8VDkuvD4y1MJCM34buKKpgSGQpqKb1h4H8QGJ6kddsPJ770pTD1ALuT66ZwEzO7fg=@vger.kernel.org X-Gm-Message-State: AOJu0YwpjBXdid/xQ9ggWRL7Zgx55xdT9AgUUk7zdB64DKl0cuWvfm6p c1DuATpMTFRhYxmqBeX836oMLa38hXWk7VvuBNdjZsV6NIziygQ6T5AM X-Gm-Gg: AeBDieuETEDLzlZawrI9ZTp6ifUS1HkfJlHbpcMWgjymUX+V3jPWxBM0MZ3l9wdcUtQ /PJ6hYGeuC0bT6eFqtZ3ov72ggkwRWpt0Wu4qmnVonDjvF+f3tHXmdgxTIey2Q0P/8Eped1aB9A Lt6oOIW1WUkV8NJsILC2HmF50pDM3iODfgo2/N6Lrd/kQ+Y4VHqafUd0kX7WiIp/aZ3ylztKuHq CXtDOJBQHdLxTO8X5ZlpMifOwdoB6wnQSfFJTl9QwHHAED0SYN7b7C8Yyp2yq4iym4OlQPt17pJ NLzJ2pmru2xKDMW9lVGqZpme8lbA1ddORyGEjzkSGDMeZoWttSzeCkXqHwiLsElRsyo08Cxz8+G GRA6/4eVsE1hQ9x7DuNOJ03XjBsGoyaJ8UTYHk9Gf1GFRAVdU19xsd0VLh1JyzKwjv36U7xQh8H AR2XEJ2KIbmiq90Q/OKyixGFEFVCY3NLayTJP9 X-Received: by 2002:a05:6512:3c85:b0:5a8:6cbc:60f3 with SMTP id 2adb3069b0e04-5a887ced391mr2447872e87.34.1778146403074; Thu, 07 May 2026 02:33:23 -0700 (PDT) Received: from builder ([2001:9e8:f13c:9216:be24:11ff:fe30:5d85]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-5a864c6f16esm4752445e87.15.2026.05.07.02.33.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 May 2026 02:33:22 -0700 (PDT) From: Jonas Jelonek To: Russell King , Andrew Lunn , Heiner Kallweit , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Maxime Chevallier Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, =?UTF-8?q?Bj=C3=B8rn=20Mork?= , Jonas Jelonek Subject: [PATCH net-next v7 2/2] net: sfp: extend SMBus support Date: Thu, 7 May 2026 09:33:01 +0000 Message-ID: <20260507093301.1144740-3-jelonek.jonas@gmail.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260507093301.1144740-1-jelonek.jonas@gmail.com> References: <20260507093301.1144740-1-jelonek.jonas@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Commit 7662abf4db94 ("net: phy: sfp: Add support for SMBus module access") added SMBus access for SFP modules, but limited it to single-byte transfers. As a side effect, hwmon is disabled (16-bit reads cannot be guaranteed atomic) and a warning is printed. Many SMBus-only I2C controllers in the wild support more than just byte access, and SFP cages are often wired to such controllers rather than to a full-featured I2C controller -- e.g. the SMBus controllers in the Realtek longan and mango SoCs, which advertise word access and I2C block reads. Today, they cannot drive an SFP at all without falling back to the byte-only path. Extend sfp_smbus_read()/sfp_smbus_write() so that, in addition to the existing byte access, they also use SMBus word access and SMBus I2C block access whenever the adapter advertises them. Both directions are handled in a single read and a single write helper that pick the largest supported transfer per chunk and fall back as needed. I2C-block is preferred unconditionally when available: the protocol carries any length 1..32, so it can serve every chunk -- including the 1- and 2-byte tails -- without help from word or byte access. Note that this requires I2C_FUNC_SMBUS_I2C_BLOCK, which reads a caller-specified number of bytes. This deviates from the official SMBus Block Read (length is supplied by the slave) but is widely supported by Linux I2C controllers/drivers. Capability matrix this implementation supports: - BYTE only: works (unchanged behaviour); 1-byte xfers, hwmon disabled. - BYTE + WORD: word for >=3D2-byte chunks, byte for trailing odd byte. - I2C_BLOCK present (with or without BYTE/WORD): block as the universal transport for every chunk. - WORD only (no BYTE/BLOCK): accepted with WARN_ONCE. Even-length transfers work; odd-length transfers (e.g. the 3-byte cotsworks fixup write) hit the BYTE branch which the adapter does not implement, so the xfer returns an error and the operation is aborted. No mainline I2C driver was found to advertise WORD without BYTE; the warning lets us learn about it if it ever shows up. Adapters with asymmetric R/W capabilities (e.g. only READ_I2C_BLOCK but not WRITE_I2C_BLOCK) remain functionally correct -- the per-iteration fallback uses the direction-specific bits -- but the shared i2c_max_block_size is sized by the all-bits-set check, so a transfer in the better-supported direction is not upgraded. None of the mainline I2C bus drivers surveyed during review advertise such asymmetry; promoting i2c_max_block_size to per-direction sizes can be revisited if needed. Signed-off-by: Jonas Jelonek Reviewed-by: Maxime Chevallier --- drivers/net/phy/sfp.c | 134 +++++++++++++++++++++++++++++++++--------- 1 file changed, 107 insertions(+), 27 deletions(-) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index e58e29a1e8d2..16d41d7ee632 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -14,6 +14,7 @@ #include #include #include +#include #include =20 #include "sfp.h" @@ -756,50 +757,110 @@ static int sfp_i2c_write(struct sfp *sfp, bool a2, u= 8 dev_addr, void *buf, return ret =3D=3D ARRAY_SIZE(msgs) ? len : 0; } =20 -static int sfp_smbus_byte_read(struct sfp *sfp, bool a2, u8 dev_addr, - void *buf, size_t len) +static int sfp_smbus_read(struct sfp *sfp, bool a2, u8 dev_addr, void *buf, + size_t len) { union i2c_smbus_data smbus_data; u8 bus_addr =3D a2 ? 0x51 : 0x50; + size_t this_len, transferred; + u32 functionality; u8 *data =3D buf; int ret; =20 - while (len) { - ret =3D i2c_smbus_xfer(sfp->i2c, bus_addr, 0, - I2C_SMBUS_READ, dev_addr, - I2C_SMBUS_BYTE_DATA, &smbus_data); - if (ret < 0) - return ret; + functionality =3D i2c_get_functionality(sfp->i2c); =20 - *data =3D smbus_data.byte; + while (len) { + this_len =3D min(len, sfp->i2c_block_size); + + if (functionality & I2C_FUNC_SMBUS_READ_I2C_BLOCK) { + smbus_data.block[0] =3D this_len; + ret =3D i2c_smbus_xfer(sfp->i2c, bus_addr, 0, + I2C_SMBUS_READ, dev_addr, + I2C_SMBUS_I2C_BLOCK_DATA, &smbus_data); + if (ret < 0) + return ret; + + memcpy(data, &smbus_data.block[1], this_len); + transferred =3D this_len; + } else if (this_len >=3D 2 && + (functionality & I2C_FUNC_SMBUS_READ_WORD_DATA)) { + ret =3D i2c_smbus_xfer(sfp->i2c, bus_addr, 0, + I2C_SMBUS_READ, dev_addr, + I2C_SMBUS_WORD_DATA, &smbus_data); + if (ret < 0) + return ret; + + put_unaligned_le16(smbus_data.word, data); + transferred =3D 2; + } else { + ret =3D i2c_smbus_xfer(sfp->i2c, bus_addr, 0, + I2C_SMBUS_READ, dev_addr, + I2C_SMBUS_BYTE_DATA, &smbus_data); + if (ret < 0) + return ret; + + *data =3D smbus_data.byte; + transferred =3D 1; + } =20 - len--; - data++; - dev_addr++; + data +=3D transferred; + len -=3D transferred; + dev_addr +=3D transferred; } =20 return data - (u8 *)buf; } =20 -static int sfp_smbus_byte_write(struct sfp *sfp, bool a2, u8 dev_addr, - void *buf, size_t len) +static int sfp_smbus_write(struct sfp *sfp, bool a2, u8 dev_addr, void *bu= f, + size_t len) { union i2c_smbus_data smbus_data; u8 bus_addr =3D a2 ? 0x51 : 0x50; + size_t this_len, transferred; + u32 functionality; u8 *data =3D buf; int ret; =20 + functionality =3D i2c_get_functionality(sfp->i2c); + while (len) { - smbus_data.byte =3D *data; - ret =3D i2c_smbus_xfer(sfp->i2c, bus_addr, 0, - I2C_SMBUS_WRITE, dev_addr, - I2C_SMBUS_BYTE_DATA, &smbus_data); - if (ret) - return ret; + this_len =3D min(len, sfp->i2c_block_size); + + if (functionality & I2C_FUNC_SMBUS_WRITE_I2C_BLOCK) { + smbus_data.block[0] =3D this_len; + memcpy(&smbus_data.block[1], data, this_len); + + ret =3D i2c_smbus_xfer(sfp->i2c, bus_addr, 0, + I2C_SMBUS_WRITE, dev_addr, + I2C_SMBUS_I2C_BLOCK_DATA, &smbus_data); + if (ret < 0) + return ret; + + transferred =3D this_len; + } else if (this_len >=3D 2 && + (functionality & I2C_FUNC_SMBUS_WRITE_WORD_DATA)) { + smbus_data.word =3D get_unaligned_le16(data); + ret =3D i2c_smbus_xfer(sfp->i2c, bus_addr, 0, + I2C_SMBUS_WRITE, dev_addr, + I2C_SMBUS_WORD_DATA, &smbus_data); + if (ret < 0) + return ret; + + transferred =3D 2; + } else { + smbus_data.byte =3D *data; + ret =3D i2c_smbus_xfer(sfp->i2c, bus_addr, 0, + I2C_SMBUS_WRITE, dev_addr, + I2C_SMBUS_BYTE_DATA, &smbus_data); + if (ret < 0) + return ret; + + transferred =3D 1; + } =20 - len--; - data++; - dev_addr++; + data +=3D transferred; + len -=3D transferred; + dev_addr +=3D transferred; } =20 return data - (u8 *)buf; @@ -815,10 +876,29 @@ static int sfp_i2c_configure(struct sfp *sfp, struct = i2c_adapter *i2c) sfp->read =3D sfp_i2c_read; sfp->write =3D sfp_i2c_write; max_block_size =3D SFP_EEPROM_BLOCK_SIZE; - } else if (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_BYTE_DATA)) { - sfp->read =3D sfp_smbus_byte_read; - sfp->write =3D sfp_smbus_byte_write; - max_block_size =3D 1; + } else if (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_BYTE_DATA) || + i2c_check_functionality(i2c, I2C_FUNC_SMBUS_I2C_BLOCK)) { + /* Either protocol alone covers any length: I2C-block carries + * 1..32 bytes per xfer, byte iterates one byte at a time. + */ + sfp->read =3D sfp_smbus_read; + sfp->write =3D sfp_smbus_write; + + if (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_I2C_BLOCK)) + max_block_size =3D SFP_EEPROM_BLOCK_SIZE; + else if (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_WORD_DATA)) + max_block_size =3D 2; + else + max_block_size =3D 1; + } else if (WARN_ONCE(i2c_check_functionality(i2c, I2C_FUNC_SMBUS_WORD_DAT= A), + "SMBus word-only adapter; odd-length transfers will fail\n")) { + /* Word-only: even-length xfers work; odd-length xfers fall + * to BYTE, which the adapter does not advertise and will + * likely fail. + */ + sfp->read =3D sfp_smbus_read; + sfp->write =3D sfp_smbus_write; + max_block_size =3D 2; } else { sfp->i2c =3D NULL; return -EINVAL; --=20 2.51.0