aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic/backport-5.4/714-v5.3-net-sfp-Stop-SFP-polling-and-interrupt-handling-duri.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/generic/backport-5.4/714-v5.3-net-sfp-Stop-SFP-polling-and-interrupt-handling-duri.patch')
-rw-r--r--target/linux/generic/backport-5.4/714-v5.3-net-sfp-Stop-SFP-polling-and-interrupt-handling-duri.patch94
1 files changed, 94 insertions, 0 deletions
diff --git a/target/linux/generic/backport-5.4/714-v5.3-net-sfp-Stop-SFP-polling-and-interrupt-handling-duri.patch b/target/linux/generic/backport-5.4/714-v5.3-net-sfp-Stop-SFP-polling-and-interrupt-handling-duri.patch
new file mode 100644
index 0000000000..0509950296
--- /dev/null
+++ b/target/linux/generic/backport-5.4/714-v5.3-net-sfp-Stop-SFP-polling-and-interrupt-handling-duri.patch
@@ -0,0 +1,94 @@
+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,