From: Jonas Jelonek Date: Tue, 16 Jun 2026 08:20:52 +0000 (+0000) Subject: realtek: replace pending SFP patches with backport X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=24ec5ff687f2b45abcf06400766420ecc46e0535;p=thirdparty%2Fopenwrt.git realtek: replace pending SFP patches with backport The SFP SMBus patches to access SFP modules with more than just byte access have finally been accepted upstream. Replace them with the upstreamed version, reorder them before our still downstream SMBus MDIO patches and refresh all. Link: https://github.com/openwrt/openwrt/pull/23825 Signed-off-by: Jonas Jelonek --- diff --git a/target/linux/realtek/patches-6.18/705-v7.1-net-sfp-initialize-i2c_block_size-at-adapter-configu.patch b/target/linux/realtek/patches-6.18/705-v7.1-net-sfp-initialize-i2c_block_size-at-adapter-configu.patch new file mode 100644 index 00000000000..c252aa95a05 --- /dev/null +++ b/target/linux/realtek/patches-6.18/705-v7.1-net-sfp-initialize-i2c_block_size-at-adapter-configu.patch @@ -0,0 +1,41 @@ +From 56d0885514491e5ed8f7593400879ab77c52504c Mon Sep 17 00:00:00 2001 +From: Jonas Jelonek +Date: Thu, 28 May 2026 20:52:40 +0000 +Subject: [PATCH] net: sfp: initialize i2c_block_size at adapter configure time + +sfp->i2c_block_size is only assigned in sfp_sm_mod_probe(), which runs +from the state machine timer after SFP_F_PRESENT has been set. Between +those two points, sfp_module_eeprom() (the ethtool -m callback) gates +only on SFP_F_PRESENT and can be entered with i2c_block_size still at +its kzalloc'd value of 0. + +On a pure-I2C adapter, sfp_i2c_read() then issues an i2c_transfer() +with msgs[1].len = 0 inside a loop that subtracts this_len from len +each iteration; on adapters that succeed a zero-length read the loop +never advances, spinning while holding rtnl_lock. + +This was previously addressed by initializing i2c_block_size in +sfp_alloc() (commit 813c2dd78618), but the initialization was dropped +when i2c_block_size was split from i2c_max_block_size. + +Initialize sfp->i2c_block_size from sfp->i2c_max_block_size in +sfp_i2c_configure(), so the field is valid as soon as the adapter is +known. sfp_sm_mod_probe() still reassigns it on each module insertion +to recover from a per-module clamp to 1 (sfp_id_needs_byte_io). + +Fixes: 7662abf4db94 ("net: phy: sfp: Add support for SMBus module access") +Cc: stable@vger.kernel.org +Signed-off-by: Jonas Jelonek +Link: https://patch.msgid.link/20260528205242.971410-2-jelonek.jonas@gmail.com +Signed-off-by: Jakub Kicinski + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -824,6 +824,7 @@ static int sfp_i2c_configure(struct sfp + return -EINVAL; + } + ++ sfp->i2c_block_size = sfp->i2c_max_block_size; + return 0; + } + diff --git a/target/linux/realtek/patches-6.18/741-net-sfp-apply-I2C-adapter-quirks-to-limit-blocks.patch b/target/linux/realtek/patches-6.18/706-01-v7.2-net-sfp-apply-I2C-adapter-quirks-to-limit-block-size.patch similarity index 81% rename from target/linux/realtek/patches-6.18/741-net-sfp-apply-I2C-adapter-quirks-to-limit-blocks.patch rename to target/linux/realtek/patches-6.18/706-01-v7.2-net-sfp-apply-I2C-adapter-quirks-to-limit-block-size.patch index 7e575141d2d..75164506462 100644 --- a/target/linux/realtek/patches-6.18/741-net-sfp-apply-I2C-adapter-quirks-to-limit-blocks.patch +++ b/target/linux/realtek/patches-6.18/706-01-v7.2-net-sfp-apply-I2C-adapter-quirks-to-limit-block-size.patch @@ -1,8 +1,7 @@ -From 572304faf8c1d30f142060c76a3e731438fc5975 Mon Sep 17 00:00:00 2001 +From f2a138abfb719a3bfd370ca79f00055ec81e4f59 Mon Sep 17 00:00:00 2001 From: Jonas Jelonek -Date: Thu, 22 Jan 2026 10:59:20 +0000 -Subject: [PATCH net-next v6 1/2] net: sfp: apply I2C adapter quirks to limit - block size +Date: Sun, 14 Jun 2026 13:34:17 +0000 +Subject: [PATCH 1/2] net: sfp: apply I2C adapter quirks to limit block size 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 @@ -19,9 +18,9 @@ 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 ---- - drivers/net/phy/sfp.c | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260614133418.2068201-2-jelonek.jonas@gmail.com +Signed-off-by: Jakub Kicinski --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -54,6 +53,6 @@ Signed-off-by: Jonas Jelonek + max_block_size = min(max_block_size, i2c->quirks->max_write_len); + + sfp->i2c_max_block_size = max_block_size; + sfp->i2c_block_size = sfp->i2c_max_block_size; return 0; } - diff --git a/target/linux/realtek/patches-6.18/706-02-v7.2-net-sfp-extend-SMBus-support.patch b/target/linux/realtek/patches-6.18/706-02-v7.2-net-sfp-extend-SMBus-support.patch new file mode 100644 index 00000000000..e0924437072 --- /dev/null +++ b/target/linux/realtek/patches-6.18/706-02-v7.2-net-sfp-extend-SMBus-support.patch @@ -0,0 +1,249 @@ +From 58b29bdf6186a8c3f2d725619c0b17cf602ac4e0 Mon Sep 17 00:00:00 2001 +From: Jonas Jelonek +Date: Sun, 14 Jun 2026 13:34:18 +0000 +Subject: [PATCH 2/2] net: sfp: extend SMBus support + +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 >=2-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 +Link: https://patch.msgid.link/20260614133418.2068201-3-jelonek.jonas@gmail.com +Signed-off-by: Jakub Kicinski + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + + #include "sfp.h" +@@ -758,50 +759,113 @@ static int sfp_i2c_write(struct sfp *sfp + return ret == ARRAY_SIZE(msgs) ? len : 0; + } + +-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 = {0}; + u8 bus_addr = a2 ? 0x51 : 0x50; ++ size_t this_len, transferred; ++ u32 functionality; + u8 *data = buf; + int ret; + +- while (len) { +- ret = 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 = i2c_get_functionality(sfp->i2c); + +- *data = smbus_data.byte; ++ while (len) { ++ this_len = min(len, sfp->i2c_block_size); + +- len--; +- data++; +- dev_addr++; ++ if (functionality & I2C_FUNC_SMBUS_READ_I2C_BLOCK) { ++ smbus_data.block[0] = this_len; ++ ret = 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; ++ ++ transferred = min_t(size_t, smbus_data.block[0], this_len); ++ if (!transferred) ++ return -EIO; ++ ++ memcpy(data, &smbus_data.block[1], transferred); ++ } else if (this_len >= 2 && ++ (functionality & I2C_FUNC_SMBUS_READ_WORD_DATA)) { ++ ret = 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 = 2; ++ } else { ++ ret = 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 = smbus_data.byte; ++ transferred = 1; ++ } ++ ++ data += transferred; ++ len -= transferred; ++ dev_addr += transferred; + } + + return data - (u8 *)buf; + } + +-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 *buf, ++ size_t len) + { + union i2c_smbus_data smbus_data; + u8 bus_addr = a2 ? 0x51 : 0x50; ++ size_t this_len, transferred; ++ u32 functionality; + u8 *data = buf; + int ret; + ++ functionality = i2c_get_functionality(sfp->i2c); ++ + while (len) { +- smbus_data.byte = *data; +- ret = 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 = min(len, sfp->i2c_block_size); + +- len--; +- data++; +- dev_addr++; ++ if (functionality & I2C_FUNC_SMBUS_WRITE_I2C_BLOCK) { ++ smbus_data.block[0] = this_len; ++ memcpy(&smbus_data.block[1], data, this_len); ++ ++ ret = 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 = this_len; ++ } else if (this_len >= 2 && ++ (functionality & I2C_FUNC_SMBUS_WRITE_WORD_DATA)) { ++ smbus_data.word = get_unaligned_le16(data); ++ ret = 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 = 2; ++ } else { ++ smbus_data.byte = *data; ++ ret = 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 = 1; ++ } ++ ++ data += transferred; ++ len -= transferred; ++ dev_addr += transferred; + } + + return data - (u8 *)buf; +@@ -817,10 +881,29 @@ static int sfp_i2c_configure(struct sfp + sfp->read = sfp_i2c_read; + sfp->write = sfp_i2c_write; + max_block_size = SFP_EEPROM_BLOCK_SIZE; +- } else if (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_BYTE_DATA)) { +- sfp->read = sfp_smbus_byte_read; +- sfp->write = sfp_smbus_byte_write; +- max_block_size = 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 = sfp_smbus_read; ++ sfp->write = sfp_smbus_write; ++ ++ if (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_I2C_BLOCK)) ++ max_block_size = SFP_EEPROM_BLOCK_SIZE; ++ else if (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_WORD_DATA)) ++ max_block_size = 2; ++ else ++ max_block_size = 1; ++ } else if (WARN_ONCE(i2c_check_functionality(i2c, I2C_FUNC_SMBUS_WORD_DATA), ++ "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 = sfp_smbus_read; ++ sfp->write = sfp_smbus_write; ++ max_block_size = 2; + } else { + sfp->i2c = NULL; + return -EINVAL; diff --git a/target/linux/realtek/patches-6.18/714-net-phy-sfp-add-support-for-SMBus.patch b/target/linux/realtek/patches-6.18/714-net-phy-sfp-add-support-for-SMBus.patch index 390ffabb990..cc6283f0a7c 100644 --- a/target/linux/realtek/patches-6.18/714-net-phy-sfp-add-support-for-SMBus.patch +++ b/target/linux/realtek/patches-6.18/714-net-phy-sfp-add-support-for-SMBus.patch @@ -10,7 +10,7 @@ Signed-off-by: Antoine Tenart --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c -@@ -850,6 +850,29 @@ static int sfp_i2c_mdiobus_create(struct +@@ -942,6 +942,29 @@ static int sfp_i2c_mdiobus_create(struct return 0; } @@ -40,7 +40,7 @@ Signed-off-by: Antoine Tenart static void sfp_i2c_mdiobus_destroy(struct sfp *sfp) { mdiobus_unregister(sfp->i2c_mii); -@@ -2024,9 +2047,15 @@ static void sfp_sm_fault(struct sfp *sfp +@@ -2116,9 +2139,15 @@ static void sfp_sm_fault(struct sfp *sfp static int sfp_sm_add_mdio_bus(struct sfp *sfp) { diff --git a/target/linux/realtek/patches-6.18/742-net-sfp-extend-SMBus-support.patch b/target/linux/realtek/patches-6.18/742-net-sfp-extend-SMBus-support.patch deleted file mode 100644 index da949896706..00000000000 --- a/target/linux/realtek/patches-6.18/742-net-sfp-extend-SMBus-support.patch +++ /dev/null @@ -1,204 +0,0 @@ -From 475b0dd976de6db975bfef7d6fdb978d2d64c535 Mon Sep 17 00:00:00 2001 -From: Jonas Jelonek -Date: Fri, 9 Jan 2026 21:04:02 +0000 -Subject: [PATCH net-next v6 2/2] net: sfp: extend SMBus support - -Commit 7662abf4db94 ("net: phy: sfp: Add support for SMBus module access") -added support for SMBus-only controllers for module access. However, this -is restricted to single-byte accesses and has the implication that hwmon -is disabled (due to missing atomicity of 16-bit accesses) and warnings -are printed. - -There are probably a lot of SMBus-only I2C controllers out in the wild -which support more than just byte access. And it also seems that in -several devices, SFP slots are attached to these SMBus controllers -instead of full-featured I2C controllers. Right now, they don't work -with SFP modules. This applies - amongst others - to I2C/SMBus-only -controllers in Realtek longan and mango SoCs. They also support word -access and I2C block reads. - -Extend the current read/write SMBus operations to support SMBus I2C -block and SMBus word access. To avoid having dedicated operations for -each kind of transfer, provide generic read and write operations that -covers all kinds of access depending on whats supported. - -For block access, this requires I2C_FUNC_SMBUS_I2C_BLOCK to be -supported as it relies on reading a pre-defined amount of bytes. -This isn't intended by the official SMBus Block Read but supported by -several I2C controllers/drivers. - -Signed-off-by: Jonas Jelonek ---- - drivers/net/phy/sfp.c | 117 +++++++++++++++++++++++++++++++++--------- - 1 file changed, 92 insertions(+), 25 deletions(-) - ---- a/drivers/net/phy/sfp.c -+++ b/drivers/net/phy/sfp.c -@@ -14,6 +14,7 @@ - #include - #include - #include -+#include - #include - - #include "sfp.h" -@@ -758,50 +759,101 @@ static int sfp_i2c_write(struct sfp *sfp - return ret == ARRAY_SIZE(msgs) ? len : 0; - } - --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 = a2 ? 0x51 : 0x50; -+ size_t this_len, transferred; -+ u32 functionality; - u8 *data = buf; - int ret; - -+ functionality = i2c_get_functionality(sfp->i2c); -+ - while (len) { -- ret = i2c_smbus_xfer(sfp->i2c, bus_addr, 0, -- I2C_SMBUS_READ, dev_addr, -- I2C_SMBUS_BYTE_DATA, &smbus_data); -+ this_len = min(len, sfp->i2c_max_block_size); -+ -+ if (functionality & I2C_FUNC_SMBUS_READ_I2C_BLOCK) { -+ smbus_data.block[0] = this_len; -+ ret = i2c_smbus_xfer(sfp->i2c, bus_addr, 0, -+ I2C_SMBUS_READ, dev_addr, -+ I2C_SMBUS_I2C_BLOCK_DATA, &smbus_data); -+ -+ memcpy(data, &smbus_data.block[1], this_len); -+ transferred = this_len; -+ } else if (this_len >= 2 && -+ functionality & I2C_FUNC_SMBUS_READ_WORD_DATA) { -+ ret = i2c_smbus_xfer(sfp->i2c, bus_addr, 0, -+ I2C_SMBUS_READ, dev_addr, -+ I2C_SMBUS_WORD_DATA, &smbus_data); -+ -+ put_unaligned_le16(smbus_data.word, data); -+ transferred = 2; -+ } else { -+ ret = i2c_smbus_xfer(sfp->i2c, bus_addr, 0, -+ I2C_SMBUS_READ, dev_addr, -+ I2C_SMBUS_BYTE_DATA, &smbus_data); -+ -+ *data = smbus_data.byte; -+ transferred = 1; -+ } -+ - if (ret < 0) - return ret; - -- *data = smbus_data.byte; -- -- len--; -- data++; -- dev_addr++; -+ data += transferred; -+ len -= transferred; -+ dev_addr += transferred; - } - - return data - (u8 *)buf; - } - --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 *buf, -+ size_t len) - { - union i2c_smbus_data smbus_data; - u8 bus_addr = a2 ? 0x51 : 0x50; -+ size_t this_len, transferred; -+ u32 functionality; - u8 *data = buf; - int ret; - -+ functionality = i2c_get_functionality(sfp->i2c); -+ - while (len) { -- smbus_data.byte = *data; -- ret = i2c_smbus_xfer(sfp->i2c, bus_addr, 0, -- I2C_SMBUS_WRITE, dev_addr, -- I2C_SMBUS_BYTE_DATA, &smbus_data); -- if (ret) -+ this_len = min(len, sfp->i2c_max_block_size); -+ -+ if (functionality & I2C_FUNC_SMBUS_WRITE_I2C_BLOCK) { -+ smbus_data.block[0] = this_len; -+ memcpy(&smbus_data.block[1], data, this_len); -+ -+ ret = i2c_smbus_xfer(sfp->i2c, bus_addr, 0, -+ I2C_SMBUS_WRITE, dev_addr, -+ I2C_SMBUS_I2C_BLOCK_DATA, &smbus_data); -+ transferred = this_len; -+ } else if (this_len >= 2 && -+ functionality & I2C_FUNC_SMBUS_WRITE_WORD_DATA) { -+ smbus_data.word = get_unaligned_le16(data); -+ ret = i2c_smbus_xfer(sfp->i2c, bus_addr, 0, -+ I2C_SMBUS_WRITE, dev_addr, -+ I2C_SMBUS_WORD_DATA, &smbus_data); -+ transferred = 2; -+ } else { -+ smbus_data.byte = *data; -+ ret = i2c_smbus_xfer(sfp->i2c, bus_addr, 0, -+ I2C_SMBUS_WRITE, dev_addr, -+ I2C_SMBUS_BYTE_DATA, &smbus_data); -+ transferred = 1; -+ } -+ -+ if (ret < 0) - return ret; - -- len--; -- data++; -- dev_addr++; -+ data += transferred; -+ len -= transferred; -+ dev_addr += transferred; - } - - return data - (u8 *)buf; -@@ -810,17 +862,32 @@ static int sfp_smbus_byte_write(struct s - static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c) - { - size_t max_block_size; -+ u32 functionality; - - sfp->i2c = i2c; -+ functionality = i2c_get_functionality(i2c); - -- if (i2c_check_functionality(i2c, I2C_FUNC_I2C)) { -+ if (functionality & I2C_FUNC_I2C) { - sfp->read = sfp_i2c_read; - sfp->write = sfp_i2c_write; - max_block_size = SFP_EEPROM_BLOCK_SIZE; -- } else if (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_BYTE_DATA)) { -- sfp->read = sfp_smbus_byte_read; -- sfp->write = sfp_smbus_byte_write; -- max_block_size = 1; -+ } else if ((functionality & I2C_FUNC_SMBUS_BYTE_DATA) == I2C_FUNC_SMBUS_BYTE_DATA || -+ (functionality & I2C_FUNC_SMBUS_I2C_BLOCK) == I2C_FUNC_SMBUS_I2C_BLOCK) { -+ sfp->read = sfp_smbus_read; -+ sfp->write = sfp_smbus_write; -+ -+ if ((functionality & I2C_FUNC_SMBUS_I2C_BLOCK) == I2C_FUNC_SMBUS_I2C_BLOCK) -+ max_block_size = SFP_EEPROM_BLOCK_SIZE; -+ else if ((functionality & I2C_FUNC_SMBUS_WORD_DATA) == I2C_FUNC_SMBUS_WORD_DATA) -+ max_block_size = 2; -+ else -+ max_block_size = 1; -+ } else if ((functionality & I2C_FUNC_SMBUS_WORD_DATA) == I2C_FUNC_SMBUS_WORD_DATA) { -+ WARN(1, "SMBus adapter only supports word access, odd reads/writes will fail!\n"); -+ -+ sfp->read = sfp_smbus_read; -+ sfp->write = sfp_smbus_write; -+ max_block_size = 2; - } else { - sfp->i2c = NULL; - return -EINVAL;