* [PATCH 5/7] SUNRPC: pass network namespace to service registering routines
From: Stanislav Kinsbursky @ 2011-12-15 17:00 UTC (permalink / raw)
To: Trond.Myklebust
Cc: linux-nfs, xemul, neilb, netdev, linux-kernel, jbottomley,
bfields, davem, devel
In-Reply-To: <20111215155252.2434.39434.stgit@localhost6.localdomain6>
Lockd and NFSd services will handle requests from and to many network
nsamespaces. And thus have to be registered and unregistered per network
namespace.
Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
---
include/linux/sunrpc/svc.h | 2 +-
net/sunrpc/svc.c | 42 +++++++++++++++++++++++-------------------
net/sunrpc/svcsock.c | 3 ++-
3 files changed, 26 insertions(+), 21 deletions(-)
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 35b37b1..d3563c2 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -428,7 +428,7 @@ void svc_destroy(struct svc_serv *);
int svc_process(struct svc_rqst *);
int bc_svc_process(struct svc_serv *, struct rpc_rqst *,
struct svc_rqst *);
-int svc_register(const struct svc_serv *, const int,
+int svc_register(const struct svc_serv *, struct net *, const int,
const unsigned short, const unsigned short);
void svc_wake_up(struct svc_serv *);
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 03e9f04..137475a 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -30,7 +30,7 @@
#define RPCDBG_FACILITY RPCDBG_SVCDSP
-static void svc_unregister(const struct svc_serv *serv);
+static void svc_unregister(const struct svc_serv *serv, struct net *net);
#define svc_serv_is_pooled(serv) ((serv)->sv_function)
@@ -375,13 +375,13 @@ static int svc_rpcb_setup(struct svc_serv *serv)
return err;
/* Remove any stale portmap registrations */
- svc_unregister(serv);
+ svc_unregister(serv, &init_net);
return 0;
}
void svc_rpcb_cleanup(struct svc_serv *serv)
{
- svc_unregister(serv);
+ svc_unregister(serv, &init_net);
rpcb_put_local(&init_net);
}
EXPORT_SYMBOL_GPL(svc_rpcb_cleanup);
@@ -790,7 +790,8 @@ EXPORT_SYMBOL_GPL(svc_exit_thread);
* Returns zero on success; a negative errno value is returned
* if any error occurs.
*/
-static int __svc_rpcb_register4(const u32 program, const u32 version,
+static int __svc_rpcb_register4(struct net *net, const u32 program,
+ const u32 version,
const unsigned short protocol,
const unsigned short port)
{
@@ -813,7 +814,7 @@ static int __svc_rpcb_register4(const u32 program, const u32 version,
return -ENOPROTOOPT;
}
- error = rpcb_v4_register(&init_net, program, version,
+ error = rpcb_v4_register(net, program, version,
(const struct sockaddr *)&sin, netid);
/*
@@ -821,7 +822,7 @@ static int __svc_rpcb_register4(const u32 program, const u32 version,
* registration request with the legacy rpcbind v2 protocol.
*/
if (error == -EPROTONOSUPPORT)
- error = rpcb_register(&init_net, program, version, protocol, port);
+ error = rpcb_register(net, program, version, protocol, port);
return error;
}
@@ -837,7 +838,8 @@ static int __svc_rpcb_register4(const u32 program, const u32 version,
* Returns zero on success; a negative errno value is returned
* if any error occurs.
*/
-static int __svc_rpcb_register6(const u32 program, const u32 version,
+static int __svc_rpcb_register6(struct net *net, const u32 program,
+ const u32 version,
const unsigned short protocol,
const unsigned short port)
{
@@ -860,7 +862,7 @@ static int __svc_rpcb_register6(const u32 program, const u32 version,
return -ENOPROTOOPT;
}
- error = rpcb_v4_register(&init_net, program, version,
+ error = rpcb_v4_register(net, program, version,
(const struct sockaddr *)&sin6, netid);
/*
@@ -880,7 +882,7 @@ static int __svc_rpcb_register6(const u32 program, const u32 version,
* Returns zero on success; a negative errno value is returned
* if any error occurs.
*/
-static int __svc_register(const char *progname,
+static int __svc_register(struct net *net, const char *progname,
const u32 program, const u32 version,
const int family,
const unsigned short protocol,
@@ -890,12 +892,12 @@ static int __svc_register(const char *progname,
switch (family) {
case PF_INET:
- error = __svc_rpcb_register4(program, version,
+ error = __svc_rpcb_register4(net, program, version,
protocol, port);
break;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
case PF_INET6:
- error = __svc_rpcb_register6(program, version,
+ error = __svc_rpcb_register6(net, program, version,
protocol, port);
#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
}
@@ -909,14 +911,16 @@ static int __svc_register(const char *progname,
/**
* svc_register - register an RPC service with the local portmapper
* @serv: svc_serv struct for the service to register
+ * @net: net namespace for the service to register
* @family: protocol family of service's listener socket
* @proto: transport protocol number to advertise
* @port: port to advertise
*
* Service is registered for any address in the passed-in protocol family
*/
-int svc_register(const struct svc_serv *serv, const int family,
- const unsigned short proto, const unsigned short port)
+int svc_register(const struct svc_serv *serv, struct net *net,
+ const int family, const unsigned short proto,
+ const unsigned short port)
{
struct svc_program *progp;
unsigned int i;
@@ -941,7 +945,7 @@ int svc_register(const struct svc_serv *serv, const int family,
if (progp->pg_vers[i]->vs_hidden)
continue;
- error = __svc_register(progp->pg_name, progp->pg_prog,
+ error = __svc_register(net, progp->pg_name, progp->pg_prog,
i, family, proto, port);
if (error < 0)
break;
@@ -958,19 +962,19 @@ int svc_register(const struct svc_serv *serv, const int family,
* any "inet6" entries anyway. So a PMAP_UNSET should be sufficient
* in this case to clear all existing entries for [program, version].
*/
-static void __svc_unregister(const u32 program, const u32 version,
+static void __svc_unregister(struct net *net, const u32 program, const u32 version,
const char *progname)
{
int error;
- error = rpcb_v4_register(&init_net, program, version, NULL, "");
+ error = rpcb_v4_register(net, program, version, NULL, "");
/*
* User space didn't support rpcbind v4, so retry this
* request with the legacy rpcbind v2 protocol.
*/
if (error == -EPROTONOSUPPORT)
- error = rpcb_register(&init_net, program, version, 0, 0);
+ error = rpcb_register(net, program, version, 0, 0);
dprintk("svc: %s(%sv%u), error %d\n",
__func__, progname, version, error);
@@ -984,7 +988,7 @@ static void __svc_unregister(const u32 program, const u32 version,
* The result of unregistration is reported via dprintk for those who want
* verification of the result, but is otherwise not important.
*/
-static void svc_unregister(const struct svc_serv *serv)
+static void svc_unregister(const struct svc_serv *serv, struct net *net)
{
struct svc_program *progp;
unsigned long flags;
@@ -1001,7 +1005,7 @@ static void svc_unregister(const struct svc_serv *serv)
dprintk("svc: attempting to unregister %sv%u\n",
progp->pg_name, i);
- __svc_unregister(progp->pg_prog, i, progp->pg_name);
+ __svc_unregister(net, progp->pg_prog, i, progp->pg_name);
}
}
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 277909e..110735f 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -1409,7 +1409,8 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
/* Register socket with portmapper */
if (*errp >= 0 && pmap_register)
- *errp = svc_register(serv, inet->sk_family, inet->sk_protocol,
+ *errp = svc_register(serv, sock->sk->sk_net, inet->sk_family,
+ inet->sk_protocol,
ntohs(inet_sk(inet)->inet_sport));
if (*errp < 0) {
^ permalink raw reply related
* Re: [PATCH 2/2] Explicitly call tcp creation and init from memcontrol.c
From: David Miller @ 2011-12-15 17:00 UTC (permalink / raw)
To: glommer; +Cc: linux-kernel, netdev, cgroups, kamezawa.hiroyu, eric.dumazet, sfr
In-Reply-To: <1323941672-14324-3-git-send-email-glommer@parallels.com>
From: Glauber Costa <glommer@parallels.com>
Date: Thu, 15 Dec 2011 13:34:32 +0400
> Walking the proto_list holds a read_lock, which prevents us from doing
> allocations. Splitting the tcp create function into create + init is
> good, but it is not enough since create_files will do allocations as well
> (dentry ones, mostly).
>
> Since this does not involve any protocol state, I propose we call the tcp
> functions explicitly from memcontrol.c
>
> With this, we lose by now the ability of doing cgroup memcontrol for
> protocols that are loaded as modules. But at least the ones I have in mind
> won't really need it (tcp_ipv6 being the only one, but it uses the same data
> structures as tcp_ipv4). So I believe this to be the simpler solution to this
> problem.
>
> Signed-off-by: Glauber Costa <glommer@parallels.com>
This is an unnecessary limitation, please fix this properly otherwise
DCCP, SCTP, etc. won't be supportable with this stuff.
^ permalink raw reply
* [PATCH 6/7] SUNRPC: register service on creation in current network namespace
From: Stanislav Kinsbursky @ 2011-12-15 17:00 UTC (permalink / raw)
To: Trond.Myklebust-HgOvQuBEEgTQT0dZR+AlfA
Cc: linux-nfs-u79uwXL29TY76Z2rM5mHXA, xemul-bzQdu9zFT3WakBO8gow8eQ,
neilb-l3A5Bk7waGM, netdev-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
jbottomley-bzQdu9zFT3WakBO8gow8eQ, bfields-uC3wQj2KruNg9hUCZPvPmw,
davem-fT/PcQaiUtIeIZ0/mPfg9Q, devel-GEFAQzZX7r8dnm+yROfE0A
In-Reply-To: <20111215155252.2434.39434.stgit-bi+AKbBUZKagILUCTcTcHdKyNwTtLsGr@public.gmane.org>
Service, using rpcbind (Lockd, NFSd) are starting from userspace call and thus
we can use current network namespace.
There could be a problem with NFSd service, because it's creation can be called
through NFSd fs from different network namespace. But this is a part of "NFSd
per net ns" task and will be fixed in future.
Signed-off-by: Stanislav Kinsbursky <skinsbursky-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
---
net/sunrpc/svc.c | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 137475a..578f962 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/slab.h>
+#include <linux/nsproxy.h>
#include <linux/sunrpc/types.h>
#include <linux/sunrpc/xdr.h>
@@ -366,16 +367,16 @@ svc_pool_for_cpu(struct svc_serv *serv, int cpu)
return &serv->sv_pools[pidx % serv->sv_nrpools];
}
-static int svc_rpcb_setup(struct svc_serv *serv)
+static int svc_rpcb_setup(struct svc_serv *serv, struct net *net)
{
int err;
- err = rpcb_create_local(&init_net);
+ err = rpcb_create_local(net);
if (err)
return err;
/* Remove any stale portmap registrations */
- svc_unregister(serv, &init_net);
+ svc_unregister(serv, net);
return 0;
}
@@ -468,7 +469,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
}
if (svc_uses_rpcbind(serv)) {
- if (svc_rpcb_setup(serv) < 0) {
+ if (svc_rpcb_setup(serv, current->nsproxy->net_ns) < 0) {
kfree(serv->sv_pools);
kfree(serv);
return NULL;
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 7/7] SUNRPC: unregister service on creation in current network namespace
From: Stanislav Kinsbursky @ 2011-12-15 17:00 UTC (permalink / raw)
To: Trond.Myklebust
Cc: linux-nfs, xemul, neilb, netdev, linux-kernel, jbottomley,
bfields, davem, devel
In-Reply-To: <20111215155252.2434.39434.stgit@localhost6.localdomain6>
On service shutdown we can be sure, that no more users of it left except
current. Thus it looks like using current network namespace context is safe in
this case.
Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
---
fs/nfsd/nfssvc.c | 4 ++--
include/linux/sunrpc/svc.h | 9 +++++----
net/sunrpc/svc.c | 14 +++++++-------
3 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index eda7d7e..fce472f 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -251,13 +251,13 @@ static void nfsd_shutdown(void)
nfsd_up = false;
}
-static void nfsd_last_thread(struct svc_serv *serv)
+static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
{
/* When last nfsd thread exits we need to do some clean-up */
nfsd_serv = NULL;
nfsd_shutdown();
- svc_rpcb_cleanup(serv);
+ svc_rpcb_cleanup(serv, net);
printk(KERN_WARNING "nfsd: last server has exited, flushing export "
"cache\n");
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index d3563c2..7b65495 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -84,7 +84,8 @@ struct svc_serv {
unsigned int sv_nrpools; /* number of thread pools */
struct svc_pool * sv_pools; /* array of thread pools */
- void (*sv_shutdown)(struct svc_serv *serv);
+ void (*sv_shutdown)(struct svc_serv *serv,
+ struct net *net);
/* Callback to use when last thread
* exits.
*/
@@ -413,14 +414,14 @@ struct svc_procedure {
/*
* Function prototypes.
*/
-void svc_rpcb_cleanup(struct svc_serv *serv);
+void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net);
struct svc_serv *svc_create(struct svc_program *, unsigned int,
- void (*shutdown)(struct svc_serv *));
+ void (*shutdown)(struct svc_serv *, struct net *net));
struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
struct svc_pool *pool, int node);
void svc_exit_thread(struct svc_rqst *);
struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int,
- void (*shutdown)(struct svc_serv *),
+ void (*shutdown)(struct svc_serv *, struct net *net),
svc_thread_fn, struct module *);
int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
int svc_pool_stats_open(struct svc_serv *serv, struct file *file);
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 578f962..b7e4ef9 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -380,10 +380,10 @@ static int svc_rpcb_setup(struct svc_serv *serv, struct net *net)
return 0;
}
-void svc_rpcb_cleanup(struct svc_serv *serv)
+void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net)
{
- svc_unregister(serv, &init_net);
- rpcb_put_local(&init_net);
+ svc_unregister(serv, net);
+ rpcb_put_local(net);
}
EXPORT_SYMBOL_GPL(svc_rpcb_cleanup);
@@ -409,7 +409,7 @@ static int svc_uses_rpcbind(struct svc_serv *serv)
*/
static struct svc_serv *
__svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
- void (*shutdown)(struct svc_serv *serv))
+ void (*shutdown)(struct svc_serv *serv, struct net *net))
{
struct svc_serv *serv;
unsigned int vers;
@@ -483,7 +483,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
struct svc_serv *
svc_create(struct svc_program *prog, unsigned int bufsize,
- void (*shutdown)(struct svc_serv *serv))
+ void (*shutdown)(struct svc_serv *serv, struct net *net))
{
return __svc_create(prog, bufsize, /*npools*/1, shutdown);
}
@@ -491,7 +491,7 @@ EXPORT_SYMBOL_GPL(svc_create);
struct svc_serv *
svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
- void (*shutdown)(struct svc_serv *serv),
+ void (*shutdown)(struct svc_serv *serv, struct net *net),
svc_thread_fn func, struct module *mod)
{
struct svc_serv *serv;
@@ -532,7 +532,7 @@ svc_destroy(struct svc_serv *serv)
svc_close_all(&serv->sv_tempsocks);
if (serv->sv_shutdown)
- serv->sv_shutdown(serv);
+ serv->sv_shutdown(serv, current->nsproxy->net_ns);
svc_close_all(&serv->sv_permsocks);
^ permalink raw reply related
* Re: [patch -next] tcp_memcontrol: fix reversed if condition
From: David Miller @ 2011-12-15 17:01 UTC (permalink / raw)
To: dan.carpenter
Cc: glommer, kuznet, jmorris, yoshfuji, kaber, netdev,
kernel-janitors
In-Reply-To: <20111215110510.GA2674@elgon.mountain>
From: Dan Carpenter <dan.carpenter@oracle.com>
Date: Thu, 15 Dec 2011 14:05:10 +0300
> We should only dereference the pointer if it's valid, not the other way
> round.
>
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
It's nice to see how thoroughly this code has been tested, sigh...
Applied, thanks a lot Dan.
> diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c
> index 171d7b6..7fed04f 100644
> --- a/net/ipv4/tcp_memcontrol.c
> +++ b/net/ipv4/tcp_memcontrol.c
> @@ -44,7 +44,7 @@ static inline struct tcp_memcontrol *tcp_from_cgproto(struct cg_proto *cg_proto)
>
> static void memcg_tcp_enter_memory_pressure(struct sock *sk)
> {
> - if (!sk->sk_cgrp->memory_pressure)
> + if (sk->sk_cgrp->memory_pressure)
> *sk->sk_cgrp->memory_pressure = 1;
> }
> EXPORT_SYMBOL(memcg_tcp_enter_memory_pressure);
^ permalink raw reply
* Re: [PATCH] phylib: update mdiobus_alloc() to allocate extra private space
From: Andy Fleming @ 2011-12-15 17:06 UTC (permalink / raw)
To: Timur Tabi; +Cc: davem, netdev, linuxppc-dev
In-Reply-To: <1323967895-5205-1-git-send-email-timur@freescale.com>
On Dec 15, 2011, at 11:51 AM, Timur Tabi wrote:
> Augment mdiobus_alloc() to take a parameter indicating the number of extra
> bytes to allocate for private data. Almost all callers of mdiobus_alloc()
> separately allocate a private data structure. By allowing mdiobus_alloc()
> to allocate extra memory, the two allocations can be merged into one.
>
> This patch does not change any of the callers to actually take advantage
> of this feature, however. That change can be made by the individual
> maintainers at their leisure. For now, all callers ask for zero additional
> bytes, which mimics the previous behavior.
Why? Doesn't this just obfuscate things a little, while providing no immediate benefit?
Andy
^ permalink raw reply
* Re: [PATCH] phylib: update mdiobus_alloc() to allocate extra private space
From: Timur Tabi @ 2011-12-15 17:12 UTC (permalink / raw)
To: Andy Fleming; +Cc: davem, netdev, linuxppc-dev
In-Reply-To: <8ABCAC4C-1D11-41AD-AE46-96EB9D40588D@freescale.com>
Andy Fleming wrote:
> Why? Doesn't this just obfuscate things a little, while providing no immediate benefit?
I see code like this frequently:
bus = mdiobus_alloc();
if (bus == NULL)
return -ENOMEM;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (priv == NULL) {
err = -ENOMEM;
goto out_free;
}
bus->priv = priv;
This can be replaced with:
bus = mdiobus_alloc(sizeof(*priv));
if (bus == NULL)
return -ENOMEM;
So the benefit is in simplifying memory management. Now you have only one allocation to manage, instead of two.
fbdev does the same thing, which is where I got the idea from. See framebuffer_alloc().
--
Timur Tabi
Linux kernel developer at Freescale
^ permalink raw reply
* Re: twice past the taps, thence out to net?
From: Eric Dumazet @ 2011-12-15 17:43 UTC (permalink / raw)
To: Vijay Subramanian; +Cc: Rick Jones, tcpdump-workers, netdev
In-Reply-To: <CAGK4HS-+jj9cvvirDm96oRvRJdwC+2kjE_LnSOXBuQy0pfnQjg@mail.gmail.com>
Le mercredi 14 décembre 2011 à 18:12 -0800, Vijay Subramanian a écrit :
> On 14 December 2011 11:27, Rick Jones <rick.jones2@hp.com> wrote:
> > While looking at "something else" with tcpdump/tcptrace, tcptrace emitted
> > lots of notices about hardware duplicated packets being detected (same TCP
> > sequence number and IP datagram ID). Sure enough, if I go into the tcpdump
> > trace (taken on the sender) I can find instances of what it was talking
> > about, separated in time by rather less than I would expect to be the RTO,
> > and often as not with few if any intervening arriving ACKs to trigger
> > anything like fast retransmit. And besides, those would have a different IP
> > datagram ID no?
> >
> > I did manage to reproduce the issue with plain netperf tcp_stream tests. I
> > had one sending system with 30 concurrent netperf tcp_stream tests to 30
> > other receiving systems. There are "hardware duplicates" in the sending
> > trace, but no duplicate segments (that I can find thus far) in the two
> > receiver side traces I took. Of course that doesn't mean "conclusively"
> > there were two actual sends but it suggests there werent.
> >
> > While I work through the "obtain permission" path to post the packet traces
> > (don't ask...) I thought I would ask if anyone else has seen something
> > similar.
> >
> > In this case, all the systems are running a 2.6.38-8 Ubuntu kernel (the same
> > sorts of issues which delay my just putting the traces up on netperf.org
> > preclude a later kernel, and I've no other test systems :( ), with Intel
> > 82576 interfaces being driven by:
> >
> > $ sudo ethtool -i eth0
> > driver: igb
> > version: 2.1.0-k2
> > firmware-version: 1.8-2
> > bus-info: 0000:05:00.0
> >
> > All the systems were connected to the same switch.
> >
>
> Rick,
> This may be of help.
> http://www.tcptrace.org/faq_ans.html#FAQ%2021
More exactly, we call dev_queue_xmit_nit() from dev_hard_start_xmit()
_before_ giving skb to device driver.
If device driver returns NETDEV_TX_BUSY, and a qdisc was setup on the
device, packet is requeued.
Later, when queue is allowed to send again packets, packet is
retransmitted (and traced a second time in dev_queue_xmit_nit())
You can see the 'requeues' counter from "tc -s -d qdisc" output :
qdisc mq 0: dev eth2 root
Sent 29421597369 bytes 20301716 pkt (dropped 0, overlimits 0 requeues 371)
backlog 0b 0p requeues 371
^ permalink raw reply
* Re: [PATCH 3/3] qmi_wwan: Driver for WWAN devices requiring use of the QMI protocol
From: Dan Williams @ 2011-12-15 17:52 UTC (permalink / raw)
To: Bjørn Mork; +Cc: netdev, linux-usb
In-Reply-To: <87r506b1ap.fsf@nemi.mork.no>
On Thu, 2011-12-15 at 11:02 +0100, Bjørn Mork wrote:
> Dan Williams <dcbw@redhat.com> writes:
>
> > So I thought the protocol acronym stood for "Qualcomm MSM/Modem
> > Interface" (see
> > https://www.codeaurora.org/gitweb/quic/le/?p=kernel/msm.git;a=commitdiff;h=5f6f87b51184e13b6c493012de787895d5d18765)
>
> That's probably correct. Don't know where I got the messaging part
> from. Should be corrected....
>
> > In any case, great work here. But I'm a bit concerned about how all
> > this should fit together. QMI is a huge protocol that does everything a
> > modem would ever want to do, and we'd likely want to be able to speak
> > QMI from userspace to the modem too so that modem managers can expose
> > the full functionality of the modems. For example Gobi modems have a
> > very minimal AT command set and most of the functionality is exposed
> > over QMI or DM. That's why the Qualcomm GobiNet driver also
> > exposed /dev/qmi for userspace access.
>
> Yes, I believe some interface should be exported. But my primary goal
> was to make something that would just work as an ethernet device with a
> minimum of external userspace dependencies. And this modem seems to
> have a fairly complete set of AT commands anyway. Ideally I would want
> to stick
>
> auto wwan0
> iface wwan0 inet dhcp
>
> in my /etc/network/interface and not need any application for that to
> work. But I realize that I must enter a SIM PIN1 code first (unless
> disabled), and that most users will want to configure a specific APN
> (although the null APN "" most likely will work just fine).
>
> But I agree that eventually the full QMI protocol should be made
> available to userspace for other uses. That should be fairly easy to do
> if you just proxy the commands. But I'm worring about the interface.
> Is the /dev/qmi from GobiNet acceptable? Why isn't it merged yet?
It would have to be /dev/qmiX (in case you have more than one
QMI-capable card in the system) and it would also have to have the right
sysfs entries so that we could match the qmiX entry up with it's parent
USB interface. Not entirely sure how to do that.
> Wouldn't something like netlink have been more suitable? How about
> security and the ability to control privileges on a command to command
> basis? And are there users? Note that even the Windows application
> supplied with the modem uses AT commands for SMS sending/receiving etc.
> The snoop I did showed a very minimal set of QMI commands. These were
> all Windows used for startup of the network interface (partly decoded by
> me):
Huawei writes custom firmware for their dongles. Gobi devices and other
devices that talk QMI don't necessarily have such a full quite of AT
commands, yet they all talk the same QMI protocol. It makes sense to
have a generic driver for this if we can. That probably means a QMI
core (like you've got with the qmi_wwan stuff) and device-specific
drives. The Huawei device would use the ECM-like stuff while the Gobi
bits would implement what gobi_net does. They might even be almost the
same, I haven't looked in a while. But they are similar enough that
they should be sharing most of the code.
But it gets more complicated. We also have Novatel and Sierra devices
that are driven by different drivers (option for Novatel, and sierra for
Sierra) and both these vendors have Gobi-based devices that also speak
QMI, but have custom Ethernet interfaces too (sierra_net for example).
The point being that we need some mechanism for exposing QMI on all
these devices, but some of them (ie Huawei) also need to use QMI to make
the Ethernet bits happen. Some don't.
[snip]
>
> > Second, does the modem actually respond to DHCP over the ECM interface?
>
> Yes. And IMHO that's the only sensible thing to do. Cannot be very
> difficult to implement that feature in the firmware. It's not like you
Not quite, Option's method is just fine too (provide an AT command that
prints the IP and DNS information that you then assign to the
interface). The devices are a lot more complicated than just doing
DHCP, and you're lucky that it works as easily as it does with the
Huawei part :) Doesn't mean it should necessarily work that way all the
time.
But companies don't necessarily like adding features to firmware.
That's a lot harder to change than features in the driver. I worked
with Sierra a couple years ago to get the sierra_net driver accepted to
the kernel and in the first round the DHCP bits were in the driver.
Which was unacceptable. They finally did move it to the firmware but
not all vendors are as easy to work with as Sierra was.
> need to write a dhcp server. You know you have only a single client on
> the other end of a point-to-point link, and the address configuration is
> given. And all broadcast/multicast requires special treatment anyway.
> I actually thought about implementing the DHCP functionality in the
> driver before I knew that the firmware already provided this.
>
> FWIW, the Windows driver implementation also depends on DHCP for address
> configuration .
Good to know.
> > If you take a look at the Android rmnet code (which is similar to your
> > driver) you'll see they extract the IP address and DNS details from the
> > QMI response. Do we need to do that here too?
>
> Based on the above, I don't think so.
>
> And if you still want to extract address details without using DHCP,
> then that information is available via the AT^DHCP? command anyway. You
> don't need QMI for that part.
Ok, also good to know. Honestly I don't really understand why everyone
just uses cdc-ether or cdc-eem these days but apparently they don't.
Dan
^ permalink raw reply
* Re: [PATCH net-next 0/6] tg3: 57766 support and new features
From: David Miller @ 2011-12-15 18:11 UTC (permalink / raw)
To: mcarlson; +Cc: netdev
In-Reply-To: <1323897002-17295-1-git-send-email-mcarlson@broadcom.com>
From: "Matt Carlson" <mcarlson@broadcom.com>
Date: Wed, 14 Dec 2011 13:09:56 -0800
> This patchset adds 57766 ASIC rev support, adds admin control over
> the RSS indirection table and makes a few minor cleanups.
I've applied patches 1-5 to net-next, please address Ben's feedback
and resubmit the updated version of patch 6.
Thanks.
^ permalink raw reply
* Re: twice past the taps, thence out to net?
From: Rick Jones @ 2011-12-15 18:32 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Vijay Subramanian, tcpdump-workers, netdev
In-Reply-To: <1323970998.2769.18.camel@edumazet-HP-Compaq-6005-Pro-SFF-PC>
> More exactly, we call dev_queue_xmit_nit() from dev_hard_start_xmit()
> _before_ giving skb to device driver.
>
> If device driver returns NETDEV_TX_BUSY, and a qdisc was setup on the
> device, packet is requeued.
>
> Later, when queue is allowed to send again packets, packet is
> retransmitted (and traced a second time in dev_queue_xmit_nit())
Is this then an unintended consequence bug, or a known feature?
rick
> You can see the 'requeues' counter from "tc -s -d qdisc" output :
>
> qdisc mq 0: dev eth2 root
> Sent 29421597369 bytes 20301716 pkt (dropped 0, overlimits 0 requeues 371)
> backlog 0b 0p requeues 371
Sure enough:
$ tc -s -d qdisc
qdisc mq 0: dev eth0 root
Sent 2212158799862 bytes 1938268098 pkt (dropped 0, overlimits 0
requeues 4975139)
backlog 0b 0p requeues 4975139
rick jones
^ permalink raw reply
* Re: twice past the taps, thence out to net?
From: Stephen Hemminger @ 2011-12-15 18:44 UTC (permalink / raw)
To: Rick Jones; +Cc: Eric Dumazet, Vijay Subramanian, tcpdump-workers, netdev
In-Reply-To: <4EEA3D58.5010101@hp.com>
On Thu, 15 Dec 2011 10:32:56 -0800
Rick Jones <rick.jones2@hp.com> wrote:
>
> > More exactly, we call dev_queue_xmit_nit() from dev_hard_start_xmit()
> > _before_ giving skb to device driver.
> >
> > If device driver returns NETDEV_TX_BUSY, and a qdisc was setup on the
> > device, packet is requeued.
> >
> > Later, when queue is allowed to send again packets, packet is
> > retransmitted (and traced a second time in dev_queue_xmit_nit())
>
> Is this then an unintended consequence bug, or a known feature?
>
> rick
>
> > You can see the 'requeues' counter from "tc -s -d qdisc" output :
> >
> > qdisc mq 0: dev eth2 root
> > Sent 29421597369 bytes 20301716 pkt (dropped 0, overlimits 0 requeues 371)
> > backlog 0b 0p requeues 371
>
> Sure enough:
>
> $ tc -s -d qdisc
> qdisc mq 0: dev eth0 root
> Sent 2212158799862 bytes 1938268098 pkt (dropped 0, overlimits 0
> requeues 4975139)
> backlog 0b 0p requeues 4975139
>
> rick jones
Device's work better if the driver proactively manages stop_queue/wake_queue.
Old devices used TX_BUSY, but newer devices tend to manage the queue
themselves.
^ permalink raw reply
* [PATCH] r8169: fix Config2 MSIEnable bit setting.
From: Francois Romieu @ 2011-12-15 18:37 UTC (permalink / raw)
To: hayeswang; +Cc: 'David Miller', 'nic_swsd', netdev
In-Reply-To: <6678D92472CB4636B48A3D97ADE27BB9@realtek.com.tw>
The MSIEnable bit is only available for the 8169.
Avoid Config2 writes for the post-8169 8168 and 810x.
Reported-by: Su Kang Yin <cantona@cantona.net>
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
Cc: Hayes Wang <hayeswang@realtek.com>
---
RTL_FEATURE_MSI has never been enabled for the 8169 itself. It could
be -next material.
drivers/net/ethernet/realtek/r8169.c | 14 ++++++++------
1 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 67bf078..c8f47f1 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -477,7 +477,6 @@ enum rtl_register_content {
/* Config1 register p.24 */
LEDS1 = (1 << 7),
LEDS0 = (1 << 6),
- MSIEnable = (1 << 5), /* Enable Message Signaled Interrupt */
Speed_down = (1 << 4),
MEMMAP = (1 << 3),
IOMAP = (1 << 2),
@@ -485,6 +484,7 @@ enum rtl_register_content {
PMEnable = (1 << 0), /* Power Management Enable */
/* Config2 register p. 25 */
+ MSIEnable = (1 << 5), /* 8169 only. Reserved in the 8168. */
PCI_Clock_66MHz = 0x01,
PCI_Clock_33MHz = 0x00,
@@ -3426,22 +3426,24 @@ static const struct rtl_cfg_info {
};
/* Cfg9346_Unlock assumed. */
-static unsigned rtl_try_msi(struct pci_dev *pdev, void __iomem *ioaddr,
+static unsigned rtl_try_msi(struct rtl8169_private *tp,
const struct rtl_cfg_info *cfg)
{
+ void __iomem *ioaddr = tp->mmio_addr;
unsigned msi = 0;
u8 cfg2;
cfg2 = RTL_R8(Config2) & ~MSIEnable;
if (cfg->features & RTL_FEATURE_MSI) {
- if (pci_enable_msi(pdev)) {
- dev_info(&pdev->dev, "no MSI. Back to INTx.\n");
+ if (pci_enable_msi(tp->pci_dev)) {
+ netif_info(tp, hw, tp->dev, "no MSI. Back to INTx.\n");
} else {
cfg2 |= MSIEnable;
msi = RTL_FEATURE_MSI;
}
}
- RTL_W8(Config2, cfg2);
+ if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
+ RTL_W8(Config2, cfg2);
return msi;
}
@@ -4077,7 +4079,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->features |= RTL_FEATURE_WOL;
if ((RTL_R8(Config5) & (UWF | BWF | MWF)) != 0)
tp->features |= RTL_FEATURE_WOL;
- tp->features |= rtl_try_msi(pdev, ioaddr, cfg);
+ tp->features |= rtl_try_msi(tp, cfg);
RTL_W8(Cfg9346, Cfg9346_Lock);
if (rtl_tbi_enabled(tp)) {
--
1.7.6.4
^ permalink raw reply related
* Re: twice past the taps, thence out to net?
From: Eric Dumazet @ 2011-12-15 18:54 UTC (permalink / raw)
To: Rick Jones; +Cc: Vijay Subramanian, tcpdump-workers, netdev
In-Reply-To: <4EEA3D58.5010101@hp.com>
Le jeudi 15 décembre 2011 à 10:32 -0800, Rick Jones a écrit :
> > More exactly, we call dev_queue_xmit_nit() from dev_hard_start_xmit()
> > _before_ giving skb to device driver.
> >
> > If device driver returns NETDEV_TX_BUSY, and a qdisc was setup on the
> > device, packet is requeued.
> >
> > Later, when queue is allowed to send again packets, packet is
> > retransmitted (and traced a second time in dev_queue_xmit_nit())
>
> Is this then an unintended consequence bug, or a known feature?
>
Its a well known feature, some people attempted to remove it ;)
http://answers.softpicks.net/answers/topic/-PATCH-tcpdump-may-trace-some-outbound-packets-twice--2204640-1.htm
^ permalink raw reply
* Re: twice past the taps, thence out to net?
From: Eric Dumazet @ 2011-12-15 19:00 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: Rick Jones, Vijay Subramanian, tcpdump-workers, netdev
In-Reply-To: <20111215104440.1eef9e47@s6510.linuxnetplumber.net>
Le jeudi 15 décembre 2011 à 10:44 -0800, Stephen Hemminger a écrit :
> On Thu, 15 Dec 2011 10:32:56 -0800
> Rick Jones <rick.jones2@hp.com> wrote:
>
> >
> > > More exactly, we call dev_queue_xmit_nit() from dev_hard_start_xmit()
> > > _before_ giving skb to device driver.
> > >
> > > If device driver returns NETDEV_TX_BUSY, and a qdisc was setup on the
> > > device, packet is requeued.
> > >
> > > Later, when queue is allowed to send again packets, packet is
> > > retransmitted (and traced a second time in dev_queue_xmit_nit())
> >
> > Is this then an unintended consequence bug, or a known feature?
> >
> > rick
> >
> > > You can see the 'requeues' counter from "tc -s -d qdisc" output :
> > >
> > > qdisc mq 0: dev eth2 root
> > > Sent 29421597369 bytes 20301716 pkt (dropped 0, overlimits 0 requeues 371)
> > > backlog 0b 0p requeues 371
> >
> > Sure enough:
> >
> > $ tc -s -d qdisc
> > qdisc mq 0: dev eth0 root
> > Sent 2212158799862 bytes 1938268098 pkt (dropped 0, overlimits 0
> > requeues 4975139)
> > backlog 0b 0p requeues 4975139
> >
> > rick jones
>
> Device's work better if the driver proactively manages stop_queue/wake_queue.
> Old devices used TX_BUSY, but newer devices tend to manage the queue
> themselves.
>
Some 'new' drivers like igb can be fooled in case skb is gso segmented ?
Because igb_xmit_frame_ring() needs skb_shinfo(skb)->nr_frags + 4
descriptors, igb should stop its queue not at MAX_SKB_FRAGS + 4, but
MAX_SKB_FRAGS*4
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 89d576c..989da36 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -4370,7 +4370,7 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
igb_tx_map(tx_ring, first, hdr_len);
/* Make sure there is space in the ring for the next send. */
- igb_maybe_stop_tx(tx_ring, MAX_SKB_FRAGS + 4);
+ igb_maybe_stop_tx(tx_ring, MAX_SKB_FRAGS * 4);
return NETDEV_TX_OK;
^ permalink raw reply related
* pull request: wireless 2011-12-15
From: John W. Linville @ 2011-12-15 19:15 UTC (permalink / raw)
To: davem; +Cc: linux-wireless, netdev, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 6553 bytes --]
commit 42a3b63bb2ca4996a3d1210a004eae2333f1119e
Dave,
Here are a few more fixes intended for the 3.2 release. They are
all small and narrowly focused.
First is a one liner fix for a signedness problem in NFC that could
lead to an incorrect return code being propogated. Next are two
iwlwifi regression fixes that received some recent attention on the
linux-wireless mailing list. A third iwlwifi fix corrects a sequence
numbering error, which can cause a lot of bad behaviour in the wireless
network. The ath9k fix corrects a potential for an array underrun.
Finally, the mwifiex fix corrects a double list deletion.
Please let me know if there are problems!
Thanks,
John
---
The following changes since commit 3f1e6d3fd37bd4f25e5b19f1c7ca21850426c33f:
sch_gred: should not use GFP_KERNEL while holding a spinlock (2011-12-12 19:08:54 -0500)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git for-davem
Dan Carpenter (1):
nfc: signedness bug in __nci_request()
Johannes Berg (1):
iwlwifi: tx_sync only on PAN context
John W. Linville (1):
Merge branch 'master' of git://git.kernel.org/.../linville/wireless into for-davem
Rajkumar Manoharan (1):
ath9k: fix max phy rate at rate control init
Wey-Yi Guy (2):
iwlwifi: do not set the sequence control bit is not needed
iwlwifi: allow to switch to HT40 if not associated
Yogesh Ashok Powar (1):
mwifiex: avoid double list_del in command cancel path
drivers/net/wireless/ath/ath9k/rc.c | 4 +++-
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 4 ++--
drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 5 ++++-
drivers/net/wireless/iwlwifi/iwl-agn.c | 6 ++++++
drivers/net/wireless/mwifiex/cmdevt.c | 9 ++-------
net/nfc/nci/core.c | 2 +-
6 files changed, 18 insertions(+), 12 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 888abc2..528d5f3 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -1271,7 +1271,9 @@ static void ath_rc_init(struct ath_softc *sc,
ath_rc_priv->max_valid_rate = k;
ath_rc_sort_validrates(rate_table, ath_rc_priv);
- ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4];
+ ath_rc_priv->rate_max_phy = (k > 4) ?
+ ath_rc_priv->valid_rate_index[k-4] :
+ ath_rc_priv->valid_rate_index[k-1];
ath_rc_priv->rate_table = rate_table;
ath_dbg(common, ATH_DBG_CONFIG,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
index a7a6def..5c7c17c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
@@ -606,8 +606,8 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
if (ctx->ht.enabled) {
/* if HT40 is used, it should not change
* after associated except channel switch */
- if (iwl_is_associated_ctx(ctx) &&
- !ctx->ht.is_40mhz)
+ if (!ctx->ht.is_40mhz ||
+ !iwl_is_associated_ctx(ctx))
iwlagn_config_ht40(conf, ctx);
} else
ctx->ht.is_40mhz = false;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 35a6b71..df1540c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -91,7 +91,10 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
tx_cmd->tid_tspec = qc[0] & 0xf;
tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
} else {
- tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+ tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+ else
+ tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
}
iwlagn_tx_cmd_protection(priv, info, fc, &tx_flags);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index bacc06c..e0e9a3d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2850,6 +2850,9 @@ static int iwlagn_mac_tx_sync(struct ieee80211_hw *hw,
int ret;
u8 sta_id;
+ if (ctx->ctxid != IWL_RXON_CTX_PAN)
+ return 0;
+
IWL_DEBUG_MAC80211(priv, "enter\n");
mutex_lock(&priv->shrd->mutex);
@@ -2898,6 +2901,9 @@ static void iwlagn_mac_finish_tx_sync(struct ieee80211_hw *hw,
struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
struct iwl_rxon_context *ctx = vif_priv->ctx;
+ if (ctx->ctxid != IWL_RXON_CTX_PAN)
+ return;
+
IWL_DEBUG_MAC80211(priv, "enter\n");
mutex_lock(&priv->shrd->mutex);
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index ac27815..6e0a3ea 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -939,7 +939,6 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
{
struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL;
unsigned long cmd_flags;
- unsigned long cmd_pending_q_flags;
unsigned long scan_pending_q_flags;
uint16_t cancel_scan_cmd = false;
@@ -949,12 +948,9 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
cmd_node = adapter->curr_cmd;
cmd_node->wait_q_enabled = false;
cmd_node->cmd_flag |= CMD_F_CANCELED;
- spin_lock_irqsave(&adapter->cmd_pending_q_lock,
- cmd_pending_q_flags);
- list_del(&cmd_node->list);
- spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
- cmd_pending_q_flags);
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+ mwifiex_complete_cmd(adapter, adapter->curr_cmd);
+ adapter->curr_cmd = NULL;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
}
@@ -981,7 +977,6 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
}
adapter->cmd_wait_q.status = -1;
- mwifiex_complete_cmd(adapter, adapter->curr_cmd);
}
/*
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index 3925c65..ea66034 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -69,7 +69,7 @@ static int __nci_request(struct nci_dev *ndev,
__u32 timeout)
{
int rc = 0;
- unsigned long completion_rc;
+ long completion_rc;
ndev->req_status = NCI_REQ_PEND;
--
John W. Linville Someday the world will need a hero, and you
linville@tuxdriver.com might be all we have. Be ready.
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply related
* Re: pull request: wireless 2011-12-15
From: Rafał Miłecki @ 2011-12-15 20:04 UTC (permalink / raw)
To: John W. Linville; +Cc: davem, linux-wireless, netdev, linux-kernel
In-Reply-To: <20111215191523.GA2561@tuxdriver.com>
2011/12/15 John W. Linville <linville@tuxdriver.com>:
> commit 42a3b63bb2ca4996a3d1210a004eae2333f1119e
>
> Dave,
>
> Here are a few more fixes intended for the 3.2 release. They are
> all small and narrowly focused.
John, I've made a mistake and didn't use [PATCH 3.2] header to make it
clean my patch is fix. Could you take a look at
[PATCH] bcma: support for suspend and resume
please?
It's not one-liner, but fixes lock ups, which I believe - we really
want to avoid.
--
Rafał
^ permalink raw reply
* Re: [PATCH net-next 6/6] tg3: Make the RSS indir tbl admin configurable
From: Matt Carlson @ 2011-12-15 21:03 UTC (permalink / raw)
To: Ben Hutchings
Cc: Matthew Carlson, davem@davemloft.net, netdev@vger.kernel.org,
Michael Chan
In-Reply-To: <1323899459.2753.19.camel@bwh-desktop>
On Wed, Dec 14, 2011 at 01:50:59PM -0800, Ben Hutchings wrote:
> On Wed, 2011-12-14 at 13:10 -0800, Matt Carlson wrote:
> > This patch adds the ethtool callbacks necessary to change the rss
> > indirection table from userspace. When setting the indirection table
> > through set_rxfh_indir, an indirection table size of zero is
> > interpreted to mean that the admin wants to relinquish control of the
> > table to the driver.
>
> I'm not convinced that this is a particularly useful option, but I won't
> object. But please document this as an optional driver behaviour in
> <linux/ethtool.h>, and add support for this in the ethtool command (e.g.
> a 'reset' or 'default' keyword).
Will do.
> > Should the number of interrupts change (e.g.
> > across a close / open call, or through a reset), any indirection table
> > values that exceed the number of RSS queues or interrupt vectors will
> > be automatically scaled back to values within range.
> >
> > Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
> > Signed-off-by: Michael Chan <mchan@broadcom.com>
> > Reviewed-by: Benjamin Li <benli@broadcom.com>
> > ---
> > drivers/net/ethernet/broadcom/tg3.c | 128 ++++++++++++++++++++++++++++++++++-
> > drivers/net/ethernet/broadcom/tg3.h | 1 +
> > 2 files changed, 128 insertions(+), 1 deletions(-)
> >
> > diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
> > index 8bf11ca..f684be9 100644
> > --- a/drivers/net/ethernet/broadcom/tg3.c
> > +++ b/drivers/net/ethernet/broadcom/tg3.c
> > @@ -8229,9 +8229,18 @@ void tg3_rss_init_indir_tbl(struct tg3 *tp)
> >
> > if (tp->irq_cnt <= 2)
> > memset(&tp->rss_ind_tbl[0], 0, sizeof(tp->rss_ind_tbl));
> > - else
> > + else if (tg3_flag(tp, USER_INDIR_TBL)) {
> > + /* Validate table against current IRQ count */
> > + for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++) {
> > + if (tp->rss_ind_tbl[i] >= tp->irq_cnt - 1) {
> > + /* Cap the vector index */
> > + tp->rss_ind_tbl[i] = tp->irq_cnt - 2;
>
> A modulo operation might make more sense. But I don't suppose this
> failure is going to happen often enough for it to be important.
I suppose that makes more sense. TG3 only has at-most 4 RSS queues, so
there really isn't much difference. Your idea places more of the
traffic in the first RSS queue, which has a slight performance
advantage. Thanks for making me rethink this. :)
> > + }
> > + }
> > + } else {
> > for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++)
> > tp->rss_ind_tbl[i] = i % (tp->irq_cnt - 1);
> > + }
> > }
> >
> > void tg3_rss_write_indir_tbl(struct tg3 *tp)
> > @@ -10719,6 +10728,120 @@ static int tg3_get_sset_count(struct net_device *dev, int sset)
> > }
> > }
> >
> > +static int tg3_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
> > + u32 *rules __always_unused)
> > +{
> > + struct tg3 *tp = netdev_priv(dev);
> > +
> > + if (!tg3_flag(tp, SUPPORT_MSIX))
> > + return -EINVAL;
>
> Should be -EOPNOTSUPP.
Will do.
> > + if (!netif_running(tp->dev))
> > + return -EAGAIN;
>
> Why? You do handle !netif_running() below...
Right. This isn't needed.
> > + switch (info->cmd) {
> > + case ETHTOOL_GRXRINGS:
> > + if (netif_running(tp->dev))
> > + info->data = tp->irq_cnt;
> > + else {
> > + info->data = num_online_cpus();
> > + if (info->data > TG3_IRQ_MAX_VECS_RSS)
> > + info->data = TG3_IRQ_MAX_VECS_RSS;
> > + }
> > +
> > + /* The first interrupt vector only
> > + * handles link interrupts.
> > + */
> > + info->data -= 1;
> > + return 0;
> > +
> > + default:
> > + return -EOPNOTSUPP;
> > + }
> > +}
> > +
> > +static int tg3_get_rxfh_indir(struct net_device *dev,
> > + struct ethtool_rxfh_indir *indir)
> > +{
> > + struct tg3 *tp = netdev_priv(dev);
> > + int i;
> > +
> > + if (!tg3_flag(tp, SUPPORT_MSIX))
> > + return -EINVAL;
>
> -EOPNOTSUPP
Will do.
> > + if (!indir->size) {
> > + indir->size = TG3_RSS_INDIR_TBL_SIZE;
> > + return 0;
> > + }
> > +
> > + if (indir->size != TG3_RSS_INDIR_TBL_SIZE)
> > + return -EINVAL;
>
> This is enough to make the ethtool command work, but you're really
> supposed to copy min(indir->size, TG3_RSS_INDIR_TBL_SIZE) entries.
Could you elaborate on this? I'm confused because I can't figure out
how returning half of an indirection table could be useful.
^ permalink raw reply
* Re: [PATCH v2] sctp: fix incorrect overflow check on autoclose
From: Vlad Yasevich @ 2011-12-15 21:07 UTC (permalink / raw)
To: Xi Wang
Cc: netdev, linux-sctp, Andrew Morton, Andrei Pelinescu-Onciul,
David S. Miller
In-Reply-To: <4EE919B5.3090901@gmail.com>
On 12/14/2011 04:48 PM, Xi Wang wrote:
> Commit 8ffd3208 voids the previous patches f6778aab and 810c0719 for
> limiting the maximum autoclose value. If userspace passes in -1 on
> 32-bit platform, the overflow check didn't work and autoclose would be
> set to 0xffffffff.
>
> This patch defines a max_autoclose for limiting the value and exposes
> it through sysctl.
>
> Suggested-by: Vlad Yasevich <vladislav.yasevich@hp.com>
> Signed-off-by: Xi Wang <xi.wang@gmail.com>
> ---
> include/net/sctp/structs.h | 4 ++++
> net/sctp/protocol.c | 3 +++
> net/sctp/socket.c | 4 ++--
> net/sctp/sysctl.c | 7 +++++++
> 4 files changed, 16 insertions(+), 2 deletions(-)
>
> diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
> index e90e7a9..781f16d 100644
> --- a/include/net/sctp/structs.h
> +++ b/include/net/sctp/structs.h
> @@ -241,6 +241,9 @@ extern struct sctp_globals {
> * bits is an indicator of when to send and window update SACK.
> */
> int rwnd_update_shift;
> +
> + /* Threshold for autoclose timeout. */
> + unsigned int max_autoclose;
> } sctp_globals;
>
> #define sctp_rto_initial (sctp_globals.rto_initial)
> @@ -281,6 +284,7 @@ extern struct sctp_globals {
> #define sctp_auth_enable (sctp_globals.auth_enable)
> #define sctp_checksum_disable (sctp_globals.checksum_disable)
> #define sctp_rwnd_upd_shift (sctp_globals.rwnd_update_shift)
> +#define sctp_max_autoclose (sctp_globals.max_autoclose)
>
> /* SCTP Socket type: UDP or TCP style. */
> typedef enum {
> diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
> index 61b9fca..4e07b18 100644
> --- a/net/sctp/protocol.c
> +++ b/net/sctp/protocol.c
> @@ -1285,6 +1285,9 @@ SCTP_STATIC __init int sctp_init(void)
> sctp_max_instreams = SCTP_DEFAULT_INSTREAMS;
> sctp_max_outstreams = SCTP_DEFAULT_OUTSTREAMS;
>
> + /* Initialize maximum autoclose timeout. */
> + sctp_max_autoclose = INT_MAX;
> +
> /* Initialize handle used for association ids. */
> idr_init(&sctp_assocs_id);
>
> diff --git a/net/sctp/socket.c b/net/sctp/socket.c
> index 13bf5fc..f8c8e66 100644
> --- a/net/sctp/socket.c
> +++ b/net/sctp/socket.c
> @@ -2200,8 +2200,8 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval,
> return -EINVAL;
> if (copy_from_user(&sp->autoclose, optval, optlen))
> return -EFAULT;
> - /* make sure it won't exceed MAX_SCHEDULE_TIMEOUT */
> - sp->autoclose = min_t(long, sp->autoclose, MAX_SCHEDULE_TIMEOUT / HZ);
> + /* make sure it won't exceed sctp_max_autoclose / HZ */
> + sp->autoclose = min(sp->autoclose, sctp_max_autoclose / HZ);
>
> return 0;
> }
> diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
> index 6b39529..b74686e 100644
> --- a/net/sctp/sysctl.c
> +++ b/net/sctp/sysctl.c
> @@ -258,6 +258,13 @@ static ctl_table sctp_table[] = {
> .extra1 = &one,
> .extra2 = &rwnd_scale_max,
> },
> + {
> + .procname = "max_autoclose",
> + .data = &sctp_max_autoclose,
> + .maxlen = sizeof(unsigned int),
> + .mode = 0644,
> + .proc_handler = &proc_dointvec_jiffies,
> + },
>
I think it would be better to keep this value in seconds and get rid
of division in the setsockopt code. We could then have a min and max
values where max value could be something like 2 days. I really don't
see an autoclose value that is bigger then that being very useful. In
fact, most of the time these values are very small as one wants to close
out idle associations.
-vlad
> { /* sentinel */ }
> };
^ permalink raw reply
* Re: [PATCH 2/2] Explicitly call tcp creation and init from memcontrol.c
From: Glauber Costa @ 2011-12-15 21:11 UTC (permalink / raw)
To: David Miller
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA, cgroups-u79uwXL29TY76Z2rM5mHXA,
kamezawa.hiroyu-+CUm20s59erQFUHtdCDX3A,
eric.dumazet-Re5JQEeQqe8AvxtiuMwx3w, sfr-3FnU+UHB4dNDw9hX6IcOSA
In-Reply-To: <20111215.120028.532844419499092747.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 1344 bytes --]
On 12/15/2011 09:00 PM, David Miller wrote:
> From: Glauber Costa<glommer-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
> Date: Thu, 15 Dec 2011 13:34:32 +0400
>
>> Walking the proto_list holds a read_lock, which prevents us from doing
>> allocations. Splitting the tcp create function into create + init is
>> good, but it is not enough since create_files will do allocations as well
>> (dentry ones, mostly).
>>
>> Since this does not involve any protocol state, I propose we call the tcp
>> functions explicitly from memcontrol.c
>>
>> With this, we lose by now the ability of doing cgroup memcontrol for
>> protocols that are loaded as modules. But at least the ones I have in mind
>> won't really need it (tcp_ipv6 being the only one, but it uses the same data
>> structures as tcp_ipv4). So I believe this to be the simpler solution to this
>> problem.
>>
>> Signed-off-by: Glauber Costa<glommer-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
>
> This is an unnecessary limitation, please fix this properly otherwise
> DCCP, SCTP, etc. won't be supportable with this stuff.
How about the following patch then ? I am keeping protocols that has the
cgroup stuff on in a separate list, that can be protected by a mutex.
Therefore we can allocate without going into troubles.
Let me know if you still have objections, I'll be happy to address them.
[-- Attachment #2: 0001-fix-sleeping-while-atomic-problem-in-sock-mem_cgroup.patch --]
[-- Type: text/plain, Size: 6504 bytes --]
>From c8fe669a9cbc7c7cbd87ce48d7eb91ed6c96cbde Mon Sep 17 00:00:00 2001
From: Glauber Costa <glommer-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
Date: Thu, 15 Dec 2011 23:47:06 +0300
Subject: [PATCH] fix sleeping while atomic problem in sock mem_cgroup.
Since we can't scan the proto_list to initialize sock cgroups, as it
holds a rwlock, and we also want to keep the code generic enough to
avoid calling the initialization functions of protocols directly,
I propose we keep the interested parties in a separate list. This list
is protected by a mutex so we can sleep and do the necessary allocations.
Signed-off-by: Glauber Costa <glommer-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
CC: Hiroyouki Kamezawa <kamezawa.hiroyu-+CUm20s59erQFUHtdCDX3A@public.gmane.org>
CC: David S. Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
CC: Eric Dumazet <eric.dumazet-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
CC: Stephen Rothwell <sfr-3FnU+UHB4dNDw9hX6IcOSA@public.gmane.org>
---
include/linux/memcontrol.h | 4 +++
include/net/sock.h | 5 +---
include/net/tcp_memcontrol.h | 2 +
mm/memcontrol.c | 52 ++++++++++++++++++++++++++++++++++++++++++
net/core/sock.c | 48 +++++++++-----------------------------
5 files changed, 70 insertions(+), 41 deletions(-)
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 9b296ea..1edd0e3 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -390,6 +390,10 @@ enum {
OVER_LIMIT,
};
+struct proto;
+void register_sock_cgroup(struct proto *prot);
+void unregister_sock_cgroup(struct proto *prot);
+
#ifdef CONFIG_INET
struct sock;
#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM
diff --git a/include/net/sock.h b/include/net/sock.h
index 6fe0dae..f8237a3 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -64,10 +64,6 @@
#include <net/dst.h>
#include <net/checksum.h>
-struct cgroup;
-struct cgroup_subsys;
-int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss);
-void mem_cgroup_sockets_destroy(struct cgroup *cgrp, struct cgroup_subsys *ss);
/*
* This structure really needs to be cleaned up.
* Most of it is for TCP, and not used by any of
@@ -858,6 +854,7 @@ struct proto {
void (*destroy_cgroup)(struct cgroup *cgrp,
struct cgroup_subsys *ss);
struct cg_proto *(*proto_cgroup)(struct mem_cgroup *memcg);
+ struct list_head cgroup_node;
#endif
};
diff --git a/include/net/tcp_memcontrol.h b/include/net/tcp_memcontrol.h
index 3512082..5aa7c4b 100644
--- a/include/net/tcp_memcontrol.h
+++ b/include/net/tcp_memcontrol.h
@@ -11,6 +11,8 @@ struct tcp_memcontrol {
int tcp_memory_pressure;
};
+struct cgroup;
+struct cgroup_subsys;
struct cg_proto *tcp_proto_cgroup(struct mem_cgroup *memcg);
int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss);
void tcp_destroy_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss);
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 7266202..6ee250d 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -4742,6 +4742,58 @@ static struct cftype kmem_cgroup_files[] = {
},
};
+static DEFINE_MUTEX(cgroup_proto_list_lock);
+static LIST_HEAD(cgroup_proto_list);
+
+static int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss)
+{
+ struct proto *proto;
+ int ret = 0;
+
+ mutex_lock(&cgroup_proto_list_lock);
+ list_for_each_entry(proto, &cgroup_proto_list, cgroup_node) {
+ if (proto->init_cgroup) {
+ ret = proto->init_cgroup(cgrp, ss);
+ if (ret)
+ goto out;
+ }
+ }
+
+ mutex_unlock(&cgroup_proto_list_lock);
+ return ret;
+out:
+ list_for_each_entry_continue_reverse(proto, &cgroup_proto_list, cgroup_node)
+ if (proto->destroy_cgroup)
+ proto->destroy_cgroup(cgrp, ss);
+ mutex_unlock(&cgroup_proto_list_lock);
+ return ret;
+}
+
+static void mem_cgroup_sockets_destroy(struct cgroup *cgrp, struct cgroup_subsys *ss)
+{
+ struct proto *proto;
+
+ mutex_lock(&cgroup_proto_list_lock);
+ list_for_each_entry_reverse(proto, &cgroup_proto_list, cgroup_node)
+ if (proto->destroy_cgroup)
+ proto->destroy_cgroup(cgrp, ss);
+ mutex_unlock(&cgroup_proto_list_lock);
+}
+
+void register_sock_cgroup(struct proto *prot)
+{
+ mutex_lock(&cgroup_proto_list_lock);
+ list_add(&prot->cgroup_node, &cgroup_proto_list);
+ mutex_unlock(&cgroup_proto_list_lock);
+}
+
+void unregister_sock_cgroup(struct proto *prot)
+{
+ mutex_lock(&cgroup_proto_list_lock);
+ list_del(&prot->cgroup_node);
+ mutex_unlock(&cgroup_proto_list_lock);
+}
+
static int register_kmem_files(struct cgroup *cont, struct cgroup_subsys *ss)
{
int ret = 0;
diff --git a/net/core/sock.c b/net/core/sock.c
index 5a6a906..3728b50 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -139,43 +139,6 @@
static DEFINE_RWLOCK(proto_list_lock);
static LIST_HEAD(proto_list);
-#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM
-int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss)
-{
- struct proto *proto;
- int ret = 0;
-
- read_lock(&proto_list_lock);
- list_for_each_entry(proto, &proto_list, node) {
- if (proto->init_cgroup) {
- ret = proto->init_cgroup(cgrp, ss);
- if (ret)
- goto out;
- }
- }
-
- read_unlock(&proto_list_lock);
- return ret;
-out:
- list_for_each_entry_continue_reverse(proto, &proto_list, node)
- if (proto->destroy_cgroup)
- proto->destroy_cgroup(cgrp, ss);
- read_unlock(&proto_list_lock);
- return ret;
-}
-
-void mem_cgroup_sockets_destroy(struct cgroup *cgrp, struct cgroup_subsys *ss)
-{
- struct proto *proto;
-
- read_lock(&proto_list_lock);
- list_for_each_entry_reverse(proto, &proto_list, node)
- if (proto->destroy_cgroup)
- proto->destroy_cgroup(cgrp, ss);
- read_unlock(&proto_list_lock);
-}
-#endif
-
/*
* Each address family might have different locking rules, so we have
* one slock key per address family:
@@ -2483,6 +2446,12 @@ int proto_register(struct proto *prot, int alloc_slab)
list_add(&prot->node, &proto_list);
assign_proto_idx(prot);
write_unlock(&proto_list_lock);
+
+#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM
+ if (prot->proto_cgroup)
+ register_sock_cgroup(prot);
+#endif
+
return 0;
out_free_timewait_sock_slab_name:
@@ -2510,6 +2479,11 @@ void proto_unregister(struct proto *prot)
list_del(&prot->node);
write_unlock(&proto_list_lock);
+#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM
+ if (prot->proto_cgroup != NULL)
+ unregister_sock_cgroup(prot);
+#endif
+
if (prot->slab != NULL) {
kmem_cache_destroy(prot->slab);
prot->slab = NULL;
--
1.7.6.4
^ permalink raw reply related
* Re: [PATCH net-next 6/6] tg3: Make the RSS indir tbl admin configurable
From: Ben Hutchings @ 2011-12-15 21:13 UTC (permalink / raw)
To: Matt Carlson; +Cc: davem@davemloft.net, netdev@vger.kernel.org, Michael Chan
In-Reply-To: <20111215210308.GA7025@mcarlson.broadcom.com>
On Thu, 2011-12-15 at 13:03 -0800, Matt Carlson wrote:
> On Wed, Dec 14, 2011 at 01:50:59PM -0800, Ben Hutchings wrote:
> > On Wed, 2011-12-14 at 13:10 -0800, Matt Carlson wrote:
[...]
> > > + if (!indir->size) {
> > > + indir->size = TG3_RSS_INDIR_TBL_SIZE;
> > > + return 0;
> > > + }
> > > +
> > > + if (indir->size != TG3_RSS_INDIR_TBL_SIZE)
> > > + return -EINVAL;
> >
> > This is enough to make the ethtool command work, but you're really
> > supposed to copy min(indir->size, TG3_RSS_INDIR_TBL_SIZE) entries.
>
> Could you elaborate on this? I'm confused because I can't figure out
> how returning half of an indirection table could be useful.
It's a generalisation of the zero-length and full-length cases. But no,
it isn't very useful, nor did I actually specify that anywhere!
Maybe there should be a driver operation to get the table size, and then
the core can make sure that drivers only ever deal with full-table
buffers. Though that wouldn't cover your reset-to-default case.
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: pull request: wireless 2011-12-15
From: John W. Linville @ 2011-12-15 21:38 UTC (permalink / raw)
To: Rafał Miłecki; +Cc: davem, linux-wireless, netdev, linux-kernel
In-Reply-To: <CACna6rw736JdkoM8zKxorCFd5oy08QTwWZ6PutoJPSr3ZN8hTg@mail.gmail.com>
On Thu, Dec 15, 2011 at 09:04:29PM +0100, Rafał Miłecki wrote:
> 2011/12/15 John W. Linville <linville@tuxdriver.com>:
> > commit 42a3b63bb2ca4996a3d1210a004eae2333f1119e
> >
> > Dave,
> >
> > Here are a few more fixes intended for the 3.2 release. They are
> > all small and narrowly focused.
>
> John, I've made a mistake and didn't use [PATCH 3.2] header to make it
> clean my patch is fix. Could you take a look at
> [PATCH] bcma: support for suspend and resume
> please?
>
> It's not one-liner, but fixes lock ups, which I believe - we really
> want to avoid.
It's late in the release cycle, and Dave specifically asked me to slow down.
Are these suspend/resume lockups a regression? Or have they always
been there? Do they happen to everyone?
John
--
John W. Linville Someday the world will need a hero, and you
linville@tuxdriver.com might be all we have. Be ready.
^ permalink raw reply
* [PATCH 3/3] net/hyperv: Add support for jumbo frame up to 64KB
From: Haiyang Zhang @ 2011-12-15 21:45 UTC (permalink / raw)
To: haiyangz, kys, davem, gregkh, linux-kernel, netdev, devel
In-Reply-To: <1323985517-1156-1-git-send-email-haiyangz@microsoft.com>
Allow the user set the MTU up to 65536 for Linux guests running on
Hyper-V 2008 R2 or later.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
---
drivers/net/hyperv/hyperv_net.h | 8 ++---
drivers/net/hyperv/netvsc.c | 6 ++--
drivers/net/hyperv/netvsc_drv.c | 70 ++++++++++++++++++++++++++++++++++-----
include/linux/hyperv.h | 2 +-
4 files changed, 68 insertions(+), 18 deletions(-)
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 2877670..dec5836 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -456,12 +456,9 @@ struct nvsp_message {
} __packed;
+#define NETVSC_MTU 65536
-
-/* #define NVSC_MIN_PROTOCOL_VERSION 1 */
-/* #define NVSC_MAX_PROTOCOL_VERSION 1 */
-
-#define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024) /* 1MB */
+#define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024*2) /* 2MB */
#define NETVSC_RECEIVE_BUFFER_ID 0xcafe
@@ -479,6 +476,7 @@ struct netvsc_device {
u32 nvsp_version;
atomic_t num_outstanding_sends;
+ bool start_remove;
bool destroy;
/*
* List of free preallocated hv_netvsc_packet to represent receive
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 46828b4..8965b45 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -42,7 +42,7 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device)
if (!net_device)
return NULL;
-
+ net_device->start_remove = false;
net_device->destroy = false;
net_device->dev = device;
net_device->ndev = ndev;
@@ -299,7 +299,7 @@ static int negotiate_nvsp_ver(struct hv_device *device,
/* NVSPv2 only: Send NDIS config */
memset(init_packet, 0, sizeof(struct nvsp_message));
init_packet->hdr.msg_type = NVSP_MSG2_TYPE_SEND_NDIS_CONFIG;
- init_packet->msg.v2_msg.send_ndis_config.mtu = ETH_DATA_LEN;
+ init_packet->msg.v2_msg.send_ndis_config.mtu = net_device->ndev->mtu;
ret = vmbus_sendpacket(device->channel, init_packet,
sizeof(struct nvsp_message),
@@ -464,7 +464,7 @@ static void netvsc_send_completion(struct hv_device *device,
atomic_dec(&net_device->num_outstanding_sends);
- if (netif_queue_stopped(ndev))
+ if (netif_queue_stopped(ndev) && !net_device->start_remove)
netif_wake_queue(ndev);
} else {
netdev_err(ndev, "Unknown send completion packet type- "
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index b7cbd12..462d05f 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -148,10 +148,12 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
struct net_device_context *net_device_ctx = netdev_priv(net);
struct hv_netvsc_packet *packet;
int ret;
- unsigned int i, num_pages;
+ unsigned int i, num_pages, npg_data;
- /* Add 1 for skb->data and additional one for RNDIS */
- num_pages = skb_shinfo(skb)->nr_frags + 1 + 1;
+ /* Add multipage for skb->data and additional one for RNDIS */
+ npg_data = (((unsigned long)skb->data + skb_headlen(skb) - 1)
+ >> PAGE_SHIFT) - ((unsigned long)skb->data >> PAGE_SHIFT) + 1;
+ num_pages = skb_shinfo(skb)->nr_frags + npg_data + 1;
/* Allocate a netvsc packet based on # of frags. */
packet = kzalloc(sizeof(struct hv_netvsc_packet) +
@@ -174,21 +176,36 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
packet->page_buf_cnt = num_pages;
/* Initialize it from the skb */
- packet->total_data_buflen = skb->len;
+ packet->total_data_buflen = skb->len;
/* Start filling in the page buffers starting after RNDIS buffer. */
packet->page_buf[1].pfn = virt_to_phys(skb->data) >> PAGE_SHIFT;
packet->page_buf[1].offset
= (unsigned long)skb->data & (PAGE_SIZE - 1);
- packet->page_buf[1].len = skb_headlen(skb);
+ if (npg_data == 1)
+ packet->page_buf[1].len = skb_headlen(skb);
+ else
+ packet->page_buf[1].len = PAGE_SIZE
+ - packet->page_buf[1].offset;
+
+ for (i = 2; i <= npg_data; i++) {
+ packet->page_buf[i].pfn = virt_to_phys(skb->data
+ + PAGE_SIZE * (i-1)) >> PAGE_SHIFT;
+ packet->page_buf[i].offset = 0;
+ packet->page_buf[i].len = PAGE_SIZE;
+ }
+ if (npg_data > 1)
+ packet->page_buf[npg_data].len = (((unsigned long)skb->data
+ + skb_headlen(skb) - 1) & (PAGE_SIZE - 1)) + 1;
/* Additional fragments are after SKB data */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
const skb_frag_t *f = &skb_shinfo(skb)->frags[i];
- packet->page_buf[i+2].pfn = page_to_pfn(skb_frag_page(f));
- packet->page_buf[i+2].offset = f->page_offset;
- packet->page_buf[i+2].len = skb_frag_size(f);
+ packet->page_buf[i+npg_data+1].pfn =
+ page_to_pfn(skb_frag_page(f));
+ packet->page_buf[i+npg_data+1].offset = f->page_offset;
+ packet->page_buf[i+npg_data+1].len = skb_frag_size(f);
}
/* Set the completion routine */
@@ -300,6 +317,39 @@ static void netvsc_get_drvinfo(struct net_device *net,
strcpy(info->fw_version, "N/A");
}
+static int netvsc_change_mtu(struct net_device *ndev, int mtu)
+{
+ struct net_device_context *ndevctx = netdev_priv(ndev);
+ struct hv_device *hdev = ndevctx->device_ctx;
+ struct netvsc_device *nvdev = hv_get_drvdata(hdev);
+ struct netvsc_device_info device_info;
+ int limit = ETH_DATA_LEN;
+
+ if (nvdev == NULL || nvdev->destroy)
+ return -ENODEV;
+
+ if (nvdev->nvsp_version == NVSP_PROTOCOL_VERSION_2)
+ limit = NETVSC_MTU;
+
+ if (mtu < 68 || mtu > limit)
+ return -EINVAL;
+
+ nvdev->start_remove = true;
+ cancel_delayed_work_sync(&ndevctx->dwork);
+ netif_stop_queue(ndev);
+ rndis_filter_device_remove(hdev);
+
+ ndev->mtu = mtu;
+
+ ndevctx->device_ctx = hdev;
+ hv_set_drvdata(hdev, ndev);
+ device_info.ring_size = ring_size;
+ rndis_filter_device_add(hdev, &device_info);
+ netif_wake_queue(ndev);
+
+ return 0;
+}
+
static const struct ethtool_ops ethtool_ops = {
.get_drvinfo = netvsc_get_drvinfo,
.get_link = ethtool_op_get_link,
@@ -310,7 +360,7 @@ static const struct net_device_ops device_ops = {
.ndo_stop = netvsc_close,
.ndo_start_xmit = netvsc_start_xmit,
.ndo_set_rx_mode = netvsc_set_multicast_list,
- .ndo_change_mtu = eth_change_mtu,
+ .ndo_change_mtu = netvsc_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
};
@@ -403,6 +453,8 @@ static int netvsc_remove(struct hv_device *dev)
return 0;
}
+ net_device->start_remove = true;
+
ndev_ctx = netdev_priv(net);
cancel_delayed_work_sync(&ndev_ctx->dwork);
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 12ec328..62b908e 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -35,7 +35,7 @@
#include <linux/mod_devicetable.h>
-#define MAX_PAGE_BUFFER_COUNT 16
+#define MAX_PAGE_BUFFER_COUNT 18
#define MAX_MULTIPAGE_BUFFER_COUNT 32 /* 128K */
#pragma pack(push, 1)
--
1.7.4.1
^ permalink raw reply related
* [PATCH 1/3] net/hyperv: Remove unnecessary kmap_atomic in netvsc driver
From: Haiyang Zhang @ 2011-12-15 21:45 UTC (permalink / raw)
To: haiyangz, kys, davem, gregkh, linux-kernel, netdev, devel
__get_free_pages() doesn't return HI memory, so the memory is always mapped.
kmap_atomic() is not necessary here. This patch removes the kmap_atomic()
calls and related code for locking and page manipulation.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
---
drivers/net/hyperv/hyperv_net.h | 6 +---
drivers/net/hyperv/netvsc.c | 53 +++----------------------------------
drivers/net/hyperv/netvsc_drv.c | 22 +--------------
drivers/net/hyperv/rndis_filter.c | 21 +-------------
4 files changed, 10 insertions(+), 92 deletions(-)
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 49b131f..ff1b520 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -39,9 +39,6 @@ struct xferpage_packet {
u32 count;
};
-/* The number of pages which are enough to cover jumbo frame buffer. */
-#define NETVSC_PACKET_MAXPAGE 4
-
/*
* Represent netvsc packet which contains 1 RNDIS and 1 ethernet frame
* within the RNDIS
@@ -77,8 +74,9 @@ struct hv_netvsc_packet {
u32 total_data_buflen;
/* Points to the send/receive buffer where the ethernet frame is */
+ void *data;
u32 page_buf_cnt;
- struct hv_page_buffer page_buf[NETVSC_PACKET_MAXPAGE];
+ struct hv_page_buffer page_buf[0];
};
struct netvsc_device_info {
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index b6ac152..bab627f 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -603,12 +603,10 @@ static void netvsc_receive(struct hv_device *device,
struct vmtransfer_page_packet_header *vmxferpage_packet;
struct nvsp_message *nvsp_packet;
struct hv_netvsc_packet *netvsc_packet = NULL;
- unsigned long start;
- unsigned long end, end_virtual;
/* struct netvsc_driver *netvscDriver; */
struct xferpage_packet *xferpage_packet = NULL;
- int i, j;
- int count = 0, bytes_remain = 0;
+ int i;
+ int count = 0;
unsigned long flags;
struct net_device *ndev;
@@ -717,53 +715,10 @@ static void netvsc_receive(struct hv_device *device,
netvsc_packet->completion.recv.recv_completion_tid =
vmxferpage_packet->d.trans_id;
+ netvsc_packet->data = (void *)((unsigned long)net_device->
+ recv_buf + vmxferpage_packet->ranges[i].byte_offset);
netvsc_packet->total_data_buflen =
vmxferpage_packet->ranges[i].byte_count;
- netvsc_packet->page_buf_cnt = 1;
-
- netvsc_packet->page_buf[0].len =
- vmxferpage_packet->ranges[i].byte_count;
-
- start = virt_to_phys((void *)((unsigned long)net_device->
- recv_buf + vmxferpage_packet->ranges[i].byte_offset));
-
- netvsc_packet->page_buf[0].pfn = start >> PAGE_SHIFT;
- end_virtual = (unsigned long)net_device->recv_buf
- + vmxferpage_packet->ranges[i].byte_offset
- + vmxferpage_packet->ranges[i].byte_count - 1;
- end = virt_to_phys((void *)end_virtual);
-
- /* Calculate the page relative offset */
- netvsc_packet->page_buf[0].offset =
- vmxferpage_packet->ranges[i].byte_offset &
- (PAGE_SIZE - 1);
- if ((end >> PAGE_SHIFT) != (start >> PAGE_SHIFT)) {
- /* Handle frame across multiple pages: */
- netvsc_packet->page_buf[0].len =
- (netvsc_packet->page_buf[0].pfn <<
- PAGE_SHIFT)
- + PAGE_SIZE - start;
- bytes_remain = netvsc_packet->total_data_buflen -
- netvsc_packet->page_buf[0].len;
- for (j = 1; j < NETVSC_PACKET_MAXPAGE; j++) {
- netvsc_packet->page_buf[j].offset = 0;
- if (bytes_remain <= PAGE_SIZE) {
- netvsc_packet->page_buf[j].len =
- bytes_remain;
- bytes_remain = 0;
- } else {
- netvsc_packet->page_buf[j].len =
- PAGE_SIZE;
- bytes_remain -= PAGE_SIZE;
- }
- netvsc_packet->page_buf[j].pfn =
- virt_to_phys((void *)(end_virtual -
- bytes_remain)) >> PAGE_SHIFT;
- netvsc_packet->page_buf_cnt++;
- if (bytes_remain == 0)
- break;
- }
- }
/* Pass it to the upper layer */
rndis_filter_receive(device, netvsc_packet);
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 7da85eb..b7cbd12 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -251,9 +251,6 @@ int netvsc_recv_callback(struct hv_device *device_obj,
{
struct net_device *net = dev_get_drvdata(&device_obj->device);
struct sk_buff *skb;
- void *data;
- int i;
- unsigned long flags;
struct netvsc_device *net_device;
net_device = hv_get_drvdata(device_obj);
@@ -272,27 +269,12 @@ int netvsc_recv_callback(struct hv_device *device_obj,
return 0;
}
- /* for kmap_atomic */
- local_irq_save(flags);
-
/*
* Copy to skb. This copy is needed here since the memory pointed by
* hv_netvsc_packet cannot be deallocated
*/
- for (i = 0; i < packet->page_buf_cnt; i++) {
- data = kmap_atomic(pfn_to_page(packet->page_buf[i].pfn),
- KM_IRQ1);
- data = (void *)(unsigned long)data +
- packet->page_buf[i].offset;
-
- memcpy(skb_put(skb, packet->page_buf[i].len), data,
- packet->page_buf[i].len);
-
- kunmap_atomic((void *)((unsigned long)data -
- packet->page_buf[i].offset), KM_IRQ1);
- }
-
- local_irq_restore(flags);
+ memcpy(skb_put(skb, packet->total_data_buflen), packet->data,
+ packet->total_data_buflen);
skb->protocol = eth_type_trans(skb, net);
skb->ip_summed = CHECKSUM_NONE;
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index 418e7aa..da181f9 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -309,7 +309,6 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
{
struct rndis_packet *rndis_pkt;
u32 data_offset;
- int i;
rndis_pkt = &msg->msg.pkt;
@@ -322,17 +321,7 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
pkt->total_data_buflen -= data_offset;
- pkt->page_buf[0].offset += data_offset;
- pkt->page_buf[0].len -= data_offset;
-
- /* Drop the 0th page, if rndis data go beyond page boundary */
- if (pkt->page_buf[0].offset >= PAGE_SIZE) {
- pkt->page_buf[1].offset = pkt->page_buf[0].offset - PAGE_SIZE;
- pkt->page_buf[1].len -= pkt->page_buf[1].offset;
- pkt->page_buf_cnt--;
- for (i = 0; i < pkt->page_buf_cnt; i++)
- pkt->page_buf[i] = pkt->page_buf[i+1];
- }
+ pkt->data = (void *)((unsigned long)pkt->data + data_offset);
pkt->is_data_pkt = true;
@@ -367,11 +356,7 @@ int rndis_filter_receive(struct hv_device *dev,
return -ENODEV;
}
- rndis_hdr = (struct rndis_message *)kmap_atomic(
- pfn_to_page(pkt->page_buf[0].pfn), KM_IRQ0);
-
- rndis_hdr = (void *)((unsigned long)rndis_hdr +
- pkt->page_buf[0].offset);
+ rndis_hdr = pkt->data;
/* Make sure we got a valid rndis message */
if ((rndis_hdr->ndis_msg_type != REMOTE_NDIS_PACKET_MSG) &&
@@ -387,8 +372,6 @@ int rndis_filter_receive(struct hv_device *dev,
sizeof(struct rndis_message) :
rndis_hdr->msg_len);
- kunmap_atomic(rndis_hdr - pkt->page_buf[0].offset, KM_IRQ0);
-
dump_rndis_message(dev, &rndis_msg);
switch (rndis_msg.ndis_msg_type) {
--
1.7.4.1
^ permalink raw reply related
* [PATCH 2/3] net/hyperv: Add NETVSP protocol version negotiation
From: Haiyang Zhang @ 2011-12-15 21:45 UTC (permalink / raw)
To: haiyangz, kys, davem, gregkh, linux-kernel, netdev, devel
In-Reply-To: <1323985517-1156-1-git-send-email-haiyangz@microsoft.com>
Automatically negotiate the highest protocol version mutually recognized by
both host and guest.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
---
drivers/net/hyperv/hyperv_net.h | 101 ++++++++++++++++++++++++++++++++++++---
drivers/net/hyperv/netvsc.c | 82 +++++++++++++++++++++----------
2 files changed, 149 insertions(+), 34 deletions(-)
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index ff1b520..2877670 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -134,8 +134,7 @@ int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter);
#define NVSP_INVALID_PROTOCOL_VERSION ((u32)0xFFFFFFFF)
#define NVSP_PROTOCOL_VERSION_1 2
-#define NVSP_MIN_PROTOCOL_VERSION NVSP_PROTOCOL_VERSION_1
-#define NVSP_MAX_PROTOCOL_VERSION NVSP_PROTOCOL_VERSION_1
+#define NVSP_PROTOCOL_VERSION_2 0x30002
enum {
NVSP_MSG_TYPE_NONE = 0,
@@ -160,11 +159,36 @@ enum {
NVSP_MSG1_TYPE_SEND_RNDIS_PKT,
NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE,
- /*
- * This should be set to the number of messages for the version with
- * the maximum number of messages.
- */
- NVSP_NUM_MSG_PER_VERSION = 9,
+ /* Version 2 messages */
+ NVSP_MSG2_TYPE_SEND_CHIMNEY_DELEGATED_BUF,
+ NVSP_MSG2_TYPE_SEND_CHIMNEY_DELEGATED_BUF_COMP,
+ NVSP_MSG2_TYPE_REVOKE_CHIMNEY_DELEGATED_BUF,
+
+ NVSP_MSG2_TYPE_RESUME_CHIMNEY_RX_INDICATION,
+
+ NVSP_MSG2_TYPE_TERMINATE_CHIMNEY,
+ NVSP_MSG2_TYPE_TERMINATE_CHIMNEY_COMP,
+
+ NVSP_MSG2_TYPE_INDICATE_CHIMNEY_EVENT,
+
+ NVSP_MSG2_TYPE_SEND_CHIMNEY_PKT,
+ NVSP_MSG2_TYPE_SEND_CHIMNEY_PKT_COMP,
+
+ NVSP_MSG2_TYPE_POST_CHIMNEY_RECV_REQ,
+ NVSP_MSG2_TYPE_POST_CHIMNEY_RECV_REQ_COMP,
+
+ NVSP_MSG2_TYPE_ALLOC_RXBUF,
+ NVSP_MSG2_TYPE_ALLOC_RXBUF_COMP,
+
+ NVSP_MSG2_TYPE_FREE_RXBUF,
+
+ NVSP_MSG2_TYPE_SEND_VMQ_RNDIS_PKT,
+ NVSP_MSG2_TYPE_SEND_VMQ_RNDIS_PKT_COMP,
+
+ NVSP_MSG2_TYPE_SEND_NDIS_CONFIG,
+
+ NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE,
+ NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE_COMP,
};
enum {
@@ -175,6 +199,7 @@ enum {
NVSP_STAT_PROTOCOL_TOO_OLD,
NVSP_STAT_INVALID_RNDIS_PKT,
NVSP_STAT_BUSY,
+ NVSP_STAT_PROTOCOL_UNSUPPORTED,
NVSP_STAT_MAX,
};
@@ -359,9 +384,69 @@ union nvsp_1_message_uber {
send_rndis_pkt_complete;
} __packed;
+
+/*
+ * Network VSP protocol version 2 messages:
+ */
+struct nvsp_2_vsc_capability {
+ union {
+ u64 data;
+ struct {
+ u64 vmq:1;
+ u64 chimney:1;
+ u64 sriov:1;
+ u64 ieee8021q:1;
+ u64 correlation_id:1;
+ };
+ };
+} __packed;
+
+struct nvsp_2_send_ndis_config {
+ u32 mtu;
+ u32 reserved;
+ struct nvsp_2_vsc_capability capability;
+} __packed;
+
+/* Allocate receive buffer */
+struct nvsp_2_alloc_rxbuf {
+ /* Allocation ID to match the allocation request and response */
+ u32 alloc_id;
+
+ /* Length of the VM shared memory receive buffer that needs to
+ * be allocated
+ */
+ u32 len;
+} __packed;
+
+/* Allocate receive buffer complete */
+struct nvsp_2_alloc_rxbuf_comp {
+ /* The NDIS_STATUS code for buffer allocation */
+ u32 status;
+
+ u32 alloc_id;
+
+ /* GPADL handle for the allocated receive buffer */
+ u32 gpadl_handle;
+
+ /* Receive buffer ID */
+ u64 recv_buf_id;
+} __packed;
+
+struct nvsp_2_free_rxbuf {
+ u64 recv_buf_id;
+} __packed;
+
+union nvsp_2_message_uber {
+ struct nvsp_2_send_ndis_config send_ndis_config;
+ struct nvsp_2_alloc_rxbuf alloc_rxbuf;
+ struct nvsp_2_alloc_rxbuf_comp alloc_rxbuf_comp;
+ struct nvsp_2_free_rxbuf free_rxbuf;
+} __packed;
+
union nvsp_all_messages {
union nvsp_message_init_uber init_msg;
union nvsp_1_message_uber v1_msg;
+ union nvsp_2_message_uber v2_msg;
} __packed;
/* ALL Messages */
@@ -391,6 +476,8 @@ struct nvsp_message {
struct netvsc_device {
struct hv_device *dev;
+ u32 nvsp_version;
+
atomic_t num_outstanding_sends;
bool destroy;
/*
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index bab627f..46828b4 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -28,6 +28,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
+#include <linux/if_ether.h>
#include "hyperv_net.h"
@@ -260,27 +261,18 @@ exit:
}
-static int netvsc_connect_vsp(struct hv_device *device)
+/* Negotiate NVSP protocol version */
+static int negotiate_nvsp_ver(struct hv_device *device,
+ struct netvsc_device *net_device,
+ struct nvsp_message *init_packet,
+ u32 nvsp_ver)
{
int ret, t;
- struct netvsc_device *net_device;
- struct nvsp_message *init_packet;
- int ndis_version;
- struct net_device *ndev;
-
- net_device = get_outbound_net_device(device);
- if (!net_device)
- return -ENODEV;
- ndev = net_device->ndev;
-
- init_packet = &net_device->channel_init_pkt;
memset(init_packet, 0, sizeof(struct nvsp_message));
init_packet->hdr.msg_type = NVSP_MSG_TYPE_INIT;
- init_packet->msg.init_msg.init.min_protocol_ver =
- NVSP_MIN_PROTOCOL_VERSION;
- init_packet->msg.init_msg.init.max_protocol_ver =
- NVSP_MAX_PROTOCOL_VERSION;
+ init_packet->msg.init_msg.init.min_protocol_ver = nvsp_ver;
+ init_packet->msg.init_msg.init.max_protocol_ver = nvsp_ver;
/* Send the init request */
ret = vmbus_sendpacket(device->channel, init_packet,
@@ -290,26 +282,62 @@ static int netvsc_connect_vsp(struct hv_device *device)
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0)
- goto cleanup;
+ return ret;
t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
+ if (t == 0)
+ return -ETIMEDOUT;
if (init_packet->msg.init_msg.init_complete.status !=
- NVSP_STAT_SUCCESS) {
- ret = -EINVAL;
- goto cleanup;
- }
+ NVSP_STAT_SUCCESS)
+ return -EINVAL;
- if (init_packet->msg.init_msg.init_complete.
- negotiated_protocol_ver != NVSP_PROTOCOL_VERSION_1) {
+ if (nvsp_ver != NVSP_PROTOCOL_VERSION_2)
+ return 0;
+
+ /* NVSPv2 only: Send NDIS config */
+ memset(init_packet, 0, sizeof(struct nvsp_message));
+ init_packet->hdr.msg_type = NVSP_MSG2_TYPE_SEND_NDIS_CONFIG;
+ init_packet->msg.v2_msg.send_ndis_config.mtu = ETH_DATA_LEN;
+
+ ret = vmbus_sendpacket(device->channel, init_packet,
+ sizeof(struct nvsp_message),
+ (unsigned long)init_packet,
+ VM_PKT_DATA_INBAND, 0);
+
+ return ret;
+}
+
+static int netvsc_connect_vsp(struct hv_device *device)
+{
+ int ret;
+ struct netvsc_device *net_device;
+ struct nvsp_message *init_packet;
+ int ndis_version;
+ struct net_device *ndev;
+
+ net_device = get_outbound_net_device(device);
+ if (!net_device)
+ return -ENODEV;
+ ndev = net_device->ndev;
+
+ init_packet = &net_device->channel_init_pkt;
+
+ /* Negotiate the latest NVSP protocol supported */
+ if (negotiate_nvsp_ver(device, net_device, init_packet,
+ NVSP_PROTOCOL_VERSION_2) == 0) {
+ net_device->nvsp_version = NVSP_PROTOCOL_VERSION_2;
+ } else if (negotiate_nvsp_ver(device, net_device, init_packet,
+ NVSP_PROTOCOL_VERSION_1) == 0) {
+ net_device->nvsp_version = NVSP_PROTOCOL_VERSION_1;
+ } else {
ret = -EPROTO;
goto cleanup;
}
+
+ pr_debug("Negotiated NVSP version:%x\n", net_device->nvsp_version);
+
/* Send the ndis version */
memset(init_packet, 0, sizeof(struct nvsp_message));
--
1.7.4.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox