* Re: [PATCH 31/40] trace syscalls: Convert various generic compat syscalls
From: Andi Kleen @ 2010-06-23 10:19 UTC (permalink / raw)
To: Ian Munsie
Cc: linux-kernel, linuxppc-dev, Jason Baron, Frederic Weisbecker,
Steven Rostedt, Ingo Molnar, Benjamin Herrenschmidt,
Paul Mackerras, Michael Ellerman, Alexander Viro, Andrew Morton,
Jeff Moyer, David Howells, Oleg Nesterov, Arnd Bergmann,
David S. Miller, Greg Kroah-Hartman, Dinakar Guniguntala,
Thomas Gleixner, Ingo Molnar, Eric Biederman, Simon Kagstrom,
WANG Cong, Sam Ravnborg
In-Reply-To: <1277287401-28571-32-git-send-email-imunsie@au1.ibm.com>
, Ian Munsie wrote:
> From: Ian Munsie<imunsie@au1.ibm.com>
>
> This patch converts numerous trivial compat syscalls through the generic
> kernel code to use the COMPAT_SYSCALL_DEFINE family of macros.
Why? This just makes the code look uglier and the functions harder
to grep for.
-Andi
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* RE: [RFC PATCH v7 01/19] Add a new structure for skb buffer from external.
From: Dong, Eddie @ 2010-06-23 10:05 UTC (permalink / raw)
To: Herbert Xu
Cc: Xin, Xiaohui, Stephen Hemminger, netdev@vger.kernel.org,
kvm@vger.kernel.org, linux-kernel@vger.kernel.org, mst@redhat.com,
mingo@elte.hu, davem@davemloft.net, jdike@linux.intel.com,
Dong, Eddie
In-Reply-To: <20100623095254.GA32491@gondor.apana.org.au>
Herbert Xu wrote:
> On Wed, Jun 23, 2010 at 04:09:40PM +0800, Dong, Eddie wrote:
>>
>> Xiaohui & Herbert:
>> Mixing copy of head & 0-copy of bulk data imposes additional
>> challange to find the guest buffer. The backend driver may be
>> unable to find a spare guest buffer from virtqueue at that time
>> which may block the receiving process then. Can't we completely
>> eliminate netdev_alloc_skb here? Assigning guest buffer at this time
>> makes life much easier.
>
> I'm not sure I understand you concern. If you mean that when
> the guest doesn't give enough pages to the host and the host
> can't receive on behalf of the guest then isn't that already
> the case with the original patch-set?
>
I mean once the frontend side driver post the buffers to the backend driver, the backend driver will "immediately" use that buffers to compose skb or gro_frags and post them to the assigned host NIC driver as receive buffers. In that case, if the backend driver recieves a packet from the NIC that requires to do copy, it may be unable to find additional free guest buffer because all of them are already used by the NIC driver. We have to reserve some guest buffers for the possible copy even if the buffer address is not identified by original skb :(
Thx, Eddie
^ permalink raw reply
* [PATCH 31/40] trace syscalls: Convert various generic compat syscalls
From: Ian Munsie @ 2010-06-23 10:03 UTC (permalink / raw)
To: linux-kernel, linuxppc-dev
Cc: Jason Baron, Frederic Weisbecker, Steven Rostedt, Ingo Molnar,
Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
Ian Munsie, Alexander Viro, Andrew Morton, Jeff Moyer,
David Howells, Oleg Nesterov, Arnd Bergmann, David S. Miller,
Greg Kroah-Hartman, Dinakar Guniguntala, Thomas Gleixner,
Ingo Molnar, Eric Biederman, Simon Kagstrom <simon.kags
In-Reply-To: <1277287401-28571-1-git-send-email-imunsie@au1.ibm.com>
From: Ian Munsie <imunsie@au1.ibm.com>
This patch converts numerous trivial compat syscalls through the generic
kernel code to use the COMPAT_SYSCALL_DEFINE family of macros.
Signed-off-by: Ian Munsie <imunsie@au1.ibm.com>
---
fs/compat.c | 2 +-
fs/compat_ioctl.c | 4 ++--
ipc/compat_mq.c | 24 ++++++++++++------------
kernel/futex_compat.c | 19 ++++++++++---------
kernel/kexec.c | 8 ++++----
kernel/ptrace.c | 4 ++--
kernel/sysctl_binary.c | 2 +-
mm/mempolicy.c | 19 ++++++++++---------
net/compat.c | 28 ++++++++++++++--------------
9 files changed, 56 insertions(+), 54 deletions(-)
diff --git a/fs/compat.c b/fs/compat.c
index df0b502..9897b7b 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1823,7 +1823,7 @@ struct compat_sel_arg_struct {
compat_uptr_t tvp;
};
-asmlinkage long compat_sys_old_select(struct compat_sel_arg_struct __user *arg)
+COMPAT_SYSCALL_DEFINE1(old_select, struct compat_sel_arg_struct __user *, arg)
{
struct compat_sel_arg_struct a;
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 641640d..60d7e91 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -1674,8 +1674,8 @@ static int compat_ioctl_check_table(unsigned int xcmd)
return ioctl_pointer[i] == xcmd;
}
-asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
- unsigned long arg)
+COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
+ unsigned long, arg)
{
struct file *filp;
int error = -EBADF;
diff --git a/ipc/compat_mq.c b/ipc/compat_mq.c
index d8d1e9f..53593d3 100644
--- a/ipc/compat_mq.c
+++ b/ipc/compat_mq.c
@@ -46,9 +46,9 @@ static inline int put_compat_mq_attr(const struct mq_attr *attr,
| __put_user(attr->mq_curmsgs, &uattr->mq_curmsgs);
}
-asmlinkage long compat_sys_mq_open(const char __user *u_name,
- int oflag, compat_mode_t mode,
- struct compat_mq_attr __user *u_attr)
+COMPAT_SYSCALL_DEFINE4(mq_open, const char __user *, u_name,
+ int, oflag, compat_mode_t, mode,
+ struct compat_mq_attr __user *, u_attr)
{
void __user *p = NULL;
if (u_attr && oflag & O_CREAT) {
@@ -75,10 +75,10 @@ static int compat_prepare_timeout(struct timespec __user * *p,
return 0;
}
-asmlinkage long compat_sys_mq_timedsend(mqd_t mqdes,
- const char __user *u_msg_ptr,
- size_t msg_len, unsigned int msg_prio,
- const struct compat_timespec __user *u_abs_timeout)
+COMPAT_SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes,
+ const char __user *, u_msg_ptr,
+ size_t, msg_len, unsigned int, msg_prio,
+ const struct compat_timespec __user *, u_abs_timeout)
{
struct timespec __user *u_ts;
@@ -102,8 +102,8 @@ asmlinkage ssize_t compat_sys_mq_timedreceive(mqd_t mqdes,
u_msg_prio, u_ts);
}
-asmlinkage long compat_sys_mq_notify(mqd_t mqdes,
- const struct compat_sigevent __user *u_notification)
+COMPAT_SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
+ const struct compat_sigevent __user *, u_notification)
{
struct sigevent __user *p = NULL;
if (u_notification) {
@@ -119,9 +119,9 @@ asmlinkage long compat_sys_mq_notify(mqd_t mqdes,
return sys_mq_notify(mqdes, p);
}
-asmlinkage long compat_sys_mq_getsetattr(mqd_t mqdes,
- const struct compat_mq_attr __user *u_mqstat,
- struct compat_mq_attr __user *u_omqstat)
+COMPAT_SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
+ const struct compat_mq_attr __user *, u_mqstat,
+ struct compat_mq_attr __user *, u_omqstat)
{
struct mq_attr mqstat;
struct mq_attr __user *p = compat_alloc_user_space(2 * sizeof(*p));
diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c
index d49afb2..d798c9f 100644
--- a/kernel/futex_compat.c
+++ b/kernel/futex_compat.c
@@ -10,6 +10,7 @@
#include <linux/compat.h>
#include <linux/nsproxy.h>
#include <linux/futex.h>
+#include <linux/syscalls.h>
#include <asm/uaccess.h>
@@ -114,9 +115,9 @@ void compat_exit_robust_list(struct task_struct *curr)
}
}
-asmlinkage long
-compat_sys_set_robust_list(struct compat_robust_list_head __user *head,
- compat_size_t len)
+COMPAT_SYSCALL_DEFINE2(set_robust_list,
+ struct compat_robust_list_head __user *, head,
+ compat_size_t, len)
{
if (!futex_cmpxchg_enabled)
return -ENOSYS;
@@ -129,9 +130,9 @@ compat_sys_set_robust_list(struct compat_robust_list_head __user *head,
return 0;
}
-asmlinkage long
-compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr,
- compat_size_t __user *len_ptr)
+COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid,
+ compat_uptr_t __user *, head_ptr,
+ compat_size_t __user *, len_ptr)
{
struct compat_robust_list_head __user *head;
unsigned long ret;
@@ -170,9 +171,9 @@ err_unlock:
return ret;
}
-asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val,
- struct compat_timespec __user *utime, u32 __user *uaddr2,
- u32 val3)
+COMPAT_SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
+ struct compat_timespec __user *, utime, u32 __user *, uaddr2,
+ u32, val3)
{
struct timespec ts;
ktime_t t, *tp = NULL;
diff --git a/kernel/kexec.c b/kernel/kexec.c
index 474a847..0b261ed 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -1024,10 +1024,10 @@ out:
}
#ifdef CONFIG_COMPAT
-asmlinkage long compat_sys_kexec_load(unsigned long entry,
- unsigned long nr_segments,
- struct compat_kexec_segment __user *segments,
- unsigned long flags)
+COMPAT_SYSCALL_DEFINE4(kexec_load, unsigned long, entry,
+ unsigned long, nr_segments,
+ struct compat_kexec_segment __user *, segments,
+ unsigned long, flags)
{
struct compat_kexec_segment in;
struct kexec_segment out, __user *ksegments;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 74a3d69..0d91d7f 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -826,8 +826,8 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
return ret;
}
-asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
- compat_long_t addr, compat_long_t data)
+COMPAT_SYSCALL_DEFINE4(ptrace, compat_long_t, request, compat_long_t, pid,
+ compat_long_t, addr, compat_long_t, data)
{
struct task_struct *child;
long ret;
diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
index 1357c57..fb061c7 100644
--- a/kernel/sysctl_binary.c
+++ b/kernel/sysctl_binary.c
@@ -1502,7 +1502,7 @@ struct compat_sysctl_args {
compat_ulong_t __unused[4];
};
-asmlinkage long compat_sys_sysctl(struct compat_sysctl_args __user *args)
+COMPAT_SYSCALL_DEFINE1(sysctl, struct compat_sysctl_args __user *, args)
{
struct compat_sysctl_args tmp;
compat_size_t __user *compat_oldlenp;
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 5d6fb33..b9fbceb 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -1372,10 +1372,10 @@ SYSCALL_DEFINE5(get_mempolicy, int __user *, policy,
#ifdef CONFIG_COMPAT
-asmlinkage long compat_sys_get_mempolicy(int __user *policy,
- compat_ulong_t __user *nmask,
- compat_ulong_t maxnode,
- compat_ulong_t addr, compat_ulong_t flags)
+COMPAT_SYSCALL_DEFINE5(get_mempolicy, int __user *, policy,
+ compat_ulong_t __user *, nmask,
+ compat_ulong_t, maxnode,
+ compat_ulong_t, addr, compat_ulong_t, flags)
{
long err;
unsigned long __user *nm = NULL;
@@ -1400,8 +1400,9 @@ asmlinkage long compat_sys_get_mempolicy(int __user *policy,
return err;
}
-asmlinkage long compat_sys_set_mempolicy(int mode, compat_ulong_t __user *nmask,
- compat_ulong_t maxnode)
+COMPAT_SYSCALL_DEFINE3(set_mempolicy, int, mode,
+ compat_ulong_t __user *, nmask,
+ compat_ulong_t, maxnode)
{
long err = 0;
unsigned long __user *nm = NULL;
@@ -1423,9 +1424,9 @@ asmlinkage long compat_sys_set_mempolicy(int mode, compat_ulong_t __user *nmask,
return sys_set_mempolicy(mode, nm, nr_bits+1);
}
-asmlinkage long compat_sys_mbind(compat_ulong_t start, compat_ulong_t len,
- compat_ulong_t mode, compat_ulong_t __user *nmask,
- compat_ulong_t maxnode, compat_ulong_t flags)
+COMPAT_SYSCALL_DEFINE6(mbind, compat_ulong_t, start, compat_ulong_t, len,
+ compat_ulong_t, mode, compat_ulong_t __user *, nmask,
+ compat_ulong_t, maxnode, compat_ulong_t, flags)
{
long err = 0;
unsigned long __user *nm = NULL;
diff --git a/net/compat.c b/net/compat.c
index ec24d9e..eb861c6 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -385,8 +385,8 @@ static int compat_sock_setsockopt(struct socket *sock, int level, int optname,
return sock_setsockopt(sock, level, optname, optval, optlen);
}
-asmlinkage long compat_sys_setsockopt(int fd, int level, int optname,
- char __user *optval, unsigned int optlen)
+COMPAT_SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname,
+ char __user *, optval, unsigned int, optlen)
{
int err;
struct socket *sock;
@@ -498,8 +498,8 @@ int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *usersta
}
EXPORT_SYMBOL(compat_sock_get_timestampns);
-asmlinkage long compat_sys_getsockopt(int fd, int level, int optname,
- char __user *optval, int __user *optlen)
+COMPAT_SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname,
+ char __user *, optval, int __user *, optlen)
{
int err;
struct socket *sock;
@@ -731,31 +731,31 @@ static unsigned char nas[20]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
AL(4),AL(5)};
#undef AL
-asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned flags)
+COMPAT_SYSCALL_DEFINE3(sendmsg, int, fd, struct compat_msghdr __user *, msg, unsigned, flags)
{
return sys_sendmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
}
-asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags)
+COMPAT_SYSCALL_DEFINE3(recvmsg, int, fd, struct compat_msghdr __user *, msg, unsigned int, flags)
{
return sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
}
-asmlinkage long compat_sys_recv(int fd, void __user *buf, size_t len, unsigned flags)
+COMPAT_SYSCALL_DEFINE4(recv, int, fd, void __user *, buf, size_t, len, unsigned, flags)
{
return sys_recv(fd, buf, len, flags | MSG_CMSG_COMPAT);
}
-asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, size_t len,
- unsigned flags, struct sockaddr __user *addr,
- int __user *addrlen)
+COMPAT_SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, buf, size_t, len,
+ unsigned, flags, struct sockaddr __user *, addr,
+ int __user *, addrlen)
{
return sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr, addrlen);
}
-asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
- unsigned vlen, unsigned int flags,
- struct compat_timespec __user *timeout)
+COMPAT_SYSCALL_DEFINE5(recvmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
+ unsigned, vlen, unsigned int, flags,
+ struct compat_timespec __user *, timeout)
{
int datagrams;
struct timespec ktspec;
@@ -775,7 +775,7 @@ asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
return datagrams;
}
-asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
+COMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args)
{
int ret;
u32 a[6];
--
1.7.1
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
* Re: [RFC PATCH v7 01/19] Add a new structure for skb buffer from external.
From: Herbert Xu @ 2010-06-23 9:52 UTC (permalink / raw)
To: Dong, Eddie
Cc: Xin, Xiaohui, Stephen Hemminger, netdev@vger.kernel.org,
kvm@vger.kernel.org, linux-kernel@vger.kernel.org, mst@redhat.com,
mingo@elte.hu, davem@davemloft.net, jdike@linux.intel.com
In-Reply-To: <1A42CE6F5F474C41B63392A5F80372B21F58CD9A@shsmsx501.ccr.corp.intel.com>
On Wed, Jun 23, 2010 at 04:09:40PM +0800, Dong, Eddie wrote:
>
> Xiaohui & Herbert:
> Mixing copy of head & 0-copy of bulk data imposes additional challange to find the guest buffer. The backend driver may be unable to find a spare guest buffer from virtqueue at that time which may block the receiving process then.
> Can't we completely eliminate netdev_alloc_skb here? Assigning guest buffer at this time makes life much easier.
I'm not sure I understand you concern. If you mean that when
the guest doesn't give enough pages to the host and the host
can't receive on behalf of the guest then isn't that already
the case with the original patch-set?
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH] phylib: Add autoload support for the LXT973 phy.
From: David Woodhouse @ 2010-06-23 9:00 UTC (permalink / raw)
To: Richard Cochran; +Cc: netdev
In-Reply-To: <20100623053723.GA3404@riccoc20.at.omicron.at>
On Wed, 2010-06-23 at 07:37 +0200, Richard Cochran wrote:
>
> Question about the whole PHY MODULE_DEVICE_TABLE system:
>
> I recently posted a phy driver for the National Semiconductor
> DP83640. During development, I used drivers/net/arm/ixp4xx_eth.c as
> the MAC driver, which was linked into the kernel (not a module). I
> noticed that the phy driver's probe function only gets called if the
> phy driver is also statically linked, but not when it is loaded as a
> module.
>
> Is this the correct behavior?
Hm, that seems like the _expected_ behaviour, certainly. The MAC driver
will probe its device at boot time, and will issue a request_module() to
load the a specific PHY driver if there is one. When no such module
turns up (which it won't if you have no file system mounted yet), it'll
just fall back to the generic PHY support.
--
David Woodhouse Open Source Technology Centre
David.Woodhouse@intel.com Intel Corporation
^ permalink raw reply
* RE: [RFC PATCH v7 01/19] Add a new structure for skb buffer from external.
From: Dong, Eddie @ 2010-06-23 8:09 UTC (permalink / raw)
To: Xin, Xiaohui, Herbert Xu
Cc: Stephen Hemminger, netdev@vger.kernel.org, kvm@vger.kernel.org,
linux-kernel@vger.kernel.org, mst@redhat.com, mingo@elte.hu,
davem@davemloft.net, jdike@linux.intel.com, Dong, Eddie
In-Reply-To: <F2E9EB7348B8264F86B6AB8151CE2D7915089FE4CC@shsmsx502.ccr.corp.intel.com>
> 3) As I have mentioned above, with this idea, netdev_alloc_skb() will
> allocate
> as usual, the data pointed by skb->data will be copied into the first
> guest buffer.
> That means we should reserve sufficient room in guest buffer. For PS
> mode
> supported driver (for example ixgbe), the room will be more than 128.
> After 128bytes,
> we will put the first frag data. Look into virtio-net.c the function
> page_to_skb()
> and receive_mergeable(), that means we should modify guest virtio-net
> driver to
> compute the offset as the parameter for skb_set_frag().
>
> How do you think about this? Attached is a patch to how to modify the
> guest driver.
> I reserve 512 bytes as an example, and transfer the header len of the
> skb in hdr->hdr_len.
>
Xiaohui & Herbert:
Mixing copy of head & 0-copy of bulk data imposes additional challange to find the guest buffer. The backend driver may be unable to find a spare guest buffer from virtqueue at that time which may block the receiving process then.
Can't we completely eliminate netdev_alloc_skb here? Assigning guest buffer at this time makes life much easier.
Thx, Eddie
^ permalink raw reply
* Re: [PATCH] sched: silence PROVE_RCU in sched_fork()
From: Li Zefan @ 2010-06-23 7:25 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Miles Lane, paulmck, Vivek Goyal, Eric Paris, Lai Jiangshan,
Ingo Molnar, LKML, nauman, eric.dumazet, netdev, Jens Axboe,
Gui Jianfeng, Johannes Berg, Paul Menage
In-Reply-To: <1277199893.1875.690.camel@laptop>
Peter Zijlstra wrote:
> Paul Menage, Li Zefan, any comments?
>
>
> ---
> Because cgroup_fork() is ran before sched_fork() [ from copy_process() ]
> and the child's pid is not yet visible the child is pinned to its
> cgroup. Therefore we can silence this warning.
>
The explanation is correct.
We silenced another warning according to the same reason.
See freezer_fork() in kernel/cgroup_freezer.c
> A nicer solution would be moving cgroup_fork() to right after
> dup_task_struct() and exclude PF_STARTING from task_subsys_state().
>
Seems PF_STARTING is set in copy_flags(), that's after dup_task_struct() and
before cgroup_fork(). But it's cleared after copy_process(), that's after
the task is linked into tasklist, so this doesn't seem work...
> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
For this patch:
Reviewed-by: Li Zefan <lizf@cn.fujitsu.com>
> ---
> kernel/sched.c | 9 +++++++++
> 1 files changed, 9 insertions(+), 0 deletions(-)
>
> diff --git a/kernel/sched.c b/kernel/sched.c
> index b697606..2e79518 100644
> --- a/kernel/sched.c
> +++ b/kernel/sched.c
> @@ -2561,7 +2561,16 @@ void sched_fork(struct task_struct *p, int clone_flags)
> if (p->sched_class->task_fork)
> p->sched_class->task_fork(p);
>
> + /*
> + * The child is not yet in the pid-hash so no cgroup attach races,
> + * and the cgroup is pinned to this child due to cgroup_fork()
> + * is ran before sched_fork().
> + *
> + * Silence PROVE_RCU.
> + */
> + rcu_read_lock();
> set_task_cpu(p, cpu);
> + rcu_read_unlock();
>
> #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
> if (likely(sched_info_on()))
>
>
>
^ permalink raw reply
* [PATCH net-2.6] cnic: Disable statistics initialization for eth clients that do not support statistics
From: Dmitry Kravkov @ 2010-06-23 7:15 UTC (permalink / raw)
To: davem, netdev; +Cc: mchan, eilong
Disable statistics initialization for eth clients that do not support
statistics. This prevents memory corruption on bnx2x hw.
Author: Dmitry Kravkov <dmitry@broadcom.com>
Signed-off-by: Dmitry Kravkov <dmitry@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
drivers/net/cnic.c | 55
++++++++++++++++++++++++++++++++-------------------
1 files changed, 34 insertions(+), 21 deletions(-)
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index fe92566..b314407 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -3919,8 +3919,9 @@ static void cnic_init_bnx2x_tx_ring(struct
cnic_dev *dev)
HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS;
context->cstorm_st_context.status_block_id = BNX2X_DEF_SB_ID;
- context->xstorm_st_context.statistics_data = (cli |
- XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE);
+ if (cli < MAX_X_STAT_COUNTER_ID)
+ context->xstorm_st_context.statistics_data = cli |
+ XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE;
context->xstorm_ag_context.cdu_reserved =
CDU_RSRVD_VALUE_TYPE_A(BNX2X_HW_CID(BNX2X_ISCSI_L2_CID, func),
@@ -3928,10 +3929,12 @@ static void cnic_init_bnx2x_tx_ring(struct
cnic_dev *dev)
ETH_CONNECTION_TYPE);
/* reset xstorm per client statistics */
- val = BAR_XSTRORM_INTMEM +
- XSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli);
- for (i = 0; i < sizeof(struct xstorm_per_client_stats) / 4; i++)
- CNIC_WR(dev, val + i * 4, 0);
+ if (cli < MAX_X_STAT_COUNTER_ID) {
+ val = BAR_XSTRORM_INTMEM +
+ XSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli);
+ for (i = 0; i < sizeof(struct xstorm_per_client_stats) / 4; i++)
+ CNIC_WR(dev, val + i * 4, 0);
+ }
cp->tx_cons_ptr =
&cp->bnx2x_def_status_blk->c_def_status_block.index_values[
@@ -3978,9 +3981,11 @@ static void cnic_init_bnx2x_rx_ring(struct
cnic_dev *dev)
BNX2X_ISCSI_RX_SB_INDEX_NUM;
context->ustorm_st_context.common.clientId = cli;
context->ustorm_st_context.common.status_block_id = BNX2X_DEF_SB_ID;
- context->ustorm_st_context.common.flags =
- USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS;
- context->ustorm_st_context.common.statistics_counter_id = cli;
+ if (cli < MAX_U_STAT_COUNTER_ID) {
+ context->ustorm_st_context.common.flags =
+ USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS;
+ context->ustorm_st_context.common.statistics_counter_id = cli;
+ }
context->ustorm_st_context.common.mc_alignment_log_size = 0;
context->ustorm_st_context.common.bd_buff_size =
cp->l2_single_buf_size;
@@ -4011,10 +4016,13 @@ static void cnic_init_bnx2x_rx_ring(struct
cnic_dev *dev)
/* client tstorm info */
tstorm_client.mtu = cp->l2_single_buf_size - 14;
- tstorm_client.config_flags =
- (TSTORM_ETH_CLIENT_CONFIG_E1HOV_REM_ENABLE |
- TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE);
- tstorm_client.statistics_counter_id = cli;
+ tstorm_client.config_flags =
TSTORM_ETH_CLIENT_CONFIG_E1HOV_REM_ENABLE;
+
+ if (cli < MAX_T_STAT_COUNTER_ID) {
+ tstorm_client.config_flags |=
+ TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE;
+ tstorm_client.statistics_counter_id = cli;
+ }
CNIC_WR(dev, BAR_TSTRORM_INTMEM +
TSTORM_CLIENT_CONFIG_OFFSET(port, cli),
@@ -4024,16 +4032,21 @@ static void cnic_init_bnx2x_rx_ring(struct
cnic_dev *dev)
((u32 *)&tstorm_client)[1]);
/* reset tstorm per client statistics */
- val = BAR_TSTRORM_INTMEM +
- TSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli);
- for (i = 0; i < sizeof(struct tstorm_per_client_stats) / 4; i++)
- CNIC_WR(dev, val + i * 4, 0);
+ if (cli < MAX_T_STAT_COUNTER_ID) {
+
+ val = BAR_TSTRORM_INTMEM +
+ TSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli);
+ for (i = 0; i < sizeof(struct tstorm_per_client_stats) / 4; i++)
+ CNIC_WR(dev, val + i * 4, 0);
+ }
/* reset ustorm per client statistics */
- val = BAR_USTRORM_INTMEM +
- USTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli);
- for (i = 0; i < sizeof(struct ustorm_per_client_stats) / 4; i++)
- CNIC_WR(dev, val + i * 4, 0);
+ if (cli < MAX_U_STAT_COUNTER_ID) {
+ val = BAR_USTRORM_INTMEM +
+ USTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli);
+ for (i = 0; i < sizeof(struct ustorm_per_client_stats) / 4; i++)
+ CNIC_WR(dev, val + i * 4, 0);
+ }
cp->rx_cons_ptr =
&cp->bnx2x_def_status_blk->u_def_status_block.index_values[
--
1.7.1
^ permalink raw reply related
* [PATCH] netfilter: xtables target SYNPROXY
From: Changli Gao @ 2010-06-23 7:06 UTC (permalink / raw)
To: Patrick McHardy
Cc: David S. Miller, Alexey Kuznetsov, Jan Engelhardt,
Jozsef Kadlecsik, Pekka Savola (ipv6), James Morris,
Hideaki YOSHIFUJI, netfilter-devel, netdev, Changli Gao
xtables target SYNPROXY.
This patch implements an xtables target SYNPROXY. As the connection to the
TCP server won't be established until the ACK from the client is received, it
can protect the TCP server from the SYN-flood attacks.
It works in the raw table of the PREROUTING chain, before conntracking system.
Syncookies is used, so no new state is introduced into the conntracking system.
In fact, until the first connection is established, conntracking system doesn't
see any packets. So when there is a SYN-flood attack, conntracking system won't
be busy on finding and deleting the un-assured ct.
As the SYN-packet of the second connection request is sent locally, the DNAT
rules which are in the PREROUTING chain should be moved to the OUTPUT chain.
Signed-off-by: Changli Gao <xiaosuo@gmail.com>
----
include/net/netfilter/nf_conntrack.h | 10
include/net/netfilter/nf_conntrack_core.h | 21
include/net/netfilter/nf_conntrack_extend.h | 2
include/net/tcp.h | 7
net/ipv4/syncookies.c | 22
net/ipv4/tcp_ipv4.c | 9
net/netfilter/Kconfig | 17
net/netfilter/Makefile | 1
net/netfilter/nf_conntrack_core.c | 42 +
net/netfilter/xt_SYNPROXY.c | 678 ++++++++++++++++++++++++++++
10 files changed, 790 insertions(+), 19 deletions(-)
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index e624dae..5e6d8e4 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -311,5 +311,15 @@ do { \
#define MODULE_ALIAS_NFCT_HELPER(helper) \
MODULE_ALIAS("nfct-helper-" helper)
+#if defined(CONFIG_NETFILTER_XT_TARGET_SYNPROXY) || \
+ defined(CONFIG_NETFILTER_XT_TARGET_SYNPROXY_MODULE)
+extern unsigned int (*syn_proxy_pre_hook)(struct sk_buff *skb,
+ struct nf_conn *ct,
+ enum ip_conntrack_info ctinfo);
+
+extern unsigned int (*syn_proxy_post_hook)(struct sk_buff *skb,
+ struct nf_conn *ct,
+ enum ip_conntrack_info ctinfo);
+#endif
#endif /* __KERNEL__ */
#endif /* _NF_CONNTRACK_H */
diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h
index aced085..637b404 100644
--- a/include/net/netfilter/nf_conntrack_core.h
+++ b/include/net/netfilter/nf_conntrack_core.h
@@ -54,6 +54,23 @@ nf_conntrack_find_get(struct net *net, u16 zone,
extern int __nf_conntrack_confirm(struct sk_buff *skb);
+static inline unsigned int syn_proxy_post_call(struct sk_buff *skb,
+ struct nf_conn *ct,
+ enum ip_conntrack_info ctinfo)
+{
+ unsigned int ret = NF_ACCEPT;
+#if defined(CONFIG_NETFILTER_XT_TARGET_SYNPROXY) || \
+ defined(CONFIG_NETFILTER_XT_TARGET_SYNPROXY_MODULE)
+ unsigned int (*syn_proxy)(struct sk_buff *, struct nf_conn *,
+ enum ip_conntrack_info);
+ syn_proxy = rcu_dereference(syn_proxy_post_hook);
+ if (syn_proxy)
+ ret = syn_proxy(skb, ct, ctinfo);
+#endif
+
+ return ret;
+}
+
/* Confirm a connection: returns NF_DROP if packet must be dropped. */
static inline int nf_conntrack_confirm(struct sk_buff *skb)
{
@@ -63,8 +80,10 @@ static inline int nf_conntrack_confirm(struct sk_buff *skb)
if (ct && !nf_ct_is_untracked(ct)) {
if (!nf_ct_is_confirmed(ct))
ret = __nf_conntrack_confirm(skb);
- if (likely(ret == NF_ACCEPT))
+ if (likely(ret == NF_ACCEPT)) {
nf_ct_deliver_cached_events(ct);
+ ret = syn_proxy_post_call(skb, ct, skb->nfctinfo);
+ }
}
return ret;
}
diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h
index 32d15bd..b2ae7e9 100644
--- a/include/net/netfilter/nf_conntrack_extend.h
+++ b/include/net/netfilter/nf_conntrack_extend.h
@@ -11,6 +11,7 @@ enum nf_ct_ext_id {
NF_CT_EXT_ACCT,
NF_CT_EXT_ECACHE,
NF_CT_EXT_ZONE,
+ NF_CT_EXT_SYNPROXY,
NF_CT_EXT_NUM,
};
@@ -19,6 +20,7 @@ enum nf_ct_ext_id {
#define NF_CT_EXT_ACCT_TYPE struct nf_conn_counter
#define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache
#define NF_CT_EXT_ZONE_TYPE struct nf_conntrack_zone
+#define NF_CT_EXT_SYNPROXY_TYPE struct syn_proxy_state
/* Extensions: optional stuff which isn't permanently in struct. */
struct nf_ct_ext {
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 18c246c..e1fa5f9 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -460,8 +460,11 @@ extern int tcp_disconnect(struct sock *sk, int flags);
extern __u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS];
extern struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
struct ip_options *opt);
-extern __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb,
- __u16 *mss);
+extern __u32 __cookie_v4_init_sequence(__be32 saddr, __be32 daddr,
+ __be16 sport, __be16 dport, __u32 seq,
+ __u16 *mssp);
+extern int cookie_v4_check_sequence(const struct iphdr *iph,
+ const struct tcphdr *th, __u32 cookie);
extern __u32 cookie_init_timestamp(struct request_sock *req);
extern bool cookie_check_timestamp(struct tcp_options_received *tcp_opt);
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 51b5662..c6b5e84 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -160,26 +160,21 @@ static __u16 const msstab[] = {
* Generate a syncookie. mssp points to the mss, which is returned
* rounded down to the value encoded in the cookie.
*/
-__u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp)
+__u32 __cookie_v4_init_sequence(__be32 saddr, __be32 daddr, __be16 sport,
+ __be16 dport, __u32 seq, __u16 *mssp)
{
- const struct iphdr *iph = ip_hdr(skb);
- const struct tcphdr *th = tcp_hdr(skb);
int mssind;
const __u16 mss = *mssp;
- tcp_synq_overflow(sk);
-
for (mssind = ARRAY_SIZE(msstab) - 1; mssind ; mssind--)
if (mss >= msstab[mssind])
break;
*mssp = msstab[mssind];
- NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESSENT);
-
- return secure_tcp_syn_cookie(iph->saddr, iph->daddr,
- th->source, th->dest, ntohl(th->seq),
+ return secure_tcp_syn_cookie(saddr, daddr, sport, dport, seq,
jiffies / (HZ * 60), mssind);
}
+EXPORT_SYMBOL(__cookie_v4_init_sequence);
/*
* This (misnamed) value is the age of syncookie which is permitted.
@@ -192,10 +187,9 @@ __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp)
* Check if a ack sequence number is a valid syncookie.
* Return the decoded mss if it is, or 0 if not.
*/
-static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
+int cookie_v4_check_sequence(const struct iphdr *iph, const struct tcphdr *th,
+ __u32 cookie)
{
- const struct iphdr *iph = ip_hdr(skb);
- const struct tcphdr *th = tcp_hdr(skb);
__u32 seq = ntohl(th->seq) - 1;
__u32 mssind = check_tcp_syn_cookie(cookie, iph->saddr, iph->daddr,
th->source, th->dest, seq,
@@ -204,6 +198,7 @@ static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
return mssind < ARRAY_SIZE(msstab) ? msstab[mssind] : 0;
}
+EXPORT_SYMBOL(cookie_v4_check_sequence);
static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
struct request_sock *req,
@@ -283,7 +278,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
goto out;
if (tcp_synq_no_recent_overflow(sk) ||
- (mss = cookie_check(skb, cookie)) == 0) {
+ (mss = cookie_v4_check_sequence(ip_hdr(skb), tcp_hdr(skb),
+ cookie)) == 0) {
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESFAILED);
goto out;
}
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 2e41e6f..3c4456d 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1333,9 +1333,16 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
if (want_cookie) {
#ifdef CONFIG_SYN_COOKIES
+ struct tcphdr *th;
+
req->cookie_ts = tmp_opt.tstamp_ok;
+ tcp_synq_overflow(sk);
+ NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESSENT);
+ th = tcp_hdr(skb);
+ isn = __cookie_v4_init_sequence(saddr, daddr, th->source,
+ th->dest, ntohl(th->seq),
+ &req->mss);
#endif
- isn = cookie_v4_init_sequence(sk, skb, &req->mss);
} else if (!isn) {
struct inet_peer *peer = NULL;
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 413ed24..fd8ad8c 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -560,6 +560,23 @@ config NETFILTER_XT_TARGET_SECMARK
To compile it as a module, choose M here. If unsure, say N.
+config NETFILTER_XT_TARGET_SYNPROXY
+ tristate '"SYNPROXY" target support (EXPERIMENTAL)'
+ depends on EXPERIMENTAL
+ depends on SYN_COOKIES
+ depends on IP_NF_RAW
+ depends on NF_CONNTRACK
+ depends on NETFILTER_ADVANCED
+ help
+ The SYNPROXY target allows a raw rule to specify that some TCP
+ connections are relayed to protect the TCP servers from the SYN-flood
+ DoS attacks. Syn cookies is used to save the initial state, so no
+ conntrack is needed until the client side connection is established.
+ It frees the connection tracking system from creating/deleting
+ conntracks when SYN-flood DoS attack acts.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config NETFILTER_XT_TARGET_TCPMSS
tristate '"TCPMSS" target support'
depends on (IPV6 || IPV6=n)
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index e28420a..4e32834 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP) += xt_TCPOPTSTRIP.o
obj-$(CONFIG_NETFILTER_XT_TARGET_TEE) += xt_TEE.o
obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o
obj-$(CONFIG_NETFILTER_XT_TARGET_IDLETIMER) += xt_IDLETIMER.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_SYNPROXY) += xt_SYNPROXY.o
# matches
obj-$(CONFIG_NETFILTER_XT_MATCH_CLUSTER) += xt_cluster.o
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 16b41b4..011fa34 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -800,6 +800,26 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
return ct;
}
+static inline unsigned int syn_proxy_pre_call(int protonum, struct sk_buff *skb,
+ struct nf_conn *ct,
+ enum ip_conntrack_info ctinfo)
+{
+ unsigned int ret = NF_ACCEPT;
+#if defined(CONFIG_NETFILTER_XT_TARGET_SYNPROXY) || \
+ defined(CONFIG_NETFILTER_XT_TARGET_SYNPROXY_MODULE)
+ unsigned int (*syn_proxy)(struct sk_buff *, struct nf_conn *,
+ enum ip_conntrack_info);
+
+ if (protonum == IPPROTO_TCP) {
+ syn_proxy = rcu_dereference(syn_proxy_pre_hook);
+ if (syn_proxy)
+ ret = syn_proxy(skb, ct, ctinfo);
+ }
+#endif
+
+ return ret;
+}
+
unsigned int
nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
struct sk_buff *skb)
@@ -855,8 +875,9 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
l3proto, l4proto, &set_reply, &ctinfo);
if (!ct) {
/* Not valid part of a connection */
- NF_CT_STAT_INC_ATOMIC(net, invalid);
- ret = NF_ACCEPT;
+ ret = syn_proxy_pre_call(protonum, skb, NULL, ctinfo);
+ if (ret == NF_ACCEPT)
+ NF_CT_STAT_INC_ATOMIC(net, invalid);
goto out;
}
@@ -869,6 +890,9 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
NF_CT_ASSERT(skb->nfct);
+ ret = syn_proxy_pre_call(protonum, skb, ct, ctinfo);
+ if (ret != NF_ACCEPT)
+ goto out;
ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum);
if (ret <= 0) {
/* Invalid: inverse of the return code tells
@@ -1476,6 +1500,17 @@ s16 (*nf_ct_nat_offset)(const struct nf_conn *ct,
u32 seq);
EXPORT_SYMBOL_GPL(nf_ct_nat_offset);
+#if defined(CONFIG_NETFILTER_XT_TARGET_SYNPROXY) || \
+ defined(CONFIG_NETFILTER_XT_TARGET_SYNPROXY_MODULE)
+unsigned int (*syn_proxy_pre_hook)(struct sk_buff *skb, struct nf_conn *ct,
+ enum ip_conntrack_info ctinfo);
+EXPORT_SYMBOL(syn_proxy_pre_hook);
+
+unsigned int (*syn_proxy_post_hook)(struct sk_buff *skb, struct nf_conn *ct,
+ enum ip_conntrack_info ctinfo);
+EXPORT_SYMBOL(syn_proxy_post_hook);
+#endif
+
int nf_conntrack_init(struct net *net)
{
int ret;
@@ -1496,6 +1531,9 @@ int nf_conntrack_init(struct net *net)
/* Howto get NAT offsets */
rcu_assign_pointer(nf_ct_nat_offset, NULL);
+
+ rcu_assign_pointer(syn_proxy_pre_hook, NULL);
+ rcu_assign_pointer(syn_proxy_post_hook, NULL);
}
return 0;
diff --git a/net/netfilter/xt_SYNPROXY.c b/net/netfilter/xt_SYNPROXY.c
new file mode 100644
index 0000000..5e05259
--- /dev/null
+++ b/net/netfilter/xt_SYNPROXY.c
@@ -0,0 +1,678 @@
+/* (C) 2010- Changli Gao <xiaosuo@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * It bases on ipt_REJECT.c
+ */
+#define pr_fmt(fmt) "SYNPROXY: " fmt
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/icmp.h>
+#include <linux/unaligned/access_ok.h>
+#include <net/icmp.h>
+#include <net/ip.h>
+#include <net/tcp.h>
+#include <net/route.h>
+#include <net/dst.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_extend.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Changli Gao <xiaosuo@gmail.com>");
+MODULE_DESCRIPTION("Xtables: \"SYNPROXY\" target for IPv4");
+MODULE_ALIAS("ipt_SYNPROXY");
+
+enum {
+ TCP_SEND_FLAG_NOTRACE = 0x1,
+ TCP_SEND_FLAG_SYNCOOKIE = 0x2,
+ TCP_SEND_FLAG_ACK2SYN = 0x4,
+};
+
+struct syn_proxy_state {
+ u16 seq_inited;
+ __be16 window;
+ u32 seq_diff;
+};
+
+static int get_mtu(const struct dst_entry *dst)
+{
+ int mtu;
+
+ mtu = dst_mtu(dst);
+ if (mtu)
+ return mtu;
+
+ return dst->dev ? dst->dev->mtu : 0;
+}
+
+static int get_advmss(const struct dst_entry *dst)
+{
+ int advmss;
+
+ advmss = dst_metric(dst, RTAX_ADVMSS);
+ if (advmss)
+ return advmss;
+ advmss = get_mtu(dst);
+ if (advmss)
+ return advmss - (sizeof(struct iphdr) + sizeof(struct tcphdr));
+
+ return TCP_MSS_DEFAULT;
+}
+
+static int syn_proxy_route(struct sk_buff *skb, struct net *net, u16 *pmss)
+{
+ const struct iphdr *iph = ip_hdr(skb);
+ struct rtable *rt;
+ struct flowi fl = {};
+ unsigned int type;
+ int flags = 0;
+ int err;
+ u16 mss;
+
+ type = inet_addr_type(net, iph->saddr);
+ if (type != RTN_LOCAL) {
+ type = inet_addr_type(net, iph->daddr);
+ if (type == RTN_LOCAL)
+ flags |= FLOWI_FLAG_ANYSRC;
+ }
+
+ if (type == RTN_LOCAL) {
+ fl.nl_u.ip4_u.daddr = iph->daddr;
+ fl.nl_u.ip4_u.saddr = iph->saddr;
+ fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
+ fl.flags = flags;
+ err = ip_route_output_key(net, &rt, &fl);
+ if (err)
+ goto out;
+
+ skb_dst_set(skb, &rt->dst);
+ } else {
+ /* non-local src, find valid iif to satisfy
+ * rp-filter when calling ip_route_input. */
+ fl.nl_u.ip4_u.daddr = iph->saddr;
+ err = ip_route_output_key(net, &rt, &fl);
+ if (err)
+ goto out;
+
+ err = ip_route_input(skb, iph->daddr, iph->saddr,
+ RT_TOS(iph->tos), rt->dst.dev);
+ if (err) {
+ dst_release(&rt->dst);
+ goto out;
+ }
+ if (pmss) {
+ mss = get_advmss(&rt->dst);
+ if (*pmss > mss)
+ *pmss = mss;
+ }
+ dst_release(&rt->dst);
+ }
+
+ err = skb_dst(skb)->error;
+ if (!err && pmss) {
+ mss = get_advmss(skb_dst(skb));
+ if (*pmss > mss)
+ *pmss = mss;
+ }
+
+out:
+ return err;
+}
+
+static int tcp_send(__be32 src, __be32 dst, __be16 sport, __be16 dport,
+ u32 seq, u32 ack_seq, __be16 window, u16 mss, u8 tcp_flags,
+ u8 tos, struct net_device *dev, int flags,
+ struct sk_buff *oskb)
+{
+ struct sk_buff *skb;
+ struct iphdr *iph;
+ struct tcphdr *th;
+ int err, len;
+
+ len = sizeof(*th);
+ if (mss)
+ len += TCPOLEN_MSS;
+
+ skb = NULL;
+ /* caller must give me a large enough oskb */
+ if (oskb) {
+ unsigned char *odata = oskb->data;
+
+ if (skb_recycle_check(oskb, 0)) {
+ oskb->data = odata;
+ skb_reset_tail_pointer(oskb);
+ skb = oskb;
+ pr_debug("recycle skb\n");
+ }
+ }
+ if (!skb) {
+ skb = alloc_skb(LL_MAX_HEADER + sizeof(*iph) + len, GFP_ATOMIC);
+ if (!skb) {
+ err = -ENOMEM;
+ goto out;
+ }
+ skb_reserve(skb, LL_MAX_HEADER);
+ }
+
+ skb_reset_network_header(skb);
+ if (!(flags & TCP_SEND_FLAG_ACK2SYN) || skb != oskb) {
+ iph = (struct iphdr *)skb_put(skb, sizeof(*iph));
+ iph->version = 4;
+ iph->ihl = sizeof(*iph) / 4;
+ iph->tos = tos;
+ /* tot_len is set in ip_local_out() */
+ iph->id = 0;
+ iph->frag_off = htons(IP_DF);
+ iph->protocol = IPPROTO_TCP;
+ iph->saddr = src;
+ iph->daddr = dst;
+ th = (struct tcphdr *)skb_put(skb, len);
+ th->source = sport;
+ th->dest = dport;
+ } else {
+ iph = (struct iphdr *)skb->data;
+ iph->id = 0;
+ iph->frag_off = htons(IP_DF);
+ skb_put(skb, iph->ihl * 4 + len);
+ th = (struct tcphdr *)(skb->data + iph->ihl * 4);
+ }
+
+ th->seq = htonl(seq);
+ th->ack_seq = htonl(ack_seq);
+ tcp_flag_byte(th) = tcp_flags;
+ th->doff = len / 4;
+ th->window = window;
+ th->urg_ptr = 0;
+
+ if ((flags & TCP_SEND_FLAG_SYNCOOKIE) && mss)
+ err = syn_proxy_route(skb, dev_net(dev), &mss);
+ else
+ err = syn_proxy_route(skb, dev_net(dev), NULL);
+ if (err)
+ goto err_out;
+
+ if ((flags & TCP_SEND_FLAG_SYNCOOKIE)) {
+ if (mss) {
+ th->seq = htonl(__cookie_v4_init_sequence(dst, src,
+ dport, sport,
+ ack_seq - 1,
+ &mss));
+ } else {
+ mss = TCP_MSS_DEFAULT;
+ th->seq = htonl(__cookie_v4_init_sequence(dst, src,
+ dport, sport,
+ ack_seq - 1,
+ &mss));
+ mss = 0;
+ }
+ }
+
+ if (mss)
+ * (__force __be32 *)(th + 1) = htonl((TCPOPT_MSS << 24) |
+ (TCPOLEN_MSS << 16) |
+ mss);
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ th->check = ~tcp_v4_check(len, src, dst, 0);
+ skb->csum_start = (unsigned char *)th - skb->head;
+ skb->csum_offset = offsetof(struct tcphdr, check);
+
+ if (!(flags & TCP_SEND_FLAG_ACK2SYN) || skb != oskb)
+ iph->ttl = dst_metric(skb_dst(skb), RTAX_HOPLIMIT);
+
+ if (skb->len > get_mtu(skb_dst(skb))) {
+ if (printk_ratelimit())
+ pr_warning("%s has smaller mtu: %d\n",
+ skb_dst(skb)->dev->name,
+ get_mtu(skb_dst(skb)));
+ err = -EINVAL;
+ goto err_out;
+ }
+
+ if ((flags & TCP_SEND_FLAG_NOTRACE)) {
+ skb->nfct = &nf_ct_untracked_get()->ct_general;
+ skb->nfctinfo = IP_CT_NEW;
+ nf_conntrack_get(skb->nfct);
+ }
+
+ pr_debug("ip_local_out: %pI4n:%hu -> %pI4n:%hu (seq=%u, "
+ "ack_seq=%u mss=%hu flags=%hhx)\n", &src, ntohs(th->source),
+ &dst, ntohs(th->dest), ntohl(th->seq), ack_seq, mss,
+ tcp_flags);
+
+ err = ip_local_out(skb);
+ if (err > 0)
+ err = net_xmit_errno(err);
+
+ pr_debug("ip_local_out: return with %d\n", err);
+out:
+ if (oskb && oskb != skb)
+ kfree_skb(oskb);
+
+ return err;
+
+err_out:
+ kfree_skb(skb);
+ goto out;
+}
+
+static int get_mss(u8 *data, int len)
+{
+ u8 olen;
+
+ while (len >= TCPOLEN_MSS) {
+ switch (data[0]) {
+ case TCPOPT_EOL:
+ return 0;
+ case TCPOPT_NOP:
+ data++;
+ len--;
+ break;
+ case TCPOPT_MSS:
+ if (data[1] != TCPOLEN_MSS)
+ return -EINVAL;
+ return get_unaligned_be16(data + 2);
+ default:
+ olen = data[1];
+ if (olen < 2 || olen > len)
+ return -EINVAL;
+ data += olen;
+ len -= olen;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static DEFINE_PER_CPU(struct syn_proxy_state, syn_proxy_state);
+
+/* syn_proxy_pre isn't under the protection of nf_conntrack_proto_tcp.c */
+static unsigned int syn_proxy_pre(struct sk_buff *skb, struct nf_conn *ct,
+ enum ip_conntrack_info ctinfo)
+{
+ struct syn_proxy_state *state;
+ struct iphdr *iph;
+ struct tcphdr *th, _th;
+
+ /* only support IPv4 now */
+ iph = ip_hdr(skb);
+ if (iph->version != 4)
+ return NF_ACCEPT;
+
+ th = skb_header_pointer(skb, iph->ihl * 4, sizeof(_th), &_th);
+ if (th == NULL)
+ return NF_DROP;
+
+ if (!ct || !nf_ct_is_confirmed(ct)) {
+ int ret;
+
+ if (!th->syn && th->ack) {
+ u16 mss;
+ struct sk_buff *rec_skb;
+
+ mss = cookie_v4_check_sequence(iph, th,
+ ntohl(th->ack_seq) - 1);
+ if (!mss)
+ return NF_ACCEPT;
+
+ pr_debug("%pI4n:%hu -> %pI4n:%hu(mss=%hu)\n",
+ &iph->saddr, ntohs(th->source),
+ &iph->daddr, ntohs(th->dest), mss);
+
+ if (skb_tailroom(skb) < TCPOLEN_MSS &&
+ skb->len < iph->ihl * 4 + sizeof(*th) + TCPOLEN_MSS)
+ rec_skb = NULL;
+ else
+ rec_skb = skb;
+
+ local_bh_disable();
+ state = &__get_cpu_var(syn_proxy_state);
+ state->seq_inited = 1;
+ state->window = th->window;
+ state->seq_diff = ntohl(th->ack_seq) - 1;
+ if (rec_skb)
+ tcp_send(iph->saddr, iph->daddr, 0, 0,
+ ntohl(th->seq) - 1, 0, th->window,
+ mss, TCPHDR_SYN, 0, skb->dev,
+ TCP_SEND_FLAG_ACK2SYN, rec_skb);
+ else
+ tcp_send(iph->saddr, iph->daddr, th->source,
+ th->dest, ntohl(th->seq) - 1, 0,
+ th->window, mss, TCPHDR_SYN,
+ iph->tos, skb->dev, 0, NULL);
+ state->seq_inited = 0;
+ local_bh_enable();
+
+ if (!rec_skb)
+ kfree_skb(skb);
+
+ return NF_STOLEN;
+ }
+
+ if (!ct || !th->syn || th->ack)
+ return NF_ACCEPT;
+
+ ret = NF_ACCEPT;
+ local_bh_disable();
+ state = &__get_cpu_var(syn_proxy_state);
+ if (state->seq_inited) {
+ struct syn_proxy_state *nstate;
+
+ nstate = nf_ct_ext_add(ct, NF_CT_EXT_SYNPROXY,
+ GFP_ATOMIC);
+ if (nstate != NULL) {
+ nstate->seq_inited = 0;
+ nstate->window = state->window;
+ nstate->seq_diff = state->seq_diff;
+ pr_debug("seq_diff: %u\n", nstate->seq_diff);
+ } else {
+ ret = NF_DROP;
+ }
+ }
+ local_bh_enable();
+
+ return ret;
+ }
+
+ state = nf_ct_ext_find(ct, NF_CT_EXT_SYNPROXY);
+ if (!state)
+ return NF_ACCEPT;
+
+ if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
+ __be32 newack;
+
+ /* don't need to mangle duplicate SYN packets */
+ if (th->syn && !th->ack)
+ return NF_ACCEPT;
+ if (!skb_make_writable(skb, ip_hdrlen(skb) + sizeof(*th)))
+ return NF_DROP;
+ th = (struct tcphdr *)(skb->data + ip_hdrlen(skb));
+ newack = htonl(ntohl(th->ack_seq) - state->seq_diff);
+ inet_proto_csum_replace4(&th->check, skb, th->ack_seq, newack,
+ 0);
+ pr_debug("alter ack seq: %u -> %u\n",
+ ntohl(th->ack_seq), ntohl(newack));
+ th->ack_seq = newack;
+ } else {
+ /* Simultaneous open ? Oh, no. The connection between
+ * client and us is established. */
+ if (th->syn && !th->ack)
+ return NF_DROP;
+ }
+
+ return NF_ACCEPT;
+}
+
+static unsigned int syn_proxy_mangle_pkt(struct sk_buff *skb, struct iphdr *iph,
+ struct tcphdr *th, u32 seq_diff)
+{
+ __be32 new;
+ int olen;
+
+ if (skb->len < (iph->ihl + th->doff) * 4)
+ return NF_DROP;
+ if (!skb_make_writable(skb, (iph->ihl + th->doff) * 4))
+ return NF_DROP;
+ iph = (struct iphdr *)(skb->data);
+ th = (struct tcphdr *)(skb->data + iph->ihl * 4);
+
+ new = tcp_flag_word(th) & (~TCP_FLAG_SYN);
+ inet_proto_csum_replace4(&th->check, skb, tcp_flag_word(th), new, 0);
+ tcp_flag_word(th) = new;
+
+ new = htonl(ntohl(th->seq) + seq_diff);
+ inet_proto_csum_replace4(&th->check, skb, th->seq, new, 0);
+ pr_debug("alter seq: %u -> %u\n", ntohl(th->seq), ntohl(new));
+ th->seq = new;
+
+ olen = th->doff - sizeof(*th) / 4;
+ if (olen) {
+ __be32 *opt;
+
+ opt = (__force __be32 *)(th + 1);
+#define TCPOPT_EOL_WORD ((TCPOPT_EOL << 24) + (TCPOPT_EOL << 16) + \
+ (TCPOPT_EOL << 8) + TCPOPT_EOL)
+ inet_proto_csum_replace4(&th->check, skb, *opt, TCPOPT_EOL_WORD,
+ 0);
+ *opt = TCPOPT_EOL_WORD;
+ }
+
+ return NF_ACCEPT;
+}
+
+static unsigned int syn_proxy_post(struct sk_buff *skb, struct nf_conn *ct,
+ enum ip_conntrack_info ctinfo)
+{
+ struct syn_proxy_state *state;
+ struct iphdr *iph;
+ struct tcphdr *th;
+
+ /* untraced packets don't have NF_CT_EXT_SYNPROXY ext, as they don't
+ * enter syn_proxy_pre() */
+ state = nf_ct_ext_find(ct, NF_CT_EXT_SYNPROXY);
+ if (state == NULL)
+ return NF_ACCEPT;
+
+ iph = ip_hdr(skb);
+ if (!skb_make_writable(skb, iph->ihl * 4 + sizeof(*th)))
+ return NF_DROP;
+ th = (struct tcphdr *)(skb->data + iph->ihl * 4);
+ if (!state->seq_inited) {
+ if (th->syn) {
+ /* It must be from original direction, as the ones
+ * from the other side are dropped in function
+ * syn_proxy_pre() */
+ if (!th->ack)
+ return NF_ACCEPT;
+
+ pr_debug("SYN-ACK %pI4n:%hu -> %pI4n:%hu "
+ "(seq=%u ack_seq=%u)\n",
+ &iph->saddr, ntohs(th->source), &iph->daddr,
+ ntohs(th->dest), ntohl(th->seq),
+ ntohl(th->ack_seq));
+
+ /* SYN-ACK from reply direction with the protection
+ * of conntrack */
+ spin_lock_bh(&ct->lock);
+ if (!state->seq_inited) {
+ state->seq_inited = 1;
+ pr_debug("update seq_diff %u -> %u\n",
+ state->seq_diff,
+ state->seq_diff - ntohl(th->seq));
+ state->seq_diff -= ntohl(th->seq);
+ }
+ spin_unlock_bh(&ct->lock);
+ tcp_send(iph->daddr, iph->saddr, th->dest, th->source,
+ ntohl(th->ack_seq),
+ ntohl(th->seq) + 1 + state->seq_diff,
+ state->window, 0, TCPHDR_ACK, iph->tos,
+ skb->dev, 0, NULL);
+
+ return syn_proxy_mangle_pkt(skb, iph, th,
+ state->seq_diff + 1);
+ } else {
+ __be32 newseq;
+
+ if (!th->rst)
+ return NF_ACCEPT;
+ newseq = htonl(state->seq_diff + 1);
+ inet_proto_csum_replace4(&th->check, skb, th->seq,
+ newseq, 0);
+ pr_debug("alter RST seq: %u -> %u\n",
+ ntohl(th->seq), ntohl(newseq));
+ th->seq = newseq;
+
+ return NF_ACCEPT;
+ }
+ }
+
+ /* ct should be in ESTABLISHED state, but if the ack packets from
+ * us are lost. */
+ if (th->syn) {
+ if (!th->ack)
+ return NF_ACCEPT;
+
+ tcp_send(iph->daddr, iph->saddr, th->dest, th->source,
+ ntohl(th->ack_seq),
+ ntohl(th->seq) + 1 + state->seq_diff,
+ state->window, 0, TCPHDR_ACK, iph->tos,
+ skb->dev, 0, NULL);
+
+ return syn_proxy_mangle_pkt(skb, iph, th, state->seq_diff + 1);
+ }
+
+ if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
+ __be32 newseq;
+
+ newseq = htonl(ntohl(th->seq) + state->seq_diff);
+ inet_proto_csum_replace4(&th->check, skb, th->seq, newseq, 0);
+ pr_debug("alter seq: %u -> %u\n", ntohl(th->seq),
+ ntohl(newseq));
+ th->seq = newseq;
+ }
+
+ return NF_ACCEPT;
+}
+
+static unsigned int tcp_process(struct sk_buff *skb)
+{
+ const struct iphdr *iph;
+ const struct tcphdr *th;
+ int err;
+ u16 mss;
+
+ iph = ip_hdr(skb);
+ if (iph->frag_off & htons(IP_OFFSET))
+ goto out;
+ if (!pskb_may_pull(skb, iph->ihl * 4 + sizeof(*th)))
+ goto out;
+ th = (const struct tcphdr *)(skb->data + iph->ihl * 4);
+ if ((tcp_flag_byte(th) &
+ (TCPHDR_FIN | TCPHDR_RST | TCPHDR_ACK | TCPHDR_SYN)) != TCPHDR_SYN)
+ goto out;
+
+ if (nf_ip_checksum(skb, NF_INET_PRE_ROUTING, iph->ihl * 4, IPPROTO_TCP))
+ goto out;
+ mss = 0;
+ if (th->doff > sizeof(*th) / 4) {
+ if (!pskb_may_pull(skb, (iph->ihl + th->doff) * 4))
+ goto out;
+ err = get_mss((u8 *)(th + 1), th->doff * 4 - sizeof(*th));
+ if (err < 0)
+ goto out;
+ if (err != 0)
+ mss = err;
+ } else if (th->doff != sizeof(*th) / 4)
+ goto out;
+
+ tcp_send(iph->daddr, iph->saddr, th->dest, th->source, 0,
+ ntohl(th->seq) + 1, 0, mss, TCPHDR_SYN | TCPHDR_ACK,
+ iph->tos, skb->dev,
+ TCP_SEND_FLAG_NOTRACE | TCP_SEND_FLAG_SYNCOOKIE, skb);
+
+ return NF_STOLEN;
+
+out:
+ return NF_DROP;
+}
+
+static unsigned int synproxy_tg(struct sk_buff *skb,
+ const struct xt_action_param *par)
+{
+ struct nf_conn *ct;
+ enum ip_conntrack_info ctinfo;
+ int ret;
+
+ /* received from lo */
+ ct = nf_ct_get(skb, &ctinfo);
+ if (ct)
+ return IPT_CONTINUE;
+
+ local_bh_disable();
+ if (!__get_cpu_var(syn_proxy_state).seq_inited)
+ ret = tcp_process(skb);
+ else
+ ret = IPT_CONTINUE;
+ local_bh_enable();
+
+ return ret;
+}
+
+static int synproxy_tg_check(const struct xt_tgchk_param *par)
+{
+ int ret;
+
+ ret = nf_ct_l3proto_try_module_get(par->family);
+ if (ret < 0)
+ pr_info("cannot load conntrack support for proto=%u\n",
+ par->family);
+
+ return ret;
+}
+
+static void synproxy_tg_destroy(const struct xt_tgdtor_param *par)
+{
+ nf_ct_l3proto_module_put(par->family);
+}
+
+static struct xt_target synproxy_tg_reg __read_mostly = {
+ .name = "SYNPROXY",
+ .family = NFPROTO_IPV4,
+ .target = synproxy_tg,
+ .table = "raw",
+ .hooks = 1 << NF_INET_PRE_ROUTING,
+ .proto = IPPROTO_TCP,
+ .checkentry = synproxy_tg_check,
+ .destroy = synproxy_tg_destroy,
+ .me = THIS_MODULE,
+};
+
+static struct nf_ct_ext_type syn_proxy_state_ext __read_mostly = {
+ .len = sizeof(struct syn_proxy_state),
+ .align = __alignof__(struct syn_proxy_state),
+ .id = NF_CT_EXT_SYNPROXY,
+};
+
+static int __init synproxy_tg_init(void)
+{
+ int err;
+
+ rcu_assign_pointer(syn_proxy_pre_hook, syn_proxy_pre);
+ rcu_assign_pointer(syn_proxy_post_hook, syn_proxy_post);
+ err = nf_ct_extend_register(&syn_proxy_state_ext);
+ if (err)
+ goto err_out;
+ err = xt_register_target(&synproxy_tg_reg);
+ if (err)
+ goto err_out2;
+
+ return err;
+
+err_out2:
+ nf_ct_extend_unregister(&syn_proxy_state_ext);
+err_out:
+ rcu_assign_pointer(syn_proxy_post_hook, NULL);
+ rcu_assign_pointer(syn_proxy_pre_hook, NULL);
+ rcu_barrier();
+
+ return err;
+}
+
+static void __exit synproxy_tg_exit(void)
+{
+ xt_unregister_target(&synproxy_tg_reg);
+ nf_ct_extend_unregister(&syn_proxy_state_ext);
+ rcu_assign_pointer(syn_proxy_post_hook, NULL);
+ rcu_assign_pointer(syn_proxy_pre_hook, NULL);
+ rcu_barrier();
+}
+
+module_init(synproxy_tg_init);
+module_exit(synproxy_tg_exit);
^ permalink raw reply related
* [PATCH net-next-2.6] snmp: add align parameter to snmp_mib_init()
From: Eric Dumazet @ 2010-06-23 6:58 UTC (permalink / raw)
To: David Miller
Cc: netdev, Hideaki YOSHIFUJI, Arnaldo Carvalho de Melo,
Vlad Yasevich, Herbert Xu
In preparation for 64bit snmp counters for some mibs,
add an 'align' parameter to snmp_mib_init(), instead
of assuming mibs only contain 'unsigned long' fields.
Callers can use __alignof__(type) to provide correct
alignment.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
CC: Herbert Xu <herbert@gondor.apana.org.au>
CC: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
CC: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
CC: Vlad Yasevich <vladislav.yasevich@hp.com>
---
include/net/ip.h | 2 +-
net/dccp/proto.c | 3 ++-
net/ipv4/af_inet.c | 27 +++++++++++++++++----------
net/ipv6/addrconf.c | 9 ++++++---
net/ipv6/af_inet6.c | 15 ++++++++++-----
net/sctp/protocol.c | 3 ++-
net/xfrm/xfrm_policy.c | 3 ++-
7 files changed, 40 insertions(+), 22 deletions(-)
diff --git a/include/net/ip.h b/include/net/ip.h
index d52f011..3b524df 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -178,7 +178,7 @@ extern struct ipv4_config ipv4_config;
#define NET_ADD_STATS_USER(net, field, adnd) SNMP_ADD_STATS_USER((net)->mib.net_statistics, field, adnd)
extern unsigned long snmp_fold_field(void __percpu *mib[], int offt);
-extern int snmp_mib_init(void __percpu *ptr[2], size_t mibsize);
+extern int snmp_mib_init(void __percpu *ptr[2], size_t mibsize, size_t align);
extern void snmp_mib_free(void __percpu *ptr[2]);
extern struct local_ports {
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index f79bcef..096250d 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -1002,7 +1002,8 @@ EXPORT_SYMBOL_GPL(dccp_shutdown);
static inline int dccp_mib_init(void)
{
return snmp_mib_init((void __percpu **)dccp_statistics,
- sizeof(struct dccp_mib));
+ sizeof(struct dccp_mib),
+ __alignof__(struct dccp_mib));
}
static inline void dccp_mib_exit(void)
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index d99e7e0..711de7c 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1425,13 +1425,13 @@ unsigned long snmp_fold_field(void __percpu *mib[], int offt)
}
EXPORT_SYMBOL_GPL(snmp_fold_field);
-int snmp_mib_init(void __percpu *ptr[2], size_t mibsize)
+int snmp_mib_init(void __percpu *ptr[2], size_t mibsize, size_t align)
{
BUG_ON(ptr == NULL);
- ptr[0] = __alloc_percpu(mibsize, __alignof__(unsigned long));
+ ptr[0] = __alloc_percpu(mibsize, align);
if (!ptr[0])
goto err0;
- ptr[1] = __alloc_percpu(mibsize, __alignof__(unsigned long));
+ ptr[1] = __alloc_percpu(mibsize, align);
if (!ptr[1])
goto err1;
return 0;
@@ -1488,25 +1488,32 @@ static const struct net_protocol icmp_protocol = {
static __net_init int ipv4_mib_init_net(struct net *net)
{
if (snmp_mib_init((void __percpu **)net->mib.tcp_statistics,
- sizeof(struct tcp_mib)) < 0)
+ sizeof(struct tcp_mib),
+ __alignof__(struct tcp_mib)) < 0)
goto err_tcp_mib;
if (snmp_mib_init((void __percpu **)net->mib.ip_statistics,
- sizeof(struct ipstats_mib)) < 0)
+ sizeof(struct ipstats_mib),
+ __alignof__(struct ipstats_mib)) < 0)
goto err_ip_mib;
if (snmp_mib_init((void __percpu **)net->mib.net_statistics,
- sizeof(struct linux_mib)) < 0)
+ sizeof(struct linux_mib),
+ __alignof__(struct linux_mib)) < 0)
goto err_net_mib;
if (snmp_mib_init((void __percpu **)net->mib.udp_statistics,
- sizeof(struct udp_mib)) < 0)
+ sizeof(struct udp_mib),
+ __alignof__(struct udp_mib)) < 0)
goto err_udp_mib;
if (snmp_mib_init((void __percpu **)net->mib.udplite_statistics,
- sizeof(struct udp_mib)) < 0)
+ sizeof(struct udp_mib),
+ __alignof__(struct udp_mib)) < 0)
goto err_udplite_mib;
if (snmp_mib_init((void __percpu **)net->mib.icmp_statistics,
- sizeof(struct icmp_mib)) < 0)
+ sizeof(struct icmp_mib),
+ __alignof__(struct icmp_mib)) < 0)
goto err_icmp_mib;
if (snmp_mib_init((void __percpu **)net->mib.icmpmsg_statistics,
- sizeof(struct icmpmsg_mib)) < 0)
+ sizeof(struct icmpmsg_mib),
+ __alignof__(struct icmpmsg_mib)) < 0)
goto err_icmpmsg_mib;
tcp_mib_init(net);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index b97bb1f..c20a7c2 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -284,13 +284,16 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp,
static int snmp6_alloc_dev(struct inet6_dev *idev)
{
if (snmp_mib_init((void __percpu **)idev->stats.ipv6,
- sizeof(struct ipstats_mib)) < 0)
+ sizeof(struct ipstats_mib),
+ __alignof__(struct ipstats_mib)) < 0)
goto err_ip;
if (snmp_mib_init((void __percpu **)idev->stats.icmpv6,
- sizeof(struct icmpv6_mib)) < 0)
+ sizeof(struct icmpv6_mib),
+ __alignof__(struct icmpv6_mib)) < 0)
goto err_icmp;
if (snmp_mib_init((void __percpu **)idev->stats.icmpv6msg,
- sizeof(struct icmpv6msg_mib)) < 0)
+ sizeof(struct icmpv6msg_mib),
+ __alignof__(struct icmpv6msg_mib)) < 0)
goto err_icmpmsg;
return 0;
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 94b1b9c..e830cd4 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -971,19 +971,24 @@ static void ipv6_packet_cleanup(void)
static int __net_init ipv6_init_mibs(struct net *net)
{
if (snmp_mib_init((void __percpu **)net->mib.udp_stats_in6,
- sizeof (struct udp_mib)) < 0)
+ sizeof(struct udp_mib),
+ __alignof__(struct udp_mib)) < 0)
return -ENOMEM;
if (snmp_mib_init((void __percpu **)net->mib.udplite_stats_in6,
- sizeof (struct udp_mib)) < 0)
+ sizeof(struct udp_mib),
+ __alignof__(struct udp_mib)) < 0)
goto err_udplite_mib;
if (snmp_mib_init((void __percpu **)net->mib.ipv6_statistics,
- sizeof(struct ipstats_mib)) < 0)
+ sizeof(struct ipstats_mib),
+ __alignof__(struct ipstats_mib)) < 0)
goto err_ip_mib;
if (snmp_mib_init((void __percpu **)net->mib.icmpv6_statistics,
- sizeof(struct icmpv6_mib)) < 0)
+ sizeof(struct icmpv6_mib),
+ __alignof__(struct icmpv6_mib)) < 0)
goto err_icmp_mib;
if (snmp_mib_init((void __percpu **)net->mib.icmpv6msg_statistics,
- sizeof(struct icmpv6msg_mib)) < 0)
+ sizeof(struct icmpv6msg_mib),
+ __alignof__(struct icmpv6msg_mib)) < 0)
goto err_icmpmsg_mib;
return 0;
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index a0e1a7f..c0e162a 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -1002,7 +1002,8 @@ int sctp_register_pf(struct sctp_pf *pf, sa_family_t family)
static inline int init_sctp_mibs(void)
{
return snmp_mib_init((void __percpu **)sctp_statistics,
- sizeof(struct sctp_mib));
+ sizeof(struct sctp_mib),
+ __alignof__(struct sctp_mib));
}
static inline void cleanup_sctp_mibs(void)
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 4bf27d9..593c06b 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2480,7 +2480,8 @@ static int __net_init xfrm_statistics_init(struct net *net)
int rv;
if (snmp_mib_init((void __percpu **)net->mib.xfrm_statistics,
- sizeof(struct linux_xfrm_mib)) < 0)
+ sizeof(struct linux_xfrm_mib),
+ __alignof__(struct linux_xfrm_mib)) < 0)
return -ENOMEM;
rv = xfrm_proc_init(net);
if (rv < 0)
^ permalink raw reply related
* [PATCH] net: add dependency on fw class module
From: Amit Kumar Salecha @ 2010-06-23 6:54 UTC (permalink / raw)
To: davem; +Cc: netdev, ameen.rahman, Anirban Chakraborty
From: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
netxen_nic and qlcnic driver depends on firmware_class module.
Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
---
drivers/net/Kconfig | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index fe113d0..71e6f8f 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2755,6 +2755,7 @@ config MYRI10GE_DCA
config NETXEN_NIC
tristate "NetXen Multi port (1/10) Gigabit Ethernet NIC"
depends on PCI
+ select FW_LOADER
help
This enables the support for NetXen's Gigabit Ethernet card.
@@ -2820,6 +2821,7 @@ config BNX2X
config QLCNIC
tristate "QLOGIC QLCNIC 1/10Gb Converged Ethernet NIC Support"
depends on PCI
+ select FW_LOADER
help
This driver supports QLogic QLE8240 and QLE8242 Converged Ethernet
devices.
--
1.6.0.2
^ permalink raw reply related
* Re: [PATCH] phylib: Add autoload support for the LXT973 phy.
From: Richard Cochran @ 2010-06-23 5:37 UTC (permalink / raw)
To: David Woodhouse; +Cc: netdev
In-Reply-To: <1277210293.21798.11.camel@localhost>
On Tue, Jun 22, 2010 at 01:38:13PM +0100, David Woodhouse wrote:
> prefer that we just remember to update the table and don't need to be
> forced :)
Oops, and thanks for catching this.
> static struct mdio_device_id lxt_tbl[] = {
> { 0x78100000, 0xfffffff0 },
> { 0x001378e0, 0xfffffff0 },
> + { 0x00137a10, 0xfffffff0 },
> { }
> };
Question about the whole PHY MODULE_DEVICE_TABLE system:
I recently posted a phy driver for the National Semiconductor
DP83640. During development, I used drivers/net/arm/ixp4xx_eth.c as
the MAC driver, which was linked into the kernel (not a module). I
noticed that the phy driver's probe function only gets called if the
phy driver is also statically linked, but not when it is loaded as a
module.
Is this the correct behavior?
Thanks,
Richard
^ permalink raw reply
* Re: linux-next: manual merge of the net tree with the net-current tree
From: Herbert Xu @ 2010-06-23 4:14 UTC (permalink / raw)
To: Stephen Rothwell
Cc: David Miller, netdev, linux-next, linux-kernel, Changli Gao,
Eric Dumazet
In-Reply-To: <20100623125116.1370bdd4.sfr@canb.auug.org.au>
On Wed, Jun 23, 2010 at 12:51:16PM +1000, Stephen Rothwell wrote:
> Hi all,
>
> Today's linux-next merge of the net tree got a conflict in
> net/ipv4/ip_output.c between commit
> 26cde9f7e2747b6d254b704594eed87ab959afa5 ("udp: Fix bogus UFO packet
> generation") from the net-current tree and commit
> d8d1f30b95a635dbd610dcc5eb641aca8f4768cf ("net-next: remove useless union
> keyword") from the net tree.
>
> Just context changes. I fixed it up (see below) and can carry the fix as
> necessary.
Looks good to me.
Thanks,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* linux-next: manual merge of the wireless tree with the net tree
From: Stephen Rothwell @ 2010-06-23 2:51 UTC (permalink / raw)
To: John W. Linville
Cc: linux-next, linux-kernel, Eric Dumazet, David Miller, netdev,
Kiran Divekar, Amitkumar Karwar
Hi John,
Today's linux-next merge of the wireless tree got a conflict in
drivers/net/wireless/libertas/host.h between commit
ba2d3587912f82d1ab4367975b1df460db60fb1e ("drivers/net: use __packed
annotation") from the net tree and commit
c2af450168af531b70564e3ceb20983199a66216 ("Libertas: Added 11d support
using cfg80211") from the wireless tree.
Just a white space change clashing with a real change! I fixed it up
(and changed some newly added "__attribute__ ((packed))" to "__packed" as
well ...) (see below) and can carry the fix as necessary.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
diff --cc drivers/net/wireless/libertas/host.h
index 3bd5d3b,112fbf1..0000000
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@@ -387,8 -387,32 +387,32 @@@ struct enc_key
struct lbs_offset_value {
u32 offset;
u32 value;
-} __attribute__ ((packed));
+} __packed;
+ #define MRVDRV_MAX_TRIPLET_802_11D 83
+
+ #define COUNTRY_CODE_LEN 3
+
+ struct mrvl_ie_domain_param_set {
+ struct mrvl_ie_header header;
+
+ u8 countrycode[COUNTRY_CODE_LEN];
+ struct ieee80211_country_ie_triplet triplet[1];
-} __attribute__ ((packed));
++} __packed;
+
+ struct cmd_ds_802_11d_domain_info {
+ __le16 action;
+ struct mrvl_ie_domain_param_set domain;
-} __attribute__ ((packed));
++} __packed;
+
+ struct lbs_802_11d_domain_reg {
+ /** Country code*/
+ u8 country_code[COUNTRY_CODE_LEN];
+ /** No. of triplet*/
+ u8 no_triplet;
+ struct ieee80211_country_ie_triplet triplet[MRVDRV_MAX_TRIPLET_802_11D];
-} __attribute__ ((packed));
++} __packed;
+
/*
* Define data structure for CMD_GET_HW_SPEC
* This structure defines the response for the GET_HW_SPEC command
^ permalink raw reply
* linux-next: manual merge of the net tree with the net-current tree
From: Stephen Rothwell @ 2010-06-23 2:51 UTC (permalink / raw)
To: David Miller, netdev
Cc: linux-next, linux-kernel, Herbert Xu, Changli Gao, Eric Dumazet
Hi all,
Today's linux-next merge of the net tree got a conflict in
net/ipv4/ip_output.c between commit
26cde9f7e2747b6d254b704594eed87ab959afa5 ("udp: Fix bogus UFO packet
generation") from the net-current tree and commit
d8d1f30b95a635dbd610dcc5eb641aca8f4768cf ("net-next: remove useless union
keyword") from the net tree.
Just context changes. I fixed it up (see below) and can carry the fix as
necessary.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
diff --cc net/ipv4/ip_output.c
index 041d41d,6cbeb2e..0000000
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@@ -873,12 -873,10 +873,12 @@@ int ip_append_data(struct sock *sk
!exthdrlen)
csummode = CHECKSUM_PARTIAL;
+ skb = skb_peek_tail(&sk->sk_write_queue);
+
inet->cork.length += length;
- if (((length> mtu) || !skb_queue_empty(&sk->sk_write_queue)) &&
+ if (((length > mtu) || (skb && skb_is_gso(skb))) &&
(sk->sk_protocol == IPPROTO_UDP) &&
- (rt->u.dst.dev->features & NETIF_F_UFO)) {
+ (rt->dst.dev->features & NETIF_F_UFO)) {
err = ip_ufo_append_data(sk, getfrag, from, length, hh_len,
fragheaderlen, transhdrlen, mtu,
flags);
@@@ -1123,9 -1121,8 +1123,9 @@@ ssize_t ip_append_page(struct sock *sk
return -EINVAL;
inet->cork.length += size;
- if ((sk->sk_protocol == IPPROTO_UDP) &&
+ if ((size + skb->len > mtu) &&
+ (sk->sk_protocol == IPPROTO_UDP) &&
- (rt->u.dst.dev->features & NETIF_F_UFO)) {
+ (rt->dst.dev->features & NETIF_F_UFO)) {
skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
}
^ permalink raw reply
* Re: bnx2 fails to compile on parisc because of missing get_dma_ops()
From: FUJITA Tomonori @ 2010-06-23 0:38 UTC (permalink / raw)
To: James.Bottomley
Cc: fujita.tomonori, lethal, davem, mchan, vapier, netdev,
linux-parisc, linux-kernel
In-Reply-To: <1277227564.9374.7.camel@mulgrave.site>
On Tue, 22 Jun 2010 12:26:04 -0500
James Bottomley <James.Bottomley@HansenPartnership.com> wrote:
> > As I wrote, there is only one user of this API and we can remove it
> > easily. Then I'm not sure it's worth fixing dma_is_consistent() in
> > many architectures. I prefer to add this to
> > feature-removal-schedule.txt to see if driver writers oppose.
>
> Let me check our two drivers: lasi and 53c700; they're the only ones we
> support on the architecture that can't do any coherence. I think we
> don't need to tell because the dma_sync_cache calls which replace
> coherent memory handling are indirected on the platform so we don't need
> a global dma_is_coherent() flag.
There is only one place where 53c700 uses dma_is_consistent() (lasi
doesn't use it):
BUG_ON(!dma_is_consistent(hostdata->dev, pScript) && L1_CACHE_BYTES < dma_get_cache_alignment());
I think that we can remove the above checking since the existing
parisc systems that can't allocate coherent memory pass this checking.
53c700 and lasi call dma_cache_sync() unconditionally so we can live
without dma_is_consistent().
^ permalink raw reply
* iproute addr flush question
From: Ben Greear @ 2010-06-22 22:46 UTC (permalink / raw)
To: NetDev
Is this supposed to work? I was hoping there was some way to
flush all secondary IPs with a single command:
[root@atom lanforge]# ./local/sbin/ip addr flush dev eth5 secondary
[root@atom lanforge]# ip addr show dev eth5
8: eth5: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN qlen 1000
link/ether 00:90:0b:13:f4:e9 brd ff:ff:ff:ff:ff:ff
inet 6.6.6.1/24 brd 6.6.6.255 scope global eth5
inet 6.6.6.2/24 scope global secondary eth5
inet 6.6.6.3/24 scope global secondary eth5
This is .34 kernel and .34 matching iproute.
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* [PATCH net-next-2.6] loopback: use u64_stats_sync infrastructure
From: Eric Dumazet @ 2010-06-22 22:44 UTC (permalink / raw)
To: David Miller; +Cc: netdev
Commit 6b10de38f0ef (loopback: Implement 64bit stats on 32bit arches)
introduced 64bit stats in loopback driver, using a private seqcount and
private helpers.
David suggested to introduce a generic infrastructure, added in (net:
Introduce u64_stats_sync infrastructure)
This patch reimplements loopback 64bit stats using the u64_stats_sync
infrastructure.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
drivers/net/loopback.c | 62 ++++++++++-----------------------------
1 file changed, 16 insertions(+), 46 deletions(-)
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 09334f8..4dd0510 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -58,53 +58,15 @@
#include <linux/tcp.h>
#include <linux/percpu.h>
#include <net/net_namespace.h>
+#include <linux/u64_stats_sync.h>
struct pcpu_lstats {
- u64 packets;
- u64 bytes;
-#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
- seqcount_t seq;
-#endif
- unsigned long drops;
+ u64 packets;
+ u64 bytes;
+ struct u64_stats_sync syncp;
+ unsigned long drops;
};
-#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
-static void inline lstats_update_begin(struct pcpu_lstats *lstats)
-{
- write_seqcount_begin(&lstats->seq);
-}
-static void inline lstats_update_end(struct pcpu_lstats *lstats)
-{
- write_seqcount_end(&lstats->seq);
-}
-static void inline lstats_fetch_and_add(u64 *packets, u64 *bytes, const struct pcpu_lstats *lstats)
-{
- u64 tpackets, tbytes;
- unsigned int seq;
-
- do {
- seq = read_seqcount_begin(&lstats->seq);
- tpackets = lstats->packets;
- tbytes = lstats->bytes;
- } while (read_seqcount_retry(&lstats->seq, seq));
-
- *packets += tpackets;
- *bytes += tbytes;
-}
-#else
-static void inline lstats_update_begin(struct pcpu_lstats *lstats)
-{
-}
-static void inline lstats_update_end(struct pcpu_lstats *lstats)
-{
-}
-static void inline lstats_fetch_and_add(u64 *packets, u64 *bytes, const struct pcpu_lstats *lstats)
-{
- *packets += lstats->packets;
- *bytes += lstats->bytes;
-}
-#endif
-
/*
* The higher levels take care of making this non-reentrant (it's
* called with bh's disabled).
@@ -126,10 +88,10 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
len = skb->len;
if (likely(netif_rx(skb) == NET_RX_SUCCESS)) {
- lstats_update_begin(lb_stats);
+ u64_stats_update_begin(&lb_stats->syncp);
lb_stats->bytes += len;
lb_stats->packets++;
- lstats_update_end(lb_stats);
+ u64_stats_update_end(&lb_stats->syncp);
} else
lb_stats->drops++;
@@ -148,10 +110,18 @@ static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev)
pcpu_lstats = (void __percpu __force *)dev->ml_priv;
for_each_possible_cpu(i) {
const struct pcpu_lstats *lb_stats;
+ u64 tbytes, tpackets;
+ unsigned int start;
lb_stats = per_cpu_ptr(pcpu_lstats, i);
- lstats_fetch_and_add(&packets, &bytes, lb_stats);
+ do {
+ start = u64_stats_fetch_begin(&lb_stats->syncp);
+ tbytes = lb_stats->bytes;
+ tpackets = lb_stats->packets;
+ } while (u64_stats_fetch_retry(&lb_stats->syncp, start));
drops += lb_stats->drops;
+ bytes += tbytes;
+ packets += tpackets;
}
stats->rx_packets = packets;
stats->tx_packets = packets;
^ permalink raw reply related
* Re: [Bugme-new] [Bug 16268] New: kernel oops when rmmod the tcp_diag modules
From: Andrew Morton @ 2010-06-22 22:25 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev, bugzilla-daemon, bugme-daemon, lyw
In-Reply-To: <1277244162.2591.198.camel@edumazet-laptop>
On Wed, 23 Jun 2010 00:02:42 +0200
Eric Dumazet <eric.dumazet@gmail.com> wrote:
> ss is kind of "netstat" with advanced features.
Someone call the namespace police!
> Well, they are faster and more predictable ways to reboot a machine, if
> you ask me :)
>
> man rmmod
>
> -f --force
doh, I missed that. Yes, that was a bit self-inflicted.
^ permalink raw reply
* Re: [Bugme-new] [Bug 16268] New: kernel oops when rmmod the tcp_diag modules
From: Eric Dumazet @ 2010-06-22 22:02 UTC (permalink / raw)
To: Andrew Morton; +Cc: netdev, bugzilla-daemon, bugme-daemon, lyw
In-Reply-To: <20100622141232.4b8f1d4a.akpm@linux-foundation.org>
Le mardi 22 juin 2010 à 14:12 -0700, Andrew Morton a écrit :
> (switched to email. Please respond via emailed reply-to-all, not via the
> bugzilla web interface).
>
> On Tue, 22 Jun 2010 00:43:37 GMT
> bugzilla-daemon@bugzilla.kernel.org wrote:
>
> > https://bugzilla.kernel.org/show_bug.cgi?id=16268
> >
> > Summary: kernel oops when rmmod the tcp_diag modules
> > Product: Networking
> > Version: 2.5
> > Kernel Version: 2.6.35-rc3
> > Platform: All
> > OS/Version: Linux
> > Tree: Mainline
> > Status: NEW
> > Severity: high
> > Priority: P1
> > Component: IPV4
> > AssignedTo: shemminger@linux-foundation.org
> > ReportedBy: lyw@cn.fujitsu.com
> > Regression: No
> >
> >
> > I found a crash problem use following scripts and steps
> >
> > #cat run_ss.sh
> > while [ 1 ]
> > do
> > ss -a
> > done
> >
> > #cat rmmod.sh
> > while [ 1 ]
> > do
> > rmmod -f tcp_diag >/dev/null 2>&1
> > rmmod -f inet_diag >/dev/null 2>&1
> > done
> >
> > step1:
> > # sh run_sh.sh
> > step2:
> > # sh rmmod.sh
>
> I assume the rmmod script runs in pararallel with run_ss.sh.
>
> What is "ss"? Something which triggers a load of kernel modules,
> presumably. Which ones?
>
ss is kind of "netstat" with advanced features.
It loads inet_diag & tcp_diag modules.
> > After step2, the kernel oopsed.
>
> yeah, that was a pretty nasty test ;)
Well, they are faster and more predictable ways to reboot a machine, if
you ask me :)
man rmmod
-f --force
This option can be extremely dangerous: it has no effect unless
CONFIG_MODULE_FORCE_UNLOAD was set when the kernel was compiled.
With this option, you can remove modules which are being used,
or which are not designed to be removed, or have been marked as
unsafe (see lsmod(8)).
I guess Linux is supposed to respect admin choice to live in a dangerous world.
^ permalink raw reply
* [PATCH v3] caif-driver: Add CAIF-SPI Protocol driver.
From: sjur.brandeland @ 2010-06-22 21:53 UTC (permalink / raw)
To: davem
Cc: sjurbr, netdev, marcel, daniel.martensson, linus.walleij,
Sjur Braendeland
From: Sjur Braendeland <sjur.brandeland@stericsson.com>
This patch introduces the CAIF SPI Protocol Driver for
CAIF Link Layer.
This driver implements a platform driver to accommodate for a
platform specific SPI device. A general platform driver is not
possible as there are no SPI Slave side Kernel API defined.
A sample CAIF SPI Platform device can be found in
.../Documentation/networking/caif/spi_porting.txt
Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
---
== RECENT CHANGES:
o Removed CONFIG_* defines from Makefile.
o Changed uint8_t to u8 et. al.
o Using netif_rx_ni instead of netif_rx from workqueue.
Documentation/networking/caif/spi_porting.txt | 208 ++++++
drivers/net/caif/Kconfig | 20 +
drivers/net/caif/Makefile | 4 +
drivers/net/caif/caif_spi.c | 847 +++++++++++++++++++++++++
drivers/net/caif/caif_spi_slave.c | 252 ++++++++
include/net/caif/caif_spi.h | 153 +++++
6 files changed, 1484 insertions(+), 0 deletions(-)
create mode 100644 Documentation/networking/caif/spi_porting.txt
create mode 100644 drivers/net/caif/caif_spi.c
create mode 100644 drivers/net/caif/caif_spi_slave.c
create mode 100644 include/net/caif/caif_spi.h
diff --git a/Documentation/networking/caif/spi_porting.txt b/Documentation/networking/caif/spi_porting.txt
new file mode 100644
index 0000000..61d7c92
--- /dev/null
+++ b/Documentation/networking/caif/spi_porting.txt
@@ -0,0 +1,208 @@
+- CAIF SPI porting -
+
+- CAIF SPI basics:
+
+Running CAIF over SPI needs some extra setup, owing to the nature of SPI.
+Two extra GPIOs have been added in order to negotiate the transfers
+ between the master and the slave. The minimum requirement for running
+CAIF over SPI is a SPI slave chip and two GPIOs (more details below).
+Please note that running as a slave implies that you need to keep up
+with the master clock. An overrun or underrun event is fatal.
+
+- CAIF SPI framework:
+
+To make porting as easy as possible, the CAIF SPI has been divided in
+two parts. The first part (called the interface part) deals with all
+generic functionality such as length framing, SPI frame negotiation
+and SPI frame delivery and transmission. The other part is the CAIF
+SPI slave device part, which is the module that you have to write if
+you want to run SPI CAIF on a new hardware. This part takes care of
+the physical hardware, both with regard to SPI and to GPIOs.
+
+- Implementing a CAIF SPI device:
+
+ - Functionality provided by the CAIF SPI slave device:
+
+ In order to implement a SPI device you will, as a minimum,
+ need to implement the following
+ functions:
+
+ int (*init_xfer) (struct cfspi_xfer * xfer, struct cfspi_dev *dev):
+
+ This function is called by the CAIF SPI interface to give
+ you a chance to set up your hardware to be ready to receive
+ a stream of data from the master. The xfer structure contains
+ both physical and logical adresses, as well as the total length
+ of the transfer in both directions.The dev parameter can be used
+ to map to different CAIF SPI slave devices.
+
+ void (*sig_xfer) (bool xfer, struct cfspi_dev *dev):
+
+ This function is called by the CAIF SPI interface when the output
+ (SPI_INT) GPIO needs to change state. The boolean value of the xfer
+ variable indicates whether the GPIO should be asserted (HIGH) or
+ deasserted (LOW). The dev parameter can be used to map to different CAIF
+ SPI slave devices.
+
+ - Functionality provided by the CAIF SPI interface:
+
+ void (*ss_cb) (bool assert, struct cfspi_ifc *ifc);
+
+ This function is called by the CAIF SPI slave device in order to
+ signal a change of state of the input GPIO (SS) to the interface.
+ Only active edges are mandatory to be reported.
+ This function can be called from IRQ context (recommended in order
+ not to introduce latency). The ifc parameter should be the pointer
+ returned from the platform probe function in the SPI device structure.
+
+ void (*xfer_done_cb) (struct cfspi_ifc *ifc);
+
+ This function is called by the CAIF SPI slave device in order to
+ report that a transfer is completed. This function should only be
+ called once both the transmission and the reception are completed.
+ This function can be called from IRQ context (recommended in order
+ not to introduce latency). The ifc parameter should be the pointer
+ returned from the platform probe function in the SPI device structure.
+
+ - Connecting the bits and pieces:
+
+ - Filling in the SPI slave device structure:
+
+ Connect the necessary callback functions.
+ Indicate clock speed (used to calculate toggle delays).
+ Chose a suitable name (helps debugging if you use several CAIF
+ SPI slave devices).
+ Assign your private data (can be used to map to your structure).
+
+ - Filling in the SPI slave platform device structure:
+ Add name of driver to connect to ("cfspi_sspi").
+ Assign the SPI slave device structure as platform data.
+
+- Padding:
+
+In order to optimize throughput, a number of SPI padding options are provided.
+Padding can be enabled independently for uplink and downlink transfers.
+Padding can be enabled for the head, the tail and for the total frame size.
+The padding needs to be correctly configured on both sides of the link.
+The padding can be changed via module parameters in cfspi_sspi.c or via
+the sysfs directory of the cfspi_sspi driver (before device registration).
+
+- CAIF SPI device template:
+
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <net/caif/caif_spi.h>
+
+MODULE_LICENSE("GPL");
+
+struct sspi_struct {
+ struct cfspi_dev sdev;
+ struct cfspi_xfer *xfer;
+};
+
+static struct sspi_struct slave;
+static struct platform_device slave_device;
+
+static irqreturn_t sspi_irq(int irq, void *arg)
+{
+ /* You only need to trigger on an edge to the active state of the
+ * SS signal. Once a edge is detected, the ss_cb() function should be
+ * called with the parameter assert set to true. It is OK
+ * (and even advised) to call the ss_cb() function in IRQ context in
+ * order not to add any delay. */
+
+ return IRQ_HANDLED;
+}
+
+static void sspi_complete(void *context)
+{
+ /* Normally the DMA or the SPI framework will call you back
+ * in something similar to this. The only thing you need to
+ * do is to call the xfer_done_cb() function, providing the pointer
+ * to the CAIF SPI interface. It is OK to call this function
+ * from IRQ context. */
+}
+
+static int sspi_init_xfer(struct cfspi_xfer *xfer, struct cfspi_dev *dev)
+{
+ /* Store transfer info. For a normal implementation you should
+ * set up your DMA here and make sure that you are ready to
+ * receive the data from the master SPI. */
+
+ struct sspi_struct *sspi = (struct sspi_struct *)dev->priv;
+
+ sspi->xfer = xfer;
+
+ return 0;
+}
+
+void sspi_sig_xfer(bool xfer, struct cfspi_dev *dev)
+{
+ /* If xfer is true then you should assert the SPI_INT to indicate to
+ * the master that you are ready to recieve the data from the master
+ * SPI. If xfer is false then you should de-assert SPI_INT to indicate
+ * that the transfer is done.
+ */
+
+ struct sspi_struct *sspi = (struct sspi_struct *)dev->priv;
+}
+
+static void sspi_release(struct device *dev)
+{
+ /*
+ * Here you should release your SPI device resources.
+ */
+}
+
+static int __init sspi_init(void)
+{
+ /* Here you should initialize your SPI device by providing the
+ * necessary functions, clock speed, name and private data. Once
+ * done, you can register your device with the
+ * platform_device_register() function. This function will return
+ * with the CAIF SPI interface initialized. This is probably also
+ * the place where you should set up your GPIOs, interrupts and SPI
+ * resources. */
+
+ int res = 0;
+
+ /* Initialize slave device. */
+ slave.sdev.init_xfer = sspi_init_xfer;
+ slave.sdev.sig_xfer = sspi_sig_xfer;
+ slave.sdev.clk_mhz = 13;
+ slave.sdev.priv = &slave;
+ slave.sdev.name = "spi_sspi";
+ slave_device.dev.release = sspi_release;
+
+ /* Initialize platform device. */
+ slave_device.name = "cfspi_sspi";
+ slave_device.dev.platform_data = &slave.sdev;
+
+ /* Register platform device. */
+ res = platform_device_register(&slave_device);
+ if (res) {
+ printk(KERN_WARNING "sspi_init: failed to register dev.\n");
+ return -ENODEV;
+ }
+
+ return res;
+}
+
+static void __exit sspi_exit(void)
+{
+ platform_device_del(&slave_device);
+}
+
+module_init(sspi_init);
+module_exit(sspi_exit);
diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig
index 0b28e01..372508e 100644
--- a/drivers/net/caif/Kconfig
+++ b/drivers/net/caif/Kconfig
@@ -14,4 +14,24 @@ config CAIF_TTY
identified as N_CAIF. When this ldisc is opened from user space
it will redirect the TTY's traffic into the CAIF stack.
+config CAIF_SPI_SLAVE
+ tristate "CAIF SPI transport driver for slave interface"
+ default n
+ ---help---
+ The CAIF Link layer SPI Protocol driver for Slave SPI interface.
+ This driver implements a platform driver to accommodate for a
+ platform specific SPI device. A sample CAIF SPI Platform device is
+ provided in Documentation/networking/caif/spi_porting.txt
+
+if CAIF_SPI_SLAVE
+config CAIF_SPI_SYNC
+ bool "Next command and length in start of frame"
+ default n
+ ---help---
+ Putting the next command and length in the start of the frame can
+ help to synchronize to the next transfer in case of over or under-runs.
+ This option also needs to be enabled on the modem.
+
+endif # CAIF_SPI_SLAVE
+
endif # CAIF
diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile
index 52b6d1f..6cbe4b6 100644
--- a/drivers/net/caif/Makefile
+++ b/drivers/net/caif/Makefile
@@ -10,3 +10,7 @@ clean-files:= Module.symvers modules.order *.cmd *~ \
# Serial interface
obj-$(CONFIG_CAIF_TTY) += caif_serial.o
+
+# SPI slave physical interfaces module
+cfspi_slave-objs := caif_spi.o caif_spi_slave.o
+obj-$(CONFIG_CAIF_SPI_SLAVE) += cfspi_slave.o
diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c
new file mode 100644
index 0000000..03049e8
--- /dev/null
+++ b/drivers/net/caif/caif_spi.c
@@ -0,0 +1,847 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
+ * Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/debugfs.h>
+#include <linux/if_arp.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/caif_spi.h>
+
+#ifndef CONFIG_CAIF_SPI_SYNC
+#define FLAVOR "Flavour: Vanilla.\n"
+#else
+#define FLAVOR "Flavour: Master CMD&LEN at start.\n"
+#endif /* CONFIG_CAIF_SPI_SYNC */
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Daniel Martensson<daniel.martensson@stericsson.com>");
+MODULE_DESCRIPTION("CAIF SPI driver");
+
+static int spi_loop;
+module_param(spi_loop, bool, S_IRUGO);
+MODULE_PARM_DESC(spi_loop, "SPI running in loopback mode.");
+
+/* SPI frame alignment. */
+module_param(spi_frm_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_frm_align, "SPI frame alignment.");
+
+/* SPI padding options. */
+module_param(spi_up_head_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_up_head_align, "SPI uplink head alignment.");
+
+module_param(spi_up_tail_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_up_tail_align, "SPI uplink tail alignment.");
+
+module_param(spi_down_head_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_down_head_align, "SPI downlink head alignment.");
+
+module_param(spi_down_tail_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_down_tail_align, "SPI downlink tail alignment.");
+
+#ifdef CONFIG_ARM
+#define BYTE_HEX_FMT "%02X"
+#else
+#define BYTE_HEX_FMT "%02hhX"
+#endif
+
+#define SPI_MAX_PAYLOAD_SIZE 4096
+/*
+ * Threshold values for the SPI packet queue. Flowcontrol will be asserted
+ * when the number of packets exceeds HIGH_WATER_MARK. It will not be
+ * deasserted before the number of packets drops below LOW_WATER_MARK.
+ */
+#define LOW_WATER_MARK 100
+#define HIGH_WATER_MARK (LOW_WATER_MARK*5)
+
+#ifdef CONFIG_UML
+
+/*
+ * We sometimes use UML for debugging, but it cannot handle
+ * dma_alloc_coherent so we have to wrap it.
+ */
+static inline void *dma_alloc(dma_addr_t *daddr)
+{
+ return kmalloc(SPI_DMA_BUF_LEN, GFP_KERNEL);
+}
+
+static inline void dma_free(void *cpu_addr, dma_addr_t handle)
+{
+ kfree(cpu_addr);
+}
+
+#else
+
+static inline void *dma_alloc(dma_addr_t *daddr)
+{
+ return dma_alloc_coherent(NULL, SPI_DMA_BUF_LEN, daddr,
+ GFP_KERNEL);
+}
+
+static inline void dma_free(void *cpu_addr, dma_addr_t handle)
+{
+ dma_free_coherent(NULL, SPI_DMA_BUF_LEN, cpu_addr, handle);
+}
+#endif /* CONFIG_UML */
+
+#ifdef CONFIG_DEBUG_FS
+
+#define DEBUGFS_BUF_SIZE 4096
+
+static struct dentry *dbgfs_root;
+
+static inline void driver_debugfs_create(void)
+{
+ dbgfs_root = debugfs_create_dir(cfspi_spi_driver.driver.name, NULL);
+}
+
+static inline void driver_debugfs_remove(void)
+{
+ debugfs_remove(dbgfs_root);
+}
+
+static inline void dev_debugfs_rem(struct cfspi *cfspi)
+{
+ debugfs_remove(cfspi->dbgfs_frame);
+ debugfs_remove(cfspi->dbgfs_state);
+ debugfs_remove(cfspi->dbgfs_dir);
+}
+
+static int dbgfs_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t dbgfs_state(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char *buf;
+ int len = 0;
+ ssize_t size;
+ struct cfspi *cfspi = (struct cfspi *)file->private_data;
+
+ buf = kzalloc(DEBUGFS_BUF_SIZE, GFP_KERNEL);
+ if (!buf)
+ return 0;
+
+ /* Print out debug information. */
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "CAIF SPI debug information:\n");
+
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len), FLAVOR);
+
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "STATE: %d\n", cfspi->dbg_state);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Previous CMD: 0x%x\n", cfspi->pcmd);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Current CMD: 0x%x\n", cfspi->cmd);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Previous TX len: %d\n", cfspi->tx_ppck_len);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Previous RX len: %d\n", cfspi->rx_ppck_len);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Current TX len: %d\n", cfspi->tx_cpck_len);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Current RX len: %d\n", cfspi->rx_cpck_len);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Next TX len: %d\n", cfspi->tx_npck_len);
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Next RX len: %d\n", cfspi->rx_npck_len);
+
+ size = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return size;
+}
+
+static ssize_t print_frame(char *buf, size_t size, char *frm,
+ size_t count, size_t cut)
+{
+ int len = 0;
+ int i;
+ for (i = 0; i < count; i++) {
+ len += snprintf((buf + len), (size - len),
+ "[0x" BYTE_HEX_FMT "]",
+ frm[i]);
+ if ((i == cut) && (count > (cut * 2))) {
+ /* Fast forward. */
+ i = count - cut;
+ len += snprintf((buf + len), (size - len),
+ "--- %u bytes skipped ---\n",
+ (int)(count - (cut * 2)));
+ }
+
+ if ((!(i % 10)) && i) {
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "\n");
+ }
+ }
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len), "\n");
+ return len;
+}
+
+static ssize_t dbgfs_frame(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char *buf;
+ int len = 0;
+ ssize_t size;
+ struct cfspi *cfspi;
+
+ cfspi = (struct cfspi *)file->private_data;
+ buf = kzalloc(DEBUGFS_BUF_SIZE, GFP_KERNEL);
+ if (!buf)
+ return 0;
+
+ /* Print out debug information. */
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Current frame:\n");
+
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Tx data (Len: %d):\n", cfspi->tx_cpck_len);
+
+ len += print_frame((buf + len), (DEBUGFS_BUF_SIZE - len),
+ cfspi->xfer.va_tx,
+ (cfspi->tx_cpck_len + SPI_CMD_SZ), 100);
+
+ len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+ "Rx data (Len: %d):\n", cfspi->rx_cpck_len);
+
+ len += print_frame((buf + len), (DEBUGFS_BUF_SIZE - len),
+ cfspi->xfer.va_rx,
+ (cfspi->rx_cpck_len + SPI_CMD_SZ), 100);
+
+ size = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return size;
+}
+
+static const struct file_operations dbgfs_state_fops = {
+ .open = dbgfs_open,
+ .read = dbgfs_state,
+ .owner = THIS_MODULE
+};
+
+static const struct file_operations dbgfs_frame_fops = {
+ .open = dbgfs_open,
+ .read = dbgfs_frame,
+ .owner = THIS_MODULE
+};
+
+static inline void dev_debugfs_add(struct cfspi *cfspi)
+{
+ cfspi->dbgfs_dir = debugfs_create_dir(cfspi->pdev->name, dbgfs_root);
+ cfspi->dbgfs_state = debugfs_create_file("state", S_IRUGO,
+ cfspi->dbgfs_dir, cfspi,
+ &dbgfs_state_fops);
+ cfspi->dbgfs_frame = debugfs_create_file("frame", S_IRUGO,
+ cfspi->dbgfs_dir, cfspi,
+ &dbgfs_frame_fops);
+}
+
+inline void cfspi_dbg_state(struct cfspi *cfspi, int state)
+{
+ cfspi->dbg_state = state;
+};
+#else
+
+static inline void driver_debugfs_create(void)
+{
+}
+
+static inline void driver_debugfs_remove(void)
+{
+}
+
+static inline void dev_debugfs_add(struct cfspi *cfspi)
+{
+}
+
+static inline void dev_debugfs_rem(struct cfspi *cfspi)
+{
+}
+
+inline void cfspi_dbg_state(struct cfspi *cfspi, int state)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static LIST_HEAD(cfspi_list);
+static spinlock_t cfspi_list_lock;
+
+/* SPI uplink head alignment. */
+static ssize_t show_up_head_align(struct device_driver *driver, char *buf)
+{
+ return sprintf(buf, "%d\n", spi_up_head_align);
+}
+
+static DRIVER_ATTR(up_head_align, S_IRUSR, show_up_head_align, NULL);
+
+/* SPI uplink tail alignment. */
+static ssize_t show_up_tail_align(struct device_driver *driver, char *buf)
+{
+ return sprintf(buf, "%d\n", spi_up_tail_align);
+}
+
+static DRIVER_ATTR(up_tail_align, S_IRUSR, show_up_tail_align, NULL);
+
+/* SPI downlink head alignment. */
+static ssize_t show_down_head_align(struct device_driver *driver, char *buf)
+{
+ return sprintf(buf, "%d\n", spi_down_head_align);
+}
+
+static DRIVER_ATTR(down_head_align, S_IRUSR, show_down_head_align, NULL);
+
+/* SPI downlink tail alignment. */
+static ssize_t show_down_tail_align(struct device_driver *driver, char *buf)
+{
+ return sprintf(buf, "%d\n", spi_down_tail_align);
+}
+
+static DRIVER_ATTR(down_tail_align, S_IRUSR, show_down_tail_align, NULL);
+
+/* SPI frame alignment. */
+static ssize_t show_frame_align(struct device_driver *driver, char *buf)
+{
+ return sprintf(buf, "%d\n", spi_frm_align);
+}
+
+static DRIVER_ATTR(frame_align, S_IRUSR, show_frame_align, NULL);
+
+int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
+{
+ u8 *dst = buf;
+ caif_assert(buf);
+
+ do {
+ struct sk_buff *skb;
+ struct caif_payload_info *info;
+ int spad = 0;
+ int epad;
+
+ skb = skb_dequeue(&cfspi->chead);
+ if (!skb)
+ break;
+
+ /*
+ * Calculate length of frame including SPI padding.
+ * The payload position is found in the control buffer.
+ */
+ info = (struct caif_payload_info *)&skb->cb;
+
+ /*
+ * Compute head offset i.e. number of bytes to add to
+ * get the start of the payload aligned.
+ */
+ if (spi_up_head_align) {
+ spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
+ *dst = (u8)(spad - 1);
+ dst += spad;
+ }
+
+ /* Copy in CAIF frame. */
+ skb_copy_bits(skb, 0, dst, skb->len);
+ dst += skb->len;
+ cfspi->ndev->stats.tx_packets++;
+ cfspi->ndev->stats.tx_bytes += skb->len;
+
+ /*
+ * Compute tail offset i.e. number of bytes to add to
+ * get the complete CAIF frame aligned.
+ */
+ epad = (skb->len + spad) & spi_up_tail_align;
+ dst += epad;
+
+ dev_kfree_skb(skb);
+
+ } while ((dst - buf) < len);
+
+ return dst - buf;
+}
+
+int cfspi_xmitlen(struct cfspi *cfspi)
+{
+ struct sk_buff *skb = NULL;
+ int frm_len = 0;
+ int pkts = 0;
+
+ /*
+ * Decommit previously commited frames.
+ * skb_queue_splice_tail(&cfspi->chead,&cfspi->qhead)
+ */
+ while (skb_peek(&cfspi->chead)) {
+ skb = skb_dequeue_tail(&cfspi->chead);
+ skb_queue_head(&cfspi->qhead, skb);
+ }
+
+ do {
+ struct caif_payload_info *info = NULL;
+ int spad = 0;
+ int epad = 0;
+
+ skb = skb_dequeue(&cfspi->qhead);
+ if (!skb)
+ break;
+
+ /*
+ * Calculate length of frame including SPI padding.
+ * The payload position is found in the control buffer.
+ */
+ info = (struct caif_payload_info *)&skb->cb;
+
+ /*
+ * Compute head offset i.e. number of bytes to add to
+ * get the start of the payload aligned.
+ */
+ if (spi_up_head_align)
+ spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
+
+ /*
+ * Compute tail offset i.e. number of bytes to add to
+ * get the complete CAIF frame aligned.
+ */
+ epad = (skb->len + spad) & spi_up_tail_align;
+
+ if ((skb->len + spad + epad + frm_len) <= CAIF_MAX_SPI_FRAME) {
+ skb_queue_tail(&cfspi->chead, skb);
+ pkts++;
+ frm_len += skb->len + spad + epad;
+ } else {
+ /* Put back packet. */
+ skb_queue_head(&cfspi->qhead, skb);
+ }
+ } while (pkts <= CAIF_MAX_SPI_PKTS);
+
+ /*
+ * Send flow on if previously sent flow off
+ * and now go below the low water mark
+ */
+ if (cfspi->flow_off_sent && cfspi->qhead.qlen < cfspi->qd_low_mark &&
+ cfspi->cfdev.flowctrl) {
+ cfspi->flow_off_sent = 0;
+ cfspi->cfdev.flowctrl(cfspi->ndev, 1);
+ }
+
+ return frm_len;
+}
+
+static void cfspi_ss_cb(bool assert, struct cfspi_ifc *ifc)
+{
+ struct cfspi *cfspi = (struct cfspi *)ifc->priv;
+
+ if (!in_interrupt())
+ spin_lock(&cfspi->lock);
+ if (assert) {
+ set_bit(SPI_SS_ON, &cfspi->state);
+ set_bit(SPI_XFER, &cfspi->state);
+ } else {
+ set_bit(SPI_SS_OFF, &cfspi->state);
+ }
+ if (!in_interrupt())
+ spin_unlock(&cfspi->lock);
+
+ /* Wake up the xfer thread. */
+ wake_up_interruptible(&cfspi->wait);
+}
+
+static void cfspi_xfer_done_cb(struct cfspi_ifc *ifc)
+{
+ struct cfspi *cfspi = (struct cfspi *)ifc->priv;
+
+ /* Transfer done, complete work queue */
+ complete(&cfspi->comp);
+}
+
+static int cfspi_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct cfspi *cfspi = NULL;
+ unsigned long flags;
+ if (!dev)
+ return -EINVAL;
+
+ cfspi = netdev_priv(dev);
+
+ skb_queue_tail(&cfspi->qhead, skb);
+
+ spin_lock_irqsave(&cfspi->lock, flags);
+ if (!test_and_set_bit(SPI_XFER, &cfspi->state)) {
+ /* Wake up xfer thread. */
+ wake_up_interruptible(&cfspi->wait);
+ }
+ spin_unlock_irqrestore(&cfspi->lock, flags);
+
+ /* Send flow off if number of bytes is above high water mark */
+ if (!cfspi->flow_off_sent &&
+ cfspi->qhead.qlen > cfspi->qd_high_mark &&
+ cfspi->cfdev.flowctrl) {
+ cfspi->flow_off_sent = 1;
+ cfspi->cfdev.flowctrl(cfspi->ndev, 0);
+ }
+
+ return 0;
+}
+
+int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len)
+{
+ u8 *src = buf;
+
+ caif_assert(buf != NULL);
+
+ do {
+ int res;
+ struct sk_buff *skb = NULL;
+ int spad = 0;
+ int epad = 0;
+ u8 *dst = NULL;
+ int pkt_len = 0;
+
+ /*
+ * Compute head offset i.e. number of bytes added to
+ * get the start of the payload aligned.
+ */
+ if (spi_down_head_align) {
+ spad = 1 + *src;
+ src += spad;
+ }
+
+ /* Read length of CAIF frame (little endian). */
+ pkt_len = *src;
+ pkt_len |= ((*(src+1)) << 8) & 0xFF00;
+ pkt_len += 2; /* Add FCS fields. */
+
+ /* Get a suitable caif packet and copy in data. */
+
+ skb = netdev_alloc_skb(cfspi->ndev, pkt_len + 1);
+ caif_assert(skb != NULL);
+
+ dst = skb_put(skb, pkt_len);
+ memcpy(dst, src, pkt_len);
+ src += pkt_len;
+
+ skb->protocol = htons(ETH_P_CAIF);
+ skb_reset_mac_header(skb);
+ skb->dev = cfspi->ndev;
+
+ /*
+ * Push received packet up the stack.
+ */
+ if (!spi_loop)
+ res = netif_rx_ni(skb);
+ else
+ res = cfspi_xmit(skb, cfspi->ndev);
+
+ if (!res) {
+ cfspi->ndev->stats.rx_packets++;
+ cfspi->ndev->stats.rx_bytes += pkt_len;
+ } else
+ cfspi->ndev->stats.rx_dropped++;
+
+ /*
+ * Compute tail offset i.e. number of bytes added to
+ * get the complete CAIF frame aligned.
+ */
+ epad = (pkt_len + spad) & spi_down_tail_align;
+ src += epad;
+ } while ((src - buf) < len);
+
+ return src - buf;
+}
+
+static int cfspi_open(struct net_device *dev)
+{
+ netif_wake_queue(dev);
+ return 0;
+}
+
+static int cfspi_close(struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ return 0;
+}
+static const struct net_device_ops cfspi_ops = {
+ .ndo_open = cfspi_open,
+ .ndo_stop = cfspi_close,
+ .ndo_start_xmit = cfspi_xmit
+};
+
+static void cfspi_setup(struct net_device *dev)
+{
+ struct cfspi *cfspi = netdev_priv(dev);
+ dev->features = 0;
+ dev->netdev_ops = &cfspi_ops;
+ dev->type = ARPHRD_CAIF;
+ dev->flags = IFF_NOARP | IFF_POINTOPOINT;
+ dev->tx_queue_len = 0;
+ dev->mtu = SPI_MAX_PAYLOAD_SIZE;
+ dev->destructor = free_netdev;
+ skb_queue_head_init(&cfspi->qhead);
+ skb_queue_head_init(&cfspi->chead);
+ cfspi->cfdev.link_select = CAIF_LINK_HIGH_BANDW;
+ cfspi->cfdev.use_frag = false;
+ cfspi->cfdev.use_stx = false;
+ cfspi->cfdev.use_fcs = false;
+ cfspi->ndev = dev;
+}
+
+int cfspi_spi_probe(struct platform_device *pdev)
+{
+ struct cfspi *cfspi = NULL;
+ struct net_device *ndev;
+ struct cfspi_dev *dev;
+ int res;
+ dev = (struct cfspi_dev *)pdev->dev.platform_data;
+
+ ndev = alloc_netdev(sizeof(struct cfspi),
+ "cfspi%d", cfspi_setup);
+ if (!dev)
+ return -ENODEV;
+
+ cfspi = netdev_priv(ndev);
+ netif_stop_queue(ndev);
+ cfspi->ndev = ndev;
+ cfspi->pdev = pdev;
+
+ /* Set flow info */
+ cfspi->flow_off_sent = 0;
+ cfspi->qd_low_mark = LOW_WATER_MARK;
+ cfspi->qd_high_mark = HIGH_WATER_MARK;
+
+ /* Assign the SPI device. */
+ cfspi->dev = dev;
+ /* Assign the device ifc to this SPI interface. */
+ dev->ifc = &cfspi->ifc;
+
+ /* Allocate DMA buffers. */
+ cfspi->xfer.va_tx = dma_alloc(&cfspi->xfer.pa_tx);
+ if (!cfspi->xfer.va_tx) {
+ printk(KERN_WARNING
+ "CFSPI: failed to allocate dma TX buffer.\n");
+ res = -ENODEV;
+ goto err_dma_alloc_tx;
+ }
+
+ cfspi->xfer.va_rx = dma_alloc(&cfspi->xfer.pa_rx);
+
+ if (!cfspi->xfer.va_rx) {
+ printk(KERN_WARNING
+ "CFSPI: failed to allocate dma TX buffer.\n");
+ res = -ENODEV;
+ goto err_dma_alloc_rx;
+ }
+
+ /* Initialize the work queue. */
+ INIT_WORK(&cfspi->work, cfspi_xfer);
+
+ /* Initialize spin locks. */
+ spin_lock_init(&cfspi->lock);
+
+ /* Initialize flow control state. */
+ cfspi->flow_stop = false;
+
+ /* Initialize wait queue. */
+ init_waitqueue_head(&cfspi->wait);
+
+ /* Create work thread. */
+ cfspi->wq = create_singlethread_workqueue(dev->name);
+ if (!cfspi->wq) {
+ printk(KERN_WARNING "CFSPI: failed to create work queue.\n");
+ res = -ENODEV;
+ goto err_create_wq;
+ }
+
+ /* Initialize work queue. */
+ init_completion(&cfspi->comp);
+
+ /* Create debugfs entries. */
+ dev_debugfs_add(cfspi);
+
+ /* Set up the ifc. */
+ cfspi->ifc.ss_cb = cfspi_ss_cb;
+ cfspi->ifc.xfer_done_cb = cfspi_xfer_done_cb;
+ cfspi->ifc.priv = cfspi;
+
+ /* Add CAIF SPI device to list. */
+ spin_lock(&cfspi_list_lock);
+ list_add_tail(&cfspi->list, &cfspi_list);
+ spin_unlock(&cfspi_list_lock);
+
+ /* Schedule the work queue. */
+ queue_work(cfspi->wq, &cfspi->work);
+
+ /* Register network device. */
+ res = register_netdev(ndev);
+ if (res) {
+ printk(KERN_ERR "CFSPI: Reg. error: %d.\n", res);
+ goto err_net_reg;
+ }
+ return res;
+
+ err_net_reg:
+ dev_debugfs_rem(cfspi);
+ set_bit(SPI_TERMINATE, &cfspi->state);
+ wake_up_interruptible(&cfspi->wait);
+ destroy_workqueue(cfspi->wq);
+ err_create_wq:
+ dma_free(cfspi->xfer.va_rx, cfspi->xfer.pa_rx);
+ err_dma_alloc_rx:
+ dma_free(cfspi->xfer.va_tx, cfspi->xfer.pa_tx);
+ err_dma_alloc_tx:
+ free_netdev(ndev);
+
+ return res;
+}
+
+int cfspi_spi_remove(struct platform_device *pdev)
+{
+ struct list_head *list_node;
+ struct list_head *n;
+ struct cfspi *cfspi = NULL;
+ struct cfspi_dev *dev;
+
+ dev = (struct cfspi_dev *)pdev->dev.platform_data;
+ spin_lock(&cfspi_list_lock);
+ list_for_each_safe(list_node, n, &cfspi_list) {
+ cfspi = list_entry(list_node, struct cfspi, list);
+ /* Find the corresponding device. */
+ if (cfspi->dev == dev) {
+ /* Remove from list. */
+ list_del(list_node);
+ /* Free DMA buffers. */
+ dma_free(cfspi->xfer.va_rx, cfspi->xfer.pa_rx);
+ dma_free(cfspi->xfer.va_tx, cfspi->xfer.pa_tx);
+ set_bit(SPI_TERMINATE, &cfspi->state);
+ wake_up_interruptible(&cfspi->wait);
+ destroy_workqueue(cfspi->wq);
+ /* Destroy debugfs directory and files. */
+ dev_debugfs_rem(cfspi);
+ unregister_netdev(cfspi->ndev);
+ spin_unlock(&cfspi_list_lock);
+ return 0;
+ }
+ }
+ spin_unlock(&cfspi_list_lock);
+ return -ENODEV;
+}
+
+static void __exit cfspi_exit_module(void)
+{
+ struct list_head *list_node;
+ struct list_head *n;
+ struct cfspi *cfspi = NULL;
+
+ list_for_each_safe(list_node, n, &cfspi_list) {
+ cfspi = list_entry(list_node, struct cfspi, list);
+ platform_device_unregister(cfspi->pdev);
+ }
+
+ /* Destroy sysfs files. */
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_up_head_align);
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_up_tail_align);
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_down_head_align);
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_down_tail_align);
+ driver_remove_file(&cfspi_spi_driver.driver, &driver_attr_frame_align);
+ /* Unregister platform driver. */
+ platform_driver_unregister(&cfspi_spi_driver);
+ /* Destroy debugfs root directory. */
+ driver_debugfs_remove();
+}
+
+static int __init cfspi_init_module(void)
+{
+ int result;
+
+ /* Initialize spin lock. */
+ spin_lock_init(&cfspi_list_lock);
+
+ /* Register platform driver. */
+ result = platform_driver_register(&cfspi_spi_driver);
+ if (result) {
+ printk(KERN_ERR "Could not register platform SPI driver.\n");
+ goto err_dev_register;
+ }
+
+ /* Create sysfs files. */
+ result =
+ driver_create_file(&cfspi_spi_driver.driver,
+ &driver_attr_up_head_align);
+ if (result) {
+ printk(KERN_ERR "Sysfs creation failed 1.\n");
+ goto err_create_up_head_align;
+ }
+
+ result =
+ driver_create_file(&cfspi_spi_driver.driver,
+ &driver_attr_up_tail_align);
+ if (result) {
+ printk(KERN_ERR "Sysfs creation failed 2.\n");
+ goto err_create_up_tail_align;
+ }
+
+ result =
+ driver_create_file(&cfspi_spi_driver.driver,
+ &driver_attr_down_head_align);
+ if (result) {
+ printk(KERN_ERR "Sysfs creation failed 3.\n");
+ goto err_create_down_head_align;
+ }
+
+ result =
+ driver_create_file(&cfspi_spi_driver.driver,
+ &driver_attr_down_tail_align);
+ if (result) {
+ printk(KERN_ERR "Sysfs creation failed 4.\n");
+ goto err_create_down_tail_align;
+ }
+
+ result =
+ driver_create_file(&cfspi_spi_driver.driver,
+ &driver_attr_frame_align);
+ if (result) {
+ printk(KERN_ERR "Sysfs creation failed 5.\n");
+ goto err_create_frame_align;
+ }
+ driver_debugfs_create();
+ return result;
+
+ err_create_frame_align:
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_down_tail_align);
+ err_create_down_tail_align:
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_down_head_align);
+ err_create_down_head_align:
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_up_tail_align);
+ err_create_up_tail_align:
+ driver_remove_file(&cfspi_spi_driver.driver,
+ &driver_attr_up_head_align);
+ err_create_up_head_align:
+ err_dev_register:
+ return result;
+}
+
+module_init(cfspi_init_module);
+module_exit(cfspi_exit_module);
diff --git a/drivers/net/caif/caif_spi_slave.c b/drivers/net/caif/caif_spi_slave.c
new file mode 100644
index 0000000..077ccf8
--- /dev/null
+++ b/drivers/net/caif/caif_spi_slave.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
+ * Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/semaphore.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/debugfs.h>
+#include <net/caif/caif_spi.h>
+
+#ifndef CONFIG_CAIF_SPI_SYNC
+#define SPI_DATA_POS SPI_CMD_SZ
+static inline int forward_to_spi_cmd(struct cfspi *cfspi)
+{
+ return cfspi->rx_cpck_len;
+}
+#else
+#define SPI_DATA_POS 0
+static inline int forward_to_spi_cmd(struct cfspi *cfspi)
+{
+ return 0;
+}
+#endif
+
+int spi_frm_align = 2;
+int spi_up_head_align = 1;
+int spi_up_tail_align;
+int spi_down_head_align = 3;
+int spi_down_tail_align = 1;
+
+#ifdef CONFIG_DEBUG_FS
+static inline void debugfs_store_prev(struct cfspi *cfspi)
+{
+ /* Store previous command for debugging reasons.*/
+ cfspi->pcmd = cfspi->cmd;
+ /* Store previous transfer. */
+ cfspi->tx_ppck_len = cfspi->tx_cpck_len;
+ cfspi->rx_ppck_len = cfspi->rx_cpck_len;
+}
+#else
+static inline void debugfs_store_prev(struct cfspi *cfspi)
+{
+}
+#endif
+
+void cfspi_xfer(struct work_struct *work)
+{
+ struct cfspi *cfspi;
+ u8 *ptr = NULL;
+ unsigned long flags;
+ int ret;
+ cfspi = container_of(work, struct cfspi, work);
+
+ /* Initialize state. */
+ cfspi->cmd = SPI_CMD_EOT;
+
+ for (;;) {
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_WAITING);
+
+ /* Wait for master talk or transmit event. */
+ wait_event_interruptible(cfspi->wait,
+ test_bit(SPI_XFER, &cfspi->state) ||
+ test_bit(SPI_TERMINATE, &cfspi->state));
+
+ if (test_bit(SPI_TERMINATE, &cfspi->state))
+ return;
+
+#if CFSPI_DBG_PREFILL
+ /* Prefill buffers for easier debugging. */
+ memset(cfspi->xfer.va_tx, 0xFF, SPI_DMA_BUF_LEN);
+ memset(cfspi->xfer.va_rx, 0xFF, SPI_DMA_BUF_LEN);
+#endif /* CFSPI_DBG_PREFILL */
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_AWAKE);
+
+ /* Check whether we have a committed frame. */
+ if (cfspi->tx_cpck_len) {
+ int len;
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_FETCH_PKT);
+
+ /* Copy commited SPI frames after the SPI indication. */
+ ptr = (u8 *) cfspi->xfer.va_tx;
+ ptr += SPI_IND_SZ;
+ len = cfspi_xmitfrm(cfspi, ptr, cfspi->tx_cpck_len);
+ WARN_ON(len != cfspi->tx_cpck_len);
+ }
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_GET_NEXT);
+
+ /* Get length of next frame to commit. */
+ cfspi->tx_npck_len = cfspi_xmitlen(cfspi);
+
+ WARN_ON(cfspi->tx_npck_len > SPI_DMA_BUF_LEN);
+
+ /*
+ * Add indication and length at the beginning of the frame,
+ * using little endian.
+ */
+ ptr = (u8 *) cfspi->xfer.va_tx;
+ *ptr++ = SPI_CMD_IND;
+ *ptr++ = (SPI_CMD_IND & 0xFF00) >> 8;
+ *ptr++ = cfspi->tx_npck_len & 0x00FF;
+ *ptr++ = (cfspi->tx_npck_len & 0xFF00) >> 8;
+
+ /* Calculate length of DMAs. */
+ cfspi->xfer.tx_dma_len = cfspi->tx_cpck_len + SPI_IND_SZ;
+ cfspi->xfer.rx_dma_len = cfspi->rx_cpck_len + SPI_CMD_SZ;
+
+ /* Add SPI TX frame alignment padding, if necessary. */
+ if (cfspi->tx_cpck_len &&
+ (cfspi->xfer.tx_dma_len % spi_frm_align)) {
+
+ cfspi->xfer.tx_dma_len += spi_frm_align -
+ (cfspi->xfer.tx_dma_len % spi_frm_align);
+ }
+
+ /* Add SPI RX frame alignment padding, if necessary. */
+ if (cfspi->rx_cpck_len &&
+ (cfspi->xfer.rx_dma_len % spi_frm_align)) {
+
+ cfspi->xfer.rx_dma_len += spi_frm_align -
+ (cfspi->xfer.rx_dma_len % spi_frm_align);
+ }
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_INIT_XFER);
+
+ /* Start transfer. */
+ ret = cfspi->dev->init_xfer(&cfspi->xfer, cfspi->dev);
+ WARN_ON(ret);
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_ACTIVE);
+
+ /*
+ * TODO: We might be able to make an assumption if this is the
+ * first loop. Make sure that minimum toggle time is respected.
+ */
+ udelay(MIN_TRANSITION_TIME_USEC);
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_SIG_ACTIVE);
+
+ /* Signal that we are ready to recieve data. */
+ cfspi->dev->sig_xfer(true, cfspi->dev);
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_XFER_DONE);
+
+ /* Wait for transfer completion. */
+ wait_for_completion(&cfspi->comp);
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_XFER_DONE);
+
+ if (cfspi->cmd == SPI_CMD_EOT) {
+ /*
+ * Clear the master talk bit. A xfer is always at
+ * least two bursts.
+ */
+ clear_bit(SPI_SS_ON, &cfspi->state);
+ }
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_INACTIVE);
+
+ /* Make sure that the minimum toggle time is respected. */
+ if (SPI_XFER_TIME_USEC(cfspi->xfer.tx_dma_len,
+ cfspi->dev->clk_mhz) <
+ MIN_TRANSITION_TIME_USEC) {
+
+ udelay(MIN_TRANSITION_TIME_USEC -
+ SPI_XFER_TIME_USEC
+ (cfspi->xfer.tx_dma_len, cfspi->dev->clk_mhz));
+ }
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_SIG_INACTIVE);
+
+ /* De-assert transfer signal. */
+ cfspi->dev->sig_xfer(false, cfspi->dev);
+
+ /* Check whether we received a CAIF packet. */
+ if (cfspi->rx_cpck_len) {
+ int len;
+
+ cfspi_dbg_state(cfspi, CFSPI_STATE_DELIVER_PKT);
+
+ /* Parse SPI frame. */
+ ptr = ((u8 *)(cfspi->xfer.va_rx + SPI_DATA_POS));
+
+ len = cfspi_rxfrm(cfspi, ptr, cfspi->rx_cpck_len);
+ WARN_ON(len != cfspi->rx_cpck_len);
+ }
+
+ /* Check the next SPI command and length. */
+ ptr = (u8 *) cfspi->xfer.va_rx;
+
+ ptr += forward_to_spi_cmd(cfspi);
+
+ cfspi->cmd = *ptr++;
+ cfspi->cmd |= ((*ptr++) << 8) & 0xFF00;
+ cfspi->rx_npck_len = *ptr++;
+ cfspi->rx_npck_len |= ((*ptr++) << 8) & 0xFF00;
+
+ WARN_ON(cfspi->rx_npck_len > SPI_DMA_BUF_LEN);
+ WARN_ON(cfspi->cmd > SPI_CMD_EOT);
+
+ debugfs_store_prev(cfspi);
+
+ /* Check whether the master issued an EOT command. */
+ if (cfspi->cmd == SPI_CMD_EOT) {
+ /* Reset state. */
+ cfspi->tx_cpck_len = 0;
+ cfspi->rx_cpck_len = 0;
+ } else {
+ /* Update state. */
+ cfspi->tx_cpck_len = cfspi->tx_npck_len;
+ cfspi->rx_cpck_len = cfspi->rx_npck_len;
+ }
+
+ /*
+ * Check whether we need to clear the xfer bit.
+ * Spin lock needed for packet insertion.
+ * Test and clear of different bits
+ * are not supported.
+ */
+ spin_lock_irqsave(&cfspi->lock, flags);
+ if (cfspi->cmd == SPI_CMD_EOT && !cfspi_xmitlen(cfspi)
+ && !test_bit(SPI_SS_ON, &cfspi->state))
+ clear_bit(SPI_XFER, &cfspi->state);
+
+ spin_unlock_irqrestore(&cfspi->lock, flags);
+ }
+}
+
+struct platform_driver cfspi_spi_driver = {
+ .probe = cfspi_spi_probe,
+ .remove = cfspi_spi_remove,
+ .driver = {
+ .name = "cfspi_sspi",
+ .owner = THIS_MODULE,
+ },
+};
diff --git a/include/net/caif/caif_spi.h b/include/net/caif/caif_spi.h
new file mode 100644
index 0000000..ce4570d
--- /dev/null
+++ b/include/net/caif/caif_spi.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CAIF_SPI_H_
+#define CAIF_SPI_H_
+
+#include <net/caif/caif_device.h>
+
+#define SPI_CMD_WR 0x00
+#define SPI_CMD_RD 0x01
+#define SPI_CMD_EOT 0x02
+#define SPI_CMD_IND 0x04
+
+#define SPI_DMA_BUF_LEN 8192
+
+#define WL_SZ 2 /* 16 bits. */
+#define SPI_CMD_SZ 4 /* 32 bits. */
+#define SPI_IND_SZ 4 /* 32 bits. */
+
+#define SPI_XFER 0
+#define SPI_SS_ON 1
+#define SPI_SS_OFF 2
+#define SPI_TERMINATE 3
+
+/* Minimum time between different levels is 50 microseconds. */
+#define MIN_TRANSITION_TIME_USEC 50
+
+/* Defines for calculating duration of SPI transfers for a particular
+ * number of bytes.
+ */
+#define SPI_MASTER_CLK_MHZ 13
+#define SPI_XFER_TIME_USEC(bytes, clk) (((bytes) * 8) / clk)
+
+/* Normally this should be aligned on the modem in order to benefit from full
+ * duplex transfers. However a size of 8188 provokes errors when running with
+ * the modem. These errors occur when packet sizes approaches 4 kB of data.
+ */
+#define CAIF_MAX_SPI_FRAME 4092
+
+/* Maximum number of uplink CAIF frames that can reside in the same SPI frame.
+ * This number should correspond with the modem setting. The application side
+ * CAIF accepts any number of embedded downlink CAIF frames.
+ */
+#define CAIF_MAX_SPI_PKTS 9
+
+/* Decides if SPI buffers should be prefilled with 0xFF pattern for easier
+ * debugging. Both TX and RX buffers will be filled before the transfer.
+ */
+#define CFSPI_DBG_PREFILL 0
+
+/* Structure describing a SPI transfer. */
+struct cfspi_xfer {
+ u16 tx_dma_len;
+ u16 rx_dma_len;
+ void *va_tx;
+ dma_addr_t pa_tx;
+ void *va_rx;
+ dma_addr_t pa_rx;
+};
+
+/* Structure implemented by the SPI interface. */
+struct cfspi_ifc {
+ void (*ss_cb) (bool assert, struct cfspi_ifc *ifc);
+ void (*xfer_done_cb) (struct cfspi_ifc *ifc);
+ void *priv;
+};
+
+/* Structure implemented by SPI clients. */
+struct cfspi_dev {
+ int (*init_xfer) (struct cfspi_xfer *xfer, struct cfspi_dev *dev);
+ void (*sig_xfer) (bool xfer, struct cfspi_dev *dev);
+ struct cfspi_ifc *ifc;
+ char *name;
+ u32 clk_mhz;
+ void *priv;
+};
+
+/* Enumeration describing the CAIF SPI state. */
+enum cfspi_state {
+ CFSPI_STATE_WAITING = 0,
+ CFSPI_STATE_AWAKE,
+ CFSPI_STATE_FETCH_PKT,
+ CFSPI_STATE_GET_NEXT,
+ CFSPI_STATE_INIT_XFER,
+ CFSPI_STATE_WAIT_ACTIVE,
+ CFSPI_STATE_SIG_ACTIVE,
+ CFSPI_STATE_WAIT_XFER_DONE,
+ CFSPI_STATE_XFER_DONE,
+ CFSPI_STATE_WAIT_INACTIVE,
+ CFSPI_STATE_SIG_INACTIVE,
+ CFSPI_STATE_DELIVER_PKT,
+ CFSPI_STATE_MAX,
+};
+
+/* Structure implemented by SPI physical interfaces. */
+struct cfspi {
+ struct caif_dev_common cfdev;
+ struct net_device *ndev;
+ struct platform_device *pdev;
+ struct sk_buff_head qhead;
+ struct sk_buff_head chead;
+ u16 cmd;
+ u16 tx_cpck_len;
+ u16 tx_npck_len;
+ u16 rx_cpck_len;
+ u16 rx_npck_len;
+ struct cfspi_ifc ifc;
+ struct cfspi_xfer xfer;
+ struct cfspi_dev *dev;
+ unsigned long state;
+ struct work_struct work;
+ struct workqueue_struct *wq;
+ struct list_head list;
+ int flow_off_sent;
+ u32 qd_low_mark;
+ u32 qd_high_mark;
+ struct completion comp;
+ wait_queue_head_t wait;
+ spinlock_t lock;
+ bool flow_stop;
+#ifdef CONFIG_DEBUG_FS
+ enum cfspi_state dbg_state;
+ u16 pcmd;
+ u16 tx_ppck_len;
+ u16 rx_ppck_len;
+ struct dentry *dbgfs_dir;
+ struct dentry *dbgfs_state;
+ struct dentry *dbgfs_frame;
+#endif /* CONFIG_DEBUG_FS */
+};
+
+extern int spi_frm_align;
+extern int spi_up_head_align;
+extern int spi_up_tail_align;
+extern int spi_down_head_align;
+extern int spi_down_tail_align;
+extern struct platform_driver cfspi_spi_driver;
+
+void cfspi_dbg_state(struct cfspi *cfspi, int state);
+int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len);
+int cfspi_xmitlen(struct cfspi *cfspi);
+int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len);
+int cfspi_spi_remove(struct platform_device *pdev);
+int cfspi_spi_probe(struct platform_device *pdev);
+int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len);
+int cfspi_xmitlen(struct cfspi *cfspi);
+int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len);
+void cfspi_xfer(struct work_struct *work);
+
+#endif /* CAIF_SPI_H_ */
--
1.6.3.3
^ permalink raw reply related
* Re: [Bugme-new] [Bug 16268] New: kernel oops when rmmod the tcp_diag modules
From: David Miller @ 2010-06-22 21:21 UTC (permalink / raw)
To: akpm; +Cc: netdev, bugzilla-daemon, bugme-daemon, lyw
In-Reply-To: <20100622141232.4b8f1d4a.akpm@linux-foundation.org>
From: Andrew Morton <akpm@linux-foundation.org>
Date: Tue, 22 Jun 2010 14:12:32 -0700
> What is "ss"? Something which triggers a load of kernel modules,
> presumably. Which ones?
'ss' is the tool which dumps sockets using netlink
^ permalink raw reply
* Re: [Bugme-new] [Bug 16268] New: kernel oops when rmmod the tcp_diag modules
From: Andrew Morton @ 2010-06-22 21:12 UTC (permalink / raw)
To: netdev; +Cc: bugzilla-daemon, bugme-daemon, lyw
In-Reply-To: <bug-16268-10286@https.bugzilla.kernel.org/>
(switched to email. Please respond via emailed reply-to-all, not via the
bugzilla web interface).
On Tue, 22 Jun 2010 00:43:37 GMT
bugzilla-daemon@bugzilla.kernel.org wrote:
> https://bugzilla.kernel.org/show_bug.cgi?id=16268
>
> Summary: kernel oops when rmmod the tcp_diag modules
> Product: Networking
> Version: 2.5
> Kernel Version: 2.6.35-rc3
> Platform: All
> OS/Version: Linux
> Tree: Mainline
> Status: NEW
> Severity: high
> Priority: P1
> Component: IPV4
> AssignedTo: shemminger@linux-foundation.org
> ReportedBy: lyw@cn.fujitsu.com
> Regression: No
>
>
> I found a crash problem use following scripts and steps
>
> #cat run_ss.sh
> while [ 1 ]
> do
> ss -a
> done
>
> #cat rmmod.sh
> while [ 1 ]
> do
> rmmod -f tcp_diag >/dev/null 2>&1
> rmmod -f inet_diag >/dev/null 2>&1
> done
>
> step1:
> # sh run_sh.sh
> step2:
> # sh rmmod.sh
I assume the rmmod script runs in pararallel with run_ss.sh.
What is "ss"? Something which triggers a load of kernel modules,
presumably. Which ones?
> After step2, the kernel oopsed.
yeah, that was a pretty nasty test ;)
> ========================================================
> Jun 22 08:44:33 RHEL6Beta kernel: Disabling lock debugging due to kernel taint
> Jun 22 08:44:33 RHEL6Beta kernel: BUG: unable to handle kernel NULL pointer
> dereference at (null)
> Jun 22 08:44:33 RHEL6Beta kernel: IP: [<f982d140>] 0xf982d140
> Jun 22 08:44:33 RHEL6Beta kernel: *pdpt = 0000000033af2001 *pde =
> 000000007d9cf067
> Jun 22 08:44:33 RHEL6Beta kernel: Oops: 0002 [#1] SMP
> Jun 22 08:44:33 RHEL6Beta kernel: last sysfs file:
> /sys/module/inet_diag/initstate
> Jun 22 08:44:33 RHEL6Beta kernel: Modules linked in: tcp_diag inet_diag
> p4_clockmod ipv6 dm_mirror dm_region_hash dm_log dm_mod snd_intel8x0
> snd_ac97_codec ac97_bus snd_seq snd_mpu401 snd_mpu401_uart snd_pcm snd_rawmidi
> snd_seq_device snd_timer snd r8169 8139too ppdev 8139cp soundcore mii
> parport_pc floppy sr_mod cdrom parport ns558 gameport sg iTCO_wdt
> iTCO_vendor_support snd_page_alloc pcspkr i2c_i801 ext3 jbd mbcache sd_mod
> crc_t10dif ata_generic pata_acpi ata_piix i915 drm_kms_helper drm i2c_algo_bit
> i2c_core video output [last unloaded: inet_diag]
> Jun 22 08:44:33 RHEL6Beta kernel:
> Jun 22 08:44:33 RHEL6Beta kernel: Pid: 27392, comm: ss Tainted: G R
> 2.6.35-rc3 #1 F61MV/AcerPower S100
> Jun 22 08:44:33 RHEL6Beta kernel: EIP: 0060:[<f982d140>] EFLAGS: 00010282 CPU:
> 0
> Jun 22 08:44:33 RHEL6Beta kernel: EIP is at 0xf982d140
> Jun 22 08:44:33 RHEL6Beta kernel: EAX: 00000000 EBX: 00000012 ECX: 00000001
> EDX: 00000000
> Jun 22 08:44:33 RHEL6Beta kernel: ESI: f4217b80 EDI: f4239f00 EBP: f4239f00
> ESP: f3b07bcc
> Jun 22 08:44:33 RHEL6Beta kernel: DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
> Jun 22 08:44:33 RHEL6Beta kernel: Process ss (pid: 27392, ti=f3b06000
> task=f4152a50 task.ti=f3b06000)
> Jun 22 08:44:33 RHEL6Beta kernel: Stack:
> Jun 22 08:44:33 RHEL6Beta kernel: 00000001 f982e6b0 00000010 00000004 00000012
> f5a74400 f982debb c064256f
> Jun 22 08:44:33 RHEL6Beta kernel: <0> 0196b67e 00000014 c09fb3e0 90e7b493
> f3b07c38 f3b07c38 f4217b80 00000344
> Jun 22 08:44:33 RHEL6Beta kernel: <0> f4239f00 00000246 f3b07d80 00000246
> 00021453 000000d0 000000d0 c0746d84
> Jun 22 08:44:33 RHEL6Beta kernel: Call Trace:
> Jun 22 08:44:33 RHEL6Beta kernel: [<c064256f>] ?
> mix_pool_bytes_extract+0x4f/0x150
> Jun 22 08:44:33 RHEL6Beta kernel: [<c0746d84>] ? __alloc_skb+0x54/0x100
> Jun 22 08:44:33 RHEL6Beta kernel: [<c0746d84>] ? __alloc_skb+0x54/0x100
> Jun 22 08:44:33 RHEL6Beta kernel: [<c074333c>] ? sock_rmalloc+0x4c/0x90
> Jun 22 08:44:33 RHEL6Beta kernel: [<c076d6e3>] ? netlink_dump+0x53/0x1b0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c04f529e>] ?
> kmem_cache_alloc_notrace+0x9e/0xb0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c076f2e0>] ? netlink_dump_start+0x130/0x1b0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c076f18e>] ? netlink_rcv_skb+0x7e/0xa0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c076eab0>] ? netlink_unicast+0x250/0x280
> Jun 22 08:44:33 RHEL6Beta kernel: [<c076f81c>] ? netlink_sendmsg+0x1bc/0x2a0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c0740982>] ? sock_sendmsg+0xd2/0x110
> Jun 22 08:44:33 RHEL6Beta kernel: [<c04374bd>] ? kmap_atomic_prot+0x11d/0x150
> Jun 22 08:44:33 RHEL6Beta kernel: [<c043750c>] ? kmap_atomic+0x1c/0x30
> Jun 22 08:44:33 RHEL6Beta kernel: [<c0437357>] ? kunmap_atomic+0x67/0x80
> Jun 22 08:44:33 RHEL6Beta kernel: [<c04ca242>] ?
> get_page_from_freelist+0x242/0x4d0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c05b8fa5>] ? _copy_from_user+0x35/0x120
> Jun 22 08:44:33 RHEL6Beta kernel: [<c05b8fa5>] ? _copy_from_user+0x35/0x120
> Jun 22 08:44:33 RHEL6Beta kernel: [<c07418e3>] ? sys_sendmsg+0x163/0x260
> Jun 22 08:44:33 RHEL6Beta kernel: [<c04f529e>] ?
> kmem_cache_alloc_notrace+0x9e/0xb0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c05787ed>] ?
> selinux_sk_alloc_security+0x6d/0xe0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c04f53ac>] ? kmem_cache_alloc+0xfc/0x120
> Jun 22 08:44:33 RHEL6Beta kernel: [<c074303e>] ? sock_init_data+0xae/0x1d0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c046df2d>] ? creds_are_invalid+0x1d/0x40
> Jun 22 08:44:33 RHEL6Beta kernel: [<c0502ea3>] ? get_empty_filp+0x123/0x1c0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c0502fc7>] ? alloc_file+0x87/0xb0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c073f6f6>] ? sock_alloc_file+0xa6/0x120
> Jun 22 08:44:33 RHEL6Beta kernel: [<c04ffeb6>] ? fd_install+0x26/0x50
> Jun 22 08:44:33 RHEL6Beta kernel: [<c073f78b>] ? sock_map_fd+0x1b/0x30
> Jun 22 08:44:33 RHEL6Beta kernel: [<c0741fcd>] ? sys_socketcall+0xed/0x2c0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c0409fdf>] ? sysenter_do_call+0x12/0x28
> Jun 22 08:44:33 RHEL6Beta kernel: Code: 00 00 00 00 00 00 00 00 00 00 00 00 00
> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> 00 00 00 00 <00> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> Jun 22 08:44:33 RHEL6Beta kernel: EIP: [<f982d140>] 0xf982d140 SS:ESP
> 0068:f3b07bcc
> Jun 22 08:44:33 RHEL6Beta kernel: CR2: 0000000000000000
> Jun 22 08:44:33 RHEL6Beta kernel: ---[ end trace 443475da32e0e7d3 ]---
> Jun 22 08:44:34 RHEL6Beta kernel: BUG: unable to handle kernel paging request
> at 0135b004
> Jun 22 08:44:34 RHEL6Beta kernel: IP: [<c047e34e>] module_put+0x1e/0x90
> Jun 22 08:44:34 RHEL6Beta kernel: *pdpt = 0000000000ab8001 *pde =
> 0000000000000000
> Jun 22 08:44:34 RHEL6Beta kernel: Oops: 0002 [#2] SMP
> Jun 22 08:44:34 RHEL6Beta kernel: last sysfs file:
> /sys/module/inet_diag/initstate
> Jun 22 08:44:34 RHEL6Beta kernel: Modules linked in: p4_clockmod ipv6 dm_mirror
> dm_region_hash dm_log dm_mod snd_intel8x0 snd_ac97_codec ac97_bus snd_seq
> snd_mpu401 snd_mpu401_uart snd_pcm snd_rawmidi snd_seq_device snd_timer snd
> r8169 8139too ppdev 8139cp soundcore mii parport_pc floppy sr_mod cdrom parport
> ns558 gameport sg iTCO_wdt iTCO_vendor_support snd_page_alloc pcspkr i2c_i801
> ext3 jbd mbcache sd_mod crc_t10dif ata_generic pata_acpi ata_piix i915
> drm_kms_helper drm i2c_algo_bit i2c_core video output [last unloaded:
> inet_diag]
> Jun 22 08:44:34 RHEL6Beta kernel:
> Jun 22 08:44:34 RHEL6Beta kernel: Pid: 27392, comm: ss Tainted: G R D
> 2.6.35-rc3 #1 F61MV/AcerPower S100
> Jun 22 08:44:34 RHEL6Beta kernel: EIP: 0060:[<c047e34e>] EFLAGS: 00010286 CPU:
> 0
> Jun 22 08:44:34 RHEL6Beta kernel: EIP is at module_put+0x1e/0x90
> Jun 22 08:44:34 RHEL6Beta kernel: EAX: 00000000 EBX: f982e7a0 ECX: f3b07a00
> EDX: 00000001
> Jun 22 08:44:34 RHEL6Beta kernel: ESI: f5486e00 EDI: f4095ee8 EBP: f5486e1c
> ESP: f3b079e8
> Jun 22 08:44:34 RHEL6Beta kernel: DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
> Jun 22 08:44:34 RHEL6Beta kernel: Process ss (pid: 27392, ti=f3b06000
> task=f4152a50 task.ti=f3b06000)
> Jun 22 08:44:34 RHEL6Beta kernel: Stack:
> Jun 22 08:44:34 RHEL6Beta kernel: f4095e00 f5486e00 f4095ee8 f5486e1c c076e568
> 00000000 c0b641a0 00006b00
> Jun 22 08:44:34 RHEL6Beta kernel: <0> 00000004 f5486e00 00000000 f57c8cf0
> c073f86a 00000000 f5ada600 00000008
> Jun 22 08:44:34 RHEL6Beta kernel: <0> c073f8df f5486e1c c05032ab 00000003
> 00000000 00000000 f7022580 f57c8cf0
> Jun 22 08:44:34 RHEL6Beta kernel: Call Trace:
> Jun 22 08:44:34 RHEL6Beta kernel: [<c076e568>] ? netlink_release+0xe8/0x210
> Jun 22 08:44:34 RHEL6Beta kernel: [<c073f86a>] ? sock_release+0x1a/0x80
> Jun 22 08:44:34 RHEL6Beta kernel: [<c073f8df>] ? sock_close+0xf/0x30
> Jun 22 08:44:34 RHEL6Beta kernel: [<c05032ab>] ? fput+0x10b/0x220
> Jun 22 08:44:34 RHEL6Beta kernel: [<c04fff67>] ? filp_close+0x47/0x80
> Jun 22 08:44:34 RHEL6Beta kernel: [<c044efda>] ? put_files_struct+0x5a/0xb0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c044fbdf>] ? do_exit+0x13f/0x750
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0801d45>] ? apic_timer_interrupt+0x31/0x38
> Jun 22 08:44:34 RHEL6Beta kernel: [<c044e531>] ? kmsg_dump+0x71/0x120
> Jun 22 08:44:34 RHEL6Beta kernel: [<c07ff121>] ? printk+0x17/0x1e
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0802b5c>] ? oops_end+0x8c/0xd0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0431202>] ? no_context+0xc2/0x190
> Jun 22 08:44:34 RHEL6Beta kernel: [<c04314bf>] ? bad_area+0xf/0x20
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0804d44>] ? do_page_fault+0x3c4/0x3f0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c046341a>] ? __request_module+0x12a/0x1c0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0804980>] ? do_page_fault+0x0/0x3f0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0801fb7>] ? error_code+0x73/0x78
> Jun 22 08:44:34 RHEL6Beta kernel: [<c064256f>] ?
> mix_pool_bytes_extract+0x4f/0x150
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0746d84>] ? __alloc_skb+0x54/0x100
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0746d84>] ? __alloc_skb+0x54/0x100
> Jun 22 08:44:34 RHEL6Beta kernel: [<c074333c>] ? sock_rmalloc+0x4c/0x90
> Jun 22 08:44:34 RHEL6Beta kernel: [<c076d6e3>] ? netlink_dump+0x53/0x1b0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c04f529e>] ?
> kmem_cache_alloc_notrace+0x9e/0xb0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c076f2e0>] ? netlink_dump_start+0x130/0x1b0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c076f18e>] ? netlink_rcv_skb+0x7e/0xa0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c076eab0>] ? netlink_unicast+0x250/0x280
> Jun 22 08:44:34 RHEL6Beta kernel: [<c076f81c>] ? netlink_sendmsg+0x1bc/0x2a0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0740982>] ? sock_sendmsg+0xd2/0x110
> Jun 22 08:44:34 RHEL6Beta kernel: [<c04374bd>] ? kmap_atomic_prot+0x11d/0x150
> Jun 22 08:44:34 RHEL6Beta kernel: [<c043750c>] ? kmap_atomic+0x1c/0x30
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0437357>] ? kunmap_atomic+0x67/0x80
> Jun 22 08:44:34 RHEL6Beta kernel: [<c04ca242>] ?
> get_page_from_freelist+0x242/0x4d0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c05b8fa5>] ? _copy_from_user+0x35/0x120
> Jun 22 08:44:34 RHEL6Beta kernel: [<c05b8fa5>] ? _copy_from_user+0x35/0x120
> Jun 22 08:44:34 RHEL6Beta kernel: [<c07418e3>] ? sys_sendmsg+0x163/0x260
> Jun 22 08:44:34 RHEL6Beta kernel: [<c04f529e>] ?
> kmem_cache_alloc_notrace+0x9e/0xb0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c05787ed>] ?
> selinux_sk_alloc_security+0x6d/0xe0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c04f53ac>] ? kmem_cache_alloc+0xfc/0x120
> Jun 22 08:44:34 RHEL6Beta kernel: [<c074303e>] ? sock_init_data+0xae/0x1d0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c046df2d>] ? creds_are_invalid+0x1d/0x40
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0502ea3>] ? get_empty_filp+0x123/0x1c0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0502fc7>] ? alloc_file+0x87/0xb0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c073f6f6>] ? sock_alloc_file+0xa6/0x120
> Jun 22 08:44:34 RHEL6Beta kernel: [<c04ffeb6>] ? fd_install+0x26/0x50
> Jun 22 08:44:34 RHEL6Beta kernel: [<c073f78b>] ? sock_map_fd+0x1b/0x30
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0741fcd>] ? sys_socketcall+0xed/0x2c0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0409fdf>] ? sysenter_do_call+0x12/0x28
> Jun 22 08:44:34 RHEL6Beta kernel: Code: e8 b8 f5 13 00 31 c0 c3 90 8d 74 26 00
> 83 ec 10 85 c0 89 1c 24 89 c3 89 74 24 04 89 7c 24 08 89 6c 24 0c 74 1d 8b 80
> 60 01 00 00 <64> ff 40 04 8b 3d e4 4b a1 c0 8b 74 24 10 85 ff 75 18 83 3b 02
> Jun 22 08:44:34 RHEL6Beta kernel: EIP: [<c047e34e>] module_put+0x1e/0x90 SS:ESP
> 0068:f3b079e8
> Jun 22 08:44:34 RHEL6Beta kernel: CR2: 000000000135b004
> Jun 22 08:44:34 RHEL6Beta kernel: ---[ end trace 443475da32e0e7d4 ]---
>
^ permalink raw reply
* Re: Can I limit number of rx queues for igb (and other Intel drivers)?
From: Ben Greear @ 2010-06-22 19:54 UTC (permalink / raw)
To: Wyborny, Carolyn; +Cc: NetDev
In-Reply-To: <EDC0E76513226749BFBC9C3FB031318FD7874B40@orsmsx508.amr.corp.intel.com>
On 06/21/2010 04:35 PM, Wyborny, Carolyn wrote:
>
>
>> -----Original Message-----
>> From: netdev-owner@vger.kernel.org
>> [mailto:netdev-owner@vger.kernel.org] On Behalf Of Ben Greear
>> Sent: Friday, June 18, 2010 3:40 PM
>> To: NetDev
>> Subject: Can I limit number of rx queues for igb (and other
>> Intel drivers)?
>>
>> I'm using pktgen to send a stream of packets with varying
>> source and destination
>> IP addresses. It appears that the fancy rx logic of the NIC
>> (I'm using igb for this test)
>> causes the received packets to appear on random rx queues and
>> so be received out
>> of order in the network core.
>>
>> I do not see the out-of-order issue when using a single
>> source/dest IP address
>> for the pktgen packets.
>>
>> So, is there a way to tell igb to use only a single rx queue?
>>
>> Thanks,
>> Ben
>>
>> --
>> Ben Greear<greearb@candelatech.com>
>> Candela Technologies Inc http://www.candelatech.com
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe netdev" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
> Hello,
>
> There is not a way to tell igb to use a single queue and ethtool does not currently have a way to do this.
>
> We also maintain an out of kernel version of the driver at SourceForge that has module parameters to do this.
>
> If you need to do this with the kernel version, we'd need to modify ethtool to be able to do this.
A module parameter would be OK, but an ethtool command to change this live
would be really nice! It may be a day or two before I get back to testing
this, but will try your out-of-tree driver with proper mod-parm invocation
then.
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* Re: [PATCH 1/5 v2]wireless:hostap_main.c warning: variable 'iface' set but not used
From: Justin P. Mattock @ 2010-06-22 18:34 UTC (permalink / raw)
To: John W. Linville; +Cc: linux-wireless, netdev, linux-kernel
In-Reply-To: <20100622181320.GD2583@tuxdriver.com>
On 06/22/2010 11:13 AM, John W. Linville wrote:
> On Mon, Jun 21, 2010 at 03:02:13PM -0700, Justin P. Mattock wrote:
>> This is a resend from version one due to trying a different approach
>> than the original(probably important to leave netdev_priv() in).
>>
>> In any case have a look, if there's another approach let me know
>> and ill test it out. The below patch fixes a warning im seeing
>> when compiling with gcc 4.6.0
>>
>> CC [M] drivers/net/wireless/hostap/hostap_main.o
>> drivers/net/wireless/hostap/hostap_main.c: In function 'hostap_set_multicast_list_queue':
>> drivers/net/wireless/hostap/hostap_main.c:744:27: warning: variable 'iface' set but not used
>> Signed-off-by: Justin P. Mattock<justinmattock@gmail.com>
>
> I already applied the other version to wireless-next-2.6. I can't
> imagine what you mean to accomplish by leaving in a call to netdev_priv
> w/o assigning the result to something.
>
> John
alright..
as for the netdev_priv, I was getting confused on this one.
Thanks for taking the time to look at this.
Justin P. Mattock
^ permalink raw reply
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