diff mbox

[2/2] net/smsc911x: Move interrupt allocation to open/stop

Message ID 1472747141-15886-3-git-send-email-jeremy.linton@arm.com
State Changes Requested, archived
Delegated to: David Miller
Headers show

Commit Message

Jeremy Linton Sept. 1, 2016, 4:25 p.m. UTC
The /proc/irq/xx information is incorrect for smsc911x because
the request_irq is happening before the register_netdev has the
proper device name. Moving it to the open also fixes the case
of when the device is renamed.

Reported-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 drivers/net/ethernet/smsc/smsc911x.c | 50 +++++++++++++++---------------------
 1 file changed, 20 insertions(+), 30 deletions(-)

Comments

Andrew Lunn Sept. 1, 2016, 5:06 p.m. UTC | #1
Hi Jeremy 

Please don't add forward references. Move the function earlier in the
file.

>  static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
>  {
>  	if (pdata->config.flags & SMSC911X_USE_32BIT)
> @@ -1514,6 +1516,7 @@ static int smsc911x_open(struct net_device *dev)
>  	unsigned int temp;
>  	unsigned int intcfg;
>  	int retval;
> +	int irq_flags;
>  
>  	/* find and start the given phy */
>  	if (!dev->phydev) {
> @@ -1584,6 +1587,14 @@ static int smsc911x_open(struct net_device *dev)
>  	pdata->software_irq_signal = 0;
>  	smp_wmb();
>  
> +	irq_flags = irq_get_trigger_type(dev->irq);
> +	if (request_irq(dev->irq, smsc911x_irqhandler,
> +			irq_flags | IRQF_SHARED, dev->name, dev)) {
> +		SMSC_WARN(pdata, probe,
> +			  "Unable to claim requested irq: %d", dev->irq);
> +		goto mii_free_out;
> +	}
> +
>  	temp = smsc911x_reg_read(pdata, INT_EN);
>  	temp |= INT_EN_SW_INT_EN_;
>  	smsc911x_reg_write(pdata, INT_EN, temp);
> @@ -1599,7 +1610,7 @@ static int smsc911x_open(struct net_device *dev)
>  		netdev_warn(dev, "ISR failed signaling test (IRQ %d)\n",
>  			    dev->irq);
>  		retval = -ENODEV;
> -		goto mii_free_out;
> +		goto irq_stop_out;
>  	}
>  	SMSC_TRACE(pdata, ifup, "IRQ handler passed test using IRQ %d",
>  		   dev->irq);
> @@ -1645,7 +1656,8 @@ static int smsc911x_open(struct net_device *dev)
>  
>  	netif_start_queue(dev);
>  	return 0;
> -
> +irq_stop_out:
> +	free_irq(dev->irq, dev);
>  mii_free_out:
>  	phy_disconnect(dev->phydev);
>  	dev->phydev = NULL;
> @@ -1672,12 +1684,15 @@ static int smsc911x_stop(struct net_device *dev)
>  	dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP);
>  	smsc911x_tx_update_txcounters(dev);
>  
> +	free_irq(dev->irq, dev);
> +
>  	/* Bring the PHY down */
>  	if (dev->phydev) {
>  		phy_stop(dev->phydev);
>  		phy_disconnect(dev->phydev);
>  		dev->phydev = NULL;
>  	}
> +	netif_carrier_off(dev);

What has this change got to do with interrupt handling?

> @@ -2479,38 +2491,18 @@ static int smsc911x_drv_probe(struct platform_device *pdev)
>  	if (retval < 0)
>  		goto out_disable_resources;
>  
> -	/* configure irq polarity and type before connecting isr */
> -	if (pdata->config.irq_polarity == SMSC911X_IRQ_POLARITY_ACTIVE_HIGH)
> -		intcfg |= INT_CFG_IRQ_POL_;
> -
> -	if (pdata->config.irq_type == SMSC911X_IRQ_TYPE_PUSH_PULL)
> -		intcfg |= INT_CFG_IRQ_TYPE_;
> -
> -	smsc911x_reg_write(pdata, INT_CFG, intcfg);


I see these removes, but where are the adds?

  Andrew
Jeremy Linton Sept. 1, 2016, 6:47 p.m. UTC | #2
Hi Andrew,

	Thanks for taking a look at this!

On 09/01/2016 12:06 PM, Andrew Lunn wrote:
> Hi Jeremy
>
> Please don't add forward references. Move the function earlier in the
> file.

Ok, but I thought it was a fairly large move due to further dependent 
functions..

>
>>  static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
>>  {
>>  	if (pdata->config.flags & SMSC911X_USE_32BIT)
>> @@ -1514,6 +1516,7 @@ static int smsc911x_open(struct net_device *dev)
>>  	unsigned int temp;
>>  	unsigned int intcfg;
>>  	int retval;
>> +	int irq_flags;
>>
>>  	/* find and start the given phy */
>>  	if (!dev->phydev) {
>> @@ -1584,6 +1587,14 @@ static int smsc911x_open(struct net_device *dev)
>>  	pdata->software_irq_signal = 0;
>>  	smp_wmb();
>>
>> +	irq_flags = irq_get_trigger_type(dev->irq);
>> +	if (request_irq(dev->irq, smsc911x_irqhandler,
>> +			irq_flags | IRQF_SHARED, dev->name, dev)) {
>> +		SMSC_WARN(pdata, probe,
>> +			  "Unable to claim requested irq: %d", dev->irq);
>> +		goto mii_free_out;
>> +	}
>> +
>>  	temp = smsc911x_reg_read(pdata, INT_EN);
>>  	temp |= INT_EN_SW_INT_EN_;
>>  	smsc911x_reg_write(pdata, INT_EN, temp);
>> @@ -1599,7 +1610,7 @@ static int smsc911x_open(struct net_device *dev)
>>  		netdev_warn(dev, "ISR failed signaling test (IRQ %d)\n",
>>  			    dev->irq);
>>  		retval = -ENODEV;
>> -		goto mii_free_out;
>> +		goto irq_stop_out;
>>  	}
>>  	SMSC_TRACE(pdata, ifup, "IRQ handler passed test using IRQ %d",
>>  		   dev->irq);
>> @@ -1645,7 +1656,8 @@ static int smsc911x_open(struct net_device *dev)
>>
>>  	netif_start_queue(dev);
>>  	return 0;
>> -
>> +irq_stop_out:
>> +	free_irq(dev->irq, dev);
>>  mii_free_out:
>>  	phy_disconnect(dev->phydev);
>>  	dev->phydev = NULL;
>> @@ -1672,12 +1684,15 @@ static int smsc911x_stop(struct net_device *dev)
>>  	dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP);
>>  	smsc911x_tx_update_txcounters(dev);
>>
>> +	free_irq(dev->irq, dev);
>> +
>>  	/* Bring the PHY down */
>>  	if (dev->phydev) {
>>  		phy_stop(dev->phydev);
>>  		phy_disconnect(dev->phydev);
>>  		dev->phydev = NULL;
>>  	}
>> +	netif_carrier_off(dev);
>
> What has this change got to do with interrupt handling?

	This is a whoops, it should be in the previous patch..

>
>> @@ -2479,38 +2491,18 @@ static int smsc911x_drv_probe(struct platform_device *pdev)
>>  	if (retval < 0)
>>  		goto out_disable_resources;
>>
>> -	/* configure irq polarity and type before connecting isr */
>> -	if (pdata->config.irq_polarity == SMSC911X_IRQ_POLARITY_ACTIVE_HIGH)
>> -		intcfg |= INT_CFG_IRQ_POL_;
>> -
>> -	if (pdata->config.irq_type == SMSC911X_IRQ_TYPE_PUSH_PULL)
>> -		intcfg |= INT_CFG_IRQ_TYPE_;
>> -
>> -	smsc911x_reg_write(pdata, INT_CFG, intcfg);
>
>
> I see these removes, but where are the adds?


	The functionality is duplicated in open, when the IRQ handler is tested.
Andrew Lunn Sept. 1, 2016, 7:45 p.m. UTC | #3
On Thu, Sep 01, 2016 at 01:47:44PM -0500, Jeremy Linton wrote:
> Hi Andrew,
> 
> 	Thanks for taking a look at this!
> 
> On 09/01/2016 12:06 PM, Andrew Lunn wrote:
> >Hi Jeremy
> >
> >Please don't add forward references. Move the function earlier in the
> >file.
> 
> Ok, but I thought it was a fairly large move due to further
> dependent functions..

There are a few other options, like moving smsc911x_open() rather than
the interrupt handler.

And i would suggest what ever you do, make it a separate patch. A
patch which says: No functional changes, just move functions around as
needed by later patches, is going to be quick and easy to review.

> >>+	netif_carrier_off(dev);
> >
> >What has this change got to do with interrupt handling?
> 
> 	This is a whoops, it should be in the previous patch..

Or a patch of its own? You also needs to be careful with ordering
against the phy_connect.

> >>@@ -2479,38 +2491,18 @@ static int smsc911x_drv_probe(struct platform_device *pdev)
> >> 	if (retval < 0)
> >> 		goto out_disable_resources;
> >>
> >>-	/* configure irq polarity and type before connecting isr */
> >>-	if (pdata->config.irq_polarity == SMSC911X_IRQ_POLARITY_ACTIVE_HIGH)
> >>-		intcfg |= INT_CFG_IRQ_POL_;
> >>-
> >>-	if (pdata->config.irq_type == SMSC911X_IRQ_TYPE_PUSH_PULL)
> >>-		intcfg |= INT_CFG_IRQ_TYPE_;
> >>-
> >>-	smsc911x_reg_write(pdata, INT_CFG, intcfg);
> >
> >
> >I see these removes, but where are the adds?
> 
> 
> 	The functionality is duplicated in open, when the IRQ handler is tested.

Ah, it is obfusticated by SMC_SET_IRQ_CFG().

If you say it is duplicated, how about a separate patch removing it,
with a clear pointer to where the duplicate is.

     Andrew
Jeremy Linton Sept. 1, 2016, 8:39 p.m. UTC | #4
Hi,

On 09/01/2016 02:45 PM, Andrew Lunn wrote:
> On Thu, Sep 01, 2016 at 01:47:44PM -0500, Jeremy Linton wrote:
>> Hi Andrew,
>>
>> 	Thanks for taking a look at this!
>>
>> On 09/01/2016 12:06 PM, Andrew Lunn wrote:
>>> Hi Jeremy
>>>
>>> Please don't add forward references. Move the function earlier in the
>>> file.
>>
>> Ok, but I thought it was a fairly large move due to further
>> dependent functions..
>
> There are a few other options, like moving smsc911x_open() rather than
> the interrupt handler.
>
> And i would suggest what ever you do, make it a separate patch. A
> patch which says: No functional changes, just move functions around as
> needed by later patches, is going to be quick and easy to review.

Yes I put it in another patch, I was busy blasting it out rather than 
checking my email...

>
>>>> +	netif_carrier_off(dev);
>>>
>>> What has this change got to do with interrupt handling?
>>
>> 	This is a whoops, it should be in the previous patch..
>
> Or a patch of its own? You also needs to be careful with ordering
> against the phy_connect.
>
>>>> @@ -2479,38 +2491,18 @@ static int smsc911x_drv_probe(struct platform_device *pdev)
>>>> 	if (retval < 0)
>>>> 		goto out_disable_resources;
>>>>
>>>> -	/* configure irq polarity and type before connecting isr */
>>>> -	if (pdata->config.irq_polarity == SMSC911X_IRQ_POLARITY_ACTIVE_HIGH)
>>>> -		intcfg |= INT_CFG_IRQ_POL_;
>>>> -
>>>> -	if (pdata->config.irq_type == SMSC911X_IRQ_TYPE_PUSH_PULL)
>>>> -		intcfg |= INT_CFG_IRQ_TYPE_;
>>>> -
>>>> -	smsc911x_reg_write(pdata, INT_CFG, intcfg);
>>>
>>>
>>> I see these removes, but where are the adds?
>>
>>
>> 	The functionality is duplicated in open, when the IRQ handler is tested.
>
> Ah, it is obfusticated by SMC_SET_IRQ_CFG().
>
> If you say it is duplicated, how about a separate patch removing it,
> with a clear pointer to where the duplicate is.

? Well, I didn't do that part, but I'm confused by your 
SMC_SET_IRQ_CFG(). AFAIK, that is smc911x not smsc911x. The code in 
question is in smsc911x_open() following "Set interrupt deassertion to 
100uS". It looks a little different but its reprogramming the INT_CFG 
preceding the interrupt being enabled.

Really, if I were feeling brave (because this driver is used in so many 
strange pieces of hardware) I would rewrite a large portion of the 
interrupt management in this driver. I started looking at it last month, 
while looking for the mdio polling issue, because I wanted to get the 
link state changes directly. While at it I noticed the WOL functionality 
could use some attention, etc, one problem after another.
diff mbox

Patch

diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c
index 6d6dcfe..8ef9776 100644
--- a/drivers/net/ethernet/smsc/smsc911x.c
+++ b/drivers/net/ethernet/smsc/smsc911x.c
@@ -154,6 +154,8 @@  struct smsc911x_data {
 /* Easy access to information */
 #define __smsc_shift(pdata, reg) ((reg) << ((pdata)->config.shift))
 
+static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id);
+
 static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
 {
 	if (pdata->config.flags & SMSC911X_USE_32BIT)
@@ -1514,6 +1516,7 @@  static int smsc911x_open(struct net_device *dev)
 	unsigned int temp;
 	unsigned int intcfg;
 	int retval;
+	int irq_flags;
 
 	/* find and start the given phy */
 	if (!dev->phydev) {
@@ -1584,6 +1587,14 @@  static int smsc911x_open(struct net_device *dev)
 	pdata->software_irq_signal = 0;
 	smp_wmb();
 
+	irq_flags = irq_get_trigger_type(dev->irq);
+	if (request_irq(dev->irq, smsc911x_irqhandler,
+			irq_flags | IRQF_SHARED, dev->name, dev)) {
+		SMSC_WARN(pdata, probe,
+			  "Unable to claim requested irq: %d", dev->irq);
+		goto mii_free_out;
+	}
+
 	temp = smsc911x_reg_read(pdata, INT_EN);
 	temp |= INT_EN_SW_INT_EN_;
 	smsc911x_reg_write(pdata, INT_EN, temp);
@@ -1599,7 +1610,7 @@  static int smsc911x_open(struct net_device *dev)
 		netdev_warn(dev, "ISR failed signaling test (IRQ %d)\n",
 			    dev->irq);
 		retval = -ENODEV;
-		goto mii_free_out;
+		goto irq_stop_out;
 	}
 	SMSC_TRACE(pdata, ifup, "IRQ handler passed test using IRQ %d",
 		   dev->irq);
@@ -1645,7 +1656,8 @@  static int smsc911x_open(struct net_device *dev)
 
 	netif_start_queue(dev);
 	return 0;
-
+irq_stop_out:
+	free_irq(dev->irq, dev);
 mii_free_out:
 	phy_disconnect(dev->phydev);
 	dev->phydev = NULL;
@@ -1672,12 +1684,15 @@  static int smsc911x_stop(struct net_device *dev)
 	dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP);
 	smsc911x_tx_update_txcounters(dev);
 
+	free_irq(dev->irq, dev);
+
 	/* Bring the PHY down */
 	if (dev->phydev) {
 		phy_stop(dev->phydev);
 		phy_disconnect(dev->phydev);
 		dev->phydev = NULL;
 	}
+	netif_carrier_off(dev);
 
 	SMSC_TRACE(pdata, ifdown, "Interface stopped");
 	return 0;
@@ -2307,7 +2322,6 @@  static int smsc911x_drv_remove(struct platform_device *pdev)
 	mdiobus_free(pdata->mii_bus);
 
 	unregister_netdev(dev);
-	free_irq(dev->irq, dev);
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 					   "smsc911x-memory");
 	if (!res)
@@ -2392,8 +2406,7 @@  static int smsc911x_drv_probe(struct platform_device *pdev)
 	struct smsc911x_data *pdata;
 	struct smsc911x_platform_config *config = dev_get_platdata(&pdev->dev);
 	struct resource *res;
-	unsigned int intcfg = 0;
-	int res_size, irq, irq_flags;
+	int res_size, irq;
 	int retval;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
@@ -2432,7 +2445,6 @@  static int smsc911x_drv_probe(struct platform_device *pdev)
 
 	pdata = netdev_priv(dev);
 	dev->irq = irq;
-	irq_flags = irq_get_trigger_type(irq);
 	pdata->ioaddr = ioremap_nocache(res->start, res_size);
 
 	pdata->dev = dev;
@@ -2479,38 +2491,18 @@  static int smsc911x_drv_probe(struct platform_device *pdev)
 	if (retval < 0)
 		goto out_disable_resources;
 
-	/* configure irq polarity and type before connecting isr */
-	if (pdata->config.irq_polarity == SMSC911X_IRQ_POLARITY_ACTIVE_HIGH)
-		intcfg |= INT_CFG_IRQ_POL_;
-
-	if (pdata->config.irq_type == SMSC911X_IRQ_TYPE_PUSH_PULL)
-		intcfg |= INT_CFG_IRQ_TYPE_;
-
-	smsc911x_reg_write(pdata, INT_CFG, intcfg);
-
-	/* Ensure interrupts are globally disabled before connecting ISR */
-	smsc911x_disable_irq_chip(dev);
-
-	retval = request_irq(dev->irq, smsc911x_irqhandler,
-			     irq_flags | IRQF_SHARED, dev->name, dev);
-	if (retval) {
-		SMSC_WARN(pdata, probe,
-			  "Unable to claim requested irq: %d", dev->irq);
-		goto out_disable_resources;
-	}
-
 	netif_carrier_off(dev);
 
 	retval = smsc911x_mii_init(pdev, dev);
 	if (retval) {
 		SMSC_WARN(pdata, probe, "Error %i initialising mii", retval);
-		goto out_free_irq;
+		goto out_disable_resources;
 	}
 
 	retval = register_netdev(dev);
 	if (retval) {
 		SMSC_WARN(pdata, probe, "Error %i registering device", retval);
-		goto out_free_irq;
+		goto out_disable_resources;
 	} else {
 		SMSC_TRACE(pdata, probe,
 			   "Network interface: \"%s\"", dev->name);
@@ -2551,8 +2543,6 @@  static int smsc911x_drv_probe(struct platform_device *pdev)
 
 	return 0;
 
-out_free_irq:
-	free_irq(dev->irq, dev);
 out_disable_resources:
 	pm_runtime_put(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);