Backport the phy/phylink/sfp patches currently queued in netdev or in mainline necessary to support GPON popular modules, specifically to support Huawei and Nokia GPON modules. Signed-off-by: Russell King <linux@armlinux.org.uk> [jonas.gorski: include kernel version in file names, refresh patches] Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
		
			
				
	
	
		
			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,
 |