Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH] CAIF: fix indentation for function arguments
From: Joe Perches @ 2013-03-07  0:07 UTC (permalink / raw)
  To: Silviu-Mihai Popescu; +Cc: netdev, sjur.brandeland, davem, linux-kernel
In-Reply-To: <1362606521-16848-1-git-send-email-silviupopescu1990@gmail.com>

On Wed, 2013-03-06 at 23:48 +0200, Silviu-Mihai Popescu wrote:
> This lines up function arguments on second and subsequent lines at the
> first column after the openning parenthesis of the first line.
[]
> diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c
[]
> @@ -301,10 +301,10 @@ static void dev_flowctrl(struct net_device *dev, int on)
>  }
>  
>  void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
> -			struct cflayer *link_support, int head_room,
> -			struct cflayer **layer, int (**rcv_func)(
> -				struct sk_buff *, struct net_device *,
> -				struct packet_type *, struct net_device *))
> +		     struct cflayer *link_support, int head_room,
> +		     struct cflayer **layer, int (**rcv_func)(
> +		     struct sk_buff *, struct net_device *,
> +		     struct packet_type *, struct net_device *))

This makes it seem that caif_enroll_dev takes more args.

I think this style is better (aligned to appropriate open paren)

void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
		     struct cflayer *link_support, int head_room,
		     struct cflayer **layer,
		     int (**rcv_func)(struct sk_buff *, struct net_device *,
				      struct packet_type *, struct net_device *))

[]

> @@ -301,8 +301,8 @@ static int caif_connect_req_to_link_param(struct cfcnfg *cnfg,
>  
>  int caif_connect_client(struct net *net, struct caif_connect_request *conn_req,
>  			struct cflayer *adap_layer, int *ifindex,
> -				int *proto_head,
> -				int *proto_tail)
> +			int *proto_head,
> +			int *proto_tail)

You could fill to 80 here.

^ permalink raw reply

* [PATCH linux-firmware] tg3: Add EEE support firmware for 57766 cards
From: Nithin Nayak Sujir @ 2013-03-07  0:07 UTC (permalink / raw)
  To: bhutchings; +Cc: netdev, mchan, Nithin Nayak Sujir

57766 devices with no nvram need a service patch firmware for the boot
code to support EEE. This patch adds the fw.

Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
---
 WHENCE             |   3 ++-
 tigon/tg357766.bin | Bin 0 -> 144 bytes
 2 files changed, 2 insertions(+), 1 deletion(-)
 create mode 100644 tigon/tg357766.bin

diff --git a/WHENCE b/WHENCE
index 7c2c921..1d1f5b7 100644
--- a/WHENCE
+++ b/WHENCE
@@ -602,11 +602,12 @@ Driver: tg3 -- Broadcom Tigon3 based gigabit Ethernet cards
 File: tigon/tg3.bin
 File: tigon/tg3_tso.bin
 File: tigon/tg3_tso5.bin
+File: tigon/tg357766.bin
 
 Licence:
  * Firmware is:
  *	Derived from proprietary unpublished source code,
- *	Copyright (C) 2000-2003 Broadcom Corporation.
+ *	Copyright (C) 2000-2013 Broadcom Corporation.
  *
  *	Permission is hereby granted for the distribution of this firmware
  *	data in hexadecimal or equivalent format, provided this copyright
diff --git a/tigon/tg357766.bin b/tigon/tg357766.bin
new file mode 100644
index 0000000000000000000000000000000000000000..b7816a0776262b3323f99f7dd071f3fdc31a2ba9
GIT binary patch
literal 144
zcmZQz00L$PhW|it@6_+LAT|)Bs5dY$e*fTLcUHr!M36y{;roAq6!Sa=M)d>+hVLKh
zUw!|;zyib)X9Uc27$g`Z#2Y~33>=3o%r=1JjsWRn3TAtNW^tYdvVro9;t32~5Ig<?
Vg&71cxZDtf@c*0v@tF*mm;f?XF`fVb

literal 0
HcmV?d00001

-- 
1.8.1.4

^ permalink raw reply related

* Re: [PATCH] netconsole: release the spinlock before __netpoll_cleanup()
From: Neil Horman @ 2013-03-07  0:08 UTC (permalink / raw)
  To: Veaceslav Falico; +Cc: netdev, amwang, davem
In-Reply-To: <1362581203-8994-1-git-send-email-vfalico@redhat.com>

On Wed, Mar 06, 2013 at 03:46:43PM +0100, Veaceslav Falico wrote:
> Commit 3335f0ca130c201f8680e97f63612053fbc16e22 removed spinlock unlocking
> before __netpoll_cleanup() in netconsole_netdev_event(), however we still
> might sleep in __netpoll_cleanup() - via synchronize_srcu(). Revert it and
> add a comment.
> 
> Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
> ---
>  drivers/net/netconsole.c |   10 ++++++++++
>  1 files changed, 10 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
> index 37add21..dd62b4c 100644
> --- a/drivers/net/netconsole.c
> +++ b/drivers/net/netconsole.c
> @@ -680,7 +680,17 @@ static int netconsole_netdev_event(struct notifier_block *this,
>  				 * rtnl_lock already held
>  				 */
>  				if (nt->np.dev) {
> +					/*
> +					 * we still might sleep in
> +					 * __netpoll_cleanup(), so release
> +					 * the lock
> +					 */
> +					spin_unlock_irqrestore(
> +							      &target_list_lock,
> +							      flags);
>  					__netpoll_cleanup(&nt->np);
> +					spin_lock_irqsave(&target_list_lock,
> +							  flags);
>  					dev_put(nt->np.dev);
>  					nt->np.dev = NULL;
>  				}
> -- 
> 1.7.1
> 
Thanks for noticing this Vaeceslav, but you can't just drop and re-acquire the
lock like this, as it protect the list_for_each_entry loop that you're in.  You
can drop the lock in the above if clause, but then, after the nt->np.dev = NULL,
go back an re-aquire the lock, and start the for loop.  I thought we had already
done this for some other purpose in this code using a label and a goto, but I
suppose I was mistaken

Best
Neil

> 

^ permalink raw reply

* Re: [PATCH net-next 06/12] ipvs: optimize dst usage for real server
From: Julian Anastasov @ 2013-03-07  0:14 UTC (permalink / raw)
  To: David Miller; +Cc: horms, lvs-devel, netdev
In-Reply-To: <20130306.170637.1142655516995808574.davem@davemloft.net>


	Hello,

On Wed, 6 Mar 2013, David Miller wrote:

> From: Julian Anastasov <ja@ssi.bg>
> Date: Wed, 6 Mar 2013 23:58:09 +0200 (EET)
> 
> > 	There are two choices: __ip_vs_get_out_rt
> > to return refdst as implemented in this patchset or
> > to return dst with additional 'bool *noref' argument,
> > so that caller can decide between skb_dst_set or
> > skb_set_dst_noref. Then may be we will need just
> > a new skb_dst_set_noref_{always,force} func that will
> > contain the old skb_set_dst_noref code, i.e. without
> > dst_hold? Not sure which variant sounds better.
> 
> Both variants are starting to sound equally ugly :-)
> 
> Let me ask about this situation in another way.
> 
> IP input route lookup clients handle this transparently,
> even for routes with next-hop exceptions and nocache
> routes, by passing the SKB into the lookup function and
> there it will sort out whether noref is actually possible.
> 
> Is there a reason that IPVS's route lookup architecture
> can't work this way too?

	May be it is possible, eg. by adding more
arguments to __ip_vs_get_out_rt and moving all dst
checks and icmp_send there. But there are some dst
checks specific to the forwarding method, so I'm not
sure in the end result yet.

	For IPVS, noref is always possible because the
dst_cache var holds reference, even for the NOCACHE case
which is more likely to occur. So, some new variant of
skb_dst_set_noref that supports NOCACHE without dst_hold
is still needed.

Regards

--
Julian Anastasov <ja@ssi.bg>

^ permalink raw reply

* Re: [PATCH] CAIF: fix indentation for function arguments
From: David Miller @ 2013-03-07  0:35 UTC (permalink / raw)
  To: joe; +Cc: silviupopescu1990, netdev, sjur.brandeland, linux-kernel
In-Reply-To: <1362614837.2093.30.camel@joe-AO722>

From: Joe Perches <joe@perches.com>
Date: Wed, 06 Mar 2013 16:07:17 -0800

> On Wed, 2013-03-06 at 23:48 +0200, Silviu-Mihai Popescu wrote:
>> This lines up function arguments on second and subsequent lines at the
>> first column after the openning parenthesis of the first line.
> []
>> diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c
> []
>> @@ -301,10 +301,10 @@ static void dev_flowctrl(struct net_device *dev, int on)
>>  }
>>  
>>  void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
>> -			struct cflayer *link_support, int head_room,
>> -			struct cflayer **layer, int (**rcv_func)(
>> -				struct sk_buff *, struct net_device *,
>> -				struct packet_type *, struct net_device *))
>> +		     struct cflayer *link_support, int head_room,
>> +		     struct cflayer **layer, int (**rcv_func)(
>> +		     struct sk_buff *, struct net_device *,
>> +		     struct packet_type *, struct net_device *))
> 
> This makes it seem that caif_enroll_dev takes more args.
> 
> I think this style is better (aligned to appropriate open paren)
> 
> void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
> 		     struct cflayer *link_support, int head_room,
> 		     struct cflayer **layer,
> 		     int (**rcv_func)(struct sk_buff *, struct net_device *,
> 				      struct packet_type *, struct net_device *))

Agreed.

^ permalink raw reply

* Re: BUG: IPv4: Attempt to release TCP socket in state 1
From: dormando @ 2013-03-07  0:41 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: Cong Wang, linux-kernel, netdev
In-Reply-To: <1362494795.15793.113.camel@edumazet-glaptop>

> On Mon, 2013-03-04 at 21:44 -0800, dormando wrote:
>
> > No 3rd party modules. There's a tiny patch for controlling initcwnd from
> > userspace and another one for the extra_free_kbytes tunable that I brought
> > up in another thread. We've had the initcwnd patch in for a long time
> > without trouble. The extra_free_kbytes tunable isn't even being used yet,
> > so all that's doing is adding a 0 somewhere.
> >
> > Only two iptables rules loaded: global NOTRACK rules for PREROUTING/OUTPUT
> > in raw.
> >
> > Kernel's as close to pristine as I can make it. We had the 10g patch in
> > but I've dropped it.
> > --
>
> Hmm, I spent time on this bug report but found nothing.
>
> Please post as much information as you can on your setup.
>
> I see you use macvlan, bridge, so maybe there is a configuration issue
> (and a kernel bug of course)

Ok... bridge module is loaded but nothing seems to be using it. No
bond/tunnels/anything enabled. I couldn't quickly figure out what was
causing it to load.

We removed the need for macvlan, started machines with a fresh boot, and
they still crashed without it, after a few hours.

Unfortunately I just saw a machine crash in the same way on 3.6.6 and
3.6.9. I'm working on getting a completely pristine 3.6.6 and 3.6.9
tested. Our patches are minor but there were a few, so I'm backing it all
out just to be sure.

Is there anything in particular which is most interesting? I can post lots
and lots and lots of information. Sadly bridge/macvlan weren't part of the
problem. .config, sysctls are easiest I guess? When this "hang" happens
the machine is still up somewhat, but we lose access to it. Syslog is
still writing entries to disk occasionally, so it's possible we could set
something up to dump more information.

It takes a day or two to cycle this, so it might take a while to get
information and test crashes.

thanks,
-Dormando

^ permalink raw reply

* [PATCH v2 resent net-next 0/4] Provide default fdb operation to allow mac filter setting
From: Vlad Yasevich @ 2013-03-07  1:39 UTC (permalink / raw)
  To: netdev; +Cc: or.gerlitz, Vlad Yasevich

This is a short series that now allows mac filter programming on any
card that support IFF_UNICAST_FLT by using the existing FDB interface.

Some existing drivers that had FDB functionality usually supported
it only in SR-IOV mode.  Since that's not always enabled, and
we want to take advantage of IFF_UNICAST_FLT support, these drivers
have been converted to call the default handler when not in SRIOV mode.

Changes since v1:
 - Restore ixgbe implementation of fdb_add since it needs to 
   enforce the limit of addresses in SR-IOV case.

Changes since RFC:
 - Removed ixgbe and mlx versions of fdb calls as recommened.
 - Added qlogic patch to use default calls when module parameter is
   not turned on.

Vlad Yasevich (4):
  net: generic fdb support for drivers without ndo_fdb_<op>
  ixgbe: Make use of the default fdb handlers.
  mlx4: Remove driver specific fdb handlers.
  qlcnic: Use generic fdb handler when driver options are not enabled.

 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c    |   42 +-----------
 drivers/net/ethernet/mellanox/mlx4/en_netdev.c   |   76 --------------------
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c |   21 ++----
 include/linux/rtnetlink.h                        |    9 +++
 net/core/rtnetlink.c                             |   81 ++++++++++++++++++++--
 5 files changed, 91 insertions(+), 138 deletions(-)

-- 
1.7.7.6

^ permalink raw reply

* [PATCH v2 resent net-next 1/4] net: generic fdb support for drivers without ndo_fdb_<op>
From: Vlad Yasevich @ 2013-03-07  1:39 UTC (permalink / raw)
  To: netdev; +Cc: or.gerlitz, Vlad Yasevich, John Fastabend
In-Reply-To: <1362620385-14553-1-git-send-email-vyasevic@redhat.com>

If the driver does not support the ndo_op use the generic
handler for it. This should work in the majority of cases.
Eventually the fdb_dflt_add call gets translated into a
__dev_set_rx_mode() call which should handle hardware
support for filtering via the IFF_UNICAST_FLT flag.

Namely IFF_UNICAST_FLT indicates if the hardware can do
unicast address filtering. If no support is available
the device is put into promisc mode.

Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
---
 include/linux/rtnetlink.h |    9 +++++
 net/core/rtnetlink.c      |   81 +++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 84 insertions(+), 6 deletions(-)

diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 489dd7bb..f28544b 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -69,6 +69,15 @@ extern int ndo_dflt_fdb_dump(struct sk_buff *skb,
 			     struct netlink_callback *cb,
 			     struct net_device *dev,
 			     int idx);
+extern int ndo_dflt_fdb_add(struct ndmsg *ndm,
+			    struct nlattr *tb[],
+			    struct net_device *dev,
+			    const unsigned char *addr,
+			     u16 flags);
+extern int ndo_dflt_fdb_del(struct ndmsg *ndm,
+			    struct nlattr *tb[],
+			    struct net_device *dev,
+			    const unsigned char *addr);
 
 extern int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
 				   struct net_device *dev, u16 mode);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index b376410..f95b6fb 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -2048,6 +2048,38 @@ errout:
 	rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
 }
 
+/**
+ * ndo_dflt_fdb_add - default netdevice operation to add an FDB entry
+ */
+int ndo_dflt_fdb_add(struct ndmsg *ndm,
+		     struct nlattr *tb[],
+		     struct net_device *dev,
+		     const unsigned char *addr,
+		     u16 flags)
+{
+	int err = -EINVAL;
+
+	/* If aging addresses are supported device will need to
+	 * implement its own handler for this.
+	 */
+	if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
+		pr_info("%s: FDB only supports static addresses\n", dev->name);
+		return err;
+	}
+
+	if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr))
+		err = dev_uc_add_excl(dev, addr);
+	else if (is_multicast_ether_addr(addr))
+		err = dev_mc_add_excl(dev, addr);
+
+	/* Only return duplicate errors if NLM_F_EXCL is set */
+	if (err == -EEXIST && !(flags & NLM_F_EXCL))
+		err = 0;
+
+	return err;
+}
+EXPORT_SYMBOL(ndo_dflt_fdb_add);
+
 static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
 	struct net *net = sock_net(skb->sk);
@@ -2100,10 +2132,13 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 	}
 
 	/* Embedded bridge, macvlan, and any other device support */
-	if ((ndm->ndm_flags & NTF_SELF) && dev->netdev_ops->ndo_fdb_add) {
-		err = dev->netdev_ops->ndo_fdb_add(ndm, tb,
-						   dev, addr,
-						   nlh->nlmsg_flags);
+	if ((ndm->ndm_flags & NTF_SELF)) {
+		if (dev->netdev_ops->ndo_fdb_add)
+			err = dev->netdev_ops->ndo_fdb_add(ndm, tb, dev, addr,
+							   nlh->nlmsg_flags);
+		else
+			err = ndo_dflt_fdb_add(ndm, tb, dev, addr,
+					       nlh->nlmsg_flags);
 
 		if (!err) {
 			rtnl_fdb_notify(dev, addr, RTM_NEWNEIGH);
@@ -2114,6 +2149,35 @@ out:
 	return err;
 }
 
+/**
+ * ndo_dflt_fdb_del - default netdevice operation to delete an FDB entry
+ */
+int ndo_dflt_fdb_del(struct ndmsg *ndm,
+		     struct nlattr *tb[],
+		     struct net_device *dev,
+		     const unsigned char *addr)
+{
+	int err = -EOPNOTSUPP;
+
+	/* If aging addresses are supported device will need to
+	 * implement its own handler for this.
+	 */
+	if (ndm->ndm_state & NUD_PERMANENT) {
+		pr_info("%s: FDB only supports static addresses\n", dev->name);
+		return -EINVAL;
+	}
+
+	if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr))
+		err = dev_uc_del(dev, addr);
+	else if (is_multicast_ether_addr(addr))
+		err = dev_mc_del(dev, addr);
+	else
+		err = -EINVAL;
+
+	return err;
+}
+EXPORT_SYMBOL(ndo_dflt_fdb_del);
+
 static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
 	struct net *net = sock_net(skb->sk);
@@ -2171,8 +2235,11 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 	}
 
 	/* Embedded bridge, macvlan, and any other device support */
-	if ((ndm->ndm_flags & NTF_SELF) && dev->netdev_ops->ndo_fdb_del) {
-		err = dev->netdev_ops->ndo_fdb_del(ndm, tb, dev, addr);
+	if (ndm->ndm_flags & NTF_SELF) {
+		if (dev->netdev_ops->ndo_fdb_del)
+			err = dev->netdev_ops->ndo_fdb_del(ndm, tb, dev, addr);
+		else
+			err = ndo_dflt_fdb_del(ndm, tb, dev, addr);
 
 		if (!err) {
 			rtnl_fdb_notify(dev, addr, RTM_DELNEIGH);
@@ -2257,6 +2324,8 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
 
 		if (dev->netdev_ops->ndo_fdb_dump)
 			idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, dev, idx);
+		else
+			ndo_dflt_fdb_dump(skb, cb, dev, idx);
 	}
 	rcu_read_unlock();
 
-- 
1.7.7.6

^ permalink raw reply related

* [PATCH v2 resent net-next 2/4] ixgbe: Make use of the default fdb handlers.
From: Vlad Yasevich @ 2013-03-07  1:39 UTC (permalink / raw)
  To: netdev; +Cc: or.gerlitz, Vlad Yasevich, John Fastabend, CC: Gregory Rose
In-Reply-To: <1362620385-14553-1-git-send-email-vyasevic@redhat.com>

For fdb_add, use the default handler in the non-SRIOV case.
For the other fdb handlers, just remove them and use the
default ones.

CC: John Fastabend <john.r.fastabend@intel.com>
Acked-By: John Fastabend <john.r.fastabend@intel.com>
CC: CC: Gregory Rose <gregory.v.rose@intel.com>
Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |   42 +------------------------
 1 files changed, 1 insertions(+), 41 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index db5611a..e56a3d1 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -7007,7 +7007,7 @@ static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
 	int err;
 
 	if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
-		return -EOPNOTSUPP;
+		return ndo_dflt_fdb_add(ndm, tb, dev, addr, flags);
 
 	/* Hardware does not support aging addresses so if a
 	 * ndm_state is given only allow permanent addresses
@@ -7038,44 +7038,6 @@ static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
 	return err;
 }
 
-static int ixgbe_ndo_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
-			     struct net_device *dev,
-			     const unsigned char *addr)
-{
-	struct ixgbe_adapter *adapter = netdev_priv(dev);
-	int err = -EOPNOTSUPP;
-
-	if (ndm->ndm_state & NUD_PERMANENT) {
-		pr_info("%s: FDB only supports static addresses\n",
-			ixgbe_driver_name);
-		return -EINVAL;
-	}
-
-	if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
-		if (is_unicast_ether_addr(addr))
-			err = dev_uc_del(dev, addr);
-		else if (is_multicast_ether_addr(addr))
-			err = dev_mc_del(dev, addr);
-		else
-			err = -EINVAL;
-	}
-
-	return err;
-}
-
-static int ixgbe_ndo_fdb_dump(struct sk_buff *skb,
-			      struct netlink_callback *cb,
-			      struct net_device *dev,
-			      int idx)
-{
-	struct ixgbe_adapter *adapter = netdev_priv(dev);
-
-	if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
-		idx = ndo_dflt_fdb_dump(skb, cb, dev, idx);
-
-	return idx;
-}
-
 static int ixgbe_ndo_bridge_setlink(struct net_device *dev,
 				    struct nlmsghdr *nlh)
 {
@@ -7171,8 +7133,6 @@ static const struct net_device_ops ixgbe_netdev_ops = {
 	.ndo_set_features = ixgbe_set_features,
 	.ndo_fix_features = ixgbe_fix_features,
 	.ndo_fdb_add		= ixgbe_ndo_fdb_add,
-	.ndo_fdb_del		= ixgbe_ndo_fdb_del,
-	.ndo_fdb_dump		= ixgbe_ndo_fdb_dump,
 	.ndo_bridge_setlink	= ixgbe_ndo_bridge_setlink,
 	.ndo_bridge_getlink	= ixgbe_ndo_bridge_getlink,
 };
-- 
1.7.7.6

^ permalink raw reply related

* [PATCH v2 resent net-next 4/4] qlcnic: Use generic fdb handler when driver options are not enabled.
From: Vlad Yasevich @ 2013-03-07  1:39 UTC (permalink / raw)
  To: netdev
  Cc: or.gerlitz, Vlad Yasevich, Jitendra Kalsaria, Sony Chacko,
	linux-driver
In-Reply-To: <1362620385-14553-1-git-send-email-vyasevic@redhat.com>

Allow qlcnic to use the generic fdb handler when the driver options
are not enabled.   Untill the driver is fully fixed, this allows
the use of the FDB interface with qlogic driver, but simply puts
the driver into promisc mode since the driver currently does not
support IFF_UNICAST_FLT.

CC: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
Acked-by: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
CC: Sony Chacko <sony.chacko@qlogic.com>
CC: linux-driver@qlogic.com
Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c |   21 ++++++---------------
 1 files changed, 6 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 28a6d48..c6f9d5e 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -253,11 +253,8 @@ static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
 	int err = -EOPNOTSUPP;
 
-	if (!adapter->fdb_mac_learn) {
-		pr_info("%s: Driver mac learn is enabled, FDB operation not allowed\n",
-			__func__);
-		return err;
-	}
+	if (!adapter->fdb_mac_learn)
+		return ndo_dflt_fdb_del(ndm, tb, netdev, addr);
 
 	if (adapter->flags & QLCNIC_ESWITCH_ENABLED) {
 		if (is_unicast_ether_addr(addr))
@@ -277,11 +274,8 @@ static int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
 	int err = 0;
 
-	if (!adapter->fdb_mac_learn) {
-		pr_info("%s: Driver mac learn is enabled, FDB operation not allowed\n",
-			__func__);
-		return -EOPNOTSUPP;
-	}
+	if (!adapter->fdb_mac_learn)
+		return ndo_dflt_fdb_add(ndm, tb, netdev, addr, flags);
 
 	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
 		pr_info("%s: FDB e-switch is not enabled\n", __func__);
@@ -306,11 +300,8 @@ static int qlcnic_fdb_dump(struct sk_buff *skb, struct netlink_callback *ncb,
 {
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
 
-	if (!adapter->fdb_mac_learn) {
-		pr_info("%s: Driver mac learn is enabled, FDB operation not allowed\n",
-			__func__);
-		return -EOPNOTSUPP;
-	}
+	if (!adapter->fdb_mac_learn)
+		return ndo_dflt_fdb_dump(skb, ncb, netdev, idx);
 
 	if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
 		idx = ndo_dflt_fdb_dump(skb, ncb, netdev, idx);
-- 
1.7.7.6

^ permalink raw reply related

* [PATCH v2 resent net-next 3/4] mlx4: Remove driver specific fdb handlers.
From: Vlad Yasevich @ 2013-03-07  1:39 UTC (permalink / raw)
  To: netdev; +Cc: or.gerlitz, Vlad Yasevich, Amir Vadai, Yan Burman
In-Reply-To: <1362620385-14553-1-git-send-email-vyasevic@redhat.com>

Remove driver specific fdb hadlers since they are the same as
the default ones.

CC: Amir Vadai <amirv@mellanox.com>
CC: Yan Burman <yanb@mellanox.com>
Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
 drivers/net/ethernet/mellanox/mlx4/en_netdev.c |   76 ------------------------
 1 files changed, 0 insertions(+), 76 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index bb4d8d9..4c37d48 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -1924,79 +1924,6 @@ static int mlx4_en_set_features(struct net_device *netdev,
 
 }
 
-static int mlx4_en_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
-			   struct net_device *dev,
-			   const unsigned char *addr, u16 flags)
-{
-	struct mlx4_en_priv *priv = netdev_priv(dev);
-	struct mlx4_dev *mdev = priv->mdev->dev;
-	int err;
-
-	if (!mlx4_is_mfunc(mdev))
-		return -EOPNOTSUPP;
-
-	/* Hardware does not support aging addresses, allow only
-	 * permanent addresses if ndm_state is given
-	 */
-	if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
-		en_info(priv, "Add FDB only supports static addresses\n");
-		return -EINVAL;
-	}
-
-	if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr))
-		err = dev_uc_add_excl(dev, addr);
-	else if (is_multicast_ether_addr(addr))
-		err = dev_mc_add_excl(dev, addr);
-	else
-		err = -EINVAL;
-
-	/* Only return duplicate errors if NLM_F_EXCL is set */
-	if (err == -EEXIST && !(flags & NLM_F_EXCL))
-		err = 0;
-
-	return err;
-}
-
-static int mlx4_en_fdb_del(struct ndmsg *ndm,
-			   struct nlattr *tb[],
-			   struct net_device *dev,
-			   const unsigned char *addr)
-{
-	struct mlx4_en_priv *priv = netdev_priv(dev);
-	struct mlx4_dev *mdev = priv->mdev->dev;
-	int err;
-
-	if (!mlx4_is_mfunc(mdev))
-		return -EOPNOTSUPP;
-
-	if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
-		en_info(priv, "Del FDB only supports static addresses\n");
-		return -EINVAL;
-	}
-
-	if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr))
-		err = dev_uc_del(dev, addr);
-	else if (is_multicast_ether_addr(addr))
-		err = dev_mc_del(dev, addr);
-	else
-		err = -EINVAL;
-
-	return err;
-}
-
-static int mlx4_en_fdb_dump(struct sk_buff *skb,
-			    struct netlink_callback *cb,
-			    struct net_device *dev, int idx)
-{
-	struct mlx4_en_priv *priv = netdev_priv(dev);
-	struct mlx4_dev *mdev = priv->mdev->dev;
-
-	if (mlx4_is_mfunc(mdev))
-		idx = ndo_dflt_fdb_dump(skb, cb, dev, idx);
-
-	return idx;
-}
-
 static const struct net_device_ops mlx4_netdev_ops = {
 	.ndo_open		= mlx4_en_open,
 	.ndo_stop		= mlx4_en_close,
@@ -2018,9 +1945,6 @@ static const struct net_device_ops mlx4_netdev_ops = {
 #ifdef CONFIG_RFS_ACCEL
 	.ndo_rx_flow_steer	= mlx4_en_filter_rfs,
 #endif
-	.ndo_fdb_add		= mlx4_en_fdb_add,
-	.ndo_fdb_del		= mlx4_en_fdb_del,
-	.ndo_fdb_dump		= mlx4_en_fdb_dump,
 };
 
 int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
-- 
1.7.7.6

^ permalink raw reply related

* Re: hitting lockdep warning as of too early VF probe with 3.9-rc1
From: Ming Lei @ 2013-03-07  2:03 UTC (permalink / raw)
  To: Or Gerlitz
  Cc: Or Gerlitz, Greg Kroah-Hartman, David Miller, Roland Dreier,
	netdev, Yan Burman, Jack Morgenstein, Liran Liss
In-Reply-To: <CAJZOPZ+_N53n59cJv00=GXETNhZJUEvgcLEB+D-ujBdSsyvM9g@mail.gmail.com>

On Thu, Mar 7, 2013 at 4:54 AM, Or Gerlitz <or.gerlitz@gmail.com> wrote:
> On Wed, Mar 6, 2013 at 4:43 AM, Ming Lei <ming.lei@canonical.com> wrote:
>> You are adding one new PCI device inside another PCI device's probe(),
>> so the new device will be probed, since PCI probe() is scheduled by
>> work_on_cpu, then cause flush_work() called inside worker function,
>> which might be a real deadlock.
>
> So if I understand correct, you recommend to somehow avoid this nested probing?

Yes, you might need to avoid the nested probing in your driver.

>
>> I am wondering why this commit can cause the problem, since the PCI
>> device will be probed with its driver if there is one driver for it. There is no
>> any limit on when the driver should be loaded into system, either before
>> device is added or after.
>
> FWIW to undertstanding the issue - the same driver (mlx4_core) is used
> by the PF and VF, so the VF driver is already loaded at the time its
> been added as new PCI device.
>
>> From driver core view, looks no wrong things are found.
>
> So this got me confused, you pointed on possible deadlock, are you
> saying the deadlock wouldn't be the result of how the driver code is
> going nor the commited we bisected?

My commit only affects the driver loading path, but your warning
is hit in driver probe path triggered by device addition, so the lockdep
warning should still be triggered without my commit since the two paths
are totally independent, right?

Thanks,
--
Ming Lei

^ permalink raw reply

* Re: [PATCH v1 1/7] USB: adds comment on suspend callback
From: Ming Lei @ 2013-03-07  2:09 UTC (permalink / raw)
  To: Alan Stern
  Cc: David S. Miller, Greg Kroah-Hartman, Jiri Kosina, Oliver Neukum,
	netdev, linux-usb, linux-input
In-Reply-To: <Pine.LNX.4.44L0.1303061012330.1955-100000@iolanthe.rowland.org>

On Wed, Mar 6, 2013 at 11:25 PM, Alan Stern <stern@rowland.harvard.edu> wrote:
> On Wed, 6 Mar 2013, Ming Lei wrote:
>
>> This patch adds comments on interface driver suspend callback
>> to emphasize that the failure return value is ignored by
>> USB core in system sleep context, so do not try to recover
>> device for this case and let resume/reset_resume callback
>> handle the suspend failure if needed.
>
> In this same patch you should also update the kerneldoc for
> usb_suspend_both().  It should mention that errors returned by the
> suspend method for @udev will be ignored during system suspend.

OK.

>
>> Signed-off-by: Ming Lei <ming.lei@canonical.com>
>> ---
>>  include/linux/usb.h |    9 ++++++++-
>>  1 file changed, 8 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/linux/usb.h b/include/linux/usb.h
>> index 4d22d0f..6e66dc4 100644
>> --- a/include/linux/usb.h
>> +++ b/include/linux/usb.h
>> @@ -978,7 +978,14 @@ struct usbdrv_wrap {
>>   *   the "usbfs" filesystem.  This lets devices provide ways to
>>   *   expose information to user space regardless of where they
>>   *   do (or don't) show up otherwise in the filesystem.
>> - * @suspend: Called when the device is going to be suspended by the system.
>> + * @suspend: Called when the device is going to be suspended by the
>> + *   system either from system sleep or runtime suspend context, and
>> + *   its failure return value will be ignored in system sleep context,
>
> This is an ungrammatical run-on sentence.  s/, and its failure/. The/

OK.

>
>> + *   so do NOT try to recover device for this case. It is suggested
>> + *   the callback always return 0 if resume/reset_resume callback can
>> + *   handle system sususpend failure at default, otherwise driver
>> + *   need to record the suspend failure and let resume/reset_resume
>> + *   handle previous system suspend failure to recover device.
>
> I don't understand what this is supposed to mean.  How about this
> instead?  "so do NOT try to continue using the device if suspend fails
> in this case.  Instead, let the resume or reset-resume routine recover
> from the failure."

Looks your description is more neat, and will take it in v2.


Thanks,
--
Ming Lei

^ permalink raw reply

* Re: kernel panic in fib6_age (linux-3.6.6) and sugguested fix
From: snakky.zhang @ 2013-03-07  2:28 UTC (permalink / raw)
  To: Zhouyi Zhou; +Cc: netdev
In-Reply-To: <CAABZP2xs4qm7j75Hu5BaXuWOF3ddzrZPJxbTGhxpOvwHxA75Uw@mail.gmail.com>

On 2013年03月06日 23:36, Zhouyi Zhou wrote:
> hi,
>    My linux-3.6.6 kernel panics very often during reboot.
>    I have reported in bugzilla.kernel.org as bug id 54731.
>
> Kernel panic backtrace (using remote gdb):
> #0  0xffffffff8176a91a in fib6_age (rt=0xffff8800571c6780, arg=0x0
> <irq_stack_union>) at net/ipv6/ip6_fib.c:1566
> #1  0xffffffff8176a461 in fib6_clean_node (w=0xffff8800655fb4e8) at
> net/ipv6/ip6_fib.c:1422
> #2  0xffffffff8176a266 in fib6_walk_continue (w=0xffff8800655fb4e8) at
> net/ipv6/ip6_fib.c:1362
> #3  0xffffffff8176a3d5 in fib6_walk (w=0xffff8800655fb4e8) at
> net/ipv6/ip6_fib.c:1406
> #4  0xffffffff8176a59d in fib6_clean_tree (net=0xffffffff81edb300 <init_net>,
> root=0xffff880036c41950
> ...
> gdb>p neigh
> (gdb) p neigh
> $18 = (struct neighbour *) 0xffffffffffffff97
>
>
>
> There are a lot of ipv6 nodes in my link local environment, and the kernel
> report IPv6: Neighbour table overflow constantly.
>
> I guess the cause of the panic is:
> dst_neigh_lookup calls ip6_neigh_lookup indirectly, and neigh_create return
> ENOBUFS in case of neighbour table full.
> 139 static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
> 140                                           struct sk_buff *skb,
> 141                                           const void *daddr)
> 142 {
> 143         struct rt6_info *rt = (struct rt6_info *) dst;
> 144         struct neighbour *n;
> 145
> 146         daddr = choose_neigh_daddr(rt, skb, daddr);
> 147         n = __ipv6_neigh_lookup(&nd_tbl, dst->dev, daddr);
> 148         if (n)
> 149                 return n;
> 150         return neigh_create(&nd_tbl, daddr, dst->dev);
> 151 }
>
> A possible fix may be:
>
>              neigh = dst_neigh_lookup(&rt->dst, &rt->rt6i_gateway);
> +           if (IS_ERR(neigh))
> +             return PTR_ERR(neigh);
>              else{
>                       neigh_flags = neigh->flags;
>                       neigh_release(neigh);
>              }
>
How about this one below? without modifying the return value:
                         __u8 neigh_flags = 0;

                         neigh = dst_neigh_lookup(&rt->dst, 
&rt->rt6i_gateway);
-                       if (neigh) {
+                       if (!IS_ERR(neigh)) {
                                 neigh_flags = neigh->flags;
                                 neigh_release(neigh);
                         }


Thanks
Xiao


> Thanks for your attention
>
> Zhouyi
> --
> 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
>
>

^ permalink raw reply

* [RFC PATCH net-next 0/3] Allow bridge to function in non-promisc mode
From: Vlad Yasevich @ 2013-03-07  2:31 UTC (permalink / raw)
  To: netdev; +Cc: Vlad Yasevich, bridge

This is a first stab at the series that allows bridge to function
in non-promiscuouse mode.

The series adds a sysfs control to turn off promiscusouse mode all on ports of
the bridge.  To handle multicast, we turn on IFF_ALLMULTI for now.  Eventually
we would deal with multicast addresses.

The second patch adds an ability to designate an uplink port on the bridge.

Finally, we add an ability to add hw address to the bridge and sync those
addresses to the uplink ports.

In this way a bridge could be programmed with appropriate mac addresses and
could function in non-promiscuouse mode.

All comments are welcome.

Vlad Yasevich (3):
  bridge: Add mac_management sysfs interface
  bridge: Allow an ability to designate an uplink port
  bridge: Implement IFF_UNICAST_FLT

 include/uapi/linux/if_link.h |    1 +
 net/bridge/br_device.c       |   51 +++++++++++++++++++++++++++++++++++++++++-
 net/bridge/br_fdb.c          |    6 +++++
 net/bridge/br_if.c           |   38 +++++++++++++++++++++++++++----
 net/bridge/br_netlink.c      |    6 +++++
 net/bridge/br_private.h      |    6 +++++
 net/bridge/br_sysfs_br.c     |   17 ++++++++++++++
 net/bridge/br_sysfs_if.c     |   13 ++++++++++
 8 files changed, 132 insertions(+), 6 deletions(-)

-- 
1.7.7.6

^ permalink raw reply

* [RFC PATCH net-next 1/3] bridge: Add mac_management sysfs interface
From: Vlad Yasevich @ 2013-03-07  2:31 UTC (permalink / raw)
  To: netdev; +Cc: bridge, Vlad Yasevich
In-Reply-To: <1362623485-18209-1-git-send-email-vyasevic@redhat.com>

Add an sysfs interface to turn MAC address management on an off.
When MAC management is off (default), all interfaces in the bridge
are in promisc mode.  When MAC management is on, promisc mode is
turned off and the expectation is that user will manually program
the MAC filter.

Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
 net/bridge/br_device.c   |   41 +++++++++++++++++++++++++++++++++++++++++
 net/bridge/br_if.c       |   22 +++++++++++++++++-----
 net/bridge/br_private.h  |    2 ++
 net/bridge/br_sysfs_br.c |   17 +++++++++++++++++
 4 files changed, 77 insertions(+), 5 deletions(-)

diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index d5f1d3f..160bc74 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -185,6 +185,46 @@ static int br_set_mac_address(struct net_device *dev, void *p)
 	return 0;
 }
 
+int br_set_promisc(struct net_bridge* br, unsigned long val)
+{
+	struct net_bridge_port *p;
+
+	if (!rtnl_trylock())
+		return restart_syscall();
+
+	spin_lock_bh(&br->lock);
+
+	if (val) {
+		if (br->promisc_enabled)
+			goto unlock;
+
+		br->promisc_enabled = 1;
+		/* For each port on the bridge, turn on promisc mode and
+		 * turn off ALLMULTI to handle multicast traffic.
+		 */
+		list_for_each_entry(p, &br->port_list, list) {
+			dev_set_promiscuity(p->dev, 1);
+			dev_set_allmulti(p->dev, -1);
+		}
+
+	} else {
+		if (!br->promisc_enabled)
+			goto unlock;
+
+		br->promisc_enabled = 0;
+		/* For each port on the bridge, turn off promisc mode */
+		list_for_each_entry(p, &br->port_list, list) {
+			dev_set_allmulti(p->dev, 1);
+			dev_set_promiscuity(p->dev, -1);
+		}
+	}
+unlock:
+	spin_unlock_bh(&br->lock);
+	rtnl_unlock();
+	return 0;
+}
+
+
 static void br_getinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
 	strlcpy(info->driver, "bridge", sizeof(info->driver));
@@ -371,6 +411,7 @@ void br_dev_setup(struct net_device *dev)
 	br->bridge_hello_time = br->hello_time = 2 * HZ;
 	br->bridge_forward_delay = br->forward_delay = 15 * HZ;
 	br->ageing_time = 300 * HZ;
+	br->promisc_enabled = 1;
 
 	br_netfilter_rtable_init(br);
 	br_stp_timer_init(br);
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index ef1b914..02b4440 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -132,7 +132,10 @@ static void del_nbp(struct net_bridge_port *p)
 
 	sysfs_remove_link(br->ifobj, p->dev->name);
 
-	dev_set_promiscuity(dev, -1);
+	if (br->promisc_enabled)
+		dev_set_promiscuity(dev, -1);
+	else
+		dev_set_allmulti(dev, -1);
 
 	spin_lock_bh(&br->lock);
 	br_stp_disable_port(p);
@@ -350,9 +353,15 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
 
 	call_netdevice_notifiers(NETDEV_JOIN, dev);
 
-	err = dev_set_promiscuity(dev, 1);
-	if (err)
-		goto put_back;
+	if (br->promisc_enabled) {
+		err = dev_set_promiscuity(dev, 1);
+		if (err)
+			goto put_back;
+	} else {
+		err = dev_set_allmulti(dev, 1);
+		if (err)
+			goto put_back;
+	}
 
 	err = kobject_init_and_add(&p->kobj, &brport_ktype, &(dev->dev.kobj),
 				   SYSFS_BRIDGE_PORT_ATTR);
@@ -414,7 +423,10 @@ err2:
 	kobject_put(&p->kobj);
 	p = NULL; /* kobject_put frees */
 err1:
-	dev_set_promiscuity(dev, -1);
+	if (br->promisc_enabled)
+		dev_set_promiscuity(dev, -1);
+	else
+		dev_set_allmulti(dev, -1);
 put_back:
 	dev_put(dev);
 	kfree(p);
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 6d314c4..4a0fa29 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -277,6 +277,7 @@ struct net_bridge
 	struct timer_list		topology_change_timer;
 	struct timer_list		gc_timer;
 	struct kobject			*ifobj;
+	u8				promisc_enabled;
 #ifdef CONFIG_BRIDGE_VLAN_FILTERING
 	u8				vlan_enabled;
 	struct net_port_vlans __rcu	*vlan_info;
@@ -327,6 +328,7 @@ extern void br_dev_setup(struct net_device *dev);
 extern void br_dev_delete(struct net_device *dev, struct list_head *list);
 extern netdev_tx_t br_dev_xmit(struct sk_buff *skb,
 			       struct net_device *dev);
+extern int br_set_promisc(struct net_bridge *br, unsigned long val);
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static inline struct netpoll_info *br_netpoll_info(struct net_bridge *br)
 {
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index 8baa9c0..5489219 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -710,6 +710,22 @@ static DEVICE_ATTR(vlan_filtering, S_IRUGO | S_IWUSR,
 		   show_vlan_filtering, store_vlan_filtering);
 #endif
 
+static ssize_t show_promisc(struct device *d,
+			    struct device_attribute *attr, char *buf)
+{
+	struct net_bridge *br = to_bridge(d);
+	return sprintf(buf, "%d\n", br->promisc_enabled);
+}
+
+static ssize_t store_promisc(struct device *d,
+			     struct device_attribute *attr,
+			     const char *buf, size_t len)
+{
+	return store_bridge_parm(d, buf, len, br_set_promisc);
+}
+static DEVICE_ATTR(promisc, S_IRUGO | S_IWUSR, show_promisc,
+		   store_promisc);
+
 static struct attribute *bridge_attrs[] = {
 	&dev_attr_forward_delay.attr,
 	&dev_attr_hello_time.attr,
@@ -753,6 +769,7 @@ static struct attribute *bridge_attrs[] = {
 #ifdef CONFIG_BRIDGE_VLAN_FILTERING
 	&dev_attr_vlan_filtering.attr,
 #endif
+	&dev_attr_promisc.attr,
 	NULL
 };
 
-- 
1.7.7.6

^ permalink raw reply related

* [RFC PATCH net-next 2/3] bridge: Allow an ability to designate an uplink port
From: Vlad Yasevich @ 2013-03-07  2:31 UTC (permalink / raw)
  To: netdev; +Cc: bridge, Vlad Yasevich
In-Reply-To: <1362623485-18209-1-git-send-email-vyasevic@redhat.com>

Allow a ports to be designated as uplink.  Multiple ports
may be designated as uplinks and they will be kept in a
list.

Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
 include/uapi/linux/if_link.h |    1 +
 net/bridge/br_device.c       |    1 +
 net/bridge/br_if.c           |   16 ++++++++++++++++
 net/bridge/br_netlink.c      |    6 ++++++
 net/bridge/br_private.h      |    4 ++++
 net/bridge/br_sysfs_if.c     |   13 +++++++++++++
 6 files changed, 41 insertions(+), 0 deletions(-)

diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index c4edfe1..b9444e9 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -220,6 +220,7 @@ enum {
 	IFLA_BRPORT_GUARD,	/* bpdu guard              */
 	IFLA_BRPORT_PROTECT,	/* root port protection    */
 	IFLA_BRPORT_FAST_LEAVE,	/* multicast fast leave    */
+	IFLA_BRPORT_UPLINK,	/* uplink port */
 	__IFLA_BRPORT_MAX
 };
 #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 160bc74..c525e36 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -396,6 +396,7 @@ void br_dev_setup(struct net_device *dev)
 	br->dev = dev;
 	spin_lock_init(&br->lock);
 	INIT_LIST_HEAD(&br->port_list);
+	INIT_LIST_HEAD(&br->uplink_list);
 	spin_lock_init(&br->hash_lock);
 
 	br->bridge_id.prio[0] = 0x80;
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 02b4440..4b0636b 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -131,6 +131,7 @@ static void del_nbp(struct net_bridge_port *p)
 	struct net_device *dev = p->dev;
 
 	sysfs_remove_link(br->ifobj, p->dev->name);
+	list_del_rcu(&p->uplink_list);
 
 	if (br->promisc_enabled)
 		dev_set_promiscuity(dev, -1);
@@ -461,6 +462,21 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
 	return 0;
 }
 
+void br_set_uplink(struct net_bridge_port *p, unsigned long v)
+{
+	if (v) {
+		if (!list_empty(&p->uplink_list))
+			return;
+
+		list_add_rcu(&p->uplink_list, &p->br->uplink_list);
+	} else {
+		if (list_empty(&p->uplink_list))
+			return;
+
+		list_del_rcu(&p->uplink_list);
+	}
+}
+
 void __net_exit br_net_exit(struct net *net)
 {
 	struct net_device *dev;
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 27aa3ee..8965b51 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -283,6 +283,7 @@ static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = {
 	[IFLA_BRPORT_MODE]	= { .type = NLA_U8 },
 	[IFLA_BRPORT_GUARD]	= { .type = NLA_U8 },
 	[IFLA_BRPORT_PROTECT]	= { .type = NLA_U8 },
+	[IFLA_BRPORT_UPLINK]	= { .type = NLA_U8 },
 };
 
 /* Change the state of the port and notify spanning tree */
@@ -347,6 +348,11 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
 		if (err)
 			return err;
 	}
+
+	if (tb[IFLA_BRPORT_UPLINK]) {
+		br_set_uplink(p, nla_get_u8(tb[IFLA_BRPORT_UPLINK]));
+	}
+
 	return 0;
 }
 
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 4a0fa29..9502b1e 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -130,6 +130,7 @@ struct net_bridge_port
 	struct net_bridge		*br;
 	struct net_device		*dev;
 	struct list_head		list;
+	struct list_head		uplink_list;
 
 	/* STP */
 	u8				priority;
@@ -277,6 +278,7 @@ struct net_bridge
 	struct timer_list		topology_change_timer;
 	struct timer_list		gc_timer;
 	struct kobject			*ifobj;
+	struct list_head		uplink_list;
 	u8				promisc_enabled;
 #ifdef CONFIG_BRIDGE_VLAN_FILTERING
 	u8				vlan_enabled;
@@ -428,6 +430,8 @@ extern int br_del_if(struct net_bridge *br,
 extern int br_min_mtu(const struct net_bridge *br);
 extern netdev_features_t br_features_recompute(struct net_bridge *br,
 	netdev_features_t features);
+extern void br_set_uplink(struct net_bridge_port *port, unsigned long v);
+
 
 /* br_input.c */
 extern int br_handle_frame_finish(struct sk_buff *skb);
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index a1ef1b6..5e1d861 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -159,6 +159,18 @@ BRPORT_ATTR_FLAG(hairpin_mode, BR_HAIRPIN_MODE);
 BRPORT_ATTR_FLAG(bpdu_guard, BR_BPDU_GUARD);
 BRPORT_ATTR_FLAG(root_block, BR_ROOT_BLOCK);
 
+static ssize_t show_uplink(struct net_bridge_port *p, char *buf)
+{
+	return sprintf(buf, "%d\n", list_empty(&p->uplink_list) ? 0 : 1);
+}
+
+static int store_uplink(struct net_bridge_port *p, unsigned long v)
+{
+	br_set_uplink(p, v);
+	return 0;
+}
+static BRPORT_ATTR(uplink, S_IRUGO | S_IWUSR, show_uplink, store_uplink);
+
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
 static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
 {
@@ -195,6 +207,7 @@ static const struct brport_attribute *brport_attrs[] = {
 	&brport_attr_hairpin_mode,
 	&brport_attr_bpdu_guard,
 	&brport_attr_root_block,
+	&brport_attr_uplink,
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
 	&brport_attr_multicast_router,
 	&brport_attr_multicast_fast_leave,
-- 
1.7.7.6

^ permalink raw reply related

* [RFC PATCH net-next 3/3] bridge: Implement IFF_UNICAST_FLT
From: Vlad Yasevich @ 2013-03-07  2:31 UTC (permalink / raw)
  To: netdev; +Cc: bridge, Vlad Yasevich
In-Reply-To: <1362623485-18209-1-git-send-email-vyasevic@redhat.com>

Implement IFF_UNICAST_FLT on the bridge.  Unicast addresses added
to the bridge device are synched to the uplink devices.  This
allows for uplink devices to change while preserving mac assignment.

Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
 net/bridge/br_device.c |    9 ++++++++-
 net/bridge/br_fdb.c    |    6 ++++++
 2 files changed, 14 insertions(+), 1 deletions(-)

diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index c525e36..61514c1 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -106,6 +106,13 @@ static int br_dev_open(struct net_device *dev)
 
 static void br_dev_set_multicast_list(struct net_device *dev)
 {
+	struct net_bridge *br = netdev_priv(dev);
+	struct net_bridge_port *uplink;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(uplink, &br->uplink_list, uplink_list)
+		dev_uc_sync(uplink->dev, dev);
+	rcu_read_unlock();
 }
 
 static int br_dev_stop(struct net_device *dev)
@@ -384,7 +391,7 @@ void br_dev_setup(struct net_device *dev)
 	SET_ETHTOOL_OPS(dev, &br_ethtool_ops);
 	SET_NETDEV_DEVTYPE(dev, &br_type);
 	dev->tx_queue_len = 0;
-	dev->priv_flags = IFF_EBRIDGE;
+	dev->priv_flags = IFF_EBRIDGE | IFF_UNICAST_FLT;
 
 	dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
 			NETIF_F_GSO_MASK | NETIF_F_HW_CSUM | NETIF_F_LLTX |
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index b0812c9..ef7b51e 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -677,6 +677,9 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
 	struct net_port_vlans *pv;
 	unsigned short vid = VLAN_N_VID;
 
+	if ((ndm->ndm_flags & NTF_SELF) && (dev->priv_flags & IFF_EBRIDGE))
+		return ndo_dflt_fdb_add(ndm, tb, dev, addr, nlh_flags);
+
 	if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE))) {
 		pr_info("bridge: RTM_NEWNEIGH with invalid state %#x\n", ndm->ndm_state);
 		return -EINVAL;
@@ -774,6 +777,9 @@ int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
 	struct net_port_vlans *pv;
 	unsigned short vid = VLAN_N_VID;
 
+	if ((ndm->ndm_flags & NTF_SELF) && (dev->priv_flags & IFF_EBRIDGE))
+		return ndo_dflt_fdb_del(ndm, tb, dev, addr);
+
 	if (tb[NDA_VLAN]) {
 		if (nla_len(tb[NDA_VLAN]) != sizeof(unsigned short)) {
 			pr_info("bridge: RTM_NEWNEIGH with invalid vlan\n");
-- 
1.7.7.6

^ permalink raw reply related

* Re: [RFC PATCH net-next 1/3] bridge: Add mac_management sysfs interface
From: Vlad Yasevich @ 2013-03-07  2:35 UTC (permalink / raw)
  To: Vlad Yasevich; +Cc: netdev, bridge
In-Reply-To: <1362623485-18209-2-git-send-email-vyasevic@redhat.com>

On 03/06/2013 09:31 PM, Vlad Yasevich wrote:
> Add an sysfs interface to turn MAC address management on an off.
> When MAC management is off (default), all interfaces in the bridge
> are in promisc mode.  When MAC management is on, promisc mode is
> turned off and the expectation is that user will manually program
> the MAC filter.

Sorry, the description is stale,  I forgot to update it after fixing up
the patch.  The change is is actually to add sysfs to control promisc
mode.  By default, it's on.  It can be turned off if user wants to.

-vlad

>
> Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
> ---
>   net/bridge/br_device.c   |   41 +++++++++++++++++++++++++++++++++++++++++
>   net/bridge/br_if.c       |   22 +++++++++++++++++-----
>   net/bridge/br_private.h  |    2 ++
>   net/bridge/br_sysfs_br.c |   17 +++++++++++++++++
>   4 files changed, 77 insertions(+), 5 deletions(-)
>
> diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
> index d5f1d3f..160bc74 100644
> --- a/net/bridge/br_device.c
> +++ b/net/bridge/br_device.c
> @@ -185,6 +185,46 @@ static int br_set_mac_address(struct net_device *dev, void *p)
>   	return 0;
>   }
>
> +int br_set_promisc(struct net_bridge* br, unsigned long val)
> +{
> +	struct net_bridge_port *p;
> +
> +	if (!rtnl_trylock())
> +		return restart_syscall();
> +
> +	spin_lock_bh(&br->lock);
> +
> +	if (val) {
> +		if (br->promisc_enabled)
> +			goto unlock;
> +
> +		br->promisc_enabled = 1;
> +		/* For each port on the bridge, turn on promisc mode and
> +		 * turn off ALLMULTI to handle multicast traffic.
> +		 */
> +		list_for_each_entry(p, &br->port_list, list) {
> +			dev_set_promiscuity(p->dev, 1);
> +			dev_set_allmulti(p->dev, -1);
> +		}
> +
> +	} else {
> +		if (!br->promisc_enabled)
> +			goto unlock;
> +
> +		br->promisc_enabled = 0;
> +		/* For each port on the bridge, turn off promisc mode */
> +		list_for_each_entry(p, &br->port_list, list) {
> +			dev_set_allmulti(p->dev, 1);
> +			dev_set_promiscuity(p->dev, -1);
> +		}
> +	}
> +unlock:
> +	spin_unlock_bh(&br->lock);
> +	rtnl_unlock();
> +	return 0;
> +}
> +
> +
>   static void br_getinfo(struct net_device *dev, struct ethtool_drvinfo *info)
>   {
>   	strlcpy(info->driver, "bridge", sizeof(info->driver));
> @@ -371,6 +411,7 @@ void br_dev_setup(struct net_device *dev)
>   	br->bridge_hello_time = br->hello_time = 2 * HZ;
>   	br->bridge_forward_delay = br->forward_delay = 15 * HZ;
>   	br->ageing_time = 300 * HZ;
> +	br->promisc_enabled = 1;
>
>   	br_netfilter_rtable_init(br);
>   	br_stp_timer_init(br);
> diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
> index ef1b914..02b4440 100644
> --- a/net/bridge/br_if.c
> +++ b/net/bridge/br_if.c
> @@ -132,7 +132,10 @@ static void del_nbp(struct net_bridge_port *p)
>
>   	sysfs_remove_link(br->ifobj, p->dev->name);
>
> -	dev_set_promiscuity(dev, -1);
> +	if (br->promisc_enabled)
> +		dev_set_promiscuity(dev, -1);
> +	else
> +		dev_set_allmulti(dev, -1);
>
>   	spin_lock_bh(&br->lock);
>   	br_stp_disable_port(p);
> @@ -350,9 +353,15 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
>
>   	call_netdevice_notifiers(NETDEV_JOIN, dev);
>
> -	err = dev_set_promiscuity(dev, 1);
> -	if (err)
> -		goto put_back;
> +	if (br->promisc_enabled) {
> +		err = dev_set_promiscuity(dev, 1);
> +		if (err)
> +			goto put_back;
> +	} else {
> +		err = dev_set_allmulti(dev, 1);
> +		if (err)
> +			goto put_back;
> +	}
>
>   	err = kobject_init_and_add(&p->kobj, &brport_ktype, &(dev->dev.kobj),
>   				   SYSFS_BRIDGE_PORT_ATTR);
> @@ -414,7 +423,10 @@ err2:
>   	kobject_put(&p->kobj);
>   	p = NULL; /* kobject_put frees */
>   err1:
> -	dev_set_promiscuity(dev, -1);
> +	if (br->promisc_enabled)
> +		dev_set_promiscuity(dev, -1);
> +	else
> +		dev_set_allmulti(dev, -1);
>   put_back:
>   	dev_put(dev);
>   	kfree(p);
> diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
> index 6d314c4..4a0fa29 100644
> --- a/net/bridge/br_private.h
> +++ b/net/bridge/br_private.h
> @@ -277,6 +277,7 @@ struct net_bridge
>   	struct timer_list		topology_change_timer;
>   	struct timer_list		gc_timer;
>   	struct kobject			*ifobj;
> +	u8				promisc_enabled;
>   #ifdef CONFIG_BRIDGE_VLAN_FILTERING
>   	u8				vlan_enabled;
>   	struct net_port_vlans __rcu	*vlan_info;
> @@ -327,6 +328,7 @@ extern void br_dev_setup(struct net_device *dev);
>   extern void br_dev_delete(struct net_device *dev, struct list_head *list);
>   extern netdev_tx_t br_dev_xmit(struct sk_buff *skb,
>   			       struct net_device *dev);
> +extern int br_set_promisc(struct net_bridge *br, unsigned long val);
>   #ifdef CONFIG_NET_POLL_CONTROLLER
>   static inline struct netpoll_info *br_netpoll_info(struct net_bridge *br)
>   {
> diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
> index 8baa9c0..5489219 100644
> --- a/net/bridge/br_sysfs_br.c
> +++ b/net/bridge/br_sysfs_br.c
> @@ -710,6 +710,22 @@ static DEVICE_ATTR(vlan_filtering, S_IRUGO | S_IWUSR,
>   		   show_vlan_filtering, store_vlan_filtering);
>   #endif
>
> +static ssize_t show_promisc(struct device *d,
> +			    struct device_attribute *attr, char *buf)
> +{
> +	struct net_bridge *br = to_bridge(d);
> +	return sprintf(buf, "%d\n", br->promisc_enabled);
> +}
> +
> +static ssize_t store_promisc(struct device *d,
> +			     struct device_attribute *attr,
> +			     const char *buf, size_t len)
> +{
> +	return store_bridge_parm(d, buf, len, br_set_promisc);
> +}
> +static DEVICE_ATTR(promisc, S_IRUGO | S_IWUSR, show_promisc,
> +		   store_promisc);
> +
>   static struct attribute *bridge_attrs[] = {
>   	&dev_attr_forward_delay.attr,
>   	&dev_attr_hello_time.attr,
> @@ -753,6 +769,7 @@ static struct attribute *bridge_attrs[] = {
>   #ifdef CONFIG_BRIDGE_VLAN_FILTERING
>   	&dev_attr_vlan_filtering.attr,
>   #endif
> +	&dev_attr_promisc.attr,
>   	NULL
>   };
>
>

^ permalink raw reply

* [PATCH net-next 6/6] tg3: Download 57766 EEE service patch firmware
From: Nithin Nayak Sujir @ 2013-03-07  3:02 UTC (permalink / raw)
  To: davem; +Cc: netdev, Nithin Nayak Sujir, Michael Chan
In-Reply-To: <1362625354-15095-1-git-send-email-nsujir@broadcom.com>

This patch downloads the EEE service patch firmware and enables the necessary
EEE flags.

Reviewed-by: Benjamin Li <benli@broadcom.com>
Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
---
 drivers/net/ethernet/broadcom/tg3.c | 138 +++++++++++++++++++++++++++++++-----
 drivers/net/ethernet/broadcom/tg3.h |   6 ++
 2 files changed, 128 insertions(+), 16 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 54f604b..2b2bee6 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -212,6 +212,7 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
 #define TG3_FW_UPDATE_FREQ_SEC		(TG3_FW_UPDATE_TIMEOUT_SEC / 2)
 
 #define FIRMWARE_TG3		"tigon/tg3.bin"
+#define FIRMWARE_TG357766	"tigon/tg357766.bin"
 #define FIRMWARE_TG3TSO		"tigon/tg3_tso.bin"
 #define FIRMWARE_TG3TSO5	"tigon/tg3_tso5.bin"
 
@@ -3568,7 +3569,7 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base,
 				 u32 cpu_scratch_base, int cpu_scratch_size,
 				 const struct tg3_firmware_hdr *fw_hdr)
 {
-	int err, lock_err, i;
+	int err, i;
 	void (*write_op)(struct tg3 *, u32, u32);
 	int total_len = tp->fw->size;
 
@@ -3579,25 +3580,34 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base,
 		return -EINVAL;
 	}
 
-	if (tg3_flag(tp, 5705_PLUS))
+	if (tg3_flag(tp, 5705_PLUS) && tg3_asic_rev(tp) != ASIC_REV_57766)
 		write_op = tg3_write_mem;
 	else
 		write_op = tg3_write_indirect_reg32;
 
-	/* It is possible that bootcode is still loading at this point.
-	 * Get the nvram lock first before halting the cpu.
-	 */
-	lock_err = tg3_nvram_lock(tp);
-	err = tg3_halt_cpu(tp, cpu_base);
-	if (!lock_err)
-		tg3_nvram_unlock(tp);
-	if (err)
-		goto out;
+	if (tg3_asic_rev(tp) != ASIC_REV_57766) {
+		/* It is possible that bootcode is still loading at this point.
+		 * Get the nvram lock first before halting the cpu.
+		 */
+		int lock_err = tg3_nvram_lock(tp);
+		err = tg3_halt_cpu(tp, cpu_base);
+		if (!lock_err)
+			tg3_nvram_unlock(tp);
+		if (err)
+			goto out;
 
-	for (i = 0; i < cpu_scratch_size; i += sizeof(u32))
-		write_op(tp, cpu_scratch_base + i, 0);
-	tw32(cpu_base + CPU_STATE, 0xffffffff);
-	tw32(cpu_base + CPU_MODE, tr32(cpu_base+CPU_MODE)|CPU_MODE_HALT);
+		for (i = 0; i < cpu_scratch_size; i += sizeof(u32))
+			write_op(tp, cpu_scratch_base + i, 0);
+		tw32(cpu_base + CPU_STATE, 0xffffffff);
+		tw32(cpu_base + CPU_MODE,
+		     tr32(cpu_base + CPU_MODE) | CPU_MODE_HALT);
+	} else {
+		/* Subtract additional main header for fragmented firmware and
+		 * advance to the first fragment
+		 */
+		total_len -= TG3_FW_HDR_LEN;
+		fw_hdr++;
+	}
 
 	do {
 		u32 *fw_data = (u32 *)(fw_hdr + 1);
@@ -3683,6 +3693,78 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
 	return 0;
 }
 
+static int tg3_validate_rxcpu_state(struct tg3 *tp)
+{
+	const int iters = 1000;
+	int i;
+	u32 val;
+
+	/* Wait for boot code to complete initialization and enter service
+	 * loop. It is then safe to download service patches
+	 */
+	for (i = 0; i < iters; i++) {
+		if (tr32(RX_CPU_HWBKPT) == TG3_SBROM_IN_SERVICE_LOOP)
+			break;
+
+		udelay(10);
+	}
+
+	if (i == iters) {
+		netdev_err(tp->dev, "Boot code not ready for service patches\n");
+		return -EBUSY;
+	}
+
+	val = tg3_read_indirect_reg32(tp, TG3_57766_FW_HANDSHAKE);
+	if (val & 0xff) {
+		netdev_warn(tp->dev,
+			    "Other patches exist. Not downloading EEE patch\n");
+		return -EEXIST;
+	}
+
+	return 0;
+}
+
+/* tp->lock is held. */
+static void tg3_load_57766_firmware(struct tg3 *tp)
+{
+	struct tg3_firmware_hdr *fw_hdr;
+
+	if (!tg3_flag(tp, NO_NVRAM))
+		return;
+
+	if (tg3_validate_rxcpu_state(tp))
+		return;
+
+	if (!tp->fw)
+		return;
+
+	/* This firmware blob has a different format than older firmware
+	 * releases as given below. The main difference is we have fragmented
+	 * data to be written to non-contiguous locations.
+	 *
+	 * In the beginning we have a firmware header identical to other
+	 * firmware which consists of version, base addr and length. The length
+	 * here is unused and set to 0xffffffff.
+	 *
+	 * This is followed by a series of firmware fragments which are
+	 * individually identical to previous firmware. i.e. they have the
+	 * firmware header and followed by data for that fragment. The version
+	 * field of the individual fragment header is unused.
+	 */
+
+	fw_hdr = (struct tg3_firmware_hdr *)tp->fw->data;
+	if (be32_to_cpu(fw_hdr->base_addr) != TG3_57766_FW_BASE_ADDR)
+		return;
+
+	if (tg3_rxcpu_pause(tp))
+		return;
+
+	/* tg3_load_firmware_cpu() will always succeed for the 57766 */
+	tg3_load_firmware_cpu(tp, 0, TG3_57766_FW_BASE_ADDR, 0, fw_hdr);
+
+	tg3_rxcpu_resume(tp);
+}
+
 /* tp->lock is held. */
 static int tg3_load_tso_firmware(struct tg3 *tp)
 {
@@ -9836,6 +9918,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
 			return err;
 	}
 
+	if (tg3_asic_rev(tp) == ASIC_REV_57766) {
+		/* Ignore any errors for the firmware download. If download
+		 * fails, the device will operate with EEE disabled
+		 */
+		tg3_load_57766_firmware(tp);
+	}
+
 	if (tg3_flag(tp, TSO_CAPABLE)) {
 		err = tg3_load_tso_firmware(tp);
 		if (err)
@@ -10940,7 +11029,15 @@ static int tg3_open(struct net_device *dev)
 
 	if (tp->fw_needed) {
 		err = tg3_request_firmware(tp);
-		if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0) {
+		if (tg3_asic_rev(tp) == ASIC_REV_57766) {
+			if (err) {
+				netdev_warn(tp->dev, "EEE capability disabled\n");
+				tp->phy_flags &= ~TG3_PHYFLG_EEE_CAP;
+			} else if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP)) {
+				netdev_warn(tp->dev, "EEE capability restored\n");
+				tp->phy_flags |= TG3_PHYFLG_EEE_CAP;
+			}
+		} else if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0) {
 			if (err)
 				return err;
 		} else if (err) {
@@ -14570,6 +14667,7 @@ static int tg3_phy_probe(struct tg3 *tp)
 	if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
 	    (tg3_asic_rev(tp) == ASIC_REV_5719 ||
 	     tg3_asic_rev(tp) == ASIC_REV_5720 ||
+	     tg3_asic_rev(tp) == ASIC_REV_57766 ||
 	     tg3_asic_rev(tp) == ASIC_REV_5762 ||
 	     (tg3_asic_rev(tp) == ASIC_REV_5717 &&
 	      tg3_chip_rev_id(tp) != CHIPREV_ID_5717_A0) ||
@@ -15379,6 +15477,9 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
 	if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0)
 		tp->fw_needed = FIRMWARE_TG3;
 
+	if (tg3_asic_rev(tp) == ASIC_REV_57766)
+		tp->fw_needed = FIRMWARE_TG357766;
+
 	tp->irq_max = 1;
 
 	if (tg3_flag(tp, 5750_PLUS)) {
@@ -15839,6 +15940,11 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
 	udelay(50);
 	tg3_nvram_init(tp);
 
+	/* If the device has an NVRAM, no need to load patch firmware */
+	if (tg3_asic_rev(tp) == ASIC_REV_57766 &&
+	    !tg3_flag(tp, NO_NVRAM))
+		tp->fw_needed = NULL;
+
 	grc_misc_cfg = tr32(GRC_MISC_CFG);
 	grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK;
 
diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h
index b5098f0..1cdc1b6 100644
--- a/drivers/net/ethernet/broadcom/tg3.h
+++ b/drivers/net/ethernet/broadcom/tg3.h
@@ -2222,6 +2222,12 @@
 #define  NIC_SRAM_MBUF_POOL_BASE5705	0x00010000
 #define  NIC_SRAM_MBUF_POOL_SIZE5705	0x0000e000
 
+#define TG3_SRAM_RXCPU_SCRATCH_BASE_57766	0x00030000
+#define  TG3_SRAM_RXCPU_SCRATCH_SIZE_57766	 0x00010000
+#define TG3_57766_FW_BASE_ADDR			0x00030000
+#define TG3_57766_FW_HANDSHAKE			0x0003fccc
+#define TG3_SBROM_IN_SERVICE_LOOP		0x51
+
 #define TG3_SRAM_RX_STD_BDCACHE_SIZE_5700	128
 #define TG3_SRAM_RX_STD_BDCACHE_SIZE_5755	64
 #define TG3_SRAM_RX_STD_BDCACHE_SIZE_5906	32
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH net-next 2/6] tg3: Refactor cpu pause/resume code
From: Nithin Nayak Sujir @ 2013-03-07  3:02 UTC (permalink / raw)
  To: davem; +Cc: netdev, Nithin Nayak Sujir, Michael Chan
In-Reply-To: <1362625354-15095-1-git-send-email-nsujir@broadcom.com>

The 57766 rxcpu needs to be paused/resumed when we download the firmware just
like we do for existing firmware. Refactor the pause/resume code to be
reusable.

This patch also renames the "offset" argument of tg3_halt_cpu to "cpu_base"
since that's what it really is.

Reviewed-by: Benjamin Li <benli@broadcom.com>
Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
---
 drivers/net/ethernet/broadcom/tg3.c | 83 ++++++++++++++++++++++++++-----------
 1 file changed, 58 insertions(+), 25 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index f6ebcaa..35a99f7 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -3452,11 +3452,58 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf)
 #define TX_CPU_SCRATCH_SIZE	0x04000
 
 /* tp->lock is held. */
-static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
+static int tg3_pause_cpu(struct tg3 *tp, u32 cpu_base)
 {
 	int i;
+	const int iters = 10000;
 
-	BUG_ON(offset == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS));
+	for (i = 0; i < iters; i++) {
+		tw32(cpu_base + CPU_STATE, 0xffffffff);
+		tw32(cpu_base + CPU_MODE,  CPU_MODE_HALT);
+		if (tr32(cpu_base + CPU_MODE) & CPU_MODE_HALT)
+			break;
+	}
+
+	return (i == iters) ? -EBUSY : 0;
+}
+
+/* tp->lock is held. */
+static int tg3_rxcpu_pause(struct tg3 *tp)
+{
+	int rc = tg3_pause_cpu(tp, RX_CPU_BASE);
+
+	tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
+	tw32_f(RX_CPU_BASE + CPU_MODE,  CPU_MODE_HALT);
+	udelay(10);
+
+	return rc;
+}
+
+/* tp->lock is held. */
+static int tg3_txcpu_pause(struct tg3 *tp)
+{
+	return tg3_pause_cpu(tp, TX_CPU_BASE);
+}
+
+/* tp->lock is held. */
+static void tg3_resume_cpu(struct tg3 *tp, u32 cpu_base)
+{
+	tw32(cpu_base + CPU_STATE, 0xffffffff);
+	tw32_f(cpu_base + CPU_MODE,  0x00000000);
+}
+
+/* tp->lock is held. */
+static void tg3_rxcpu_resume(struct tg3 *tp)
+{
+	tg3_resume_cpu(tp, RX_CPU_BASE);
+}
+
+/* tp->lock is held. */
+static int tg3_halt_cpu(struct tg3 *tp, u32 cpu_base)
+{
+	int rc;
+
+	BUG_ON(cpu_base == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS));
 
 	if (tg3_asic_rev(tp) == ASIC_REV_5906) {
 		u32 val = tr32(GRC_VCPU_EXT_CTRL);
@@ -3464,17 +3511,8 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
 		tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_HALT_CPU);
 		return 0;
 	}
-	if (offset == RX_CPU_BASE) {
-		for (i = 0; i < 10000; i++) {
-			tw32(offset + CPU_STATE, 0xffffffff);
-			tw32(offset + CPU_MODE,  CPU_MODE_HALT);
-			if (tr32(offset + CPU_MODE) & CPU_MODE_HALT)
-				break;
-		}
-
-		tw32(offset + CPU_STATE, 0xffffffff);
-		tw32_f(offset + CPU_MODE,  CPU_MODE_HALT);
-		udelay(10);
+	if (cpu_base == RX_CPU_BASE) {
+		rc = tg3_rxcpu_pause(tp);
 	} else {
 		/*
 		 * There is only an Rx CPU for the 5750 derivative in the
@@ -3483,17 +3521,12 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
 		if (tg3_flag(tp, IS_SSB_CORE))
 			return 0;
 
-		for (i = 0; i < 10000; i++) {
-			tw32(offset + CPU_STATE, 0xffffffff);
-			tw32(offset + CPU_MODE,  CPU_MODE_HALT);
-			if (tr32(offset + CPU_MODE) & CPU_MODE_HALT)
-				break;
-		}
+		rc = tg3_txcpu_pause(tp);
 	}
 
-	if (i >= 10000) {
+	if (rc) {
 		netdev_err(tp->dev, "%s timed out, %s CPU\n",
-			   __func__, offset == RX_CPU_BASE ? "RX" : "TX");
+			   __func__, cpu_base == RX_CPU_BASE ? "RX" : "TX");
 		return -ENODEV;
 	}
 
@@ -3604,8 +3637,8 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
 			   tr32(RX_CPU_BASE + CPU_PC), info.fw_base);
 		return -ENODEV;
 	}
-	tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
-	tw32_f(RX_CPU_BASE + CPU_MODE,  0x00000000);
+
+	tg3_rxcpu_resume(tp);
 
 	return 0;
 }
@@ -3667,8 +3700,8 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
 			   __func__, tr32(cpu_base + CPU_PC), info.fw_base);
 		return -ENODEV;
 	}
-	tw32(cpu_base + CPU_STATE, 0xffffffff);
-	tw32_f(cpu_base + CPU_MODE,  0x00000000);
+
+	tg3_resume_cpu(tp, cpu_base);
 	return 0;
 }
 
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH net-next 4/6] tg3: Cleanup firmware parsing code
From: Nithin Nayak Sujir @ 2013-03-07  3:02 UTC (permalink / raw)
  To: davem; +Cc: netdev, Nithin Nayak Sujir, Michael Chan
In-Reply-To: <1362625354-15095-1-git-send-email-nsujir@broadcom.com>

The current firmware header parsing is complicated due to interpreting it as a
u32 array and accessing header members via array offsets. Add tg3_firmware_hdr
structure to access the firmware fields instead of hardcoding offsets. The same
header format will be used for individual firmware fragments in the 57766.

The fw_hdr and tg3 structures have all the information required for
loading the fw. Remove the redundant fw_info structure and pass fw_hdr
instead.

Reviewed-by: Benjamin Li <benli@broadcom.com>
Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
---
 drivers/net/ethernet/broadcom/tg3.c | 63 ++++++++++++++++---------------------
 drivers/net/ethernet/broadcom/tg3.h |  7 +++++
 2 files changed, 34 insertions(+), 36 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 4705169..87bd0e3 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -3536,19 +3536,14 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 cpu_base)
 	return 0;
 }
 
-struct fw_info {
-	unsigned int fw_base;
-	unsigned int fw_len;
-	const __be32 *fw_data;
-};
-
 /* tp->lock is held. */
 static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base,
 				 u32 cpu_scratch_base, int cpu_scratch_size,
-				 struct fw_info *info)
+				 const struct tg3_firmware_hdr *fw_hdr)
 {
 	int err, lock_err, i;
 	void (*write_op)(struct tg3 *, u32, u32);
+	u32 *fw_data = (u32 *)(fw_hdr + 1);
 
 	if (cpu_base == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS)) {
 		netdev_err(tp->dev,
@@ -3576,11 +3571,12 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base,
 		write_op(tp, cpu_scratch_base + i, 0);
 	tw32(cpu_base + CPU_STATE, 0xffffffff);
 	tw32(cpu_base + CPU_MODE, tr32(cpu_base+CPU_MODE)|CPU_MODE_HALT);
-	for (i = 0; i < (info->fw_len / sizeof(u32)); i++)
-		write_op(tp, (cpu_scratch_base +
-			      (info->fw_base & 0xffff) +
-			      (i * sizeof(u32))),
-			      be32_to_cpu(info->fw_data[i]));
+	for (i = 0; i < (tp->fw->size - TG3_FW_HDR_LEN) / sizeof(u32); i++)
+		write_op(tp, cpu_scratch_base +
+			     (be32_to_cpu(fw_hdr->base_addr) & 0xffff) +
+			     (i * sizeof(u32)),
+			 be32_to_cpu(fw_data[i]));
+
 
 	err = 0;
 
@@ -3612,11 +3608,10 @@ static int tg3_pause_cpu_and_set_pc(struct tg3 *tp, u32 cpu_base, u32 pc)
 /* tp->lock is held. */
 static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
 {
-	struct fw_info info;
-	const __be32 *fw_data;
+	const struct tg3_firmware_hdr *fw_hdr;
 	int err;
 
-	fw_data = (void *)tp->fw->data;
+	fw_hdr = (struct tg3_firmware_hdr *)tp->fw->data;
 
 	/* Firmware blob starts with version numbers, followed by
 	   start address and length. We are setting complete length.
@@ -3624,28 +3619,26 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
 	   Remainder is the blob to be loaded contiguously
 	   from start address. */
 
-	info.fw_base = be32_to_cpu(fw_data[1]);
-	info.fw_len = tp->fw->size - 12;
-	info.fw_data = &fw_data[3];
-
 	err = tg3_load_firmware_cpu(tp, RX_CPU_BASE,
 				    RX_CPU_SCRATCH_BASE, RX_CPU_SCRATCH_SIZE,
-				    &info);
+				    fw_hdr);
 	if (err)
 		return err;
 
 	err = tg3_load_firmware_cpu(tp, TX_CPU_BASE,
 				    TX_CPU_SCRATCH_BASE, TX_CPU_SCRATCH_SIZE,
-				    &info);
+				    fw_hdr);
 	if (err)
 		return err;
 
 	/* Now startup only the RX cpu. */
-	err = tg3_pause_cpu_and_set_pc(tp, RX_CPU_BASE, info.fw_base);
+	err = tg3_pause_cpu_and_set_pc(tp, RX_CPU_BASE,
+				       be32_to_cpu(fw_hdr->base_addr));
 	if (err) {
 		netdev_err(tp->dev, "%s fails to set RX CPU PC, is %08x "
 			   "should be %08x\n", __func__,
-			   tr32(RX_CPU_BASE + CPU_PC), info.fw_base);
+			   tr32(RX_CPU_BASE + CPU_PC),
+				be32_to_cpu(fw_hdr->base_addr));
 		return -ENODEV;
 	}
 
@@ -3657,15 +3650,14 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
 /* tp->lock is held. */
 static int tg3_load_tso_firmware(struct tg3 *tp)
 {
-	struct fw_info info;
-	const __be32 *fw_data;
+	const struct tg3_firmware_hdr *fw_hdr;
 	unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
 	int err;
 
 	if (!tg3_flag(tp, FW_TSO))
 		return 0;
 
-	fw_data = (void *)tp->fw->data;
+	fw_hdr = (struct tg3_firmware_hdr *)tp->fw->data;
 
 	/* Firmware blob starts with version numbers, followed by
 	   start address and length. We are setting complete length.
@@ -3673,10 +3665,7 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
 	   Remainder is the blob to be loaded contiguously
 	   from start address. */
 
-	info.fw_base = be32_to_cpu(fw_data[1]);
 	cpu_scratch_size = tp->fw_len;
-	info.fw_len = tp->fw->size - 12;
-	info.fw_data = &fw_data[3];
 
 	if (tg3_asic_rev(tp) == ASIC_REV_5705) {
 		cpu_base = RX_CPU_BASE;
@@ -3689,16 +3678,18 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
 
 	err = tg3_load_firmware_cpu(tp, cpu_base,
 				    cpu_scratch_base, cpu_scratch_size,
-				    &info);
+				    fw_hdr);
 	if (err)
 		return err;
 
 	/* Now startup the cpu. */
-	err = tg3_pause_cpu_and_set_pc(tp, cpu_base, info.fw_base);
+	err = tg3_pause_cpu_and_set_pc(tp, cpu_base,
+				       be32_to_cpu(fw_hdr->base_addr));
 	if (err) {
 		netdev_err(tp->dev,
 			   "%s fails to set CPU PC, is %08x should be %08x\n",
-			   __func__, tr32(cpu_base + CPU_PC), info.fw_base);
+			   __func__, tr32(cpu_base + CPU_PC),
+			   be32_to_cpu(fw_hdr->base_addr));
 		return -ENODEV;
 	}
 
@@ -10598,7 +10589,7 @@ static int tg3_test_msi(struct tg3 *tp)
 
 static int tg3_request_firmware(struct tg3 *tp)
 {
-	const __be32 *fw_data;
+	const struct tg3_firmware_hdr *fw_hdr;
 
 	if (request_firmware(&tp->fw, tp->fw_needed, &tp->pdev->dev)) {
 		netdev_err(tp->dev, "Failed to load firmware \"%s\"\n",
@@ -10606,15 +10597,15 @@ static int tg3_request_firmware(struct tg3 *tp)
 		return -ENOENT;
 	}
 
-	fw_data = (void *)tp->fw->data;
+	fw_hdr = (struct tg3_firmware_hdr *)tp->fw->data;
 
 	/* Firmware blob starts with version numbers, followed by
 	 * start address and _full_ length including BSS sections
 	 * (which must be longer than the actual data, of course
 	 */
 
-	tp->fw_len = be32_to_cpu(fw_data[2]);	/* includes bss */
-	if (tp->fw_len < (tp->fw->size - 12)) {
+	tp->fw_len = be32_to_cpu(fw_hdr->len);	/* includes bss */
+	if (tp->fw_len < (tp->fw->size - TG3_FW_HDR_LEN)) {
 		netdev_err(tp->dev, "bogus length %d in \"%s\"\n",
 			   tp->fw_len, tp->fw_needed);
 		release_firmware(tp->fw);
diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h
index eb41b6f..b5098f0 100644
--- a/drivers/net/ethernet/broadcom/tg3.h
+++ b/drivers/net/ethernet/broadcom/tg3.h
@@ -3065,6 +3065,13 @@ enum TG3_FLAGS {
 	TG3_FLAG_NUMBER_OF_FLAGS,	/* Last entry in enum TG3_FLAGS */
 };
 
+struct tg3_firmware_hdr {
+	__be32 version; /* unused for fragments */
+	__be32 base_addr;
+	__be32 len;
+};
+#define TG3_FW_HDR_LEN         (sizeof(struct tg3_firmware_hdr))
+
 struct tg3 {
 	/* begin "general, frequently-used members" cacheline section */
 
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH net-next 0/6] Add support to download EEE firmware for the 57766
From: Nithin Nayak Sujir @ 2013-03-07  3:02 UTC (permalink / raw)
  To: davem; +Cc: netdev, Nithin Nayak Sujir

For the 57766 devices with no NVRAM, there is not enough space for the complete
boot code with EEE support. On these devices, the tg3 driver has to download
a service patch firmware to the scratchpad for the boot code to execute. This
patchset adds support to do the above.

A major portion of this patchset is refactoring the existing firmware download
section to allow a cleaner merge of the 57766 download. The 57766 firmware
differs from previous firmware in that it's not written to a contiguous area in
memory. It consists of multiple fragments to be written to different locations.
The patchset makes an attempt to make the new firmware format to be an
extension of the existing format.


Matt Carlson (1):
  tg3: Add new FW_TSO flag

Nithin Nayak Sujir (5):
  tg3: Refactor cpu pause/resume code
  tg3: Refactor the 2nd type of cpu pause
  tg3: Cleanup firmware parsing code
  tg3: Enhance firmware download code to support fragmented firmware
  tg3: Download 57766 EEE service patch firmware

 drivers/net/ethernet/broadcom/tg3.c | 378 ++++++++++++++++++++++++++----------
 drivers/net/ethernet/broadcom/tg3.h |  18 +-
 2 files changed, 288 insertions(+), 108 deletions(-)

-- 
1.8.1.4

^ permalink raw reply

* [PATCH net-next 1/6] tg3: Add new FW_TSO flag
From: Nithin Nayak Sujir @ 2013-03-07  3:02 UTC (permalink / raw)
  To: davem; +Cc: netdev, Matt Carlson, Nithin Nayak Sujir, Michael Chan
In-Reply-To: <1362625354-15095-1-git-send-email-nsujir@broadcom.com>

From: Matt Carlson <mcarlson@broadcom.com>

tg3 used the fw_needed member loosely as a synonym for firmware TSO. Now
that the 57766 needs firmware download support, fw_needed can no longer be
used like this. This patch creates a new FW_TSO flag and changes the
code to use it.

Also rearrange all the TSO flags together in the enum.

Reviewed-by: Benjamin Li <benli@broadcom.com>
Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
---
 drivers/net/ethernet/broadcom/tg3.c | 11 +++++------
 drivers/net/ethernet/broadcom/tg3.h |  5 +++--
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index fdb9b56..f6ebcaa 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -3618,9 +3618,7 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
 	unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
 	int err, i;
 
-	if (tg3_flag(tp, HW_TSO_1) ||
-	    tg3_flag(tp, HW_TSO_2) ||
-	    tg3_flag(tp, HW_TSO_3))
+	if (!tg3_flag(tp, FW_TSO))
 		return 0;
 
 	fw_data = (void *)tp->fw->data;
@@ -15293,7 +15291,8 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
 	} else if (tg3_asic_rev(tp) != ASIC_REV_5700 &&
 		   tg3_asic_rev(tp) != ASIC_REV_5701 &&
 		   tg3_chip_rev_id(tp) != CHIPREV_ID_5705_A0) {
-			tg3_flag_set(tp, TSO_BUG);
+		tg3_flag_set(tp, FW_TSO);
+		tg3_flag_set(tp, TSO_BUG);
 		if (tg3_asic_rev(tp) == ASIC_REV_5705)
 			tp->fw_needed = FIRMWARE_TG3TSO5;
 		else
@@ -15304,7 +15303,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
 	if (tg3_flag(tp, HW_TSO_1) ||
 	    tg3_flag(tp, HW_TSO_2) ||
 	    tg3_flag(tp, HW_TSO_3) ||
-	    tp->fw_needed) {
+	    tg3_flag(tp, FW_TSO)) {
 		/* For firmware TSO, assume ASF is disabled.
 		 * We'll disable TSO later if we discover ASF
 		 * is enabled in tg3_get_eeprom_hw_cfg().
@@ -15591,7 +15590,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
 	 */
 	tg3_get_eeprom_hw_cfg(tp);
 
-	if (tp->fw_needed && tg3_flag(tp, ENABLE_ASF)) {
+	if (tg3_flag(tp, FW_TSO) && tg3_flag(tp, ENABLE_ASF)) {
 		tg3_flag_clear(tp, TSO_CAPABLE);
 		tg3_flag_clear(tp, TSO_BUG);
 		tp->fw_needed = NULL;
diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h
index 8d7d4c2..eb41b6f 100644
--- a/drivers/net/ethernet/broadcom/tg3.h
+++ b/drivers/net/ethernet/broadcom/tg3.h
@@ -3009,17 +3009,18 @@ enum TG3_FLAGS {
 	TG3_FLAG_JUMBO_CAPABLE,
 	TG3_FLAG_CHIP_RESETTING,
 	TG3_FLAG_INIT_COMPLETE,
-	TG3_FLAG_TSO_BUG,
 	TG3_FLAG_MAX_RXPEND_64,
-	TG3_FLAG_TSO_CAPABLE,
 	TG3_FLAG_PCI_EXPRESS, /* BCM5785 + pci_is_pcie() */
 	TG3_FLAG_ASF_NEW_HANDSHAKE,
 	TG3_FLAG_HW_AUTONEG,
 	TG3_FLAG_IS_NIC,
 	TG3_FLAG_FLASH,
+	TG3_FLAG_FW_TSO,
 	TG3_FLAG_HW_TSO_1,
 	TG3_FLAG_HW_TSO_2,
 	TG3_FLAG_HW_TSO_3,
+	TG3_FLAG_TSO_CAPABLE,
+	TG3_FLAG_TSO_BUG,
 	TG3_FLAG_ICH_WORKAROUND,
 	TG3_FLAG_1SHOT_MSI,
 	TG3_FLAG_NO_FWARE_REPORTED,
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH net-next 5/6] tg3: Enhance firmware download code to support fragmented firmware
From: Nithin Nayak Sujir @ 2013-03-07  3:02 UTC (permalink / raw)
  To: davem; +Cc: netdev, Nithin Nayak Sujir, Michael Chan
In-Reply-To: <1362625354-15095-1-git-send-email-nsujir@broadcom.com>

This lays the ground work to download the 57766 fragmented firmware. We
loop until we've written data equal to tp->fw->size minus headers.

Reviewed-by: Benjamin Li <benli@broadcom.com>
Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
---
 drivers/net/ethernet/broadcom/tg3.c | 48 ++++++++++++++++++++++++++++++++-----
 1 file changed, 42 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 87bd0e3..54f604b 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -3536,6 +3536,33 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 cpu_base)
 	return 0;
 }
 
+static int tg3_fw_data_len(struct tg3 *tp,
+			   const struct tg3_firmware_hdr *fw_hdr)
+{
+	int fw_len;
+
+	/* Non fragmented firmware have one firmware header followed by a
+	 * contiguous chunk of data to be written. The length field in that
+	 * header is not the length of data to be written but the complete
+	 * length of the bss. The data length is determined based on
+	 * tp->fw->size minus headers.
+	 *
+	 * Fragmented firmware have a main header followed by multiple
+	 * fragments. Each fragment is identical to non fragmented firmware
+	 * with a firmware header followed by a contiguous chunk of data. In
+	 * the main header, the length field is unused and set to 0xffffffff.
+	 * In each fragment header the length is the entire size of that
+	 * fragment i.e. fragment data + header length. Data length is
+	 * therefore length field in the header minus TG3_FW_HDR_LEN.
+	 */
+	if (tp->fw_len == 0xffffffff)
+		fw_len = be32_to_cpu(fw_hdr->len);
+	else
+		fw_len = tp->fw->size;
+
+	return (fw_len - TG3_FW_HDR_LEN) / sizeof(u32);
+}
+
 /* tp->lock is held. */
 static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base,
 				 u32 cpu_scratch_base, int cpu_scratch_size,
@@ -3543,7 +3570,7 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base,
 {
 	int err, lock_err, i;
 	void (*write_op)(struct tg3 *, u32, u32);
-	u32 *fw_data = (u32 *)(fw_hdr + 1);
+	int total_len = tp->fw->size;
 
 	if (cpu_base == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS)) {
 		netdev_err(tp->dev,
@@ -3571,12 +3598,21 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base,
 		write_op(tp, cpu_scratch_base + i, 0);
 	tw32(cpu_base + CPU_STATE, 0xffffffff);
 	tw32(cpu_base + CPU_MODE, tr32(cpu_base+CPU_MODE)|CPU_MODE_HALT);
-	for (i = 0; i < (tp->fw->size - TG3_FW_HDR_LEN) / sizeof(u32); i++)
-		write_op(tp, cpu_scratch_base +
-			     (be32_to_cpu(fw_hdr->base_addr) & 0xffff) +
-			     (i * sizeof(u32)),
-			 be32_to_cpu(fw_data[i]));
 
+	do {
+		u32 *fw_data = (u32 *)(fw_hdr + 1);
+		for (i = 0; i < tg3_fw_data_len(tp, fw_hdr); i++)
+			write_op(tp, cpu_scratch_base +
+				     (be32_to_cpu(fw_hdr->base_addr) & 0xffff) +
+				     (i * sizeof(u32)),
+				 be32_to_cpu(fw_data[i]));
+
+		total_len -= be32_to_cpu(fw_hdr->len);
+
+		/* Advance to next fragment */
+		fw_hdr = (struct tg3_firmware_hdr *)
+			 ((void *)fw_hdr + be32_to_cpu(fw_hdr->len));
+	} while (total_len > 0);
 
 	err = 0;
 
-- 
1.8.1.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox