kernel: copy kernel 4.19 code to 5.4
[openwrt/openwrt.git] / target / linux / generic / backport-5.4 / 714-v5.3-net-sfp-Stop-SFP-polling-and-interrupt-handling-duri.patch
1 From 254236a22109efa84c9e9f5a9c76a1719439e309 Mon Sep 17 00:00:00 2001
2 From: Robert Hancock <hancock@sedsystems.ca>
3 Date: Fri, 7 Jun 2019 10:42:35 -0600
4 Subject: [PATCH 612/660] net: sfp: Stop SFP polling and interrupt handling
5 during shutdown
6
7 SFP device polling can cause problems during the shutdown process if the
8 parent devices of the network controller have been shut down already.
9 This problem was seen on the iMX6 platform with PCIe devices, where
10 accessing the device after the bus is shut down causes a hang.
11
12 Free any acquired GPIO interrupts and stop all delayed work in the SFP
13 driver during the shutdown process, so that we ensure that no pending
14 operations are still occurring after the SFP shutdown completes.
15
16 Signed-off-by: Robert Hancock <hancock@sedsystems.ca>
17 Signed-off-by: David S. Miller <davem@davemloft.net>
18 ---
19 drivers/net/phy/sfp.c | 31 ++++++++++++++++++++++++++-----
20 1 file changed, 26 insertions(+), 5 deletions(-)
21
22 --- a/drivers/net/phy/sfp.c
23 +++ b/drivers/net/phy/sfp.c
24 @@ -183,6 +183,7 @@ struct sfp {
25 int (*write)(struct sfp *, bool, u8, void *, size_t);
26
27 struct gpio_desc *gpio[GPIO_MAX];
28 + int gpio_irq[GPIO_MAX];
29
30 bool attached;
31 struct mutex st_mutex; /* Protects state */
32 @@ -1803,7 +1804,7 @@ static int sfp_probe(struct platform_dev
33 const struct sff_data *sff;
34 struct sfp *sfp;
35 bool poll = false;
36 - int irq, err, i;
37 + int err, i;
38
39 sfp = sfp_alloc(&pdev->dev);
40 if (IS_ERR(sfp))
41 @@ -1885,19 +1886,22 @@ static int sfp_probe(struct platform_dev
42 if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i])
43 continue;
44
45 - irq = gpiod_to_irq(sfp->gpio[i]);
46 - if (!irq) {
47 + sfp->gpio_irq[i] = gpiod_to_irq(sfp->gpio[i]);
48 + if (!sfp->gpio_irq[i]) {
49 poll = true;
50 continue;
51 }
52
53 - err = devm_request_threaded_irq(sfp->dev, irq, NULL, sfp_irq,
54 + err = devm_request_threaded_irq(sfp->dev, sfp->gpio_irq[i],
55 + NULL, sfp_irq,
56 IRQF_ONESHOT |
57 IRQF_TRIGGER_RISING |
58 IRQF_TRIGGER_FALLING,
59 dev_name(sfp->dev), sfp);
60 - if (err)
61 + if (err) {
62 + sfp->gpio_irq[i] = 0;
63 poll = true;
64 + }
65 }
66
67 if (poll)
68 @@ -1928,9 +1932,26 @@ static int sfp_remove(struct platform_de
69 return 0;
70 }
71
72 +static void sfp_shutdown(struct platform_device *pdev)
73 +{
74 + struct sfp *sfp = platform_get_drvdata(pdev);
75 + int i;
76 +
77 + for (i = 0; i < GPIO_MAX; i++) {
78 + if (!sfp->gpio_irq[i])
79 + continue;
80 +
81 + devm_free_irq(sfp->dev, sfp->gpio_irq[i], sfp);
82 + }
83 +
84 + cancel_delayed_work_sync(&sfp->poll);
85 + cancel_delayed_work_sync(&sfp->timeout);
86 +}
87 +
88 static struct platform_driver sfp_driver = {
89 .probe = sfp_probe,
90 .remove = sfp_remove,
91 + .shutdown = sfp_shutdown,
92 .driver = {
93 .name = "sfp",
94 .of_match_table = sfp_of_match,