Commit 9e49fe4d authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 5270041d 2158e856
...@@ -185,12 +185,14 @@ struct sfp { ...@@ -185,12 +185,14 @@ struct sfp {
int (*write)(struct sfp *, bool, u8, void *, size_t); int (*write)(struct sfp *, bool, u8, void *, size_t);
struct gpio_desc *gpio[GPIO_MAX]; struct gpio_desc *gpio[GPIO_MAX];
int gpio_irq[GPIO_MAX];
bool attached; bool attached;
struct mutex st_mutex; /* Protects state */
unsigned int state; unsigned int state;
struct delayed_work poll; struct delayed_work poll;
struct delayed_work timeout; struct delayed_work timeout;
struct mutex sm_mutex; struct mutex sm_mutex; /* Protects state machine */
unsigned char sm_mod_state; unsigned char sm_mod_state;
unsigned char sm_dev_state; unsigned char sm_dev_state;
unsigned short sm_state; unsigned short sm_state;
...@@ -1720,6 +1722,7 @@ static void sfp_check_state(struct sfp *sfp) ...@@ -1720,6 +1722,7 @@ static void sfp_check_state(struct sfp *sfp)
{ {
unsigned int state, i, changed; unsigned int state, i, changed;
mutex_lock(&sfp->st_mutex);
state = sfp_get_state(sfp); state = sfp_get_state(sfp);
changed = state ^ sfp->state; changed = state ^ sfp->state;
changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT; changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT;
...@@ -1745,6 +1748,7 @@ static void sfp_check_state(struct sfp *sfp) ...@@ -1745,6 +1748,7 @@ static void sfp_check_state(struct sfp *sfp)
sfp_sm_event(sfp, state & SFP_F_LOS ? sfp_sm_event(sfp, state & SFP_F_LOS ?
SFP_E_LOS_HIGH : SFP_E_LOS_LOW); SFP_E_LOS_HIGH : SFP_E_LOS_LOW);
rtnl_unlock(); rtnl_unlock();
mutex_unlock(&sfp->st_mutex);
} }
static irqreturn_t sfp_irq(int irq, void *data) static irqreturn_t sfp_irq(int irq, void *data)
...@@ -1775,6 +1779,7 @@ static struct sfp *sfp_alloc(struct device *dev) ...@@ -1775,6 +1779,7 @@ static struct sfp *sfp_alloc(struct device *dev)
sfp->dev = dev; sfp->dev = dev;
mutex_init(&sfp->sm_mutex); mutex_init(&sfp->sm_mutex);
mutex_init(&sfp->st_mutex);
INIT_DELAYED_WORK(&sfp->poll, sfp_poll); INIT_DELAYED_WORK(&sfp->poll, sfp_poll);
INIT_DELAYED_WORK(&sfp->timeout, sfp_timeout); INIT_DELAYED_WORK(&sfp->timeout, sfp_timeout);
...@@ -1802,7 +1807,7 @@ static int sfp_probe(struct platform_device *pdev) ...@@ -1802,7 +1807,7 @@ static int sfp_probe(struct platform_device *pdev)
struct i2c_adapter *i2c; struct i2c_adapter *i2c;
struct sfp *sfp; struct sfp *sfp;
bool poll = false; bool poll = false;
int irq, err, i; int err, i;
sfp = sfp_alloc(&pdev->dev); sfp = sfp_alloc(&pdev->dev);
if (IS_ERR(sfp)) if (IS_ERR(sfp))
...@@ -1901,20 +1906,23 @@ static int sfp_probe(struct platform_device *pdev) ...@@ -1901,20 +1906,23 @@ static int sfp_probe(struct platform_device *pdev)
if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i]) if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i])
continue; continue;
irq = gpiod_to_irq(sfp->gpio[i]); sfp->gpio_irq[i] = gpiod_to_irq(sfp->gpio[i]);
if (!irq) { if (!sfp->gpio_irq[i]) {
poll = true; poll = true;
continue; 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_ONESHOT |
IRQF_TRIGGER_RISING | IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING, IRQF_TRIGGER_FALLING,
dev_name(sfp->dev), sfp); dev_name(sfp->dev), sfp);
if (err) if (err) {
sfp->gpio_irq[i] = 0;
poll = true; poll = true;
} }
}
if (poll) if (poll)
mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
...@@ -1944,9 +1952,26 @@ static int sfp_remove(struct platform_device *pdev) ...@@ -1944,9 +1952,26 @@ static int sfp_remove(struct platform_device *pdev)
return 0; 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 = { static struct platform_driver sfp_driver = {
.probe = sfp_probe, .probe = sfp_probe,
.remove = sfp_remove, .remove = sfp_remove,
.shutdown = sfp_shutdown,
.driver = { .driver = {
.name = "sfp", .name = "sfp",
.of_match_table = sfp_of_match, .of_match_table = sfp_of_match,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment