diff mbox

[PATCHv4,2/2] tg3: Allow ethtool to enable/disable loopback.

Message ID 1304559247-16111-1-git-send-email-maheshb@google.com
State RFC, archived
Delegated to: David Miller
Headers show

Commit Message

This patch adds tg3_set_features() to handle loopback mode. Currently the
capability is added for the devices which support internal MAC loopback mode.
So when enabled, it enables internal-MAC loopback.

Signed-off-by: Mahesh Bandewar <maheshb@google.com>
---
Changes since v3:
 (a) Corrected the condition (|| => &&) where loopback capability is added.
 (b) set_features() always returns 0.
 (c) Clear the loopback bit in ndo_open callback to avoid discrepancy.

Changes since v2:
 Implemtned Joe Perches's style change.

Changes since v1:
 Implemented Matt Carlson's suggestions.
  (a) Enable this capability on the devices which are capable of MAC-loopback
      mode.
  (b) check if the device is running before making changes.
  (c) check bits before making changes.

 drivers/net/tg3.c |   69 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 69 insertions(+), 0 deletions(-)

Comments

=?ISO-8859-2?Q?Micha=B3_Miros=B3aw?= May 5, 2011, 6:59 a.m. UTC | #1
2011/5/5 Mahesh Bandewar <maheshb@google.com>:
> This patch adds tg3_set_features() to handle loopback mode. Currently the
> capability is added for the devices which support internal MAC loopback mode.
> So when enabled, it enables internal-MAC loopback.
>
> Signed-off-by: Mahesh Bandewar <maheshb@google.com>
> ---
> Changes since v3:
>  (a) Corrected the condition (|| => &&) where loopback capability is added.
>  (b) set_features() always returns 0.
>  (c) Clear the loopback bit in ndo_open callback to avoid discrepancy.
>
> Changes since v2:
>  Implemtned Joe Perches's style change.
>
> Changes since v1:
>  Implemented Matt Carlson's suggestions.
>  (a) Enable this capability on the devices which are capable of MAC-loopback
>      mode.
>  (b) check if the device is running before making changes.
>  (c) check bits before making changes.
>
>  drivers/net/tg3.c |   69 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 69 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
> index 7c7c9a8..7f7a290 100644
> --- a/drivers/net/tg3.c
> +++ b/drivers/net/tg3.c
> @@ -6309,6 +6309,44 @@ dma_error:
>        return NETDEV_TX_OK;
>  }
>
> +static int tg3_set_loopback(struct net_device *dev, u32 features)
> +{
> +       struct tg3 *tp = netdev_priv(dev);
> +       u32 cur_mode = 0;
> +       int retval = 0;

void? You always return zero and don't check it in callers.

[...]
> @@ -9485,6 +9533,15 @@ static int tg3_open(struct net_device *dev)
>
>        netif_tx_start_all_queues(dev);
>
> +       /*
> +        * Reset loopback feature if it was turned on while the device was down
> +        * to avoid and any discrepancy in features reporting.
> +        */
> +       if (dev->features & NETIF_F_LOOPBACK) {
> +               dev->features &= ~NETIF_F_LOOPBACK;
> +               dev->wanted_features &= ~NETIF_F_LOOPBACK;
> +       }
> +

if (dev->features & NETIF_F_LOOPBACK)
  tg3_set_loopback(dev, dev->features);

Whatever you do, don't modify wanted_features in drivers.

BTW, similar problems (also like in previous versions) are in
forcedeth implementation.

Best Regards,
Michał Mirosław
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
On Wed, May 4, 2011 at 11:59 PM, Michał Mirosław <mirqus@gmail.com> wrote:
> 2011/5/5 Mahesh Bandewar <maheshb@google.com>:
>> This patch adds tg3_set_features() to handle loopback mode. Currently the
>> capability is added for the devices which support internal MAC loopback mode.
>> So when enabled, it enables internal-MAC loopback.
>>
>> Signed-off-by: Mahesh Bandewar <maheshb@google.com>
>> ---
>> Changes since v3:
>>  (a) Corrected the condition (|| => &&) where loopback capability is added.
>>  (b) set_features() always returns 0.
>>  (c) Clear the loopback bit in ndo_open callback to avoid discrepancy.
>>
>> Changes since v2:
>>  Implemtned Joe Perches's style change.
>>
>> Changes since v1:
>>  Implemented Matt Carlson's suggestions.
>>  (a) Enable this capability on the devices which are capable of MAC-loopback
>>      mode.
>>  (b) check if the device is running before making changes.
>>  (c) check bits before making changes.
>>
>>  drivers/net/tg3.c |   69 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  1 files changed, 69 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
>> index 7c7c9a8..7f7a290 100644
>> --- a/drivers/net/tg3.c
>> +++ b/drivers/net/tg3.c
>> @@ -6309,6 +6309,44 @@ dma_error:
>>        return NETDEV_TX_OK;
>>  }
>>
>> +static int tg3_set_loopback(struct net_device *dev, u32 features)
>> +{
>> +       struct tg3 *tp = netdev_priv(dev);
>> +       u32 cur_mode = 0;
>> +       int retval = 0;
>
> void? You always return zero and don't check it in callers.
>
> [...]
>> @@ -9485,6 +9533,15 @@ static int tg3_open(struct net_device *dev)
>>
>>        netif_tx_start_all_queues(dev);
>>
>> +       /*
>> +        * Reset loopback feature if it was turned on while the device was down
>> +        * to avoid and any discrepancy in features reporting.
>> +        */
>> +       if (dev->features & NETIF_F_LOOPBACK) {
>> +               dev->features &= ~NETIF_F_LOOPBACK;
>> +               dev->wanted_features &= ~NETIF_F_LOOPBACK;
>> +       }
>> +
>
> if (dev->features & NETIF_F_LOOPBACK)
>  tg3_set_loopback(dev, dev->features);
>
Unfortunately at this stage device will not be able to set-loopback so
I resorted to clearing the bit(s).

> Whatever you do, don't modify wanted_features in drivers.
>
Since just clearing the 'features' would leave wanted_features in
discrepant state, I thought this will bring it to a sane state. So
what is a preferred way?

> BTW, similar problems (also like in previous versions) are in
> forcedeth implementation.
Yes, whatever we decide about the state of the wanted_features, I'll
implement similarly for forcedeth. Which previous problem you are
referring to? Is it the return value? There is a different kind of
failure (error while writing the register). Since update_features()
cant handle return value, I'm ignoring the return value. As far as the
correct return code is concerned, I wasn't sure what is appropriate
return code here (may be PHY_ERROR would be appropriate there) but
again I could ignore it just the way rest of the code is ignoring.

>
> Best Regards,
> Michał Mirosław
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
=?ISO-8859-2?Q?Micha=B3_Miros=B3aw?= May 5, 2011, 6:35 p.m. UTC | #3
W dniu 5 maja 2011 19:47 użytkownik Mahesh Bandewar
<maheshb@google.com> napisał:
> On Wed, May 4, 2011 at 11:59 PM, Michał Mirosław <mirqus@gmail.com> wrote:
>> 2011/5/5 Mahesh Bandewar <maheshb@google.com>:
>>> This patch adds tg3_set_features() to handle loopback mode. Currently the
>>> capability is added for the devices which support internal MAC loopback mode.
>>> So when enabled, it enables internal-MAC loopback.
[...]
>>> @@ -9485,6 +9533,15 @@ static int tg3_open(struct net_device *dev)
>>>
>>>        netif_tx_start_all_queues(dev);
>>>
>>> +       /*
>>> +        * Reset loopback feature if it was turned on while the device was down
>>> +        * to avoid and any discrepancy in features reporting.
>>> +        */
>>> +       if (dev->features & NETIF_F_LOOPBACK) {
>>> +               dev->features &= ~NETIF_F_LOOPBACK;
>>> +               dev->wanted_features &= ~NETIF_F_LOOPBACK;
>>> +       }
>>> +
>>
>> if (dev->features & NETIF_F_LOOPBACK)
>>  tg3_set_loopback(dev, dev->features);
>>
> Unfortunately at this stage device will not be able to set-loopback so
> I resorted to clearing the bit(s).

ndo_fix_features+ndo_set_features might be caled before ndo_open - the
first might be just from register_netdev() so even before ndo_open
callback.

>> Whatever you do, don't modify wanted_features in drivers.
> Since just clearing the 'features' would leave wanted_features in
> discrepant state, I thought this will bring it to a sane state. So
> what is a preferred way?

If you really can't do other way, driver should keep additional state
that is checked in ndo_fix_features callback.

>> BTW, similar problems (also like in previous versions) are in
>> forcedeth implementation.
> Yes, whatever we decide about the state of the wanted_features, I'll
> implement similarly for forcedeth. Which previous problem you are
> referring to? Is it the return value? There is a different kind of
> failure (error while writing the register). Since update_features()
> cant handle return value, I'm ignoring the return value. As far as the
> correct return code is concerned, I wasn't sure what is appropriate
> return code here (may be PHY_ERROR would be appropriate there) but
> again I could ignore it just the way rest of the code is ignoring.

Let's wait for this threads points to be resolved. You will probably
change the forcedeth's implementation then anyway. :-)

Best Regards,
Michał Mirosław
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
On Thu, May 5, 2011 at 11:35 AM, Michał Mirosław <mirqus@gmail.com> wrote:
> W dniu 5 maja 2011 19:47 użytkownik Mahesh Bandewar
> <maheshb@google.com> napisał:
>> On Wed, May 4, 2011 at 11:59 PM, Michał Mirosław <mirqus@gmail.com> wrote:
>>> 2011/5/5 Mahesh Bandewar <maheshb@google.com>:
>>>> This patch adds tg3_set_features() to handle loopback mode. Currently the
>>>> capability is added for the devices which support internal MAC loopback mode.
>>>> So when enabled, it enables internal-MAC loopback.
> [...]
>>>> @@ -9485,6 +9533,15 @@ static int tg3_open(struct net_device *dev)
>>>>
>>>>        netif_tx_start_all_queues(dev);
>>>>
>>>> +       /*
>>>> +        * Reset loopback feature if it was turned on while the device was down
>>>> +        * to avoid and any discrepancy in features reporting.
>>>> +        */
>>>> +       if (dev->features & NETIF_F_LOOPBACK) {
>>>> +               dev->features &= ~NETIF_F_LOOPBACK;
>>>> +               dev->wanted_features &= ~NETIF_F_LOOPBACK;
>>>> +       }
>>>> +
>>>
>>> if (dev->features & NETIF_F_LOOPBACK)
>>>  tg3_set_loopback(dev, dev->features);
>>>
>> Unfortunately at this stage device will not be able to set-loopback so
>> I resorted to clearing the bit(s).
>
> ndo_fix_features+ndo_set_features might be caled before ndo_open - the
> first might be just from register_netdev() so even before ndo_open
> callback.
>
ndo_open is the triggering event, so anything before that point does
not really help.

>>> Whatever you do, don't modify wanted_features in drivers.
>> Since just clearing the 'features' would leave wanted_features in
>> discrepant state, I thought this will bring it to a sane state. So
>> what is a preferred way?
>
> If you really can't do other way, driver should keep additional state
> that is checked in ndo_fix_features callback.
>
ndo_fix_features callback is called just before calling
ndo_set_features callback. Also this is called during update_features,
so having the state maintained is not really going to help in this
scenario since that is not happening when device reaches ready state
(to remove this discrepancy in the feature-set).

There must be a reason (that you did not explain!) why driver code
should not alter wanted_feature set. So in this scenario, just leaving
the wanted_features as it is and clearing the features bit is correct
/ enough?


>>> BTW, similar problems (also like in previous versions) are in
>>> forcedeth implementation.
>> Yes, whatever we decide about the state of the wanted_features, I'll
>> implement similarly for forcedeth. Which previous problem you are
>> referring to? Is it the return value? There is a different kind of
>> failure (error while writing the register). Since update_features()
>> cant handle return value, I'm ignoring the return value. As far as the
>> correct return code is concerned, I wasn't sure what is appropriate
>> return code here (may be PHY_ERROR would be appropriate there) but
>> again I could ignore it just the way rest of the code is ignoring.
>
> Let's wait for this threads points to be resolved. You will probably
> change the forcedeth's implementation then anyway. :-)
>
agreed.

Thanks,
--mahesh..
> Best Regards,
> Michał Mirosław
>
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
=?ISO-8859-2?Q?Micha=B3_Miros=B3aw?= May 6, 2011, 6:35 a.m. UTC | #5
W dniu 6 maja 2011 01:16 użytkownik Mahesh Bandewar
<maheshb@google.com> napisał:
> On Thu, May 5, 2011 at 11:35 AM, Michał Mirosław <mirqus@gmail.com> wrote:
>> W dniu 5 maja 2011 19:47 użytkownik Mahesh Bandewar
>> <maheshb@google.com> napisał:
>>> On Wed, May 4, 2011 at 11:59 PM, Michał Mirosław <mirqus@gmail.com> wrote:
>>>> 2011/5/5 Mahesh Bandewar <maheshb@google.com>:
>>>>> This patch adds tg3_set_features() to handle loopback mode. Currently the
>>>>> capability is added for the devices which support internal MAC loopback mode.
>>>>> So when enabled, it enables internal-MAC loopback.
>> [...]
>>>>> @@ -9485,6 +9533,15 @@ static int tg3_open(struct net_device *dev)
>>>>>
>>>>>        netif_tx_start_all_queues(dev);
>>>>>
>>>>> +       /*
>>>>> +        * Reset loopback feature if it was turned on while the device was down
>>>>> +        * to avoid and any discrepancy in features reporting.
>>>>> +        */
>>>>> +       if (dev->features & NETIF_F_LOOPBACK) {
>>>>> +               dev->features &= ~NETIF_F_LOOPBACK;
>>>>> +               dev->wanted_features &= ~NETIF_F_LOOPBACK;
>>>>> +       }
>>>>> +
>>>>
>>>> if (dev->features & NETIF_F_LOOPBACK)
>>>>  tg3_set_loopback(dev, dev->features);
>>>>
>>> Unfortunately at this stage device will not be able to set-loopback so
>>> I resorted to clearing the bit(s).
>> ndo_fix_features+ndo_set_features might be caled before ndo_open - the
>> first might be just from register_netdev() so even before ndo_open
>> callback.
> ndo_open is the triggering event, so anything before that point does
> not really help.

You're right - I forgot that netif_running() becomes true just before
ndo_open is called. I have a hard time to convince myself that you
can't program the hardware for loopback just at the end of ndo_open
callback.

>>>> Whatever you do, don't modify wanted_features in drivers.
>>> Since just clearing the 'features' would leave wanted_features in
>>> discrepant state, I thought this will bring it to a sane state. So
>>> what is a preferred way?
>> If you really can't do other way, driver should keep additional state
>> that is checked in ndo_fix_features callback.
> ndo_fix_features callback is called just before calling
> ndo_set_features callback. Also this is called during update_features,
> so having the state maintained is not really going to help in this
> scenario since that is not happening when device reaches ready state
> (to remove this discrepancy in the feature-set).

You can call netdev_update_features() at the end of ndo_open. But that
would be the same in the end as just enabling the loopback there.

> There must be a reason (that you did not explain!) why driver code
> should not alter wanted_feature set. So in this scenario, just leaving
> the wanted_features as it is and clearing the features bit is correct
> / enough?

wanted_features reflects a set of features the user wants. I assume
that no code can change the user himself, so changing wanted_features
instead would break this connection. You can view wanted_features as a
cache of user's intention. ;-)

Best Regards,
Michał Mirosław
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 7c7c9a8..7f7a290 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -6309,6 +6309,44 @@  dma_error:
 	return NETDEV_TX_OK;
 }
 
+static int tg3_set_loopback(struct net_device *dev, u32 features)
+{
+	struct tg3 *tp = netdev_priv(dev);
+	u32 cur_mode = 0;
+	int retval = 0;
+
+	spin_lock_bh(&tp->lock);
+	cur_mode = tr32(MAC_MODE);
+	if (features & NETIF_F_LOOPBACK) {
+		if (cur_mode & MAC_MODE_PORT_INT_LPBACK)
+			goto sfeatures_unlock;
+
+		/*
+		 * Clear MAC_MODE_HALF_DUPLEX or you won't get packets back in
+		 * loopback mode if Half-Duplex mode was negotiated earlier.
+		 */
+		cur_mode &= ~MAC_MODE_HALF_DUPLEX;
+
+		/* Enable internal MAC loopback mode */
+		tw32(MAC_MODE, cur_mode | MAC_MODE_PORT_INT_LPBACK);
+		netif_carrier_on(tp->dev);
+		netdev_info(dev, "Internal MAC loopback mode enabled.\n");
+	} else {
+		if (!(cur_mode & MAC_MODE_PORT_INT_LPBACK))
+			goto sfeatures_unlock;
+
+		/* Disable internal MAC loopback mode */
+		tw32(MAC_MODE, cur_mode & ~MAC_MODE_PORT_INT_LPBACK);
+		/* Force link status check */
+		tg3_setup_phy(tp, 1);
+		netdev_info(dev, "Internal MAC loopback mode disabled.\n");
+	}
+
+sfeatures_unlock:
+	spin_unlock_bh(&tp->lock);
+	return retval;
+}
+
 static u32 tg3_fix_features(struct net_device *dev, u32 features)
 {
 	struct tg3 *tp = netdev_priv(dev);
@@ -6319,6 +6357,16 @@  static u32 tg3_fix_features(struct net_device *dev, u32 features)
 	return features;
 }
 
+static int tg3_set_features(struct net_device *dev, u32 features)
+{
+	u32 changed = dev->features ^ features;
+
+	if ((changed & NETIF_F_LOOPBACK) && netif_running(dev))
+		tg3_set_loopback(dev, features);
+
+	return 0;
+}
+
 static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp,
 			       int new_mtu)
 {
@@ -9485,6 +9533,15 @@  static int tg3_open(struct net_device *dev)
 
 	netif_tx_start_all_queues(dev);
 
+	/*
+	 * Reset loopback feature if it was turned on while the device was down
+	 * to avoid and any discrepancy in features reporting.
+	 */
+	if (dev->features & NETIF_F_LOOPBACK) {
+		dev->features &= ~NETIF_F_LOOPBACK;
+		dev->wanted_features &= ~NETIF_F_LOOPBACK;
+	}
+
 	return 0;
 
 err_out3:
@@ -15029,6 +15086,7 @@  static const struct net_device_ops tg3_netdev_ops = {
 	.ndo_tx_timeout		= tg3_tx_timeout,
 	.ndo_change_mtu		= tg3_change_mtu,
 	.ndo_fix_features	= tg3_fix_features,
+	.ndo_set_features	= tg3_set_features,
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	.ndo_poll_controller	= tg3_poll_controller,
 #endif
@@ -15045,6 +15103,7 @@  static const struct net_device_ops tg3_netdev_ops_dma_bug = {
 	.ndo_do_ioctl		= tg3_ioctl,
 	.ndo_tx_timeout		= tg3_tx_timeout,
 	.ndo_change_mtu		= tg3_change_mtu,
+	.ndo_set_features	= tg3_set_features,
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	.ndo_poll_controller	= tg3_poll_controller,
 #endif
@@ -15242,6 +15301,16 @@  static int __devinit tg3_init_one(struct pci_dev *pdev,
 	dev->features |= hw_features;
 	dev->vlan_features |= hw_features;
 
+	/*
+	 * Add loopback capability only for a subset of devices that support
+	 * MAC-LOOPBACK. Eventually this need to be enhanced to allow INT-PHY
+	 * loopback for the remaining devices.
+	 */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5780 &&
+	    !tg3_flag(tp, CPMU_PRESENT))
+		/* Add the loopback capability */
+		dev->hw_features |= NETIF_F_LOOPBACK;
+
 	if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 &&
 	    !tg3_flag(tp, TSO_CAPABLE) &&
 	    !(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH)) {