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,
 |