mirror of https://github.com/hak5/openwrt.git
95 lines
2.6 KiB
Diff
95 lines
2.6 KiB
Diff
From 254236a22109efa84c9e9f5a9c76a1719439e309 Mon Sep 17 00:00:00 2001
|
|
From: Robert Hancock <hancock@sedsystems.ca>
|
|
Date: Fri, 7 Jun 2019 10:42:35 -0600
|
|
Subject: [PATCH 612/660] 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: Robert Hancock <hancock@sedsystems.ca>
|
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
---
|
|
drivers/net/phy/sfp.c | 31 ++++++++++++++++++++++++++-----
|
|
1 file changed, 26 insertions(+), 5 deletions(-)
|
|
|
|
--- a/drivers/net/phy/sfp.c
|
|
+++ b/drivers/net/phy/sfp.c
|
|
@@ -183,6 +183,7 @@ 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 */
|
|
@@ -1803,7 +1804,7 @@ static int sfp_probe(struct platform_dev
|
|
const struct sff_data *sff;
|
|
struct sfp *sfp;
|
|
bool poll = false;
|
|
- int irq, err, i;
|
|
+ int err, i;
|
|
|
|
sfp = sfp_alloc(&pdev->dev);
|
|
if (IS_ERR(sfp))
|
|
@@ -1885,19 +1886,22 @@ static int sfp_probe(struct platform_dev
|
|
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)
|
|
@@ -1928,9 +1932,26 @@ static int sfp_remove(struct platform_de
|
|
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,
|