From nobody Sat Jun 13 19:03:53 2026 Received: from mail-wm1-f41.google.com (mail-wm1-f41.google.com [209.85.128.41]) (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 EA89F3DB64A for ; Tue, 5 May 2026 20:06:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778011617; cv=none; b=Klec7WHf3Y9X6Ly4Ikza+95fSFHYxyp5aGPs65n6wTiM23tmpM+JhhLmpr3JgD2XND+qYn2ZunDnubzC+wTjFsz4c2oNwLTjCPwO+l9DWS1x3k8oso7AFAhySYFQWx6kN36COZ2rRW8z3W9p5w24zUhj49ydL2h7gQB3qFHnWGM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778011617; c=relaxed/simple; bh=VpoQujZ9GQMnf5nQHTEp2Qyqm03Jlz6XjLvYPy3uE5A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=eLl+yDR2jbUeVTchQCzyrKq/kOcYkLqZMK9cSEcDMA0qwbJcAYRI2yu3lyHV97MfFq4sOV/JQAxwQuzOyV4h96jG9QLk6vTBfLvm8JUY36jsd9cCORT9sXbcqhCxrR3CAOOMQ5XEL0Q2tu1Zgst6zLbVG6kqgS3cAe2+WONO43Y= 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=aWxCDt1R; arc=none smtp.client-ip=209.85.128.41 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="aWxCDt1R" Received: by mail-wm1-f41.google.com with SMTP id 5b1f17b1804b1-4891e86fabeso69253875e9.1 for ; Tue, 05 May 2026 13:06:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778011614; x=1778616414; 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=dIrvNnWJICom0gFogZEpaj6AR2Yk4bcfuHPYqmXxhME=; b=aWxCDt1R4Rw8NEFsOYsFIaucTAbRvEtwUQ3e3rZkrfFNRWER4L0wyfSuni5c3Ai1fw JslgXJS0IyAFXZ7d83YglLzIyfRc85OIUMGxWLGadyw9aKd/iBqg0OAOgdfNa30EvqJX QQsl/KN8YPuQ0/gdAZa+fH+0gKlL4Il3GgfuxlQ4hbzc6i4tJ/xfboXEIDm5IgFLuipd dOwfv8NsJakbs2ampDzZywkLKKRHJX9es/R8I12UsNFUItcH+LHAeM3LYpFdgow2ffBi MVLxr5gMD5zQaK1Vqn1MW7qbf25YF79/bqdVUa2eMSEEM2XKx3DnUivhiq8eD127xYdB aLeg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778011614; x=1778616414; 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=dIrvNnWJICom0gFogZEpaj6AR2Yk4bcfuHPYqmXxhME=; b=D2+R6L+ANV/00oUw32dFItA2XO6JwgJv5HABvXDpX1MWZEek7ZgpR/6z8F+3dgqhrB FmGlnHszYlrCgfnjgo7yVHrm8LX4ycDgKxgNiaP2YiOVZV95h1KC2pKN5qgk6+J94kvi 5W3tu29JOHs056z8BtAo8XNawhNzRobXm1t3OgeNlt4wVjzasOutlGYzEJrnyOHGm5gY ImPfbvtVdd4+fY9kykwpkIoJTw5M5zpHTyAGbVUPVYFxIOleXDQmrJZg2ISZQEmKu3lx 2tfdIqPL5WwkU0O3BtNLo7a598deoykgswWkBfEneLIM7b1MmXO/ujlZadDrKCYlkzHg ZKvQ== X-Forwarded-Encrypted: i=1; AFNElJ98amUhD1oWVruMd7gsDWPYu/WP3m5neAsteZkJ+jGNmUTi5865B0qekLNF/63+YnkNZIFdQN+2C0KypoE=@vger.kernel.org X-Gm-Message-State: AOJu0Yz3SbrcUn0FFN0cFP75Ex39AwbysfrpDN/iWrvQpgAC+akpJfAX phvaX9w52uefhK7BJhGMLka0gtg+wJGDMRecp+1JLO3Uyz2g18wOvfzz X-Gm-Gg: AeBDievkRYEkZcs5v26EmVdUadgVNwrYyrDWK/aANsVZFS0SWJjCDUIaO0IAN/YaY1B c56jo6t0cTlI9hGVI54N3RngkHMHQli6Hm/FR76ZKCcHSX0vV+u6mDNCBBAYsvef1C0nihvlnyA FPTe7ZEhD3Lz39tVX9YqPrGrysTBMHZw846suYIVm6ak77UdSNHpHlR9F/1wWq+HgTAliB6x+VQ ekzR0GSoedez2BltA1jhoGo0/6WAHRzVkgeYlgpIgk6Eamrv5jhbNO+GGRlSH55bfg+S9mWGU5N vJ2k1ykYyielTxnp+q4JOIl0YXB3QtkXOkEe2lbVLRq/8EE4CmS4wvnzu65lmVpxCxmDIPBuipe w8Uh1bWR3zbqZdL8geDsPogh7r9R6IsCY81wAyGsbWUFxnTlkPzpjSS3Gvjz0nmWdjoS69yFCzW PHRZUfKkMl09xU1WrvYLoZiy0SzTTmKMf7pAuV X-Received: by 2002:a05:600c:4512:b0:489:284:44ab with SMTP id 5b1f17b1804b1-48e51e1deedmr11519335e9.12.1778011614325; Tue, 05 May 2026 13:06:54 -0700 (PDT) Received: from builder ([2001:9e8:f130:ed16:be24:11ff:fe30:5d85]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-45055f2203csm7049511f8f.37.2026.05.05.13.06.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 May 2026 13:06:54 -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 v6 1/2] net: sfp: apply I2C adapter quirks to limit block size Date: Tue, 5 May 2026 20:06:46 +0000 Message-ID: <20260505200647.1125311-2-jelonek.jonas@gmail.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260505200647.1125311-1-jelonek.jonas@gmail.com> References: <20260505200647.1125311-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 19:03:53 2026 Received: from mail-wm1-f41.google.com (mail-wm1-f41.google.com [209.85.128.41]) (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 DD35A3DBD70 for ; Tue, 5 May 2026 20:06:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778011618; cv=none; b=Vl9RQKMjx8mcGHeINUeF4OS447Lkta8ZoDlm0r8e5PhXE2Twh5YN3FLOxaotsTjJ2LVLetl1padikv7+uEX8nosGUGVxgtIi8r4il/wY65uByQnJRTZPAWtWbjgB8XXZhWBSFd3ZRJ+zSvkn8PMsQhFCHvxxDrGkc3Gw93oFiz0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778011618; c=relaxed/simple; bh=/6dzk1jr+79SJHIdMSRwnwDs2x3cGknf33OZc7Jj+l0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=GPdq1Wa+EDI8yiY5/fy3c8q+SvzzstQrvvcQXU/2KYwXuomPUHvaj6vJFKG07StMzc+fXqBS3kPimTe/FZXhvrq9q/QmNJhSm7NSDJ/HdesYt4T9p8FvpsHcrJn4+hSi5mA6AKu83oI8Q4nUCA+R4XpQONQp+882JPARTXhufjs= 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=H3C1alNf; arc=none smtp.client-ip=209.85.128.41 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="H3C1alNf" Received: by mail-wm1-f41.google.com with SMTP id 5b1f17b1804b1-488ad135063so53825405e9.0 for ; Tue, 05 May 2026 13:06:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778011615; x=1778616415; 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=dvQM/tenYkxEUMoprI80x3BX3qXYZMNrSMzU+mvDCJQ=; b=H3C1alNflMKw5MIArki5Shn5gi7c9vQarm8Q7DDUyhWmKPP2tqXzvvrt35FZl5Et9s o4fO+5hykYfARy9DrO85mxa+h/69Ier5jDkRIV0MZKaDX7m3FDhtOn3BgeeNmToL8drk 6vbCqATui69QjKmghUtpnnlZrGzXUheEeSs7EL5jj7+nNvLRLOTQmRynWTWqaEoM/iwi x+VncmYQRwEQia2cSFWIVemxWzkzw7P+w1MAyJNFAwxmCLNzPNvnQevR9bgX2O8YPRQu SdCvZ4LGNlROdPi453MZDCbWvONAFQUCgU5j2UhAkcXPACQ3yd3VogMbNXfn2QXE7Nr0 /3WA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778011615; x=1778616415; 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=dvQM/tenYkxEUMoprI80x3BX3qXYZMNrSMzU+mvDCJQ=; b=HQVVVY2mIAVHqy07m4bxqZzbFTi8t1OB6xZGdYKVjmCnk0SpdjRhuhKMWHvjAwvnxS vsYDMd5uXkMBc1WDmE2f67uuwKoJ2Q2kOZPG3Gd7CmSzNAow54hjF77Pvezn8op7T5+D WYNz2RXfJTyIljdbTLkG77lWVzdMYIu02mlTKHc/OhZbEusjPPsFFswNfltB+GjjBI3m cVxGwGC346lZp5CrZuhD89bfvSgr6NnObqC27xybUe8apfUCqHWnFQkL96wOdBu/zzBn VT2sJinViOroiAt8VC7UHErXU+bofn3yb/Enm30UPlWIBYjAXwR9DM2VN5lmamHe9D3+ Yt+g== X-Forwarded-Encrypted: i=1; AFNElJ/bm657gTnC/1a3R37GanQRlnFu7aR8KBM1C8oqIJpxANRs8uV2dHHAiqhndYhTy2sAbrajJpOYqJ76qj4=@vger.kernel.org X-Gm-Message-State: AOJu0YyYC61C2/2im4YROzo4ggl4Z+1nf6/eJzhPhuLkxxw9jL0gaSLm sIKK8gtufkoYxR2M4P4Lb8o3N85X4K0ZbKy8fgHtVIhQVN5HqzYLavo1 X-Gm-Gg: AeBDievVEGbS0HJH5TSbDcoxNm0ObKmNc6ugECGcGauegogJEP4nv3q4cGhXBqSalQy pv2cST/Z7IjVRKsGfB7tqB4l1RDYql0pG0NlSGEeuGKWrMPC+XoLHiVy0g2xssKCMdRO/R8hbJZ xTSQu4ByV2C0Ahqlki+/hr6uaSK5WqaKwXT9wdyiWEM0vI19L3XdwAU9FwH1FwZLfPdDNkyQtcm OEuiOx+hQk5JRmaa8Ol1X8lcNmL3uXnX42IpWJpmz5PSSCwwdUZo5e0jQCUxACYCzpX9ZEHexHk NLxDVz29uNlC1BO4gcEIZ8Juv97aOEkHumrIWjrfDMA5iydZPM4ERxQjWHsPuLB5slKioihDRwO tOeL5DLihw/NvOw7F8JafWpTJTEF7nZ5VzxGfO74R3pwHa6r+JOdeUrEPpyD/aFstM/35XslV8u L/XTR31MVQU5z9Kvxf1wHb7ABvjPHjLX7BS98k X-Received: by 2002:a05:600c:8485:b0:488:af7f:775f with SMTP id 5b1f17b1804b1-48e51f32a64mr11647685e9.18.1778011615158; Tue, 05 May 2026 13:06:55 -0700 (PDT) Received: from builder ([2001:9e8:f130:ed16:be24:11ff:fe30:5d85]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-45055f2203csm7049511f8f.37.2026.05.05.13.06.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 May 2026 13:06:54 -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 v6 2/2] net: sfp: extend SMBus support Date: Tue, 5 May 2026 20:06:47 +0000 Message-ID: <20260505200647.1125311-3-jelonek.jonas@gmail.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260505200647.1125311-1-jelonek.jonas@gmail.com> References: <20260505200647.1125311-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 --- 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..8ad650cbe862 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_max_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_max_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)) { + /* I2C-block carries any length 1..32, byte serves the + * 1-byte tail when block is absent: either alone is a + * complete transport. + */ + 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 (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_WORD_DATA)) { + /* Word-only: even-length xfers work; odd-length xfers + * will error out at i2c_smbus_xfer(). + */ + WARN_ONCE(1, "sfp: SMBus word-only adapter; odd-length transfers will fa= il\n"); + 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