From nobody Mon Jun 15 10:30:37 2026 Received: from mail-wm1-f50.google.com (mail-wm1-f50.google.com [209.85.128.50]) (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 C3DFB3845BD for ; Fri, 12 Jun 2026 14:28:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781274536; cv=none; b=QXnu6/GXYtHB+vWDWWd5NlQ3wrMwCJZB8Tp5k95XUi6ajuuaLmeNHOMPnkJZxqY7GaXo61GNpfTwFO5wM1AtXW9nqmmN1vFd9zByqIiBI+bR9y1nGbiCexUY+YEfSWX5ddNQAHJXEAKH3n/Eegwf1VjOVM9dmIQuD5Xiwd4a/NI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781274536; c=relaxed/simple; bh=vC7gffF3nph/f7RymsI38P5G/8V/ZI0hrB57Y33Oh98=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pJcWUKPsiFpgYF+Z7DImzfOzrCYptT2HSx/7lH8KteeiOMpbNY1WGV3HUuCJbs7MCSkIfmurvA+5nuhNhKAPQuV4FoATyNC+VRwG1Rh9kkr162i0R3EXF0VAOkBIdauHc5Gtf8IKk8Z1Z0WLGh3WerwkWUEhOBXridwxdR4Y0eE= 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=jS0PMIoc; arc=none smtp.client-ip=209.85.128.50 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="jS0PMIoc" Received: by mail-wm1-f50.google.com with SMTP id 5b1f17b1804b1-490be29c1c5so10969745e9.2 for ; Fri, 12 Jun 2026 07:28:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1781274533; x=1781879333; 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=eyKTqLVZ2GkXstSMIq5XRH7NFzj7gG6vhpUIFQhTa+U=; b=jS0PMIoc1Q2pWxVlSTpLSuUL5lz0R37odqre6Epg/QOPbAza2D/2fUa1p/OZFSP0gU RssVM+LvUU5ysGj3tJx3kbuxU0noLJUKA9J5HcZJpQv3L1GTD8UIVWeWeQ60scY7jQyu dBOyITszDNAqtrx+cM1p2WX/omzKHhwDaSnSzjlVK4oCgYUBIr7Q3X0Cv+mvBh9P6FWh fOmg6S+4m+J5NIHOwbBsxzIUdjWs+DykihhZjLWv0JGeqr8y4A29tm8sg011dYCx0dNU 2QtRKUyBvmJNhnYuBOS0XBJl/6ETex51OJs9ltzCfQ+oDV2XXifS3+afGrIHWTp4BCqn RRtg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781274533; x=1781879333; 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=eyKTqLVZ2GkXstSMIq5XRH7NFzj7gG6vhpUIFQhTa+U=; b=V4LyH95mvTsV7Dp/S3dkazEK4qzKrA5NK9YoSPmC7frAAQDjemW8CJbw+SSeYXmytB kcW8tDzH7d8O/32LvVQch493xTZmqpqUrcsmJjCa6wjvGNbBMmgZKtjrF5MbIRjQjhIw Z6CG6sqHVkzBErpEfrPWeqd2BmMSJRPRtqdCx40HpKp3K5t/OCfRoqX7M9iEtiC4Sdcs rveCaZcQRqQlWeczsmBe+wgqfxwQVM2x1gszq5J30Y9H2vX+Zi4xoVT4iPDGD3FykQqr pjavYfvXPzkktAYu0OCA6jl/Lo5/fUqYEebhM2Fv9sH3yFY2hlcX1q/JkzqyZnpCffzg JT/Q== X-Forwarded-Encrypted: i=1; AFNElJ+rbV2aEE/xW3KSsT+4piuyo+mB0TBH6veCntMwwcWxy+/NrzU3I/n0kkTLv07Kh+64PUO25T8TBriTxYU=@vger.kernel.org X-Gm-Message-State: AOJu0YwTjC5kYeoSIkhzpfZw81igehKyiDMBGK9st7a9Xp5Dvk8PSqYF MmSwOT3TRJIaniopX7GD/SNUxbmMy+Jusea2SICrMSGuv3lhOout9Ge7 X-Gm-Gg: Acq92OGWSXNO03kDSqhZ4OX3IyTUZbQle4U1npladg0AYjbiLHP6B6/K/MOe8cevqkA gNtGNh3n2sLbaJs96WByQ515Jxk3HM9aDMaCeDFqBwKQ7I2wba5EuYDIgnq4hmR6rp6+ZkyyhRQ sTh6MkcKgomFGrOV+MMJ504pcCn0zFyg8fBkOSzUuqen8jUezXdct8C2UNAybTmZYsm6O64zYJT /tl1+XNinP0SP0SgyjTY79HtKeG5EU55JMNu2TQGWMI71IgphTiVaXbRJUI5mfKJGzE4d5MtCai xKgapc3cdGVFfAYyeiZDUwQz8qCqBaG4pacoHkFyKCkLzc0JeL+7Rx/BGDBptg8G2+naIuOc9nv 0gZ7tOios2FhVwCgjcbl5Z/q9dfd5ICqGbOxqrPx5cncFB+Asn+jJmKeUBp78RDEMc51Q3vmKSs YIt1F2mCcNaVqyvker0YQ7tXsz6A== X-Received: by 2002:a05:600c:314a:b0:490:da12:f1fa with SMTP id 5b1f17b1804b1-490ec503f0cmr38320045e9.31.1781274532909; Fri, 12 Jun 2026 07:28:52 -0700 (PDT) Received: from builder ([2001:9e8:f11c:fd16:be24:11ff:fe30:5d85]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-490e2c0d360sm175410705e9.0.2026.06.12.07.28.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Jun 2026 07:28:52 -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?= , Simon Horman , Jonas Jelonek Subject: [PATCH net-next v10 1/2] net: sfp: apply I2C adapter quirks to limit block size Date: Fri, 12 Jun 2026 14:28:39 +0000 Message-ID: <20260612142840.462664-2-jelonek.jonas@gmail.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260612142840.462664-1-jelonek.jonas@gmail.com> References: <20260612142840.462664-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 18f2584dbe7b..3c232991faa1 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -810,21 +810,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; sfp->i2c_block_size =3D sfp->i2c_max_block_size; return 0; } --=20 2.51.0 From nobody Mon Jun 15 10:30:37 2026 Received: from mail-wm1-f52.google.com (mail-wm1-f52.google.com [209.85.128.52]) (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 621CA388E51 for ; Fri, 12 Jun 2026 14:28:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781274537; cv=none; b=nJyUcUXR7A3D6Q/GTo2LTJiUf2skcsQn/1P8+OAe4HHyjGT4GftXQFG2sAVIzioBPWK8vBuGGTdqzV97VQAjK8gxVF9DOJ/rtXV/wcvV+ghprDAlzBAIU4S3WFiXMd8HBVUM9VtrIwHWZCSLwGhT+ZYbd39KyEI5VhnRAsHrmXw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781274537; c=relaxed/simple; bh=drYtyk8sa8FtyY+He0WDGl1ZCXxmi2hMWg4so7bVPYE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=p696knk9CAgHS4NHhj52/C66RomFNMItoE+Nt2+vvu+2o/6W6knx7yF9ee8gF5AzyIhLNky3P9R1tvx0w8CIZEUZzFoic4bDEOTa9Ejx+8cDUrJcPAO6ofAkjRMTj50doTYN/TWNpraj3U7lA5OeHHFlOIQut8KCp0jylSFy4UQ= 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=YuQFOLBF; arc=none smtp.client-ip=209.85.128.52 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="YuQFOLBF" Received: by mail-wm1-f52.google.com with SMTP id 5b1f17b1804b1-490ac10e337so6854035e9.3 for ; Fri, 12 Jun 2026 07:28:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1781274534; x=1781879334; 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=IJHkOnPoCLmJvnRHd2fhpyqTWYKMhK9N637R6tbusLw=; b=YuQFOLBFSpaCjl+UlpAtWR8++gBhHBSTxV2JwIv6+myWkMc7jy2sKPOpikBBchX1dZ Ydv85PRXIgus4pP7wfTJviSMxANQxNdAFsURjn5xMCBq95cxTvF0EUKT5VtfiKg7QuOG Sd1aucRsql8USc8RP110ZqX1VWhx2HhALwEj12WUvwYi1OTTP9hvCt1EZn3BuXog7aQZ Zh3EwAub44Lg8Z4F+iEaRV+ZxBhaHWj4HejOgb4mV/DjgqroWM2YdU3NR8CjDt/T/GV5 b4yos/ovuksDPfcpfAW4urpUm4R4VwiGZL4WOFV49UshcNGQV4z4IajOK8jeOoSyaVx5 D6fQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781274534; x=1781879334; 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=IJHkOnPoCLmJvnRHd2fhpyqTWYKMhK9N637R6tbusLw=; b=S8uFmhiew3NP8xFTPkA30JtDyD2MPIW98Ocxaf9UuqNnYLYGO84OcQGMYri7kYxk2s tuf2p9vNCRoi/K3RSOXmpFsQCV1a4znbbnLxqKJiT+aJnQltyWcjmEjR8/Ikp9bu0G+A LHFEqw8xLvUKQcvi+twIpiLPlIj6+Fv1ssKwNnl4MaD361ewNSfBgrRbPKm4wKy7FOln 4EyMp4WCQMjxBtk4QPAkLorsPBIHhvh4GKwTAduCWGZd9XwvqqF6YbxDEuqIsZa1Mtac JruhHDrCYJHiUD6367CAghP/bAB8z6ilRBVX/ohFtCfq0rbajw34to0+VqQdyu5CeBP4 6vDQ== X-Forwarded-Encrypted: i=1; AFNElJ8Z81qKnrqfa1HNbV+lVHKLatK/3OyURhe5X/HXwUDw+uivHRfUdvMRKto1V0704sMFSyAZb3JcuDMTP8w=@vger.kernel.org X-Gm-Message-State: AOJu0YyucgGktr3OOFySmaZntOgZU4NMqf+PhOcR91N43ffbx0UsLqvf tZ+VYROrBv4IguMZ+nXJFZQ5RAgDYrurbJFvIOHCnXkdDBplRdRwgWDT X-Gm-Gg: Acq92OEYo+wwLJUviYVigrAW/Y2zoHn7A9/mRZqrShoYdvy4CO2orDg3+dlhz2Q4UwC 84mZ0u6lj04nMNQpW0Q0cO3yOzFMmFWgnA6esioHItuKAFeavYkiXjopcuJOWfcxiSRgu9Ma/md OKXoSOd95q+G3c2YWImyJMrktPBkI1s50MpCumUow5fntLHykOIvUgT1eZnGFGARU4ATdykYGW8 xVi0w/aArFHZ8WFGcb4n/GbtA5cAmqc1Fr6OWVDlOvxkt2z9jOzcjLySLSUyEwSgAioAedzWk7o 3HBwh7AoL/s/JUM5ICG5LOh0VZi0cIbHnq6U2GqdyUg581hkNojmeUQlUGXKR1nI0hEgjLEnqf6 AukUqyzE9HysN5cxDsrgViptl4z5iUz6a6FH2mN+8n3+JRvQzUCFjWpQafZRCPYRGC/LHzGwNcv e4JZkgghGh0M1AxonX3v/3rba+9A== X-Received: by 2002:a05:600c:3586:b0:490:c024:2ec8 with SMTP id 5b1f17b1804b1-490ec339ec0mr49511075e9.0.1781274533730; Fri, 12 Jun 2026 07:28:53 -0700 (PDT) Received: from builder ([2001:9e8:f11c:fd16:be24:11ff:fe30:5d85]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-490e2c0d360sm175410705e9.0.2026.06.12.07.28.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Jun 2026 07:28:53 -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?= , Simon Horman , Jonas Jelonek Subject: [PATCH net-next v10 2/2] net: sfp: extend SMBus support Date: Fri, 12 Jun 2026 14:28:40 +0000 Message-ID: <20260612142840.462664-3-jelonek.jonas@gmail.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260612142840.462664-1-jelonek.jonas@gmail.com> References: <20260612142840.462664-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 | 136 +++++++++++++++++++++++++++++++++--------- 1 file changed, 108 insertions(+), 28 deletions(-) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 3c232991faa1..b9046b833fc4 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" @@ -759,50 +760,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; + union i2c_smbus_data smbus_data =3D {0}; 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; @@ -818,10 +879,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