Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH v6 04/46] percpu_rwlock: Implement the core design of Per-CPU Reader-Writer Locks
From: Michel Lespinasse @ 2013-02-18 15:45 UTC (permalink / raw)
  To: Srivatsa S. Bhat
  Cc: tglx, peterz, tj, oleg, paulmck, rusty, mingo, akpm, namhyung,
	rostedt, wangyun, xiaoguangrong, rjw, sbw, fweisbec, linux,
	nikunj, linux-pm, linux-arch, linux-arm-kernel, linuxppc-dev,
	netdev, linux-doc, linux-kernel, vincent.guittot
In-Reply-To: <20130218123856.26245.46705.stgit@srivatsabhat.in.ibm.com>

Hi Srivasta,

I admit not having followed in detail the threads about the previous
iteration, so some of my comments may have been discussed already
before - apologies if that is the case.

On Mon, Feb 18, 2013 at 8:38 PM, Srivatsa S. Bhat
<srivatsa.bhat@linux.vnet.ibm.com> wrote:
> Reader-writer locks and per-cpu counters are recursive, so they can be
> used in a nested fashion in the reader-path, which makes per-CPU rwlocks also
> recursive. Also, this design of switching the synchronization scheme ensures
> that you can safely nest and use these locks in a very flexible manner.

I like the general idea of switching between per-cpu and global
rwlocks as needed; however I dislike unfair locks, and especially
unfair recursive rwlocks.

If you look at rwlock_t, the main reason we haven't been able to
implement reader/writer fairness there is because tasklist_lock makes
use of the recursive nature of the rwlock_t read side. I'm worried
about introducing more lock usages that would make use of the same
property for your proposed lock.

I am fine with your proposal not implementing reader/writer fairness
from day 1, but I am worried about your proposal having a recursive
reader side. Or, to put it another way: if your proposal didn't have a
recursive reader side, and rwlock_t could somehow be changed to
implement reader/writer fairness, then this property could
automatically propagate into your proposed rwlock; but if anyone makes
use of the recursive nature of your proposal then implementing
reader/writer fairness later won't be as easy.

I see that the very next change in this series is talking about
acquiring the read side from interrupts, so it does look like you're
planning to make use of the recursive nature of the read side. I kinda
wish you didn't, as this is exactly replicating the design of
tasklist_lock which is IMO problematic. Your prior proposal of
disabling interrupts during the read side had other disadvantages, but
I think it was nice that it didn't rely on having a recursive read
side.

> +#define reader_yet_to_switch(pcpu_rwlock, cpu)                             \
> +       (ACCESS_ONCE(per_cpu_ptr((pcpu_rwlock)->rw_state, cpu)->reader_refcnt))
> +
> +#define reader_percpu_nesting_depth(pcpu_rwlock)                 \
> +       (__this_cpu_read((pcpu_rwlock)->rw_state->reader_refcnt))
> +
> +#define reader_uses_percpu_refcnt(pcpu_rwlock)                         \
> +                               reader_percpu_nesting_depth(pcpu_rwlock)
> +
> +#define reader_nested_percpu(pcpu_rwlock)                              \
> +                       (reader_percpu_nesting_depth(pcpu_rwlock) > 1)
> +
> +#define writer_active(pcpu_rwlock)                                     \
> +       (__this_cpu_read((pcpu_rwlock)->rw_state->writer_signal))

I'm personally not a fan of such one-line shorthand functions - I
think they tend to make the code harder to read instead of easier, as
one constantly has to refer to them to understand what's actually
going on.

>  void percpu_write_lock(struct percpu_rwlock *pcpu_rwlock)
>  {
> +       unsigned int cpu;
> +
> +       /*
> +        * Tell all readers that a writer is becoming active, so that they
> +        * start switching over to the global rwlock.
> +        */
> +       for_each_possible_cpu(cpu)
> +               per_cpu_ptr(pcpu_rwlock->rw_state, cpu)->writer_signal = true;

I don't see anything preventing a race with the corresponding code in
percpu_write_unlock() that sets writer_signal back to false. Did I
miss something here ? It seems to me we don't have any guarantee that
all writer signals will be set to true at the end of the loop...

-- 
Michel "Walken" Lespinasse
A program is never fully debugged until the last user dies.

^ permalink raw reply

* [PATCH ipsec] af_key: initialize satype in key_notify_policy_flush()
From: Nicolas Dichtel @ 2013-02-18 15:24 UTC (permalink / raw)
  To: steffen.klassert, herbert, davem; +Cc: netdev, Nicolas Dichtel

This field was left uninitialized. Some user daemons perform check against this
field.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 net/key/af_key.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/net/key/af_key.c b/net/key/af_key.c
index 5b426a6..f9bd41e 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -2688,6 +2688,7 @@ static int key_notify_policy_flush(const struct km_event *c)
 	hdr->sadb_msg_pid = c->portid;
 	hdr->sadb_msg_version = PF_KEY_V2;
 	hdr->sadb_msg_errno = (uint8_t) 0;
+	hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC;
 	hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
 	pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net);
 	return 0;
-- 
1.8.0.1

^ permalink raw reply related

* Re: [PATCH v5 00/45] CPU hotplug: stop_machine()-free CPU hotplug
From: Steven Rostedt @ 2013-02-18 15:30 UTC (permalink / raw)
  To: Vincent Guittot
  Cc: Srivatsa S. Bhat, paulmck, Russell King - ARM Linux, linux-doc,
	peterz, fweisbec, linux-kernel, walken, mingo, linux-arch,
	xiaoguangrong, wangyun, nikunj, linux-pm, Rusty Russell, rjw,
	namhyung, tglx, linux-arm-kernel, netdev, oleg, sbw, tj, akpm,
	linuxppc-dev
In-Reply-To: <CAKfTPtA1aTseD6Gntkf_zbCEbfZzt3P2-P1un6iF5_1TdVLjRQ@mail.gmail.com>

On Mon, 2013-02-18 at 11:58 +0100, Vincent Guittot wrote:

> My tests have been done without cpuidle because i have some issues
> with function tracer and cpuidle
> 
> But the cpu hotplug and cpuidle work well when I run the tests without
> enabling the function tracer
> 

I know suspend and resume has issues with function tracing (because it
makes things like calling smp_processor_id() crash the system), but I'm
unaware of issues with hotplug itself. Could be some of the same issues.

Can you give me more details, I'll try to investigate it.

Thanks,

-- Steve

^ permalink raw reply

* Re: [PATCH 3/3] driver: net: ethernet: cpsw: dual emac interface implementation
From: Mugunthan V N @ 2013-02-18 15:10 UTC (permalink / raw)
  To: Peter Korsgaard
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <87mwv1kaln.fsf-D6SC8u56vOOJDPpyT6T3/w@public.gmane.org>

On 2/18/2013 7:06 PM, Peter Korsgaard wrote:
>>>>>> "M" == Mugunthan V N <mugunthanvnm-l0cyMroinI0@public.gmane.org> writes:
>   M> The CPSW switch can act as Dual EMAC by segregating the switch ports
>   M> using VLAN and port VLAN as per the TRM description in
>   M> 14.3.2.10.2 Dual Mac Mode
>
>   M> Following CPSW components will be common for both the interfaces.
>   M> * Interrupt source is common for both eth interfaces
>   M> * Interrupt pacing is common for both interfaces
>   M> * Hardware statistics is common for all the ports
>   M> * CPDMA is common for both eth interface
>   M> * CPTS is common for both the interface and it should not be enabled on
>   M>   both the interface as timestamping information doesn't contain port
>   M>   information.
>
>   M> Constrains
>   M> * Reserved VID of One port should not be used in other interface which will
>   M>   enable switching functionality
>   M> * Same VID must not be used in both the interface which will enable switching
>   M>   functionality
>
>   M> Signed-off-by: Mugunthan V N <mugunthanvnm-l0cyMroinI0@public.gmane.org>
>   M> ---
>   M>  Documentation/devicetree/bindings/net/cpsw.txt |    2 +
>   M>  drivers/net/ethernet/ti/cpsw.c                 |  335 ++++++++++++++++++++----
>   M>  include/linux/platform_data/cpsw.h             |    3 +
>   M>  3 files changed, 288 insertions(+), 52 deletions(-)
>
>   M> diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
>   M> index 6ddd028..ecfdf75 100644
>   M> --- a/Documentation/devicetree/bindings/net/cpsw.txt
>   M> +++ b/Documentation/devicetree/bindings/net/cpsw.txt
>   M> @@ -24,6 +24,8 @@ Required properties:
>   M>  Optional properties:
>   M>  - ti,hwmods		: Must be "cpgmac0"
>   M>  - no_bd_ram		: Must be 0 or 1
>   M> +- dual_emac		: Specifies Switch to act as Dual EMAC
>   M> +- dual_emac_res_vlan	: Specifies VID to be used to segregate the ports
>
> You forgot to CC devicetree-discuss. Properties normally use dashes (-)
> instead of underscores (_). These properties are more about
> configuration and not hardware.
>
> It is not clear to me from the description that dual_emac is a boolean
> (0/1). Shouldn't dual_emacs_res_vlan be a property of the slave?
>
> It would also be good to update the example below with this.
Since the series is already applied in net-next tree, i will submit a 
patch with incorporating
the above comments. Will add devicetree-discuss in my future patches.

Regards
Mugunthan V N

^ permalink raw reply

* [PATCH] ipv6: xfrm6_mode_tunnel: Fix warning
From: Fabio Estevam @ 2013-02-18 14:15 UTC (permalink / raw)
  To: davem; +Cc: pshelar, edumazet, netdev, Fabio Estevam

Fix the following warning:

net/ipv6/xfrm6_mode_tunnel.c:72:2: warning: suggest parentheses around assignment used as truth value [-Wparentheses]

Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
---
 net/ipv6/xfrm6_mode_tunnel.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c
index 93c41a8..9bf6a74 100644
--- a/net/ipv6/xfrm6_mode_tunnel.c
+++ b/net/ipv6/xfrm6_mode_tunnel.c
@@ -69,7 +69,8 @@ static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
 	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
 		goto out;
 
-	if (err = skb_unclone(skb, GFP_ATOMIC))
+	err = skb_unclone(skb, GFP_ATOMIC);
+	if (err)
 		goto out;
 
 	if (x->props.flags & XFRM_STATE_DECAP_DSCP)
-- 
1.7.9.5

^ permalink raw reply related

* Re: [PATCH net-next 2/3] tipc: byte-based overload control on socket receive queue
From: Neil Horman @ 2013-02-18 14:47 UTC (permalink / raw)
  To: Paul Gortmaker; +Cc: David Miller, netdev, Jon Maloy, Ying Xue
In-Reply-To: <1360969067-29956-3-git-send-email-paul.gortmaker@windriver.com>

On Fri, Feb 15, 2013 at 05:57:46PM -0500, Paul Gortmaker wrote:
> From: Ying Xue <ying.xue@windriver.com>
> 
> Change overload control to be purely byte-based, using
> sk->sk_rmem_alloc as byte counter, and compare it to a calculated
> upper limit for the socket receive queue.
> 
> For all connection messages, irrespective of message importance,
> the overload limit is set to a constant value (i.e, 67MB). This
> limit should normally never be reached because of the lower
> limit used by the flow control algorithm, and is there only
> as a last resort in case a faulty peer doesn't respect the send
> window limit.
> 
> For datagram messages, message importance is taken into account
> when calculating the overload limit. The calculation is based
> on sk->sk_rcvbuf, and is hence configurable via the socket option
> SO_RCVBUF.
> 
> Cc: Neil Horman <nhorman@tuxdriver.com>
> Signed-off-by: Ying Xue <ying.xue@windriver.com>
> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>

This looks alot better, thank you.  I still have a few questions though.  See
inline.

> ---
>  net/tipc/socket.c | 77 ++++++++++++++++++++++++++++---------------------------
>  1 file changed, 39 insertions(+), 38 deletions(-)
> 
> diff --git a/net/tipc/socket.c b/net/tipc/socket.c
> index f6ceecd..cbe2f6e 100644
> --- a/net/tipc/socket.c
> +++ b/net/tipc/socket.c
> @@ -43,7 +43,8 @@
>  #define SS_LISTENING	-1	/* socket is listening */
>  #define SS_READY	-2	/* socket is connectionless */
>  
> -#define OVERLOAD_LIMIT_BASE	10000
> +#define CONN_OVERLOAD_LIMIT	((TIPC_FLOW_CONTROL_WIN * 2 + 1) * \
> +				SKB_TRUESIZE(TIPC_MAX_USER_MSG_SIZE))
>  #define CONN_TIMEOUT_DEFAULT	8000	/* default connect timeout = 8s */
>  
>  struct tipc_sock {
> @@ -202,7 +203,6 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol,
>  
>  	sock_init_data(sock, sk);
>  	sk->sk_backlog_rcv = backlog_rcv;
> -	sk->sk_rcvbuf = TIPC_FLOW_CONTROL_WIN * 2 * TIPC_MAX_USER_MSG_SIZE * 2;
>  	sk->sk_data_ready = tipc_data_ready;
>  	sk->sk_write_space = tipc_write_space;
>  	tipc_sk(sk)->p = tp_ptr;
> @@ -1142,34 +1142,6 @@ static void tipc_data_ready(struct sock *sk, int len)
>  }
>  
>  /**
> - * rx_queue_full - determine if receive queue can accept another message
> - * @msg: message to be added to queue
> - * @queue_size: current size of queue
> - * @base: nominal maximum size of queue
> - *
> - * Returns 1 if queue is unable to accept message, 0 otherwise
> - */
> -static int rx_queue_full(struct tipc_msg *msg, u32 queue_size, u32 base)
> -{
> -	u32 threshold;
> -	u32 imp = msg_importance(msg);
> -
> -	if (imp == TIPC_LOW_IMPORTANCE)
> -		threshold = base;
> -	else if (imp == TIPC_MEDIUM_IMPORTANCE)
> -		threshold = base * 2;
> -	else if (imp == TIPC_HIGH_IMPORTANCE)
> -		threshold = base * 100;
> -	else
> -		return 0;
> -
> -	if (msg_connected(msg))
> -		threshold *= 4;
> -
> -	return queue_size >= threshold;
> -}
> -
> -/**
>   * filter_connect - Handle all incoming messages for a connection-based socket
>   * @tsock: TIPC socket
>   * @msg: message
> @@ -1247,6 +1219,36 @@ static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf)
>  }
>  
>  /**
> + * rcvbuf_limit - get proper overload limit of socket receive queue
> + * @sk: socket
> + * @buf: message
> + *
> + * For all connection oriented messages, irrespective of importance,
> + * the default overload value (i.e. 67MB) is set as limit.
> + *
> + * For all connectionless messages, by default new queue limits are
> + * as belows:
> + *
> + * TIPC_LOW_IMPORTANCE       (5MB)
> + * TIPC_MEDIUM_IMPORTANCE    (10MB)
> + * TIPC_HIGH_IMPORTANCE      (20MB)
> + * TIPC_CRITICAL_IMPORTANCE  (40MB)
> + *
> + * Returns overload limit according to corresponding message importance
> + */
> +static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf)
> +{
> +	struct tipc_msg *msg = buf_msg(buf);
> +	unsigned int limit;
> +
> +	if (msg_connected(msg))
> +		limit = CONN_OVERLOAD_LIMIT;
This still strikes me as a bit wierd.  If you really can't tolerate the default
rmem settings in proc, have you considered separating the rmem and wmem values
out into their own sysctls?  Decnet is an example of a protocol that does this
IIRC.  If you did that, then you wouldn't be mysteriously violating the
sk_rcvbuf value that gets set on all new sockets (and you could make this
legitimately tunable).

> +	else
> +		limit = sk->sk_rcvbuf << (msg_importance(msg) + 5);
Same here.  You're using sk_rcvbuf as a base value, rather than a maximum value.
It seems to me, sk_rcvbuf should be the maximum backlog at which you will store
incomming messages.  You can discard lower importance messages at fractions of
sk_rcvbuf if you need to.  If you create separate rmem and wmem sysctls you can
still make the queue limits you document above work, and you won't violate the
receive buffer value set in the socket.

You might also consider looking into adding support for memory accounting, so
that you can play a little more fast and loose with memory limits on an
individual socket when the system as a whole isn't under pressure (tcp and sctp
aer good examples of this).

Neil

^ permalink raw reply

* Re: Re: [BUG arm-soc] mvneta: tx queue done sometimes causes kernel panic
From: Masami Hiramatsu @ 2013-02-18 14:34 UTC (permalink / raw)
  To: Thomas Petazzoni
  Cc: Eric Dumazet, linux-arm-kernel, yrl.pp-manager.tt@hitachi.com,
	linux-kernel, David S. Miller, netdev
In-Reply-To: <20130216022043.65d5c940@skate>

(2013/02/16 10:20), Thomas Petazzoni wrote:
> Hello,
> 
> On Fri, 15 Feb 2013 08:52:12 -0800, Eric Dumazet wrote:
> 
>> Driver is buggy, as TX completion can happen both from ndo_start_xmit()
>> and a timer, and there is no spinlock or appropriate synchro.
> 
> Yes, it is a known issue. I did post a patch fixing the problem on
> netdev@ a while ago [1], but while it was fixing the problem, it wasn't
> considered the right approach. Being busy with other Marvell Armada
> 370/XP developments, I haven't yet had the time to investigate the
> issue again.
> 
> [1] https://patchwork.kernel.org/patch/1941601/

Thank you for pointing that.

I've tried the above patch and found at least this panic
disappeared (even if it was not the right approach).

Thanks again!

-- 
Masami HIRAMATSU
IT Management Research Dept. Linux Technology Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com

^ permalink raw reply

* [PATCH] ipv4: xfrm4_mode_tunnel: Fix warning
From: Fabio Estevam @ 2013-02-18 13:45 UTC (permalink / raw)
  To: davem; +Cc: pshelar, edumazet, netdev, Fabio Estevam

Fix the following warning:

net/ipv4/xfrm4_mode_tunnel.c:145:2: warning: suggest parentheses around assignment used as truth value [-Wparentheses]

Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
---
 net/ipv4/xfrm4_mode_tunnel.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c
index 1162ace..fe5189e 100644
--- a/net/ipv4/xfrm4_mode_tunnel.c
+++ b/net/ipv4/xfrm4_mode_tunnel.c
@@ -142,7 +142,8 @@ static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
 	for_each_input_rcu(rcv_notify_handlers, handler)
 		handler->handler(skb);
 
-	if (err = skb_unclone(skb, GFP_ATOMIC))
+	err = skb_unclone(skb, GFP_ATOMIC);
+	if (err)
 		goto out;
 
 	if (x->props.flags & XFRM_STATE_DECAP_DSCP)
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH net-next 1/2] ip_gre: allow CSUM capable devices to handle packets
From: Dmitry Kravkov @ 2013-02-18 13:39 UTC (permalink / raw)
  To: davem, netdev; +Cc: Dmitry Kravkov

If device is not able to handle checksumming it will
be handled in dev_xmit

Signed-off-by: Dmitry Kravkov <dmitry@broadcom.com>
---
 net/ipv4/ip_gre.c |    7 ++-----
 1 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index a56f118..cdc31ac 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -745,12 +745,9 @@ static struct sk_buff *handle_offloads(struct sk_buff *skb)
 			goto error;
 		skb_shinfo(skb)->gso_type |= SKB_GSO_GRE;
 		return skb;
-	} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		err = skb_checksum_help(skb);
-		if (unlikely(err))
-			goto error;
 	}
-	skb->ip_summed = CHECKSUM_NONE;
+	if (skb->ip_summed != CHECKSUM_PARTIAL)
+		skb->ip_summed = CHECKSUM_NONE;
 
 	return skb;
 
-- 
1.7.7.2

^ permalink raw reply related

* [PATCH net-next 2/2] ip_gre: propogate target device GSO capability to the tunnel device
From: Dmitry Kravkov @ 2013-02-18 13:39 UTC (permalink / raw)
  To: davem, netdev; +Cc: Dmitry Kravkov
In-Reply-To: <1361194791-11493-1-git-send-email-dmitry@broadcom.com>


Signed-off-by: Dmitry Kravkov <dmitry@broadcom.com>
---
 net/ipv4/ip_gre.c |   10 ++++++++--
 1 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index cdc31ac..31bc941 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -1103,8 +1103,14 @@ static int ipgre_tunnel_bind_dev(struct net_device *dev)
 	tunnel->hlen = addend;
 	/* TCP offload with GRE SEQ is not supported. */
 	if (!(tunnel->parms.o_flags & GRE_SEQ)) {
-		dev->features		|= NETIF_F_GSO_SOFTWARE;
-		dev->hw_features	|= NETIF_F_GSO_SOFTWARE;
+		/* device supports enc gso offload*/
+		if (tdev->hw_enc_features & NETIF_F_GRE_GSO) {
+			dev->features		|= NETIF_F_TSO;
+			dev->hw_features	|= NETIF_F_TSO;
+		} else {
+			dev->features		|= NETIF_F_GSO_SOFTWARE;
+			dev->hw_features	|= NETIF_F_GSO_SOFTWARE;
+		}
 	}
 
 	return mtu;
-- 
1.7.7.2

^ permalink raw reply related

* Re: [PATCH 3/3] driver: net: ethernet: cpsw: dual emac interface implementation
From: Peter Korsgaard @ 2013-02-18 13:36 UTC (permalink / raw)
  To: Mugunthan V N
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1360612340-9266-4-git-send-email-mugunthanvnm-l0cyMroinI0@public.gmane.org>

>>>>> "M" == Mugunthan V N <mugunthanvnm-l0cyMroinI0@public.gmane.org> writes:

 M> The CPSW switch can act as Dual EMAC by segregating the switch ports
 M> using VLAN and port VLAN as per the TRM description in
 M> 14.3.2.10.2 Dual Mac Mode

 M> Following CPSW components will be common for both the interfaces.
 M> * Interrupt source is common for both eth interfaces
 M> * Interrupt pacing is common for both interfaces
 M> * Hardware statistics is common for all the ports
 M> * CPDMA is common for both eth interface
 M> * CPTS is common for both the interface and it should not be enabled on
 M>   both the interface as timestamping information doesn't contain port
 M>   information.

 M> Constrains
 M> * Reserved VID of One port should not be used in other interface which will
 M>   enable switching functionality
 M> * Same VID must not be used in both the interface which will enable switching
 M>   functionality

 M> Signed-off-by: Mugunthan V N <mugunthanvnm-l0cyMroinI0@public.gmane.org>
 M> ---
 M>  Documentation/devicetree/bindings/net/cpsw.txt |    2 +
 M>  drivers/net/ethernet/ti/cpsw.c                 |  335 ++++++++++++++++++++----
 M>  include/linux/platform_data/cpsw.h             |    3 +
 M>  3 files changed, 288 insertions(+), 52 deletions(-)

 M> diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
 M> index 6ddd028..ecfdf75 100644
 M> --- a/Documentation/devicetree/bindings/net/cpsw.txt
 M> +++ b/Documentation/devicetree/bindings/net/cpsw.txt
 M> @@ -24,6 +24,8 @@ Required properties:
 M>  Optional properties:
 M>  - ti,hwmods		: Must be "cpgmac0"
 M>  - no_bd_ram		: Must be 0 or 1
 M> +- dual_emac		: Specifies Switch to act as Dual EMAC
 M> +- dual_emac_res_vlan	: Specifies VID to be used to segregate the ports

You forgot to CC devicetree-discuss. Properties normally use dashes (-)
instead of underscores (_). These properties are more about
configuration and not hardware.

It is not clear to me from the description that dual_emac is a boolean
(0/1). Shouldn't dual_emacs_res_vlan be a property of the slave?

It would also be good to update the example below with this.




 M>  Note: "ti,hwmods" field is used to fetch base address and irq
 M>  resources from TI, omap hwmod data base during device registration.
 M> diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
 M> index 4b964bb..4ceed6e 100644
 M> --- a/drivers/net/ethernet/ti/cpsw.c
 M> +++ b/drivers/net/ethernet/ti/cpsw.c
 M> @@ -122,6 +122,10 @@ do {								\
 M>  #define CPSW_VLAN_AWARE		BIT(1)
 M>  #define CPSW_ALE_VLAN_AWARE	1
 
 M> +#define CPSW_FIFO_NORMAL_MODE		(0 << 15)
 M> +#define CPSW_FIFO_DUAL_MAC_MODE		(1 << 15)
 M> +#define CPSW_FIFO_RATE_LIMIT_MODE	(2 << 15)
 M> +
 M>  #define cpsw_enable_irq(priv)	\
 M>  	do {			\
 M>  		u32 i;		\
 M> @@ -254,7 +258,7 @@ struct cpsw_ss_regs {
 M>  struct cpsw_host_regs {
 M>  	u32	max_blks;
 M>  	u32	blk_cnt;
 M> -	u32	flow_thresh;
 M> +	u32	tx_in_ctl;
 M>  	u32	port_vlan;
 M>  	u32	tx_pri_map;
 M>  	u32	cpdma_tx_pri_map;
 M> @@ -281,6 +285,9 @@ struct cpsw_slave {
 M>  	u32				mac_control;
 M>  	struct cpsw_slave_data		*data;
 M>  	struct phy_device		*phy;
 M> +	struct net_device		*ndev;
 M> +	u32				port_vlan;
 M> +	u32				open_stat;
 M>  };
 
 M>  static inline u32 slave_read(struct cpsw_slave *slave, u32 offset)
 M> @@ -320,15 +327,63 @@ struct cpsw_priv {
 M>  	u32 irqs_table[4];
 M>  	u32 num_irqs;
 M>  	struct cpts *cpts;
 M> +	u32 emac_port;
 M>  };
 
 M>  #define napi_to_priv(napi)	container_of(napi, struct cpsw_priv, napi)
 M> -#define for_each_slave(priv, func, arg...)			\
 M> -	do {							\
 M> -		int idx;					\
 M> -		for (idx = 0; idx < (priv)->data.slaves; idx++)	\
 M> -			(func)((priv)->slaves + idx, ##arg);	\
 M> +#define for_each_slave(priv, func, arg...)				\
 M> +	do {								\
 M> +		int idx;						\
 M> +		if (priv->data.dual_emac)				\
 M> +			(func)((priv)->slaves + priv->emac_port, ##arg);\
 M> +		else							\
 M> +			for (idx = 0; idx < (priv)->data.slaves; idx++)	\
 M> +				(func)((priv)->slaves + idx, ##arg);	\
 M> +	} while (0)
 M> +#define cpsw_get_slave_ndev(priv, __slave_no__)				\
 M> +	(priv->slaves[__slave_no__].ndev)
 M> +#define cpsw_get_slave_priv(priv, __slave_no__)				\
 M> +	((priv->slaves[__slave_no__].ndev) ?				\
 M> +		netdev_priv(priv->slaves[__slave_no__].ndev) : NULL)	\
 M> +
 M> +#define cpsw_dual_emac_src_port_detect(status, priv, ndev, skb)		\
 M> +	do {								\
 M> +		if (!priv->data.dual_emac)				\
 M> +			break;						\
 M> +		if (CPDMA_RX_SOURCE_PORT(status) == 1) {		\
 M> +			ndev = cpsw_get_slave_ndev(priv, 0);		\
 M> +			priv = netdev_priv(ndev);			\
 M> +			skb->dev = ndev;				\
 M> +		} else if (CPDMA_RX_SOURCE_PORT(status) == 2) {		\
 M> +			ndev = cpsw_get_slave_ndev(priv, 1);		\
 M> +			priv = netdev_priv(ndev);			\
 M> +			skb->dev = ndev;				\
 M> +		}							\
 M>  	} while (0)
 M> +#define cpsw_add_mcast(priv, addr)					\
 M> +	do {								\
 M> +		if (priv->data.dual_emac) {				\
 M> +			struct cpsw_slave *slave = priv->slaves +	\
 M> +						priv->emac_port;	\
 M> +			int slave_port = cpsw_get_slave_port(priv,	\
 M> +						slave->slave_num);	\
 M> +			cpsw_ale_add_mcast(priv->ale, addr,		\
 M> +				1 << slave_port | 1 << priv->host_port,	\
 M> +				ALE_VLAN, slave->port_vlan, 0);		\
 M> +		} else {						\
 M> +			cpsw_ale_add_mcast(priv->ale, addr,		\
 M> +				ALE_ALL_PORTS << priv->host_port,	\
 M> +				0, 0, 0);				\
 M> +		}							\
 M> +	} while (0)
 M> +
 M> +static inline int cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num)
 M> +{
 M> +	if (priv->host_port == 0)
 M> +		return slave_num + 1;
 M> +	else
 M> +		return slave_num;
 M> +}
 
 M>  static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
 M>  {
 M> @@ -348,8 +403,7 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
 
 M>  		/* program multicast address list into ALE register */
 M>  		netdev_for_each_mc_addr(ha, ndev) {
 M> -			cpsw_ale_add_mcast(priv->ale, (u8 *)ha->addr,
 M> -				ALE_ALL_PORTS << priv->host_port, 0, 0, 0);
 M> +			cpsw_add_mcast(priv, (u8 *)ha->addr);
 M>  		}
 M>  	}
 M>  }
 M> @@ -396,6 +450,8 @@ void cpsw_rx_handler(void *token, int len, int status)
 M>  	struct cpsw_priv	*priv = netdev_priv(ndev);
 M>  	int			ret = 0;
 
 M> +	cpsw_dual_emac_src_port_detect(status, priv, ndev, skb);
 M> +
 M>  	/* free and bail if we are shutting down */
 M>  	if (unlikely(!netif_running(ndev)) ||
 M>  			unlikely(!netif_carrier_ok(ndev))) {
 M> @@ -437,18 +493,17 @@ static irqreturn_t cpsw_interrupt(int irq, void *dev_id)
 M>  		cpsw_intr_disable(priv);
 M>  		cpsw_disable_irq(priv);
 M>  		napi_schedule(&priv->napi);
 M> +	} else {
 M> +		priv = cpsw_get_slave_priv(priv, 1);
 M> +		if (likely(priv) && likely(netif_running(priv->ndev))) {
 M> +			cpsw_intr_disable(priv);
 M> +			cpsw_disable_irq(priv);
 M> +			napi_schedule(&priv->napi);
 M> +		}
 M>  	}
 M>  	return IRQ_HANDLED;
 M>  }
 
 M> -static inline int cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num)
 M> -{
 M> -	if (priv->host_port == 0)
 M> -		return slave_num + 1;
 M> -	else
 M> -		return slave_num;
 M> -}
 M> -
 M>  static int cpsw_poll(struct napi_struct *napi, int budget)
 M>  {
 M>  	struct cpsw_priv	*priv = napi_to_priv(napi);
 M> @@ -566,6 +621,54 @@ static inline int __show_stat(char *buf, int maxlen, const char *name, u32 val)
 M>  				leader + strlen(name), val);
 M>  }
 
 M> +static int cpsw_common_res_usage_state(struct cpsw_priv *priv)
 M> +{
 M> +	u32 i;
 M> +	u32 usage_count = 0;
 M> +
 M> +	if (!priv->data.dual_emac)
 M> +		return 0;
 M> +
 M> +	for (i = 0; i < priv->data.slaves; i++)
 M> +		if (priv->slaves[i].open_stat)
 M> +			usage_count++;
 M> +
 M> +	return usage_count;
 M> +}
 M> +
 M> +static inline int cpsw_tx_packet_submit(struct net_device *ndev,
 M> +			struct cpsw_priv *priv, struct sk_buff *skb)
 M> +{
 M> +	if (!priv->data.dual_emac)
 M> +		return cpdma_chan_submit(priv->txch, skb, skb->data,
 M> +				  skb->len, 0, GFP_KERNEL);
 M> +
 M> +	if (ndev == cpsw_get_slave_ndev(priv, 0))
 M> +		return cpdma_chan_submit(priv->txch, skb, skb->data,
 M> +				  skb->len, 1, GFP_KERNEL);
 M> +	else
 M> +		return cpdma_chan_submit(priv->txch, skb, skb->data,
 M> +				  skb->len, 2, GFP_KERNEL);
 M> +}
 M> +
 M> +static inline void cpsw_add_dual_emac_def_ale_entries(
 M> +		struct cpsw_priv *priv, struct cpsw_slave *slave,
 M> +		u32 slave_port)
 M> +{
 M> +	u32 port_mask = 1 << slave_port | 1 << priv->host_port;
 M> +
 M> +	if (priv->version == CPSW_VERSION_1)
 M> +		slave_write(slave, slave->port_vlan, CPSW1_PORT_VLAN);
 M> +	else
 M> +		slave_write(slave, slave->port_vlan, CPSW2_PORT_VLAN);
 M> +	cpsw_ale_add_vlan(priv->ale, slave->port_vlan, port_mask,
 M> +			  port_mask, port_mask, 0);
 M> +	cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
 M> +			   port_mask, ALE_VLAN, slave->port_vlan, 0);
 M> +	cpsw_ale_add_ucast(priv->ale, priv->mac_addr,
 M> +		priv->host_port, ALE_VLAN, slave->port_vlan);
 M> +}
 M> +
 M>  static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
 M>  {
 M>  	char name[32];
 M> @@ -595,8 +698,11 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
 
 M>  	slave_port = cpsw_get_slave_port(priv, slave->slave_num);
 
 M> -	cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
 M> -			   1 << slave_port, 0, 0, ALE_MCAST_FWD_2);
 M> +	if (priv->data.dual_emac)
 M> +		cpsw_add_dual_emac_def_ale_entries(priv, slave, slave_port);
 M> +	else
 M> +		cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
 M> +				   1 << slave_port, 0, 0, ALE_MCAST_FWD_2);
 
 slave-> phy = phy_connect(priv->ndev, slave->data->phy_id,
 M>  				 &cpsw_adjust_link, slave->data->phy_if);
 M> @@ -634,6 +740,7 @@ static inline void cpsw_add_default_vlan(struct cpsw_priv *priv)
 M>  static void cpsw_init_host_port(struct cpsw_priv *priv)
 M>  {
 M>  	u32 control_reg;
 M> +	u32 fifo_mode;
 
 M>  	/* soft reset the controller and initialize ale */
 M>  	soft_reset("cpsw", &priv->regs->soft_reset);
 M> @@ -645,6 +752,9 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
 M>  	control_reg = readl(&priv->regs->control);
 M>  	control_reg |= CPSW_VLAN_AWARE;
 M>  	writel(control_reg, &priv->regs->control);
 M> +	fifo_mode = (priv->data.dual_emac) ? CPSW_FIFO_DUAL_MAC_MODE :
 M> +		     CPSW_FIFO_NORMAL_MODE;
 M> +	writel(fifo_mode, &priv->host_port_regs->tx_in_ctl);
 
 M>  	/* setup host port priority mapping */
 M>  	__raw_writel(CPDMA_TX_PRIORITY_MAP,
 M> @@ -654,9 +764,12 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
 M>  	cpsw_ale_control_set(priv->ale, priv->host_port,
 M>  			     ALE_PORT_STATE, ALE_PORT_STATE_FORWARD);
 
 M> -	cpsw_ale_add_ucast(priv->ale, priv->mac_addr, priv->host_port, 0, 0);
 M> -	cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
 M> -			   1 << priv->host_port, 0, 0, ALE_MCAST_FWD_2);
 M> +	if (!priv->data.dual_emac) {
 M> +		cpsw_ale_add_ucast(priv->ale, priv->mac_addr, priv->host_port,
 M> +				   0, 0);
 M> +		cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
 M> +				   1 << priv->host_port, 0, 0, ALE_MCAST_FWD_2);
 M> +	}
 M>  }
 
 M>  static int cpsw_ndo_open(struct net_device *ndev)
 M> @@ -665,7 +778,8 @@ static int cpsw_ndo_open(struct net_device *ndev)
 M>  	int i, ret;
 M>  	u32 reg;
 
 M> -	cpsw_intr_disable(priv);
 M> +	if (!cpsw_common_res_usage_state(priv))
 M> +		cpsw_intr_disable(priv);
 M>  	netif_carrier_off(ndev);
 
 M>  	pm_runtime_get_sync(&priv->pdev->dev);
 M> @@ -677,46 +791,54 @@ static int cpsw_ndo_open(struct net_device *ndev)
 M>  		 CPSW_RTL_VERSION(reg));
 
 M>  	/* initialize host and slave ports */
 M> -	cpsw_init_host_port(priv);
 M> +	if (!cpsw_common_res_usage_state(priv))
 M> +		cpsw_init_host_port(priv);
 M>  	for_each_slave(priv, cpsw_slave_open, priv);
 
 M>  	/* Add default VLAN */
 M> -	cpsw_add_default_vlan(priv);
 M> +	if (!priv->data.dual_emac)
 M> +		cpsw_add_default_vlan(priv);
 
 M> -	/* setup tx dma to fixed prio and zero offset */
 M> -	cpdma_control_set(priv->dma, CPDMA_TX_PRIO_FIXED, 1);
 M> -	cpdma_control_set(priv->dma, CPDMA_RX_BUFFER_OFFSET, 0);
 M> +	if (!cpsw_common_res_usage_state(priv)) {
 M> +		/* setup tx dma to fixed prio and zero offset */
 M> +		cpdma_control_set(priv->dma, CPDMA_TX_PRIO_FIXED, 1);
 M> +		cpdma_control_set(priv->dma, CPDMA_RX_BUFFER_OFFSET, 0);
 
 M> -	/* disable priority elevation and enable statistics on all ports */
 M> -	__raw_writel(0, &priv->regs->ptype);
 M> +		/* disable priority elevation */
 M> +		__raw_writel(0, &priv->regs->ptype);
 
 M> -	/* enable statistics collection only on the host port */
 M> -	__raw_writel(0x7, &priv->regs->stat_port_en);
 M> +		/* enable statistics collection only on all ports */
 M> +		__raw_writel(0x7, &priv->regs->stat_port_en);
 
 M> -	if (WARN_ON(!priv->data.rx_descs))
 M> -		priv->data.rx_descs = 128;
 M> +		if (WARN_ON(!priv->data.rx_descs))
 M> +			priv->data.rx_descs = 128;
 
 M> -	for (i = 0; i < priv->data.rx_descs; i++) {
 M> -		struct sk_buff *skb;
 M> +		for (i = 0; i < priv->data.rx_descs; i++) {
 M> +			struct sk_buff *skb;
 
 M> -		ret = -ENOMEM;
 M> -		skb = netdev_alloc_skb_ip_align(priv->ndev,
 M> -						priv->rx_packet_max);
 M> -		if (!skb)
 M> -			break;
 M> -		ret = cpdma_chan_submit(priv->rxch, skb, skb->data,
 M> +			ret = -ENOMEM;
 M> +			skb = netdev_alloc_skb_ip_align(priv->ndev,
 M> +							priv->rx_packet_max);
 M> +			if (!skb)
 M> +				break;
 M> +			ret = cpdma_chan_submit(priv->rxch, skb, skb->data,
 M>  					skb_tailroom(skb), 0, GFP_KERNEL);
 M> -		if (WARN_ON(ret < 0))
 M> -			break;
 M> +			if (WARN_ON(ret < 0))
 M> +				break;
 M> +		}
 M> +		/* continue even if we didn't manage to submit all
 M> +		 * receive descs
 M> +		 */
 M> +		cpsw_info(priv, ifup, "submitted %d rx descriptors\n", i);
 M>  	}
 M> -	/* continue even if we didn't manage to submit all receive descs */
 M> -	cpsw_info(priv, ifup, "submitted %d rx descriptors\n", i);
 
 M>  	cpdma_ctlr_start(priv->dma);
 M>  	cpsw_intr_enable(priv);
 M>  	napi_enable(&priv->napi);
 M>  	cpdma_ctlr_eoi(priv->dma);
 
 M> +	if (priv->data.dual_emac)
 M> +		priv->slaves[priv->emac_port].open_stat = true;
 M>  	return 0;
 M>  }
 
 M> @@ -737,12 +859,17 @@ static int cpsw_ndo_stop(struct net_device *ndev)
 M>  	netif_stop_queue(priv->ndev);
 M>  	napi_disable(&priv->napi);
 M>  	netif_carrier_off(priv->ndev);
 M> -	cpsw_intr_disable(priv);
 M> -	cpdma_ctlr_int_ctrl(priv->dma, false);
 M> -	cpdma_ctlr_stop(priv->dma);
 M> -	cpsw_ale_stop(priv->ale);
 M> +
 M> +	if (cpsw_common_res_usage_state(priv) <= 1) {
 M> +		cpsw_intr_disable(priv);
 M> +		cpdma_ctlr_int_ctrl(priv->dma, false);
 M> +		cpdma_ctlr_stop(priv->dma);
 M> +		cpsw_ale_stop(priv->ale);
 M> +	}
 M>  	for_each_slave(priv, cpsw_slave_stop, priv);
 M>  	pm_runtime_put_sync(&priv->pdev->dev);
 M> +	if (priv->data.dual_emac)
 M> +		priv->slaves[priv->emac_port].open_stat = false;
 M>  	return 0;
 M>  }
 
 M> @@ -766,8 +893,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
 
 M>  	skb_tx_timestamp(skb);
 
 M> -	ret = cpdma_chan_submit(priv->txch, skb, skb->data,
 M> -				skb->len, 0, GFP_KERNEL);
 M> +	ret = cpsw_tx_packet_submit(ndev, priv, skb);
 M>  	if (unlikely(ret != 0)) {
 M>  		cpsw_err(priv, tx_err, "desc submit failed\n");
 M>  		goto fail;
 M> @@ -836,9 +962,14 @@ static void cpsw_hwtstamp_v1(struct cpsw_priv *priv)
 
 M>  static void cpsw_hwtstamp_v2(struct cpsw_priv *priv)
 M>  {
 M> -	struct cpsw_slave *slave = &priv->slaves[priv->data.cpts_active_slave];
 M> +	struct cpsw_slave *slave;
 M>  	u32 ctrl, mtype;
 
 M> +	if (priv->data.dual_emac)
 M> +		slave = &priv->slaves[priv->emac_port];
 M> +	else
 M> +		slave = &priv->slaves[priv->data.cpts_active_slave];
 M> +
 M>  	ctrl = slave_read(slave, CPSW2_CONTROL);
 M>  	ctrl &= ~CTRL_ALL_TS_MASK;
 
 M> @@ -1124,6 +1255,7 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv,
 slave-> data	= data;
 slave-> regs	= regs + slave_reg_ofs;
 slave-> sliver	= regs + sliver_reg_ofs;
 M> +	slave->port_vlan = data->dual_emac_res_vlan;
 M>  }
 
 M>  static int cpsw_probe_dt(struct cpsw_platform_data *data,
 M> @@ -1204,6 +1336,9 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
 M>  	}
 data-> mac_control = prop;
 
 M> +	if (!of_property_read_u32(node, "dual_emac", &prop))
 M> +		data->dual_emac = prop;
 M> +
 M>  	/*
 M>  	 * Populate all the child nodes here...
 M>  	 */
 M> @@ -1237,6 +1372,18 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
 M>  		if (mac_addr)
 M>  			memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN);
 
 M> +		if (data->dual_emac) {
 M> +			if (of_property_read_u32(node, "dual_emac_res_vlan",
 M> +						 &prop)) {
 M> +				pr_err("Missing dual_emac_res_vlan in DT.\n");
 M> +				slave_data->dual_emac_res_vlan = i+1;
 M> +				pr_err("Using %d as Reserved VLAN for %d slave\n",
 M> +				       slave_data->dual_emac_res_vlan, i);
 M> +			} else {
 M> +				slave_data->dual_emac_res_vlan = prop;
 M> +			}
 M> +		}
 M> +
 M>  		i++;
 M>  	}
 
 M> @@ -1247,6 +1394,79 @@ error_ret:
 M>  	return ret;
 M>  }
 
 M> +static int cpsw_probe_dual_emac(struct platform_device *pdev,
 M> +				struct cpsw_priv *priv)
 M> +{
 M> +	struct cpsw_platform_data	*data = &priv->data;
 M> +	struct net_device		*ndev;
 M> +	struct cpsw_priv		*priv_sl2;
 M> +	int ret = 0, i;
 M> +
 M> +	ndev = alloc_etherdev(sizeof(struct cpsw_priv));
 M> +	if (!ndev) {
 M> +		pr_err("cpsw: error allocating net_device\n");
 M> +		return -ENOMEM;
 M> +	}
 M> +
 M> +	priv_sl2 = netdev_priv(ndev);
 M> +	spin_lock_init(&priv_sl2->lock);
 M> +	priv_sl2->data = *data;
 M> +	priv_sl2->pdev = pdev;
 M> +	priv_sl2->ndev = ndev;
 M> +	priv_sl2->dev  = &ndev->dev;
 M> +	priv_sl2->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG);
 M> +	priv_sl2->rx_packet_max = max(rx_packet_max, 128);
 M> +
 M> +	if (is_valid_ether_addr(data->slave_data[1].mac_addr)) {
 M> +		memcpy(priv_sl2->mac_addr, data->slave_data[1].mac_addr,
 M> +			ETH_ALEN);
 M> +		pr_info("cpsw: Detected MACID = %pM\n", priv_sl2->mac_addr);
 M> +	} else {
 M> +		random_ether_addr(priv_sl2->mac_addr);
 M> +		pr_info("cpsw: Random MACID = %pM\n", priv_sl2->mac_addr);
 M> +	}
 M> +	memcpy(ndev->dev_addr, priv_sl2->mac_addr, ETH_ALEN);
 M> +
 M> +	priv_sl2->slaves = priv->slaves;
 M> +	priv_sl2->clk = priv->clk;
 M> +
 M> +	priv_sl2->cpsw_res = priv->cpsw_res;
 M> +	priv_sl2->regs = priv->regs;
 M> +	priv_sl2->host_port = priv->host_port;
 M> +	priv_sl2->host_port_regs = priv->host_port_regs;
 M> +	priv_sl2->wr_regs = priv->wr_regs;
 M> +	priv_sl2->dma = priv->dma;
 M> +	priv_sl2->txch = priv->txch;
 M> +	priv_sl2->rxch = priv->rxch;
 M> +	priv_sl2->ale = priv->ale;
 M> +	priv_sl2->emac_port = 1;
 M> +	priv->slaves[1].ndev = ndev;
 M> +	priv_sl2->cpts = priv->cpts;
 M> +	priv_sl2->version = priv->version;
 M> +
 M> +	for (i = 0; i < priv->num_irqs; i++) {
 M> +		priv_sl2->irqs_table[i] = priv->irqs_table[i];
 M> +		priv_sl2->num_irqs = priv->num_irqs;
 M> +	}
 M> +
 M> +	ndev->features |= NETIF_F_HW_VLAN_FILTER;
 M> +
 M> +	ndev->netdev_ops = &cpsw_netdev_ops;
 M> +	SET_ETHTOOL_OPS(ndev, &cpsw_ethtool_ops);
 M> +	netif_napi_add(ndev, &priv_sl2->napi, cpsw_poll, CPSW_POLL_WEIGHT);
 M> +
 M> +	/* register the network device */
 M> +	SET_NETDEV_DEV(ndev, &pdev->dev);
 M> +	ret = register_netdev(ndev);
 M> +	if (ret) {
 M> +		pr_err("cpsw: error registering net device\n");
 M> +		free_netdev(ndev);
 M> +		ret = -ENODEV;
 M> +	}
 M> +
 M> +	return ret;
 M> +}
 M> +
 M>  static int cpsw_probe(struct platform_device *pdev)
 M>  {
 M>  	struct cpsw_platform_data	*data = pdev->dev.platform_data;
 M> @@ -1310,6 +1530,9 @@ static int cpsw_probe(struct platform_device *pdev)
 M>  	for (i = 0; i < data->slaves; i++)
 priv-> slaves[i].slave_num = i;
 
 M> +	priv->slaves[0].ndev = ndev;
 M> +	priv->emac_port = 0;
 M> +
 priv-> clk = clk_get(&pdev->dev, "fck");
 M>  	if (IS_ERR(priv->clk)) {
 M>  		dev_err(&pdev->dev, "fck is not found\n");
 M> @@ -1484,6 +1707,14 @@ static int cpsw_probe(struct platform_device *pdev)
 M>  	cpsw_notice(priv, probe, "initialized device (regs %x, irq %d)\n",
 priv-> cpsw_res->start, ndev->irq);
 
 M> +	if (priv->data.dual_emac) {
 M> +		ret = cpsw_probe_dual_emac(pdev, priv);
 M> +		if (ret) {
 M> +			cpsw_err(priv, probe, "error probe slave 2 emac interface\n");
 M> +			goto clean_irq_ret;
 M> +		}
 M> +	}
 M> +
 M>  	return 0;
 
 M>  clean_irq_ret:
 M> diff --git a/include/linux/platform_data/cpsw.h b/include/linux/platform_data/cpsw.h
 M> index e962cfd..798fb80 100644
 M> --- a/include/linux/platform_data/cpsw.h
 M> +++ b/include/linux/platform_data/cpsw.h
 M> @@ -21,6 +21,8 @@ struct cpsw_slave_data {
 M>  	char		phy_id[MII_BUS_ID_SIZE];
 M>  	int		phy_if;
 M>  	u8		mac_addr[ETH_ALEN];
 M> +	u16		dual_emac_res_vlan;	/* Reserved VLAN for DualEMAC */
 M> +
 M>  };
 
 M>  struct cpsw_platform_data {
 M> @@ -36,6 +38,7 @@ struct cpsw_platform_data {
 M>  	u32	rx_descs;	/* Number of Rx Descriptios */
 M>  	u32	mac_control;	/* Mac control register */
 M>  	u16	default_vlan;	/* Def VLAN for ALE lookup in VLAN aware mode*/
 M> +	bool	dual_emac;	/* Enable Dual EMAC mode */
 M>  };
 
 M>  #endif /* __CPSW_H__ */
 M> -- 
 M> 1.7.9.5

 M> --
 M> To unsubscribe from this list: send the line "unsubscribe netdev" in
 M> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
 M> More majordomo info at  http://vger.kernel.org/majordomo-info.html


-- 
Bye, Peter Korsgaard

^ permalink raw reply

* Re: [RFC PATCH net-next (V2, RESENT)] ipv6: Queue fragments per interface for multicast/link-local addresses.
From: Erik Hugne @ 2013-02-18 13:19 UTC (permalink / raw)
  To: YOSHIFUJI Hideaki; +Cc: netdev, netfilter-devel
In-Reply-To: <511FB776.8000901@linux-ipv6.org>

On Sun, Feb 17, 2013 at 01:44:38AM +0900, YOSHIFUJI Hideaki wrote:
> We should queue fragments for the same link-local address on
> different interfaces (e.g. fe80::1%eth0 and fe80::1%eth1) to the
> different queue, because of nature of addressing architecture.
> 
> Similarly, we should queue fragments for multicast on different
> interface to the different queue.  This is okay because
> application joins group on speicific interface, and multicast
> traffic is expected only on that interface.
>

Your patch does solve the reassembly problem when macvlans are defined, thanks!

A tad unrelated, but i think there's still some ipv6 multicast filtering 
work to be done in the macvlan driver. If you for example join an all scope 
mcast address, ff09::1 on macvlan 0 it will implicitly be 'joined' on all 
other macvlans aswell..

I can buy that linklocal multicast packets are cloned out to all macvlan devices,
but if a specific prefix is joined on one of them, i dont think it's correct that
all sibling devices should receive that traffic, unless they asked for it.

//E

^ permalink raw reply

* [PATCH net-next 1/2] ip_gre: allow CSUM capable devices to handle packets
From: y @ 2013-02-18 13:15 UTC (permalink / raw)
  To: davem, netdev; +Cc: Dmitry Kravkov

From: Dmitry Kravkov <dmitry@broadcom.com>

If device is not able to handle checksumming it will
be handled in dev_xmit

Signed-off-by: Dmitry Kravkov <dmitry@broadcom.com>
---
 net/ipv4/ip_gre.c |    7 ++-----
 1 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index a56f118..cdc31ac 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -745,12 +745,9 @@ static struct sk_buff *handle_offloads(struct sk_buff *skb)
 			goto error;
 		skb_shinfo(skb)->gso_type |= SKB_GSO_GRE;
 		return skb;
-	} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		err = skb_checksum_help(skb);
-		if (unlikely(err))
-			goto error;
 	}
-	skb->ip_summed = CHECKSUM_NONE;
+	if (skb->ip_summed != CHECKSUM_PARTIAL)
+		skb->ip_summed = CHECKSUM_NONE;
 
 	return skb;
 
-- 
1.7.7.2

^ permalink raw reply related

* [PATCH net-next 2/2] ip_gre: propogate target device GSO capability to the tunnel device
From: y @ 2013-02-18 13:15 UTC (permalink / raw)
  To: davem, netdev; +Cc: Dmitry Kravkov
In-Reply-To: <1361193320-11181-1-git-send-email-y>

From: Dmitry Kravkov <dmitry@broadcom.com>


Signed-off-by: Dmitry Kravkov <dmitry@broadcom.com>
---
 net/ipv4/ip_gre.c |   10 ++++++++--
 1 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index cdc31ac..31bc941 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -1103,8 +1103,14 @@ static int ipgre_tunnel_bind_dev(struct net_device *dev)
 	tunnel->hlen = addend;
 	/* TCP offload with GRE SEQ is not supported. */
 	if (!(tunnel->parms.o_flags & GRE_SEQ)) {
-		dev->features		|= NETIF_F_GSO_SOFTWARE;
-		dev->hw_features	|= NETIF_F_GSO_SOFTWARE;
+		/* device supports enc gso offload*/
+		if (tdev->hw_enc_features & NETIF_F_GRE_GSO) {
+			dev->features		|= NETIF_F_TSO;
+			dev->hw_features	|= NETIF_F_TSO;
+		} else {
+			dev->features		|= NETIF_F_GSO_SOFTWARE;
+			dev->hw_features	|= NETIF_F_GSO_SOFTWARE;
+		}
 	}
 
 	return mtu;
-- 
1.7.7.2

^ permalink raw reply related

* Re: [PATCH v6 33/46] cris/smp: Use get/put_online_cpus_atomic() to prevent CPU offline
From: Jesper Nilsson @ 2013-02-18 13:07 UTC (permalink / raw)
  To: Srivatsa S. Bhat
  Cc: tglx, peterz, tj, oleg, paulmck, rusty, mingo, akpm, namhyung,
	rostedt, wangyun, xiaoguangrong, rjw, sbw, fweisbec, linux,
	nikunj, linux-pm, linux-arch, linux-arm-kernel, linuxppc-dev,
	netdev, linux-doc, linux-kernel, walken, vincent.guittot
In-Reply-To: <20130218124254.26245.4577.stgit@srivatsabhat.in.ibm.com>

On Mon, Feb 18, 2013 at 06:12:54PM +0530, Srivatsa S. Bhat wrote:
> Once stop_machine() is gone from the CPU offline path, we won't be able to
> depend on preempt_disable() or local_irq_disable() to prevent CPUs from
> going offline from under us.
> 
> Use the get/put_online_cpus_atomic() APIs to prevent CPUs from going offline,
> while invoking from atomic context.
> 
> Cc: Mikael Starvik <starvik@axis.com>

> Cc: linux-cris-kernel@axis.com
> Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>

Acked-by: Jesper Nilsson <jesper.nilsson@axis.com>

/^JN - Jesper Nilsson
-- 
               Jesper Nilsson -- jesper.nilsson@axis.com

^ permalink raw reply

* [PATCH] bonding: Fix initialize after use for 3ad machine state spinlock
From: Nikolay Aleksandrov @ 2013-02-18 12:45 UTC (permalink / raw)
  To: netdev; +Cc: andy, fubar, davem

The 3ad machine state spinlock can be used before it is inititialized
while doing bond_enslave() (and the port is being initialized) since
port->slave is set before the lock is prepared, thus causing soft
lock-ups and a multitude of other nasty bugs.

Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com>
---
 drivers/net/bonding/bond_3ad.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 1720742..96d471e 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -389,13 +389,13 @@ static u8 __get_duplex(struct port *port)
 
 /**
  * __initialize_port_locks - initialize a port's STATE machine spinlock
- * @port: the port we're looking at
+ * @port: the slave of the port we're looking at
  *
  */
-static inline void __initialize_port_locks(struct port *port)
+static inline void __initialize_port_locks(struct slave *port)
 {
 	// make sure it isn't called twice
-	spin_lock_init(&(SLAVE_AD_INFO(port->slave).state_machine_lock));
+	spin_lock_init(&(SLAVE_AD_INFO(port).state_machine_lock));
 }
 
 //conversions
@@ -1910,6 +1910,7 @@ int bond_3ad_bind_slave(struct slave *slave)
 
 		ad_initialize_port(port, bond->params.lacp_fast);
 
+		__initialize_port_locks(slave);
 		port->slave = slave;
 		port->actor_port_number = SLAVE_AD_INFO(slave).id;
 		// key is determined according to the link speed, duplex and user key(which is yet not supported)
@@ -1932,8 +1933,6 @@ int bond_3ad_bind_slave(struct slave *slave)
 		port->next_port_in_aggregator = NULL;
 
 		__disable_port(port);
-		__initialize_port_locks(port);
-
 
 		// aggregator initialization
 		aggregator = &(SLAVE_AD_INFO(slave).aggregator);
-- 
1.7.11.7

^ permalink raw reply related

* [PATCH] bonding: Fix race condition between bond_enslave() and bond_3ad_update_lacp_rate()
From: Nikolay Aleksandrov @ 2013-02-18 12:45 UTC (permalink / raw)
  To: netdev; +Cc: andy, fubar, davem

port->slave can be NULL since it's being initialized in bond_enslave
thus dereferencing a NULL pointer in bond_3ad_update_lacp_rate()
Also fix a minor bug, which could cause a port not to have
AD_STATE_LACP_TIMEOUT since there's no sync between
bond_3ad_update_lacp_rate() and bond_3ad_bind_slave(), by changing
the read_lock to a write_lock_bh in bond_3ad_update_lacp_rate().

Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com>
---
 drivers/net/bonding/bond_3ad.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index a030e63..1720742 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2494,11 +2494,13 @@ void bond_3ad_update_lacp_rate(struct bonding *bond)
 	struct port *port = NULL;
 	int lacp_fast;
 
-	read_lock(&bond->lock);
+	write_lock_bh(&bond->lock);
 	lacp_fast = bond->params.lacp_fast;
 
 	bond_for_each_slave(bond, slave, i) {
 		port = &(SLAVE_AD_INFO(slave).port);
+		if (port->slave == NULL)
+			continue;
 		__get_state_machine_lock(port);
 		if (lacp_fast)
 			port->actor_oper_port_state |= AD_STATE_LACP_TIMEOUT;
@@ -2507,5 +2509,5 @@ void bond_3ad_update_lacp_rate(struct bonding *bond)
 		__release_state_machine_lock(port);
 	}
 
-	read_unlock(&bond->lock);
+	write_unlock_bh(&bond->lock);
 }
-- 
1.7.11.7

^ permalink raw reply related

* [PATCH v6 43/46] tile: Use get/put_online_cpus_atomic() to prevent CPU offline
From: Srivatsa S. Bhat @ 2013-02-18 12:44 UTC (permalink / raw)
  To: tglx, peterz, tj, oleg, paulmck, rusty, mingo, akpm, namhyung
  Cc: rostedt, wangyun, xiaoguangrong, rjw, sbw, fweisbec, linux,
	nikunj, srivatsa.bhat, linux-pm, linux-arch, linux-arm-kernel,
	linuxppc-dev, netdev, linux-doc, linux-kernel, walken,
	vincent.guittot
In-Reply-To: <20130218123714.26245.61816.stgit@srivatsabhat.in.ibm.com>

Once stop_machine() is gone from the CPU offline path, we won't be able to
depend on preempt_disable() or local_irq_disable() to prevent CPUs from
going offline from under us.

Use the get/put_online_cpus_atomic() APIs to prevent CPUs from going offline,
while invoking from atomic context.

Cc: Chris Metcalf <cmetcalf@tilera.com>
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
---

 arch/tile/kernel/smp.c |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/tile/kernel/smp.c b/arch/tile/kernel/smp.c
index cbc73a8..fb30624 100644
--- a/arch/tile/kernel/smp.c
+++ b/arch/tile/kernel/smp.c
@@ -15,6 +15,7 @@
  */
 
 #include <linux/smp.h>
+#include <linux/cpu.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/irq.h>
@@ -82,9 +83,12 @@ void send_IPI_many(const struct cpumask *mask, int tag)
 void send_IPI_allbutself(int tag)
 {
 	struct cpumask mask;
+
+	get_online_cpus_atomic();
 	cpumask_copy(&mask, cpu_online_mask);
 	cpumask_clear_cpu(smp_processor_id(), &mask);
 	send_IPI_many(&mask, tag);
+	put_online_cpus_atomic();
 }
 
 /*

^ permalink raw reply related

* [PATCH v6 46/46] Documentation/cpu-hotplug: Remove references to stop_machine()
From: Srivatsa S. Bhat @ 2013-02-18 12:44 UTC (permalink / raw)
  To: tglx, peterz, tj, oleg, paulmck, rusty, mingo, akpm, namhyung
  Cc: rostedt, wangyun, xiaoguangrong, rjw, sbw, fweisbec, linux,
	nikunj, srivatsa.bhat, linux-pm, linux-arch, linux-arm-kernel,
	linuxppc-dev, netdev, linux-doc, linux-kernel, walken,
	vincent.guittot
In-Reply-To: <20130218123714.26245.61816.stgit@srivatsabhat.in.ibm.com>

Since stop_machine() is no longer used in the CPU offline path, we cannot
disable CPU hotplug using preempt_disable()/local_irq_disable() etc. We
need to use the newly introduced get/put_online_cpus_atomic() APIs.
Reflect this in the documentation.

Cc: Rob Landley <rob@landley.net>
Cc: linux-doc@vger.kernel.org
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Reviewed-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
---

 Documentation/cpu-hotplug.txt |   17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/Documentation/cpu-hotplug.txt b/Documentation/cpu-hotplug.txt
index 9f40135..7f907ec 100644
--- a/Documentation/cpu-hotplug.txt
+++ b/Documentation/cpu-hotplug.txt
@@ -113,13 +113,15 @@ Never use anything other than cpumask_t to represent bitmap of CPUs.
 	#include <linux/cpu.h>
 	get_online_cpus() and put_online_cpus():
 
-The above calls are used to inhibit cpu hotplug operations. While the
+The above calls are used to inhibit cpu hotplug operations, when invoked from
+non-atomic context (because the above functions can sleep). While the
 cpu_hotplug.refcount is non zero, the cpu_online_mask will not change.
-If you merely need to avoid cpus going away, you could also use
-preempt_disable() and preempt_enable() for those sections.
-Just remember the critical section cannot call any
-function that can sleep or schedule this process away. The preempt_disable()
-will work as long as stop_machine_run() is used to take a cpu down.
+
+However, if you are executing in atomic context (ie., you can't afford to
+sleep), and you merely need to avoid cpus going offline, you can use
+get_online_cpus_atomic() and put_online_cpus_atomic() for those sections.
+Just remember the critical section cannot call any function that can sleep or
+schedule this process away.
 
 CPU Hotplug - Frequently Asked Questions.
 
@@ -360,6 +362,9 @@ A: There are two ways.  If your code can be run in interrupt context, use
 		return err;
 	}
 
+   If my_func_on_cpu() itself cannot block, use get/put_online_cpus_atomic()
+   instead of get/put_online_cpus() to prevent CPUs from going offline.
+
 Q: How do we determine how many CPUs are available for hotplug.
 A: There is no clear spec defined way from ACPI that can give us that
    information today. Based on some input from Natalie of Unisys,

^ permalink raw reply related

* [PATCH v6 45/46] CPU hotplug, stop_machine: Decouple CPU hotplug from stop_machine() in Kconfig
From: Srivatsa S. Bhat @ 2013-02-18 12:44 UTC (permalink / raw)
  To: tglx, peterz, tj, oleg, paulmck, rusty, mingo, akpm, namhyung
  Cc: rostedt, wangyun, xiaoguangrong, rjw, sbw, fweisbec, linux,
	nikunj, srivatsa.bhat, linux-pm, linux-arch, linux-arm-kernel,
	linuxppc-dev, netdev, linux-doc, linux-kernel, walken,
	vincent.guittot
In-Reply-To: <20130218123714.26245.61816.stgit@srivatsabhat.in.ibm.com>

Simply dropping HOTPLUG_CPU from the dependency list of STOP_MACHINE will
lead to the following kconfig issue, reported by Fengguang Wu:

"warning: (HAVE_TEXT_POKE_SMP) selects STOP_MACHINE which has unmet direct
dependencies (SMP && MODULE_UNLOAD)"

So drop HOTPLUG_CPU and add HAVE_TEXT_POKE_SMP to the dependency list of
STOP_MACHINE.

And while at it, also cleanup a comment that refers to CPU hotplug being
dependent on stop_machine().

Cc: David Howells <dhowells@redhat.com>
Reported-by: Fengguang Wu <fengguang.wu@intel.com>
Suggested-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Reviewed-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
---

 include/linux/stop_machine.h |    2 +-
 init/Kconfig                 |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/linux/stop_machine.h b/include/linux/stop_machine.h
index 3b5e910..ce2d3c4 100644
--- a/include/linux/stop_machine.h
+++ b/include/linux/stop_machine.h
@@ -120,7 +120,7 @@ int stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus);
  * @cpus: the cpus to run the @fn() on (NULL = any online cpu)
  *
  * Description: This is a special version of the above, which assumes cpus
- * won't come or go while it's being called.  Used by hotplug cpu.
+ * won't come or go while it's being called.
  */
 int __stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus);
 
diff --git a/init/Kconfig b/init/Kconfig
index be8b7f5..f4f79af 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1711,7 +1711,7 @@ config INIT_ALL_POSSIBLE
 config STOP_MACHINE
 	bool
 	default y
-	depends on (SMP && MODULE_UNLOAD) || HOTPLUG_CPU
+	depends on (SMP && (MODULE_UNLOAD || HAVE_TEXT_POKE_SMP))
 	help
 	  Need stop_machine() primitive.
 


^ permalink raw reply related

* [PATCH v6 44/46] cpu: No more __stop_machine() in _cpu_down()
From: Srivatsa S. Bhat @ 2013-02-18 12:44 UTC (permalink / raw)
  To: tglx, peterz, tj, oleg, paulmck, rusty, mingo, akpm, namhyung
  Cc: rostedt, wangyun, xiaoguangrong, rjw, sbw, fweisbec, linux,
	nikunj, srivatsa.bhat, linux-pm, linux-arch, linux-arm-kernel,
	linuxppc-dev, netdev, linux-doc, linux-kernel, walken,
	vincent.guittot
In-Reply-To: <20130218123714.26245.61816.stgit@srivatsabhat.in.ibm.com>

From: Paul E. McKenney <paul.mckenney@linaro.org>

The _cpu_down() function invoked as part of the CPU-hotplug offlining
process currently invokes __stop_machine(), which is slow and inflicts
substantial real-time latencies on the entire system.  This patch
substitutes stop_one_cpu() for __stop_machine() in order to improve
both performance and real-time latency.

There were a number of uses of preempt_disable() or local_irq_disable()
that were intended to block CPU-hotplug offlining. These were fixed by
using get/put_online_cpus_atomic(), which is the new synchronization
primitive to prevent CPU offline, while invoking from atomic context.

Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
[ srivatsa.bhat@linux.vnet.ibm.com: Refer to the new sync primitives for
  readers (in the changelog); s/stop_cpus/stop_one_cpu and fix comment
  referring to stop_machine in the code]
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
---

 kernel/cpu.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/cpu.c b/kernel/cpu.c
index 58dd1df..652fb53 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -337,7 +337,7 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
 	}
 	smpboot_park_threads(cpu);
 
-	err = __stop_machine(take_cpu_down, &tcd_param, cpumask_of(cpu));
+	err = stop_one_cpu(cpu, take_cpu_down, &tcd_param);
 	if (err) {
 		/* CPU didn't die: tell everyone.  Can't complain. */
 		smpboot_unpark_threads(cpu);
@@ -349,7 +349,7 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
 	/*
 	 * The migration_call() CPU_DYING callback will have removed all
 	 * runnable tasks from the cpu, there's only the idle task left now
-	 * that the migration thread is done doing the stop_machine thing.
+	 * that the migration thread is done doing the stop_one_cpu() thing.
 	 *
 	 * Wait for the stop thread to go away.
 	 */

^ permalink raw reply related

* [PATCH v6 42/46] sparc: Use get/put_online_cpus_atomic() to prevent CPU offline
From: Srivatsa S. Bhat @ 2013-02-18 12:44 UTC (permalink / raw)
  To: tglx, peterz, tj, oleg, paulmck, rusty, mingo, akpm, namhyung
  Cc: rostedt, wangyun, xiaoguangrong, rjw, sbw, fweisbec, linux,
	nikunj, srivatsa.bhat, linux-pm, linux-arch, linux-arm-kernel,
	linuxppc-dev, netdev, linux-doc, linux-kernel, walken,
	vincent.guittot
In-Reply-To: <20130218123714.26245.61816.stgit@srivatsabhat.in.ibm.com>

Once stop_machine() is gone from the CPU offline path, we won't be able to
depend on preempt_disable() or local_irq_disable() to prevent CPUs from
going offline from under us.

Use the get/put_online_cpus_atomic() APIs to prevent CPUs from going offline,
while invoking from atomic context.

Cc: "David S. Miller" <davem@davemloft.net>
Cc: Sam Ravnborg <sam@ravnborg.org>
Cc: sparclinux@vger.kernel.org
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
---

 arch/sparc/kernel/leon_smp.c  |    2 ++
 arch/sparc/kernel/smp_64.c    |    9 +++++----
 arch/sparc/kernel/sun4d_smp.c |    2 ++
 arch/sparc/kernel/sun4m_smp.c |    3 +++
 4 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/arch/sparc/kernel/leon_smp.c b/arch/sparc/kernel/leon_smp.c
index 0f3fb6d..441d3ac 100644
--- a/arch/sparc/kernel/leon_smp.c
+++ b/arch/sparc/kernel/leon_smp.c
@@ -420,6 +420,7 @@ static void leon_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
 		unsigned long flags;
 
 		spin_lock_irqsave(&cross_call_lock, flags);
+		get_online_cpus_atomic();
 
 		{
 			/* If you make changes here, make sure gcc generates proper code... */
@@ -476,6 +477,7 @@ static void leon_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
 			} while (++i <= high);
 		}
 
+		put_online_cpus_atomic();
 		spin_unlock_irqrestore(&cross_call_lock, flags);
 	}
 }
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c
index 537eb66..e1d7300 100644
--- a/arch/sparc/kernel/smp_64.c
+++ b/arch/sparc/kernel/smp_64.c
@@ -894,7 +894,8 @@ void smp_flush_dcache_page_impl(struct page *page, int cpu)
 	atomic_inc(&dcpage_flushes);
 #endif
 
-	this_cpu = get_cpu();
+	get_online_cpus_atomic();
+	this_cpu = smp_processor_id();
 
 	if (cpu == this_cpu) {
 		__local_flush_dcache_page(page);
@@ -920,7 +921,7 @@ void smp_flush_dcache_page_impl(struct page *page, int cpu)
 		}
 	}
 
-	put_cpu();
+	put_online_cpus_atomic();
 }
 
 void flush_dcache_page_all(struct mm_struct *mm, struct page *page)
@@ -931,7 +932,7 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page)
 	if (tlb_type == hypervisor)
 		return;
 
-	preempt_disable();
+	get_online_cpus_atomic();
 
 #ifdef CONFIG_DEBUG_DCFLUSH
 	atomic_inc(&dcpage_flushes);
@@ -956,7 +957,7 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page)
 	}
 	__local_flush_dcache_page(page);
 
-	preempt_enable();
+	put_online_cpus_atomic();
 }
 
 void __irq_entry smp_new_mmu_context_version_client(int irq, struct pt_regs *regs)
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index ddaea31..1fa7ff2 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -300,6 +300,7 @@ static void sun4d_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
 		unsigned long flags;
 
 		spin_lock_irqsave(&cross_call_lock, flags);
+		get_online_cpus_atomic();
 
 		{
 			/*
@@ -356,6 +357,7 @@ static void sun4d_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
 			} while (++i <= high);
 		}
 
+		put_online_cpus_atomic();
 		spin_unlock_irqrestore(&cross_call_lock, flags);
 	}
 }
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index 128af73..5599548 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -192,6 +192,7 @@ static void sun4m_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
 		unsigned long flags;
 
 		spin_lock_irqsave(&cross_call_lock, flags);
+		get_online_cpus_atomic();
 
 		/* Init function glue. */
 		ccall_info.func = func;
@@ -238,6 +239,8 @@ static void sun4m_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
 					barrier();
 			} while (++i < ncpus);
 		}
+
+		put_online_cpus_atomic();
 		spin_unlock_irqrestore(&cross_call_lock, flags);
 }
 

^ permalink raw reply related

* [PATCH v6 41/46] sh: Use get/put_online_cpus_atomic() to prevent CPU offline
From: Srivatsa S. Bhat @ 2013-02-18 12:44 UTC (permalink / raw)
  To: tglx, peterz, tj, oleg, paulmck, rusty, mingo, akpm, namhyung
  Cc: rostedt, wangyun, xiaoguangrong, rjw, sbw, fweisbec, linux,
	nikunj, srivatsa.bhat, linux-pm, linux-arch, linux-arm-kernel,
	linuxppc-dev, netdev, linux-doc, linux-kernel, walken,
	vincent.guittot
In-Reply-To: <20130218123714.26245.61816.stgit@srivatsabhat.in.ibm.com>

Once stop_machine() is gone from the CPU offline path, we won't be able to
depend on preempt_disable() or local_irq_disable() to prevent CPUs from
going offline from under us.

Use the get/put_online_cpus_atomic() APIs to prevent CPUs from going offline,
while invoking from atomic context.

Cc: Paul Mundt <lethal@linux-sh.org>
Cc: linux-sh@vger.kernel.org
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
---

 arch/sh/kernel/smp.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c
index 2062aa8..232fabe 100644
--- a/arch/sh/kernel/smp.c
+++ b/arch/sh/kernel/smp.c
@@ -357,7 +357,7 @@ static void flush_tlb_mm_ipi(void *mm)
  */
 void flush_tlb_mm(struct mm_struct *mm)
 {
-	preempt_disable();
+	get_online_cpus_atomic();
 
 	if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
 		smp_call_function(flush_tlb_mm_ipi, (void *)mm, 1);
@@ -369,7 +369,7 @@ void flush_tlb_mm(struct mm_struct *mm)
 	}
 	local_flush_tlb_mm(mm);
 
-	preempt_enable();
+	put_online_cpus_atomic();
 }
 
 struct flush_tlb_data {
@@ -390,7 +390,7 @@ void flush_tlb_range(struct vm_area_struct *vma,
 {
 	struct mm_struct *mm = vma->vm_mm;
 
-	preempt_disable();
+	get_online_cpus_atomic();
 	if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
 		struct flush_tlb_data fd;
 
@@ -405,7 +405,7 @@ void flush_tlb_range(struct vm_area_struct *vma,
 				cpu_context(i, mm) = 0;
 	}
 	local_flush_tlb_range(vma, start, end);
-	preempt_enable();
+	put_online_cpus_atomic();
 }
 
 static void flush_tlb_kernel_range_ipi(void *info)
@@ -433,7 +433,7 @@ static void flush_tlb_page_ipi(void *info)
 
 void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 {
-	preempt_disable();
+	get_online_cpus_atomic();
 	if ((atomic_read(&vma->vm_mm->mm_users) != 1) ||
 	    (current->mm != vma->vm_mm)) {
 		struct flush_tlb_data fd;
@@ -448,7 +448,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 				cpu_context(i, vma->vm_mm) = 0;
 	}
 	local_flush_tlb_page(vma, page);
-	preempt_enable();
+	put_online_cpus_atomic();
 }
 
 static void flush_tlb_one_ipi(void *info)


^ permalink raw reply related

* [PATCH v6 40/46] powerpc: Use get/put_online_cpus_atomic() to prevent CPU offline
From: Srivatsa S. Bhat @ 2013-02-18 12:43 UTC (permalink / raw)
  To: tglx, peterz, tj, oleg, paulmck, rusty, mingo, akpm, namhyung
  Cc: rostedt, wangyun, xiaoguangrong, rjw, sbw, fweisbec, linux,
	nikunj, srivatsa.bhat, linux-pm, linux-arch, linux-arm-kernel,
	linuxppc-dev, netdev, linux-doc, linux-kernel, walken,
	vincent.guittot
In-Reply-To: <20130218123714.26245.61816.stgit@srivatsabhat.in.ibm.com>

Once stop_machine() is gone from the CPU offline path, we won't be able to
depend on preempt_disable() or local_irq_disable() to prevent CPUs from
going offline from under us.

Use the get/put_online_cpus_atomic() APIs to prevent CPUs from going offline,
while invoking from atomic context.

Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: linuxppc-dev@lists.ozlabs.org
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
---

 arch/powerpc/mm/mmu_context_nohash.c |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/powerpc/mm/mmu_context_nohash.c b/arch/powerpc/mm/mmu_context_nohash.c
index e779642..29f58cf 100644
--- a/arch/powerpc/mm/mmu_context_nohash.c
+++ b/arch/powerpc/mm/mmu_context_nohash.c
@@ -196,6 +196,7 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
 
 	/* No lockless fast path .. yet */
 	raw_spin_lock(&context_lock);
+	get_online_cpus_atomic();
 
 	pr_hard("[%d] activating context for mm @%p, active=%d, id=%d",
 		cpu, next, next->context.active, next->context.id);
@@ -279,6 +280,7 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
 	/* Flick the MMU and release lock */
 	pr_hardcont(" -> %d\n", id);
 	set_context(id, next->pgd);
+	put_online_cpus_atomic();
 	raw_spin_unlock(&context_lock);
 }
 

^ permalink raw reply related

* [PATCH v6 39/46] parisc: Use get/put_online_cpus_atomic() to prevent CPU offline
From: Srivatsa S. Bhat @ 2013-02-18 12:43 UTC (permalink / raw)
  To: tglx, peterz, tj, oleg, paulmck, rusty, mingo, akpm, namhyung
  Cc: rostedt, wangyun, xiaoguangrong, rjw, sbw, fweisbec, linux,
	nikunj, srivatsa.bhat, linux-pm, linux-arch, linux-arm-kernel,
	linuxppc-dev, netdev, linux-doc, linux-kernel, walken,
	vincent.guittot
In-Reply-To: <20130218123714.26245.61816.stgit@srivatsabhat.in.ibm.com>

Once stop_machine() is gone from the CPU offline path, we won't be able to
depend on preempt_disable() or local_irq_disable() to prevent CPUs from
going offline from under us.

Use the get/put_online_cpus_atomic() APIs to prevent CPUs from going offline,
while invoking from atomic context.

Cc: "James E.J. Bottomley" <jejb@parisc-linux.org>
Cc: linux-parisc@vger.kernel.org
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
---

 arch/parisc/kernel/smp.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
index 6266730..f7851b7 100644
--- a/arch/parisc/kernel/smp.c
+++ b/arch/parisc/kernel/smp.c
@@ -229,11 +229,13 @@ static inline void
 send_IPI_allbutself(enum ipi_message_type op)
 {
 	int i;
-	
+
+	get_online_cpus_atomic();
 	for_each_online_cpu(i) {
 		if (i != smp_processor_id())
 			send_IPI_single(i, op);
 	}
+	put_online_cpus_atomic();
 }
 
 

^ 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