Commit 257c2559 authored by Robert Hancock's avatar Robert Hancock Committed by David S. Miller

net: sfp: Stop SFP polling and interrupt handling during shutdown

SFP device polling can cause problems during the shutdown process if the
parent devices of the network controller have been shut down already.
This problem was seen on the iMX6 platform with PCIe devices, where
accessing the device after the bus is shut down causes a hang.

Free any acquired GPIO interrupts and stop all delayed work in the SFP
driver during the shutdown process, so that we ensure that no pending
operations are still occurring after the SFP shutdown completes.
Signed-off-by: default avatarRobert Hancock <hancock@sedsystems.ca>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5270041d
...@@ -185,6 +185,7 @@ struct sfp { ...@@ -185,6 +185,7 @@ 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;
unsigned int state; unsigned int state;
...@@ -1802,7 +1803,7 @@ static int sfp_probe(struct platform_device *pdev) ...@@ -1802,7 +1803,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,19 +1902,22 @@ static int sfp_probe(struct platform_device *pdev) ...@@ -1901,19 +1902,22 @@ 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)
...@@ -1944,9 +1948,26 @@ static int sfp_remove(struct platform_device *pdev) ...@@ -1944,9 +1948,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