diff options
author | David S. Miller <davem@davemloft.net> | 2019-06-09 19:25:59 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-06-09 19:25:59 -0700 |
commit | 9e49fe4d6e17a38e8168effee181f001d2d22a5a (patch) | |
tree | 50eb78dea2a7df27e52f863b4c2a288ac4e54e9f | |
parent | 5270041d342de6f1e6a3b6634c1ceaa67d1f87ea (diff) | |
parent | 2158e856f56bb762ef90f3ec244d41a519826f75 (diff) | |
download | linux-9e49fe4d6e17a38e8168effee181f001d2d22a5a.tar.bz2 |
Merge branch 'SFP-polling-fixes'
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>
-rw-r--r-- | drivers/net/phy/sfp.c | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index a991c80e6567..97960d73b4ab 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -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; @@ -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; @@ -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) @@ -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); @@ -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)) @@ -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) @@ -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, |