b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | From 40e0b3b15f7da92e6b065292b14af7b9bfb1c6e0 Mon Sep 17 00:00:00 2001 |
| 2 | From: Russell King <rmk+kernel@armlinux.org.uk> |
| 3 | Date: Fri, 13 Sep 2019 23:00:35 +0100 |
| 4 | Subject: [PATCH 642/660] net: sfp: soft status and control support |
| 5 | |
| 6 | Add support for the soft status and control register, which allows |
| 7 | TX_FAULT and RX_LOS to be monitored and TX_DISABLE to be set. We |
| 8 | make use of this when the board does not support GPIOs for these |
| 9 | signals. |
| 10 | |
| 11 | Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> |
| 12 | --- |
| 13 | drivers/net/phy/sfp.c | 110 ++++++++++++++++++++++++++++++++++-------- |
| 14 | include/linux/sfp.h | 4 ++ |
| 15 | 2 files changed, 94 insertions(+), 20 deletions(-) |
| 16 | |
| 17 | --- a/drivers/net/phy/sfp.c |
| 18 | +++ b/drivers/net/phy/sfp.c |
| 19 | @@ -201,7 +201,10 @@ struct sfp { |
| 20 | struct gpio_desc *gpio[GPIO_MAX]; |
| 21 | int gpio_irq[GPIO_MAX]; |
| 22 | |
| 23 | + bool need_poll; |
| 24 | + |
| 25 | struct mutex st_mutex; /* Protects state */ |
| 26 | + unsigned int state_soft_mask; |
| 27 | unsigned int state; |
| 28 | struct delayed_work poll; |
| 29 | struct delayed_work timeout; |
| 30 | @@ -395,24 +398,90 @@ static int sfp_i2c_configure(struct sfp |
| 31 | } |
| 32 | |
| 33 | /* Interface */ |
| 34 | -static unsigned int sfp_get_state(struct sfp *sfp) |
| 35 | +static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len) |
| 36 | { |
| 37 | - return sfp->get_state(sfp); |
| 38 | + return sfp->read(sfp, a2, addr, buf, len); |
| 39 | } |
| 40 | |
| 41 | -static void sfp_set_state(struct sfp *sfp, unsigned int state) |
| 42 | +static int sfp_write(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len) |
| 43 | { |
| 44 | - sfp->set_state(sfp, state); |
| 45 | + return sfp->write(sfp, a2, addr, buf, len); |
| 46 | } |
| 47 | |
| 48 | -static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len) |
| 49 | +static unsigned int sfp_soft_get_state(struct sfp *sfp) |
| 50 | { |
| 51 | - return sfp->read(sfp, a2, addr, buf, len); |
| 52 | + unsigned int state = 0; |
| 53 | + u8 status; |
| 54 | + |
| 55 | + if (sfp_read(sfp, true, SFP_STATUS, &status, sizeof(status)) == |
| 56 | + sizeof(status)) { |
| 57 | + if (status & SFP_STATUS_RX_LOS) |
| 58 | + state |= SFP_F_LOS; |
| 59 | + if (status & SFP_STATUS_TX_FAULT) |
| 60 | + state |= SFP_F_TX_FAULT; |
| 61 | + } |
| 62 | + |
| 63 | + return state & sfp->state_soft_mask; |
| 64 | } |
| 65 | |
| 66 | -static int sfp_write(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len) |
| 67 | +static void sfp_soft_set_state(struct sfp *sfp, unsigned int state) |
| 68 | { |
| 69 | - return sfp->write(sfp, a2, addr, buf, len); |
| 70 | + u8 status; |
| 71 | + |
| 72 | + if (sfp_read(sfp, true, SFP_STATUS, &status, sizeof(status)) == |
| 73 | + sizeof(status)) { |
| 74 | + if (state & SFP_F_TX_DISABLE) |
| 75 | + status |= SFP_STATUS_TX_DISABLE_FORCE; |
| 76 | + else |
| 77 | + status &= ~SFP_STATUS_TX_DISABLE_FORCE; |
| 78 | + |
| 79 | + sfp_write(sfp, true, SFP_STATUS, &status, sizeof(status)); |
| 80 | + } |
| 81 | +} |
| 82 | + |
| 83 | +static void sfp_soft_start_poll(struct sfp *sfp) |
| 84 | +{ |
| 85 | + const struct sfp_eeprom_id *id = &sfp->id; |
| 86 | + |
| 87 | + sfp->state_soft_mask = 0; |
| 88 | + if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_DISABLE && |
| 89 | + !sfp->gpio[GPIO_TX_DISABLE]) |
| 90 | + sfp->state_soft_mask |= SFP_F_TX_DISABLE; |
| 91 | + if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_FAULT && |
| 92 | + !sfp->gpio[GPIO_TX_FAULT]) |
| 93 | + sfp->state_soft_mask |= SFP_F_TX_FAULT; |
| 94 | + if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS && |
| 95 | + !sfp->gpio[GPIO_LOS]) |
| 96 | + sfp->state_soft_mask |= SFP_F_LOS; |
| 97 | + |
| 98 | + if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) && |
| 99 | + !sfp->need_poll) |
| 100 | + mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); |
| 101 | +} |
| 102 | + |
| 103 | +static void sfp_soft_stop_poll(struct sfp *sfp) |
| 104 | +{ |
| 105 | + sfp->state_soft_mask = 0; |
| 106 | +} |
| 107 | + |
| 108 | +static unsigned int sfp_get_state(struct sfp *sfp) |
| 109 | +{ |
| 110 | + unsigned int state = sfp->get_state(sfp); |
| 111 | + |
| 112 | + if (state & SFP_F_PRESENT && |
| 113 | + sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT)) |
| 114 | + state |= sfp_soft_get_state(sfp); |
| 115 | + |
| 116 | + return state; |
| 117 | +} |
| 118 | + |
| 119 | +static void sfp_set_state(struct sfp *sfp, unsigned int state) |
| 120 | +{ |
| 121 | + sfp->set_state(sfp, state); |
| 122 | + |
| 123 | + if (state & SFP_F_PRESENT && |
| 124 | + sfp->state_soft_mask & SFP_F_TX_DISABLE) |
| 125 | + sfp_soft_set_state(sfp, state); |
| 126 | } |
| 127 | |
| 128 | static unsigned int sfp_check(void *buf, size_t len) |
| 129 | @@ -1407,11 +1476,6 @@ static void sfp_sm_fault(struct sfp *sfp |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | -static void sfp_sm_mod_init(struct sfp *sfp) |
| 134 | -{ |
| 135 | - sfp_module_tx_enable(sfp); |
| 136 | -} |
| 137 | - |
| 138 | static void sfp_sm_probe_for_phy(struct sfp *sfp) |
| 139 | { |
| 140 | /* Setting the serdes link mode is guesswork: there's no |
| 141 | @@ -1574,7 +1638,7 @@ static int sfp_sm_mod_probe(struct sfp * |
| 142 | (int)sizeof(id.ext.datecode), id.ext.datecode); |
| 143 | |
| 144 | /* Check whether we support this module */ |
| 145 | - if (!sfp->type->module_supported(&sfp->id)) { |
| 146 | + if (!sfp->type->module_supported(&id)) { |
| 147 | dev_err(sfp->dev, |
| 148 | "module is not supported - phys id 0x%02x 0x%02x\n", |
| 149 | sfp->id.base.phys_id, sfp->id.base.phys_ext_id); |
| 150 | @@ -1764,6 +1828,7 @@ static void sfp_sm_main(struct sfp *sfp, |
| 151 | if (sfp->mod_phy) |
| 152 | sfp_sm_phy_detach(sfp); |
| 153 | sfp_module_tx_disable(sfp); |
| 154 | + sfp_soft_stop_poll(sfp); |
| 155 | sfp_sm_next(sfp, SFP_S_DOWN, 0); |
| 156 | return; |
| 157 | } |
| 158 | @@ -1775,7 +1840,10 @@ static void sfp_sm_main(struct sfp *sfp, |
| 159 | sfp->sm_dev_state != SFP_DEV_UP) |
| 160 | break; |
| 161 | |
| 162 | - sfp_sm_mod_init(sfp); |
| 163 | + if (!(sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE)) |
| 164 | + sfp_soft_start_poll(sfp); |
| 165 | + |
| 166 | + sfp_module_tx_enable(sfp); |
| 167 | |
| 168 | /* Initialise the fault clearance retries */ |
| 169 | sfp->sm_retries = 5; |
| 170 | @@ -2031,7 +2099,10 @@ static void sfp_poll(struct work_struct |
| 171 | struct sfp *sfp = container_of(work, struct sfp, poll.work); |
| 172 | |
| 173 | sfp_check_state(sfp); |
| 174 | - mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); |
| 175 | + |
| 176 | + if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) || |
| 177 | + sfp->need_poll) |
| 178 | + mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); |
| 179 | } |
| 180 | |
| 181 | static struct sfp *sfp_alloc(struct device *dev) |
| 182 | @@ -2076,7 +2147,6 @@ static int sfp_probe(struct platform_dev |
| 183 | const struct sff_data *sff; |
| 184 | struct i2c_adapter *i2c; |
| 185 | struct sfp *sfp; |
| 186 | - bool poll = false; |
| 187 | int err, i; |
| 188 | |
| 189 | sfp = sfp_alloc(&pdev->dev); |
| 190 | @@ -2184,7 +2254,7 @@ static int sfp_probe(struct platform_dev |
| 191 | sfp->gpio_irq[i] = gpiod_to_irq(sfp->gpio[i]); |
| 192 | if (sfp->gpio_irq[i] < 0) { |
| 193 | sfp->gpio_irq[i] = 0; |
| 194 | - poll = true; |
| 195 | + sfp->need_poll = true; |
| 196 | continue; |
| 197 | } |
| 198 | |
| 199 | @@ -2196,11 +2266,11 @@ static int sfp_probe(struct platform_dev |
| 200 | dev_name(sfp->dev), sfp); |
| 201 | if (err) { |
| 202 | sfp->gpio_irq[i] = 0; |
| 203 | - poll = true; |
| 204 | + sfp->need_poll = true; |
| 205 | } |
| 206 | } |
| 207 | |
| 208 | - if (poll) |
| 209 | + if (sfp->need_poll) |
| 210 | mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); |
| 211 | |
| 212 | /* We could have an issue in cases no Tx disable pin is available or |
| 213 | --- a/include/linux/sfp.h |
| 214 | +++ b/include/linux/sfp.h |
| 215 | @@ -428,6 +428,10 @@ enum { |
| 216 | SFP_TEC_CUR = 0x6c, |
| 217 | |
| 218 | SFP_STATUS = 0x6e, |
| 219 | + SFP_STATUS_TX_DISABLE = BIT(7), |
| 220 | + SFP_STATUS_TX_DISABLE_FORCE = BIT(6), |
| 221 | + SFP_STATUS_TX_FAULT = BIT(2), |
| 222 | + SFP_STATUS_RX_LOS = BIT(1), |
| 223 | SFP_ALARM0 = 0x70, |
| 224 | SFP_ALARM0_TEMP_HIGH = BIT(7), |
| 225 | SFP_ALARM0_TEMP_LOW = BIT(6), |