Skip to content

Commit f3c9a66

Browse files
Russell Kingdavem330
authored andcommitted
net: sfp: soft status and control support
Add support for the soft status and control register, which allows TX_FAULT and RX_LOS to be monitored and TX_DISABLE to be set. We make use of this when the board does not support GPIOs for these signals. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 9ce3335 commit f3c9a66

File tree

2 files changed

+94
-20
lines changed

2 files changed

+94
-20
lines changed

drivers/net/phy/sfp.c

Lines changed: 90 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,10 @@ struct sfp {
201201
struct gpio_desc *gpio[GPIO_MAX];
202202
int gpio_irq[GPIO_MAX];
203203

204+
bool need_poll;
205+
204206
struct mutex st_mutex; /* Protects state */
207+
unsigned int state_soft_mask;
205208
unsigned int state;
206209
struct delayed_work poll;
207210
struct delayed_work timeout;
@@ -395,24 +398,90 @@ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
395398
}
396399

397400
/* Interface */
398-
static unsigned int sfp_get_state(struct sfp *sfp)
401+
static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
399402
{
400-
return sfp->get_state(sfp);
403+
return sfp->read(sfp, a2, addr, buf, len);
401404
}
402405

403-
static void sfp_set_state(struct sfp *sfp, unsigned int state)
406+
static int sfp_write(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
404407
{
405-
sfp->set_state(sfp, state);
408+
return sfp->write(sfp, a2, addr, buf, len);
406409
}
407410

408-
static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
411+
static unsigned int sfp_soft_get_state(struct sfp *sfp)
409412
{
410-
return sfp->read(sfp, a2, addr, buf, len);
413+
unsigned int state = 0;
414+
u8 status;
415+
416+
if (sfp_read(sfp, true, SFP_STATUS, &status, sizeof(status)) ==
417+
sizeof(status)) {
418+
if (status & SFP_STATUS_RX_LOS)
419+
state |= SFP_F_LOS;
420+
if (status & SFP_STATUS_TX_FAULT)
421+
state |= SFP_F_TX_FAULT;
422+
}
423+
424+
return state & sfp->state_soft_mask;
411425
}
412426

413-
static int sfp_write(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
427+
static void sfp_soft_set_state(struct sfp *sfp, unsigned int state)
414428
{
415-
return sfp->write(sfp, a2, addr, buf, len);
429+
u8 status;
430+
431+
if (sfp_read(sfp, true, SFP_STATUS, &status, sizeof(status)) ==
432+
sizeof(status)) {
433+
if (state & SFP_F_TX_DISABLE)
434+
status |= SFP_STATUS_TX_DISABLE_FORCE;
435+
else
436+
status &= ~SFP_STATUS_TX_DISABLE_FORCE;
437+
438+
sfp_write(sfp, true, SFP_STATUS, &status, sizeof(status));
439+
}
440+
}
441+
442+
static void sfp_soft_start_poll(struct sfp *sfp)
443+
{
444+
const struct sfp_eeprom_id *id = &sfp->id;
445+
446+
sfp->state_soft_mask = 0;
447+
if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_DISABLE &&
448+
!sfp->gpio[GPIO_TX_DISABLE])
449+
sfp->state_soft_mask |= SFP_F_TX_DISABLE;
450+
if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_FAULT &&
451+
!sfp->gpio[GPIO_TX_FAULT])
452+
sfp->state_soft_mask |= SFP_F_TX_FAULT;
453+
if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS &&
454+
!sfp->gpio[GPIO_LOS])
455+
sfp->state_soft_mask |= SFP_F_LOS;
456+
457+
if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) &&
458+
!sfp->need_poll)
459+
mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
460+
}
461+
462+
static void sfp_soft_stop_poll(struct sfp *sfp)
463+
{
464+
sfp->state_soft_mask = 0;
465+
}
466+
467+
static unsigned int sfp_get_state(struct sfp *sfp)
468+
{
469+
unsigned int state = sfp->get_state(sfp);
470+
471+
if (state & SFP_F_PRESENT &&
472+
sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT))
473+
state |= sfp_soft_get_state(sfp);
474+
475+
return state;
476+
}
477+
478+
static void sfp_set_state(struct sfp *sfp, unsigned int state)
479+
{
480+
sfp->set_state(sfp, state);
481+
482+
if (state & SFP_F_PRESENT &&
483+
sfp->state_soft_mask & SFP_F_TX_DISABLE)
484+
sfp_soft_set_state(sfp, state);
416485
}
417486

418487
static unsigned int sfp_check(void *buf, size_t len)
@@ -1407,11 +1476,6 @@ static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn)
14071476
}
14081477
}
14091478

1410-
static void sfp_sm_mod_init(struct sfp *sfp)
1411-
{
1412-
sfp_module_tx_enable(sfp);
1413-
}
1414-
14151479
static void sfp_sm_probe_for_phy(struct sfp *sfp)
14161480
{
14171481
/* Setting the serdes link mode is guesswork: there's no
@@ -1574,7 +1638,7 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
15741638
(int)sizeof(id.ext.datecode), id.ext.datecode);
15751639

15761640
/* Check whether we support this module */
1577-
if (!sfp->type->module_supported(&sfp->id)) {
1641+
if (!sfp->type->module_supported(&id)) {
15781642
dev_err(sfp->dev,
15791643
"module is not supported - phys id 0x%02x 0x%02x\n",
15801644
sfp->id.base.phys_id, sfp->id.base.phys_ext_id);
@@ -1764,6 +1828,7 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
17641828
if (sfp->mod_phy)
17651829
sfp_sm_phy_detach(sfp);
17661830
sfp_module_tx_disable(sfp);
1831+
sfp_soft_stop_poll(sfp);
17671832
sfp_sm_next(sfp, SFP_S_DOWN, 0);
17681833
return;
17691834
}
@@ -1775,7 +1840,10 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
17751840
sfp->sm_dev_state != SFP_DEV_UP)
17761841
break;
17771842

1778-
sfp_sm_mod_init(sfp);
1843+
if (!(sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE))
1844+
sfp_soft_start_poll(sfp);
1845+
1846+
sfp_module_tx_enable(sfp);
17791847

17801848
/* Initialise the fault clearance retries */
17811849
sfp->sm_retries = 5;
@@ -2031,7 +2099,10 @@ static void sfp_poll(struct work_struct *work)
20312099
struct sfp *sfp = container_of(work, struct sfp, poll.work);
20322100

20332101
sfp_check_state(sfp);
2034-
mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
2102+
2103+
if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) ||
2104+
sfp->need_poll)
2105+
mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
20352106
}
20362107

20372108
static struct sfp *sfp_alloc(struct device *dev)
@@ -2076,7 +2147,6 @@ static int sfp_probe(struct platform_device *pdev)
20762147
const struct sff_data *sff;
20772148
struct i2c_adapter *i2c;
20782149
struct sfp *sfp;
2079-
bool poll = false;
20802150
int err, i;
20812151

20822152
sfp = sfp_alloc(&pdev->dev);
@@ -2183,7 +2253,7 @@ static int sfp_probe(struct platform_device *pdev)
21832253

21842254
sfp->gpio_irq[i] = gpiod_to_irq(sfp->gpio[i]);
21852255
if (!sfp->gpio_irq[i]) {
2186-
poll = true;
2256+
sfp->need_poll = true;
21872257
continue;
21882258
}
21892259

@@ -2195,11 +2265,11 @@ static int sfp_probe(struct platform_device *pdev)
21952265
dev_name(sfp->dev), sfp);
21962266
if (err) {
21972267
sfp->gpio_irq[i] = 0;
2198-
poll = true;
2268+
sfp->need_poll = true;
21992269
}
22002270
}
22012271

2202-
if (poll)
2272+
if (sfp->need_poll)
22032273
mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
22042274

22052275
/* We could have an issue in cases no Tx disable pin is available or

include/linux/sfp.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,10 @@ enum {
428428
SFP_TEC_CUR = 0x6c,
429429

430430
SFP_STATUS = 0x6e,
431+
SFP_STATUS_TX_DISABLE = BIT(7),
432+
SFP_STATUS_TX_DISABLE_FORCE = BIT(6),
433+
SFP_STATUS_TX_FAULT = BIT(2),
434+
SFP_STATUS_RX_LOS = BIT(1),
431435
SFP_ALARM0 = 0x70,
432436
SFP_ALARM0_TEMP_HIGH = BIT(7),
433437
SFP_ALARM0_TEMP_LOW = BIT(6),

0 commit comments

Comments
 (0)