| b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | From 559391fc20fae506adcb311b904cc544c76436c0 Mon Sep 17 00:00:00 2001 |
| 2 | From: Russell King <rmk+kernel@armlinux.org.uk> |
| 3 | Date: Thu, 7 Nov 2019 18:52:07 +0000 |
| 4 | Subject: [PATCH 634/660] net: sfp: allow modules with slow diagnostics to |
| 5 | probe |
| 6 | |
| 7 | When a module is inserted, we attempt to read read the ID from address |
| 8 | 0x50. Once we are able to read the ID, we immediately attempt to |
| 9 | initialise the hwmon support by reading from address 0x51. If this |
| 10 | fails, then we fall into error state, and assume that the module is |
| 11 | not usable. |
| 12 | |
| 13 | Modules such as the ALCATELLUCENT 3FE46541AA use a real EEPROM for |
| 14 | I2C address 0x50, which responds immediately. However, address 0x51 |
| 15 | is an emulated, which only becomes available once the on-board firmware |
| 16 | has booted. This prompts us to fall into the error state. |
| 17 | |
| 18 | Since the module may be usable without diagnostics, arrange for the |
| 19 | hwmon probe independent of the rest of the SFP itself, retrying every |
| 20 | 5s for up to about 60s for the monitoring to become available, and |
| 21 | print an error message if it doesn't become available. |
| 22 | |
| 23 | Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> |
| 24 | --- |
| 25 | drivers/net/phy/sfp.c | 96 +++++++++++++++++++++++++++++++++---------- |
| 26 | 1 file changed, 74 insertions(+), 22 deletions(-) |
| 27 | |
| 28 | --- a/drivers/net/phy/sfp.c |
| 29 | +++ b/drivers/net/phy/sfp.c |
| 30 | @@ -218,6 +218,8 @@ struct sfp { |
| 31 | |
| 32 | #if IS_ENABLED(CONFIG_HWMON) |
| 33 | struct sfp_diag diag; |
| 34 | + struct delayed_work hwmon_probe; |
| 35 | + unsigned int hwmon_tries; |
| 36 | struct device *hwmon_dev; |
| 37 | char *hwmon_name; |
| 38 | #endif |
| 39 | @@ -1159,29 +1161,27 @@ static const struct hwmon_chip_info sfp_ |
| 40 | .info = sfp_hwmon_info, |
| 41 | }; |
| 42 | |
| 43 | -static int sfp_hwmon_insert(struct sfp *sfp) |
| 44 | +static void sfp_hwmon_probe(struct work_struct *work) |
| 45 | { |
| 46 | + struct sfp *sfp = container_of(work, struct sfp, hwmon_probe.work); |
| 47 | int err, i; |
| 48 | |
| 49 | - if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE) |
| 50 | - return 0; |
| 51 | - |
| 52 | - if (!(sfp->id.ext.diagmon & SFP_DIAGMON_DDM)) |
| 53 | - return 0; |
| 54 | - |
| 55 | - if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE) |
| 56 | - /* This driver in general does not support address |
| 57 | - * change. |
| 58 | - */ |
| 59 | - return 0; |
| 60 | - |
| 61 | err = sfp_read(sfp, true, 0, &sfp->diag, sizeof(sfp->diag)); |
| 62 | - if (err < 0) |
| 63 | - return err; |
| 64 | + if (err < 0) { |
| 65 | + if (sfp->hwmon_tries--) { |
| 66 | + mod_delayed_work(system_wq, &sfp->hwmon_probe, |
| 67 | + T_PROBE_RETRY_SLOW); |
| 68 | + } else { |
| 69 | + dev_warn(sfp->dev, "hwmon probe failed: %d\n", err); |
| 70 | + } |
| 71 | + return; |
| 72 | + } |
| 73 | |
| 74 | sfp->hwmon_name = kstrdup(dev_name(sfp->dev), GFP_KERNEL); |
| 75 | - if (!sfp->hwmon_name) |
| 76 | - return -ENODEV; |
| 77 | + if (!sfp->hwmon_name) { |
| 78 | + dev_err(sfp->dev, "out of memory for hwmon name\n"); |
| 79 | + return; |
| 80 | + } |
| 81 | |
| 82 | for (i = 0; sfp->hwmon_name[i]; i++) |
| 83 | if (hwmon_is_bad_char(sfp->hwmon_name[i])) |
| 84 | @@ -1191,18 +1191,52 @@ static int sfp_hwmon_insert(struct sfp * |
| 85 | sfp->hwmon_name, sfp, |
| 86 | &sfp_hwmon_chip_info, |
| 87 | NULL); |
| 88 | + if (IS_ERR(sfp->hwmon_dev)) |
| 89 | + dev_err(sfp->dev, "failed to register hwmon device: %ld\n", |
| 90 | + PTR_ERR(sfp->hwmon_dev)); |
| 91 | +} |
| 92 | + |
| 93 | +static int sfp_hwmon_insert(struct sfp *sfp) |
| 94 | +{ |
| 95 | + if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE) |
| 96 | + return 0; |
| 97 | + |
| 98 | + if (!(sfp->id.ext.diagmon & SFP_DIAGMON_DDM)) |
| 99 | + return 0; |
| 100 | + |
| 101 | + if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE) |
| 102 | + /* This driver in general does not support address |
| 103 | + * change. |
| 104 | + */ |
| 105 | + return 0; |
| 106 | + |
| 107 | + mod_delayed_work(system_wq, &sfp->hwmon_probe, 1); |
| 108 | + sfp->hwmon_tries = R_PROBE_RETRY_SLOW; |
| 109 | |
| 110 | - return PTR_ERR_OR_ZERO(sfp->hwmon_dev); |
| 111 | + return 0; |
| 112 | } |
| 113 | |
| 114 | static void sfp_hwmon_remove(struct sfp *sfp) |
| 115 | { |
| 116 | + cancel_delayed_work_sync(&sfp->hwmon_probe); |
| 117 | if (!IS_ERR_OR_NULL(sfp->hwmon_dev)) { |
| 118 | hwmon_device_unregister(sfp->hwmon_dev); |
| 119 | sfp->hwmon_dev = NULL; |
| 120 | kfree(sfp->hwmon_name); |
| 121 | } |
| 122 | } |
| 123 | + |
| 124 | +static int sfp_hwmon_init(struct sfp *sfp) |
| 125 | +{ |
| 126 | + INIT_DELAYED_WORK(&sfp->hwmon_probe, sfp_hwmon_probe); |
| 127 | + |
| 128 | + return 0; |
| 129 | +} |
| 130 | + |
| 131 | +static void sfp_hwmon_exit(struct sfp *sfp) |
| 132 | +{ |
| 133 | + cancel_delayed_work_sync(&sfp->hwmon_probe); |
| 134 | +} |
| 135 | #else |
| 136 | static int sfp_hwmon_insert(struct sfp *sfp) |
| 137 | { |
| 138 | @@ -1212,6 +1246,15 @@ static int sfp_hwmon_insert(struct sfp * |
| 139 | static void sfp_hwmon_remove(struct sfp *sfp) |
| 140 | { |
| 141 | } |
| 142 | + |
| 143 | +static int sfp_hwmon_init(struct sfp *sfp) |
| 144 | +{ |
| 145 | + return 0; |
| 146 | +} |
| 147 | + |
| 148 | +static void sfp_hwmon_exit(struct sfp *sfp) |
| 149 | +{ |
| 150 | +} |
| 151 | #endif |
| 152 | |
| 153 | /* Helpers */ |
| 154 | @@ -1548,10 +1591,6 @@ static int sfp_sm_mod_probe(struct sfp * |
| 155 | if (ret < 0) |
| 156 | return ret; |
| 157 | |
| 158 | - ret = sfp_hwmon_insert(sfp); |
| 159 | - if (ret < 0) |
| 160 | - return ret; |
| 161 | - |
| 162 | return 0; |
| 163 | } |
| 164 | |
| 165 | @@ -1700,6 +1739,15 @@ static void sfp_sm_module(struct sfp *sf |
| 166 | case SFP_MOD_ERROR: |
| 167 | break; |
| 168 | } |
| 169 | + |
| 170 | +#if IS_ENABLED(CONFIG_HWMON) |
| 171 | + if (sfp->sm_mod_state >= SFP_MOD_WAITDEV && |
| 172 | + IS_ERR_OR_NULL(sfp->hwmon_dev)) { |
| 173 | + err = sfp_hwmon_insert(sfp); |
| 174 | + if (err) |
| 175 | + dev_warn(sfp->dev, "hwmon probe failed: %d\n", err); |
| 176 | + } |
| 177 | +#endif |
| 178 | } |
| 179 | |
| 180 | static void sfp_sm_main(struct sfp *sfp, unsigned int event) |
| 181 | @@ -2001,6 +2049,8 @@ static struct sfp *sfp_alloc(struct devi |
| 182 | INIT_DELAYED_WORK(&sfp->poll, sfp_poll); |
| 183 | INIT_DELAYED_WORK(&sfp->timeout, sfp_timeout); |
| 184 | |
| 185 | + sfp_hwmon_init(sfp); |
| 186 | + |
| 187 | return sfp; |
| 188 | } |
| 189 | |
| 190 | @@ -2008,6 +2058,8 @@ static void sfp_cleanup(void *data) |
| 191 | { |
| 192 | struct sfp *sfp = data; |
| 193 | |
| 194 | + sfp_hwmon_exit(sfp); |
| 195 | + |
| 196 | cancel_delayed_work_sync(&sfp->poll); |
| 197 | cancel_delayed_work_sync(&sfp->timeout); |
| 198 | if (sfp->i2c_mii) { |