Skip to content

Commit

Permalink
Merge branch 'SFP-polling-fixes'
Browse files Browse the repository at this point in the history
Robert Hancock says:

====================
SFP polling fixes

This has an updated version of an earlier patch to ensure that SFP
operations are stopped during shutdown, and another patch suggested by
Russell King to address a potential concurrency issue with SFP state
checks.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jun 10, 2019
2 parents 5270041 + 2158e85 commit 9e49fe4
Showing 1 changed file with 31 additions and 6 deletions.
37 changes: 31 additions & 6 deletions drivers/net/phy/sfp.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,12 +185,14 @@ struct sfp {
int (*write)(struct sfp *, bool, u8, void *, size_t);

struct gpio_desc *gpio[GPIO_MAX];
int gpio_irq[GPIO_MAX];

bool attached;
struct mutex st_mutex; /* Protects state */
unsigned int state;
struct delayed_work poll;
struct delayed_work timeout;
struct mutex sm_mutex;
struct mutex sm_mutex; /* Protects state machine */
unsigned char sm_mod_state;
unsigned char sm_dev_state;
unsigned short sm_state;
Expand Down Expand Up @@ -1720,6 +1722,7 @@ static void sfp_check_state(struct sfp *sfp)
{
unsigned int state, i, changed;

mutex_lock(&sfp->st_mutex);
state = sfp_get_state(sfp);
changed = state ^ sfp->state;
changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT;
Expand All @@ -1745,6 +1748,7 @@ static void sfp_check_state(struct sfp *sfp)
sfp_sm_event(sfp, state & SFP_F_LOS ?
SFP_E_LOS_HIGH : SFP_E_LOS_LOW);
rtnl_unlock();
mutex_unlock(&sfp->st_mutex);
}

static irqreturn_t sfp_irq(int irq, void *data)
Expand Down Expand Up @@ -1775,6 +1779,7 @@ static struct sfp *sfp_alloc(struct device *dev)
sfp->dev = dev;

mutex_init(&sfp->sm_mutex);
mutex_init(&sfp->st_mutex);
INIT_DELAYED_WORK(&sfp->poll, sfp_poll);
INIT_DELAYED_WORK(&sfp->timeout, sfp_timeout);

Expand Down Expand Up @@ -1802,7 +1807,7 @@ static int sfp_probe(struct platform_device *pdev)
struct i2c_adapter *i2c;
struct sfp *sfp;
bool poll = false;
int irq, err, i;
int err, i;

sfp = sfp_alloc(&pdev->dev);
if (IS_ERR(sfp))
Expand Down Expand Up @@ -1901,19 +1906,22 @@ static int sfp_probe(struct platform_device *pdev)
if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i])
continue;

irq = gpiod_to_irq(sfp->gpio[i]);
if (!irq) {
sfp->gpio_irq[i] = gpiod_to_irq(sfp->gpio[i]);
if (!sfp->gpio_irq[i]) {
poll = true;
continue;
}

err = devm_request_threaded_irq(sfp->dev, irq, NULL, sfp_irq,
err = devm_request_threaded_irq(sfp->dev, sfp->gpio_irq[i],
NULL, sfp_irq,
IRQF_ONESHOT |
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING,
dev_name(sfp->dev), sfp);
if (err)
if (err) {
sfp->gpio_irq[i] = 0;
poll = true;
}
}

if (poll)
Expand Down Expand Up @@ -1944,9 +1952,26 @@ static int sfp_remove(struct platform_device *pdev)
return 0;
}

static void sfp_shutdown(struct platform_device *pdev)
{
struct sfp *sfp = platform_get_drvdata(pdev);
int i;

for (i = 0; i < GPIO_MAX; i++) {
if (!sfp->gpio_irq[i])
continue;

devm_free_irq(sfp->dev, sfp->gpio_irq[i], sfp);
}

cancel_delayed_work_sync(&sfp->poll);
cancel_delayed_work_sync(&sfp->timeout);
}

static struct platform_driver sfp_driver = {
.probe = sfp_probe,
.remove = sfp_remove,
.shutdown = sfp_shutdown,
.driver = {
.name = "sfp",
.of_match_table = sfp_of_match,
Expand Down

0 comments on commit 9e49fe4

Please sign in to comment.