Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'net-sfp-improve-high-power-module-implementation'

Russell King says:

====================
net: sfp: improve high power module implementation

This series aims to improve the power level switching between standard
level 1 and the higher power levels.

The first patch updates the DT binding documentation to include the
minimum and default of 1W, which is the base level that every SFP cage
must support. Hence, it makes sense to document this in the binding.

The second patch enforces a minimum of 1W when parsing the firmware
description, and optimises the code for that case; there's no need to
check for SFF8472 compliance since we will not need to touch the
A2h registers.

Patch 3 validates that the module supports SFF-8472 rev 10.2 before
checking for power level 2 - rev 10.2 is where support for power
levels was introduced, so if the module doesn't support this revision,
it doesn't support power levels. Setting the power level 2 declaration
bit is likely to be spurious.

Patch 4 does the same for power level 3, except this was introduced in
SFF-8472 rev 11.9. The revision code was never updated, so we use the
rev 11.4 to signify this.

Patch 5 cleans up the code - rather than using BIT(0), we now use a
properly named value for the power level select bit.

Patch 6 introduces a read-modify-write helper.

Patch 7 gets rid of the DM7052 hack (which sets a power level
declaration bit but is not compatible with SFF-8472 rev 10.2, and
the module does not implement the A2h I2C address.)

Series tested with my DM7052.

v2: update sff.sfp.yaml with Rob's feedback
====================

Andrew's review tags from v1.

Link: https://lore.kernel.org/r/Y0%2F7dAB8OU3jrbz6@shell.armlinux.org.uk
Link: https://lore.kernel.org/r/Y1K17UtfFopACIi2@shell.armlinux.org.uk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+48 -42
+2 -1
Documentation/devicetree/bindings/net/sff,sfp.yaml
··· 22 22 phandle of an I2C bus controller for the SFP two wire serial 23 23 24 24 maximum-power-milliwatt: 25 - maxItems: 1 25 + minimum: 1000 26 + default: 1000 26 27 description: 27 28 Maximum module power consumption Specifies the maximum power consumption 28 29 allowable by a module in the slot, in milli-Watts. Presently, modules can
+44 -41
drivers/net/phy/sfp.c
··· 608 608 return sfp->write(sfp, a2, addr, buf, len); 609 609 } 610 610 611 + static int sfp_modify_u8(struct sfp *sfp, bool a2, u8 addr, u8 mask, u8 val) 612 + { 613 + int ret; 614 + u8 old, v; 615 + 616 + ret = sfp_read(sfp, a2, addr, &old, sizeof(old)); 617 + if (ret != sizeof(old)) 618 + return ret; 619 + 620 + v = (old & ~mask) | (val & mask); 621 + if (v == old) 622 + return sizeof(v); 623 + 624 + return sfp_write(sfp, a2, addr, &v, sizeof(v)); 625 + } 626 + 611 627 static unsigned int sfp_soft_get_state(struct sfp *sfp) 612 628 { 613 629 unsigned int state = 0; ··· 649 633 650 634 static void sfp_soft_set_state(struct sfp *sfp, unsigned int state) 651 635 { 652 - u8 status; 636 + u8 mask = SFP_STATUS_TX_DISABLE_FORCE; 637 + u8 val = 0; 653 638 654 - if (sfp_read(sfp, true, SFP_STATUS, &status, sizeof(status)) == 655 - sizeof(status)) { 656 - if (state & SFP_F_TX_DISABLE) 657 - status |= SFP_STATUS_TX_DISABLE_FORCE; 658 - else 659 - status &= ~SFP_STATUS_TX_DISABLE_FORCE; 639 + if (state & SFP_F_TX_DISABLE) 640 + val |= SFP_STATUS_TX_DISABLE_FORCE; 660 641 661 - sfp_write(sfp, true, SFP_STATUS, &status, sizeof(status)); 662 - } 642 + 643 + sfp_modify_u8(sfp, true, SFP_STATUS, mask, val); 663 644 } 664 645 665 646 static void sfp_soft_start_poll(struct sfp *sfp) ··· 1774 1761 u32 power_mW = 1000; 1775 1762 bool supports_a2; 1776 1763 1777 - if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_POWER_DECL)) 1764 + if (sfp->id.ext.sff8472_compliance >= SFP_SFF8472_COMPLIANCE_REV10_2 && 1765 + sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_POWER_DECL)) 1778 1766 power_mW = 1500; 1779 - if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL)) 1767 + /* Added in Rev 11.9, but there is no compliance code for this */ 1768 + if (sfp->id.ext.sff8472_compliance >= SFP_SFF8472_COMPLIANCE_REV11_4 && 1769 + sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL)) 1780 1770 power_mW = 2000; 1771 + 1772 + /* Power level 1 modules (max. 1W) are always supported. */ 1773 + if (power_mW <= 1000) { 1774 + sfp->module_power_mW = power_mW; 1775 + return 0; 1776 + } 1781 1777 1782 1778 supports_a2 = sfp->id.ext.sff8472_compliance != 1783 1779 SFP_SFF8472_COMPLIANCE_NONE || ··· 1809 1787 power_mW / 1000, (power_mW / 100) % 10); 1810 1788 return 0; 1811 1789 } 1812 - } 1813 - 1814 - if (power_mW <= 1000) { 1815 - /* Modules below 1W do not require a power change sequence */ 1816 - sfp->module_power_mW = power_mW; 1817 - return 0; 1818 1790 } 1819 1791 1820 1792 if (!supports_a2) { ··· 1837 1821 1838 1822 static int sfp_sm_mod_hpower(struct sfp *sfp, bool enable) 1839 1823 { 1840 - u8 val; 1841 1824 int err; 1842 1825 1843 - err = sfp_read(sfp, true, SFP_EXT_STATUS, &val, sizeof(val)); 1844 - if (err != sizeof(val)) { 1845 - dev_err(sfp->dev, "Failed to read EEPROM: %pe\n", ERR_PTR(err)); 1846 - return -EAGAIN; 1847 - } 1848 - 1849 - /* DM7052 reports as a high power module, responds to reads (with 1850 - * all bytes 0xff) at 0x51 but does not accept writes. In any case, 1851 - * if the bit is already set, we're already in high power mode. 1852 - */ 1853 - if (!!(val & BIT(0)) == enable) 1854 - return 0; 1855 - 1856 - if (enable) 1857 - val |= BIT(0); 1858 - else 1859 - val &= ~BIT(0); 1860 - 1861 - err = sfp_write(sfp, true, SFP_EXT_STATUS, &val, sizeof(val)); 1862 - if (err != sizeof(val)) { 1863 - dev_err(sfp->dev, "Failed to write EEPROM: %pe\n", 1864 - ERR_PTR(err)); 1826 + err = sfp_modify_u8(sfp, true, SFP_EXT_STATUS, 1827 + SFP_EXT_STATUS_PWRLVL_SELECT, 1828 + enable ? SFP_EXT_STATUS_PWRLVL_SELECT : 0); 1829 + if (err != sizeof(u8)) { 1830 + dev_err(sfp->dev, "failed to %sable high power: %pe\n", 1831 + enable ? "en" : "dis", ERR_PTR(err)); 1865 1832 return -EAGAIN; 1866 1833 } 1867 1834 ··· 2728 2729 2729 2730 device_property_read_u32(&pdev->dev, "maximum-power-milliwatt", 2730 2731 &sfp->max_power_mW); 2731 - if (!sfp->max_power_mW) 2732 + if (sfp->max_power_mW < 1000) { 2733 + if (sfp->max_power_mW) 2734 + dev_warn(sfp->dev, 2735 + "Firmware bug: host maximum power should be at least 1W\n"); 2732 2736 sfp->max_power_mW = 1000; 2737 + } 2733 2738 2734 2739 dev_info(sfp->dev, "Host maximum power %u.%uW\n", 2735 2740 sfp->max_power_mW / 1000, (sfp->max_power_mW / 100) % 10);
+2
include/linux/sfp.h
··· 489 489 SFP_WARN1_RXPWR_LOW = BIT(6), 490 490 491 491 SFP_EXT_STATUS = 0x76, 492 + SFP_EXT_STATUS_PWRLVL_SELECT = BIT(0), 493 + 492 494 SFP_VSL = 0x78, 493 495 SFP_PAGE = 0x7f, 494 496 };