* Re: [patch net-next-2.6 4/4] bridge: implement slave management operations
From: Stephen Hemminger @ 2011-02-28 22:17 UTC (permalink / raw)
To: Jiri Pirko; +Cc: netdev, davem, kaber, fubar
In-Reply-To: <20110211152346.GD2763@psychotron.brq.redhat.com>
On Fri, 11 Feb 2011 16:23:47 +0100
Jiri Pirko <jpirko@redhat.com> wrote:
>
> Signed-off-by: Jiri Pirko <jpirko@redhat.com>
NAK
This does not belong in ethtool. It should be done by rt_netlink_ops.
I am working on doing that right now.
--
^ permalink raw reply
* Re: Bug inkvm_set_irq
From: Jean-Philippe Menil @ 2011-02-28 22:34 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: netdev, kvm, virtualization
In-Reply-To: <4D6BBB88.5060709@univ-nantes.fr>
[-- Attachment #1: Type: text/plain, Size: 14653 bytes --]
Hi,
here is another trace with kvm.ko compiled with debug flags.
the bug:
[12099.503414] BUG: unable to handle kernel paging request at
000000000b6635e9
[12099.503462] IP: [<ffffffffa03ee877>] kvm_set_irq+0x37/0x140 [kvm]
[12099.503521] PGD 45d8d2067 PUD 45d58e067 PMD 0
[12099.503560] Oops: 0000 [#1] SMP
[12099.503591] last sysfs file:
/sys/devices/system/cpu/cpu11/cache/index2/shared_cpu_map
[12099.503641] CPU 0
[12099.503648] Modules linked in: netconsole configfs vhost_net macvtap
macvlan tun veth powernow_k8 mperf cpufreq_userspace cpufreq_stats
cpufreq_powersave cpufreq_ondemand freq_table cpufreq_conservative fuse
xt_physdev ip6t_LOG ip6table_filter ip6_tables ipt_LOG xt_multiport
xt_limit xt_tcpudp xt_state iptable_filter ip_tables x_tables
nf_conntrack_tftp nf_conntrack_ftp nf_conntrack_ipv4 nf_defrag_ipv4
8021q bridge stp ext2 mbcache dm_round_robin dm_multipath
nf_conntrack_ipv6 nf_conntrack nf_defrag_ipv6 kvm_amd kvm ipv6 snd_pcm
snd_timer snd soundcore snd_page_alloc shpchp pci_hotplug tpm_tis
i2c_nforce2 tpm i2c_core pcspkr evdev psmouse joydev tpm_bios processor
ghes dcdbas hed button serio_raw thermal_sys xfs exportfs dm_mod sg
sr_mod cdrom usbhid hid usb_storage ses sd_mod enclosure megaraid_sas
ohci_hcd lpfc scsi_transport_fc bnx2 scsi_tgt scsi_mod ehci_hcd [last
unloaded: scsi_wait_scan]
[12099.504277]
[12099.504302] Pid: 1742, comm: kworker/0:2 Not tainted
2.6.37.2-dsiun-110105+ #2 Dell Inc. PowerEdge M605/0K543T
[12099.504373] RIP: 0010:[<ffffffffa03ee877>] [<ffffffffa03ee877>]
kvm_set_irq+0x37/0x140 [kvm]
[12099.504444] RSP: 0018:ffff88045e013d00 EFLAGS: 00010246
[12099.504474] RAX: 000000000b6634c1 RBX: 0000000000000018 RCX:
0000000000000001
[12099.504508] RDX: 0000000000000000 RSI: 0000000000000000 RDI:
ffff880419b600c0
[12099.504541] RBP: ffff88045e013dd0 R08: ffff88045e012000 R09:
0000000000000000
[12099.504575] R10: 0000000000000000 R11: 00000000ffffffff R12:
ffff880419b600c0
[12099.504609] R13: ffff880419b600c0 R14: ffffffffa03efaa0 R15:
0000000000000001
[12099.504643] FS: 00007f3abaa05710(0000) GS:ffff88007f800000(0000)
knlGS:0000000000000000
[12099.504693] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[12099.504724] CR2: 000000000b6635e9 CR3: 000000045e2bc000 CR4:
00000000000006f0
[12099.504757] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[12099.504791] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7:
0000000000000400
[12099.504825] Process kworker/0:2 (pid: 1742, threadinfo
ffkvm_set_irqff88045e012000, task ffff88045ffb0d60)
[12099.504874] Stack:
[12099.504897] 00000000000119c0 00000000000119c0 00000000000119c0
ffff88045ffb0d60
[12099.504953] ffff88045ffb1010 ffff88045e013fd8 ffff88045ffb1018
ffff88045e012010
[12099.505009] 00000000000119c0 ffff88045e013fd8 00000000000119c0
00000000000119c0
[12099.505065] Call Trace:
[12099.505099] [<ffffffff813818ce>] ? common_interrupt+0xe/0x13
[12099.505145] [<ffffffffa03efaa0>] ? irqfd_inject+0x0/0x50 [kvm]
[12099.505145] [<ffffffffa03efaca>] irqfd_inject+0x2a/0x50 [kvm]
[12099.505145] [<ffffffff8106b7bb>] process_one_work+0x11b/0x450
[12099.505145] [<ffffffff8106bf37>] worker_thread+0x157/0x410
[12099.505145] [<ffffffff8103a569>] ? __wake_up_common+0x59/0x90
[12099.505145] [<ffffffff8106bde0>] ? worker_thread+0x0/0x410
[12099.505145] [<ffffffff8106f996>] kthread+0x96/0xa0
[12099.505145] [<ffffffff81003c64>] kernel_thread_helper+0x4/0x10
[12099.505145] [<ffffffff8106f900>] ? kthread+0x0/0xa0
[12099.505145] [<ffffffff81003c60>] ? kernel_thread_helper+0x0/0x10
[12099.505145] Code: 55 49 89 fd 41 54 53 89 d3 48 81 ec a8 00 00 00 8b
15 a6 75 03 00 89 b5 3c ff ff ff 85 d2 0f 85 d5 00 00 00 49 8b 85 58 24
00 00 <3b> 98 28 01 00 00 73 61 89 db 48 8b 84 d8 30 01 00 00 48 85 c0
[12099.505145] RIP [<ffffffffa03ee877>] kvm_set_irq+0x37/0x140 [kvm]
[12099.505145] RSP <ffff88045e013d00>
[12099.505145] CR2: 000000000b6635e9
markup_oops result:
root@ayrshire:~# cat bug.txt | perl markup_oops.pl -m
/lib/modules/2.6.37.2-dsiun-110105+/kernel/arch/x86/kvm/kvm.ko
/boot/vmlinuz-2.6.37.2-dsiun-110105+
vmaoffset = 18446744072103034880 ffffffffa03ee841: 48 89 e5
mov %rsp,%rbp
ffffffffa03ee844: 41 57 push %r15
ffffffffa03ee846: 41 89 cf mov %ecx,%r15d | %r15 =>
1 %ecx = 1
ffffffffa03ee849: 41 56 push %r14 | %r14 =>
ffffffffa03efaa0
ffffffffa03ee84b: 41 55 push %r13
ffffffffa03ee84d: 49 89 fd mov %rdi,%r13 | %edi =
ffff880419b600c0 %r13 => ffff880419b600c0
ffffffffa03ee850: 41 54 push %r12 | %r12 =>
ffff880419b600c0
ffffffffa03ee852: 53 push %rbx
ffffffffa03ee853: 89 d3 mov %edx,%ebx | %ebx => 18
ffffffffa03ee855: 48 81 ec a8 00 00 00 sub $0xa8,%rsp
ffffffffa03ee85c: 8b 15 00 00 00 00 mov 0x0(%rip),%edx #
ffffffffa03ee862 <kvm_set_irq+0x22>
ffffffffa03ee862: 89 b5 3c ff ff ff mov %esi,-0xc4(%rbp) |
%esi = 0
ffffffffa03ee868: 85 d2 test %edx,%edx | %edx => 0
ffffffffa03ee86a: 0f 85 d5 00 00 00 jne ffffffffa03ee945
<kvm_set_irq+0x105>
ffffffffa03ee870: 49 8b 85 58 24 00 00 mov 0x2458(%r13),%rax |
%eax => b6634c1 %r13 = ffff880419b600c0
*ffffffffa03ee877: 3b 98 28 01 00 00 cmp 0x128(%rax),%ebx | %eax
= b6634c1 %ebx = 18 <--- faulting instruction
ffffffffa03ee87d: 73 61 jae ffffffffa03ee8e0
<kvm_set_irq+0xa0>
ffffffffa03ee87f: 89 db mov %ebx,%ebx
ffffffffa03ee881: 48 8b 84 d8 30 01 00 mov 0x130(%rax,%rbx,8),%rax
ffffffffa03ee888: 00
ffffffffa03ee889: 48 85 c0 test %rax,%rax
ffffffffa03ee88c: 74 52 je ffffffffa03ee8e0
<kvm_set_irq+0xa0>
ffffffffa03ee88e: 48 8d 95 40 ff ff ff lea -0xc0(%rbp),%rdx
ffffffffa03ee895: 31 db xor %ebx,%ebx
ffffffffa03ee897: 48 8b 08 mov (%rax),%rcx
ffffffffa03ee89a: 83 c3 01 add $0x1,%ebx
ffffffffa03ee89d: 0f 18 09 prefetcht0 (%rcx)
ffffffffa03ee8a0: 48 8b 48 e0 mov -0x20(%rax),%rcx
ffffffffa03ee8a4: 48 89 0a mov %rcx,(%rdx)
ffffffffa03ee8a7: 48 8b 48 e8 mov -0x18(%rax),%rcx
ffffffffa03ee8ab: 48 89 4a 08 mov %rcx,0x8(%rdx)
ffffffffa03ee8af: 48 8b 48 f0 mov -0x10(%rax),%rcx
ffffffffa03ee8b3: 48 89 4a 10 mov %rcx,0x10(%rdx)
ffffffffa03ee8b7: 48 8b 48 f8 mov -0x8(%rax),%rcx
ffffffffa03ee8bb: 48 89 4a 18 mov %rcx,0x18(%rdx)
ffffffffa03ee8bf: 48 8b 08 mov (%rax),%rcx
The relvant part of objdump for kvm_set_irq:
root@ayrshire:~# objdump -ldS
/lib/modules/2.6.37.2-dsiun-110105+/kernel/arch/x86/kvm/kvm.ko > dump.txt
0000000000006840 <kvm_set_irq>:
kvm_set_irq():
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:148
6840: 55 push %rbp
6841: 48 89 e5 mov %rsp,%rbp
6844: 41 57 push %r15
6846: 41 89 cf mov %ecx,%r15d
6849: 41 56 push %r14
684b: 41 55 push %r13
684d: 49 89 fd mov %rdi,%r13
6850: 41 54 push %r12
6852: 53 push %rbx
6853: 89 d3 mov %edx,%ebx
6855: 48 81 ec a8 00 00 00 sub $0xa8,%rsp
trace_kvm_set_irq():
/usr/src/GIT/linux-2.6-stable/include/trace/events/kvm.h:10
685c: 8b 15 00 00 00 00 mov 0x0(%rip),%edx #
6862 <kvm_set_irq+0x22>
kvm_set_irq():
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:148
6862: 89 b5 3c ff ff ff mov %esi,-0xc4(%rbp)
trace_kvm_set_irq():
/usr/src/GIT/linux-2.6-stable/include/trace/events/kvm.h:10
6868: 85 d2 test %edx,%edx
686a: 0f 85 d5 00 00 00 jne 6945 <kvm_set_irq+0x105>
kvm_set_irq():
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:161
6870: 49 8b 85 58 24 00 00 mov 0x2458(%r13),%rax
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:162
6877: 3b 98 28 01 00 00 cmp 0x128(%rax),%ebx
687d: 73 61 jae 68e0 <kvm_set_irq+0xa0>
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:163
687f: 89 db mov %ebx,%ebx
6881: 48 8b 84 d8 30 01 00 mov 0x130(%rax,%rbx,8),%rax
6888: 00
6889: 48 85 c0 test %rax,%rax
688c: 74 52 je 68e0 <kvm_set_irq+0xa0>
688e: 48 8d 95 40 ff ff ff lea -0xc0(%rbp),%rdx
6895: 31 db xor %ebx,%ebx
6897: 48 8b 08 mov (%rax),%rcx
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:164
689a: 83 c3 01 add $0x1,%ebx
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:163
689d: 0f 18 09 prefetcht0 (%rcx)
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:164
68a0: 48 8b 48 e0 mov -0x20(%rax),%rcx
68a4: 48 89 0a mov %rcx,(%rdx)
68a7: 48 8b 48 e8 mov -0x18(%rax),%rcx
68ab: 48 89 4a 08 mov %rcx,0x8(%rdx)
68af: 48 8b 48 f0 mov -0x10(%rax),%rcx
68b3: 48 89 4a 10 mov %rcx,0x10(%rdx)
68b7: 48 8b 48 f8 mov -0x8(%rax),%rcx
68bb: 48 89 4a 18 mov %rcx,0x18(%rdx)
68bf: 48 8b 08 mov (%rax),%rcx
68c2: 48 89 4a 20 mov %rcx,0x20(%rdx)
68c6: 48 8b 48 08 mov 0x8(%rax),%rcx
68ca: 48 89 4a 28 mov %rcx,0x28(%rdx)
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:163
68ce: 48 8b 00 mov (%rax),%rax
68d1: 48 83 c2 30 add $0x30,%rdx
68d5: 48 85 c0 test %rax,%rax
68d8: 75 bd jne 6897 <kvm_set_irq+0x57>
68da: eb 06 jmp 68e2 <kvm_set_irq+0xa2>
68dc: 0f 1f 40 00 nopl 0x0(%rax)
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:162
68e0: 31 db xor %ebx,%ebx
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:169
68e2: 4c 8d b5 40 ff ff ff lea -0xc0(%rbp),%r14
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:162
68e9: 41 bc ff ff ff ff mov $0xffffffff,%r12d
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:167
68ef: 85 db test %ebx,%ebx
68f1: 74 3d je 6930 <kvm_set_irq+0xf0>
68f3: 83 eb 01 sub $0x1,%ebx
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:169
68f6: 44 89 f9 mov %r15d,%ecx
68f9: 8b 95 3c ff ff ff mov -0xc4(%rbp),%edx
68ff: 48 63 c3 movslq %ebx,%rax
6902: 4c 89 ee mov %r13,%rsi
6905: 48 8d 04 40 lea (%rax,%rax,2),%rax
6909: 48 c1 e0 04 shl $0x4,%rax
690d: 49 8d 3c 06 lea (%r14,%rax,1),%rdi
6911: ff 94 05 48 ff ff ff callq *-0xb8(%rbp,%rax,1)
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:170
6918: 85 c0 test %eax,%eax
691a: 78 d3 js 68ef <kvm_set_irq+0xaf>
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:173
691c: 45 85 e4 test %r12d,%r12d
691f: ba 00 00 00 00 mov $0x0,%edx
6924: 44 0f 48 e2 cmovs %edx,%r12d
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:167
6928: 85 db test %ebx,%ebx
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:173
692a: 46 8d 24 20 lea (%rax,%r12,1),%r12d
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:167
692e: 75 c3 jne 68f3 <kvm_set_irq+0xb3>
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:177
6930: 48 81 c4 a8 00 00 00 add $0xa8,%rsp
6937: 44 89 e0 mov %r12d,%eax
693a: 5b pop %rbx
693b: 41 5c pop %r12
693d: 41 5d pop %r13
693f: 41 5e pop %r14
6941: 41 5f pop %r15
6943: c9 leaveq
6944: c3 retq
trace_kvm_set_irq():
/usr/src/GIT/linux-2.6-stable/include/trace/events/kvm.h:10
6945: 4c 8b 25 00 00 00 00 mov 0x0(%rip),%r12 #
694c <kvm_set_irq+0x10c>
694c: 4d 85 e4 test %r12,%r12
694f: 0f 84 1b ff ff ff je 6870 <kvm_set_irq+0x30>
6955: 49 8b 04 24 mov (%r12),%rax
6959: 49 8b 7c 24 08 mov 0x8(%r12),%rdi
695e: 49 83 c4 10 add $0x10,%r12
6962: 8b 8d 3c ff ff ff mov -0xc4(%rbp),%ecx
6968: 44 89 fa mov %r15d,%edx
696b: 89 de mov %ebx,%esi
696d: ff d0 callq *%rax
696f: 49 8b 04 24 mov (%r12),%rax
6973: 48 85 c0 test %rax,%rax
6976: 75 e1 jne 6959 <kvm_set_irq+0x119>
6978: e9 f3 fe ff ff jmpq 6870 <kvm_set_irq+0x30>
kvm_set_irq():
697d: 0f 1f 00 nopl (%rax)
So, if i've read correctly, the offset is 0x6877 ?
root@ayrshire:~# addr2line -e
/lib/modules/2.6.37.2-dsiun-110105+/kernel/arch/x86/kvm/kvm.ko 0x6877
/usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:162
Is it the correct way to analyse this?
Regards.
[-- Attachment #2: jean-philippe_menil.vcf --]
[-- Type: text/x-vcard, Size: 361 bytes --]
begin:vcard
fn:Jean-Philippe Menil
n:Menil;Jean-Philippe
org;quoted-printable:Universit=C3=A9 de Nantes;IRTS - DSI
adr;quoted-printable:;;2 rue de la Houssini=C3=A8re;Nantes;Loire-Atlantique;44382;France
email;internet:jean-philippe.menil@univ-nantes.fr
title;quoted-printable:Administrateur R=C3=A9seau
url:http://www.cri.univ-nantes.fr
version:2.1
end:vcard
^ permalink raw reply
* Re: [patch net-next-2.6 4/4] bridge: implement slave management operations
From: Stephen Hemminger @ 2011-02-28 22:45 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: Jiri Pirko, netdev, davem, kaber, fubar
In-Reply-To: <20110228141729.09c3b770@nehalam>
On Mon, 28 Feb 2011 14:17:29 -0800
Stephen Hemminger <shemminger@linux-foundation.org> wrote:
> On Fri, 11 Feb 2011 16:23:47 +0100
> Jiri Pirko <jpirko@redhat.com> wrote:
>
> >
> > Signed-off-by: Jiri Pirko <jpirko@redhat.com>
>
Never mind, this is good. I was confusing slave with bridge initialization
and netdevice ops with ethtool ops.
Ethtool ops seems to be growing like weeds lately...
--
^ permalink raw reply
* Re: [PATCH] RxRPC: Fix v1 keys
From: Andrew Morton @ 2011-02-28 23:01 UTC (permalink / raw)
To: David Howells; +Cc: netdev, linux-kernel, Anton Blanchard
In-Reply-To: <20110228132753.30463.24909.stgit@warthog.procyon.org.uk>
On Mon, 28 Feb 2011 13:27:53 +0000
David Howells <dhowells@redhat.com> wrote:
> From: Anton Blanchard <anton@au1.ibm.com>
>
> commit 339412841d7 (RxRPC: Allow key payloads to be passed in XDR form)
> broke klog for me. I notice the v1 key struct had a kif_version field
> added:
>
> -struct rxkad_key {
> - u16 security_index; /* RxRPC header security index */
> - u16 ticket_len; /* length of ticket[] */
> - u32 expiry; /* time at which expires */
> - u32 kvno; /* key version number */
> - u8 session_key[8]; /* DES session key */
> - u8 ticket[0]; /* the encrypted ticket */
> -};
>
> +struct rxrpc_key_data_v1 {
> + u32 kif_version; /* 1 */
> + u16 security_index;
> + u16 ticket_length;
> + u32 expiry; /* time_t */
> + u32 kvno;
> + u8 session_key[8];
> + u8 ticket[0];
> +};
>
> However the code in rxrpc_instantiate strips it away:
>
> data += sizeof(kver);
> datalen -= sizeof(kver);
>
> Removing kif_version fixes my problem.
>
> Signed-off-by: Anton Blanchard <anton@samba.org>
> Signed-off-by: David Howells <dhowells@redhat.com>
> ---
>
> include/keys/rxrpc-type.h | 1 -
> 1 files changed, 0 insertions(+), 1 deletions(-)
>
> diff --git a/include/keys/rxrpc-type.h b/include/keys/rxrpc-type.h
> index 5cb86c3..fc48754 100644
> --- a/include/keys/rxrpc-type.h
> +++ b/include/keys/rxrpc-type.h
> @@ -99,7 +99,6 @@ struct rxrpc_key_token {
> * structure of raw payloads passed to add_key() or instantiate key
> */
> struct rxrpc_key_data_v1 {
> - u32 kif_version; /* 1 */
> u16 security_index;
> u16 ticket_length;
> u32 expiry; /* time_t */
Isn't the patch also needed in 2.6.37.x?
^ permalink raw reply
* Re: [PATCHv2 net-next-2.6] ethtool: Compat handling for struct ethtool_rxnfc
From: Kees Cook @ 2011-02-28 23:51 UTC (permalink / raw)
To: Ben Hutchings; +Cc: David Miller, Alexander Duyck, Santwona Behera, netdev
In-Reply-To: <1298930141.2569.22.camel@bwh-desktop>
Hi Ben,
On Mon, Feb 28, 2011 at 09:55:41PM +0000, Ben Hutchings wrote:
> I'm not sure whether more checks on rule_cnt are required for security
> or whether compat_alloc_user_space() and copy_in_user() can be relied on
> to limit any buffer overrun to the user process's own memory. It looks
> like this is safe on x86.
I'm less familiar with the compat world, but it looks sane to me. All the
copy_in_user() calls are calculated based on structure sizes, right? Except
for the rule_cnt one, which was already bounds-checked for output. AFAIK,
reading beyond the end of &rxnfc->rule_locs[0] should be contained to
userspace memory due to the access_ok() check in copy_in_user().
> + switch (ethcmd) {
> + default:
> + break;
> + case ETHTOOL_GRXCLSRLALL:
> + /* Buffer size is variable */
> + if (get_user(rule_cnt, &compat_rxnfc->rule_cnt))
> + return -EFAULT;
> + if (rule_cnt > KMALLOC_MAX_SIZE / sizeof(u32))
> + return -ENOMEM;
> + buf_size += rule_cnt * sizeof(u32);
> + /* fall through */
> + case ETHTOOL_GRXRINGS:
> + case ETHTOOL_GRXCLSRLCNT:
> + case ETHTOOL_GRXCLSRULE:
> + convert_out = true;
> + /* fall through */
> + case ETHTOOL_SRXCLSRLDEL:
> + case ETHTOOL_SRXCLSRLINS:
> + buf_size += sizeof(struct ethtool_rxnfc);
> + convert_in = true;
> + break;
> + }
> ...
> + if (convert_out) {
> ...
> + if (ethcmd == ETHTOOL_GRXCLSRLALL) {
> + if (get_user(rule_cnt, &compat_rxnfc->rule_cnt) ||
> + copy_in_user(&compat_rxnfc->rule_locs[0],
> + &rxnfc->rule_locs[0],
> + rule_cnt * sizeof(u32)))
> + return -EFAULT;
-Kees
--
Kees Cook
Ubuntu Security Team
^ permalink raw reply
* Re: [PATCHv2 net-next-2.6] ethtool: Compat handling for struct ethtool_rxnfc
From: Ben Hutchings @ 2011-03-01 0:10 UTC (permalink / raw)
To: Kees Cook; +Cc: David Miller, Alexander Duyck, Santwona Behera, netdev
In-Reply-To: <20110228235157.GG4669@outflux.net>
On Mon, 2011-02-28 at 15:51 -0800, Kees Cook wrote:
> Hi Ben,
>
> On Mon, Feb 28, 2011 at 09:55:41PM +0000, Ben Hutchings wrote:
> > I'm not sure whether more checks on rule_cnt are required for security
> > or whether compat_alloc_user_space() and copy_in_user() can be relied on
> > to limit any buffer overrun to the user process's own memory. It looks
> > like this is safe on x86.
>
> I'm less familiar with the compat world, but it looks sane to me. All the
> copy_in_user() calls are calculated based on structure sizes, right? Except
> for the rule_cnt one, which was already bounds-checked for output.
[...]
No, because the native ioctl implementation writes out the actual number
of rules to rxnfc->rule_cnt and we then read that back into rule_cnt
before performing the copy from rxnfc->rule_locs to
compat_rxnfc->rule_locs. So userland can race with us and modify that
value.
We could use the original value of rule_cnt to calculate the size to
copy; it would just mean copying more than we need to most of the time.
Ben.
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: [ethtool PATCH 2/2] Add RX packet classification interface
From: Ben Hutchings @ 2011-03-01 0:35 UTC (permalink / raw)
To: Alexander Duyck; +Cc: Santwona Behera, netdev@vger.kernel.org
In-Reply-To: <4D642222.6050202@intel.com>
On Tue, 2011-02-22 at 12:52 -0800, Alexander Duyck wrote:
[...]
> >> @@ -408,6 +425,14 @@ static int msglvl_changed;
> >> static u32 msglvl_wanted = 0;
> >> static u32 msglvl_mask = 0;
> >>
> >> +static int rx_rings_get = 0;
> >> +static int rx_class_rule_get = -1;
> >> +static int rx_class_rule_getall = 0;
> >> +static int rx_class_rule_del = -1;
> >> +static int rx_class_rule_added = 0;
> >> +static struct ethtool_rx_flow_spec rx_rule_fs;
> >> +static u8 rxclass_loc_valid = 0;
> >> +
> >> static enum {
> >> ONLINE=0,
> >> OFFLINE,
> > [...]
> >> @@ -945,6 +974,23 @@ static void parse_cmdline(int argc, char **argp)
> >> rxflow_str_to_type(argp[i]);
> >> if (!rx_fhash_get)
> >> show_usage(1);
> >> + } else if (!strcmp(argp[i], "rx-rings")) {
> >> + i += 1;
> >> + rx_rings_get = 1;
> >
> > I'm not convinced of the value of a separate rx-rings option/keyword.
> > However it's probably worth displaying the number of rings/queues when
> > showing other flow hashing and steering/filtering information (the -x
> > option does this).
>
> My thought was that it would be useful for determining the number of
> rings prior to adding a rule. Especially if we have any kind of scripts
> running on top of ethtool so that we can avoid rules that will fail due
> to ring values being greater than the actual number of rings. I might
> try looking into adding it to the display options for the filters.
I think it would also be appropriate to add this to the output of the
-g/--show-ring option.
[...]
> >> } else
> >> show_usage(1);
> >> break;
> >
> > I don't think the same options (-n, -N) should be used both for flow
> > hashing and n-tuple flow steering/filtering. This command-line
> > interface and the structure used in the ethtool API just seem to reflect
> > the implementation in the niu driver.
> >
> > (In fact I would much prefer it if the -u and -U options could be used
> > for both the rxnfc and rxntuple interfaces. But I haven't thought about
> > how the differences in functionality would be exposed to or hidden from
> > the user.)
>
> I was kind of thinking about merging the two interfaces too, but I was
> looking at it more from the perspective of moving away from ntuple more
> towards this newer interface. My main motivation being that the filter
> display option is so badly broken for ntuple that it would be easier to
> make ntuple a subset of the flow classifier instead of the other way around.
>
> What would you think of using the "flow-type" keyword to indicate legacy
> ntuple support, and then adding something like "class-rule-add", and
> "class-rule-del" to add support for the network flow classifier calls?
I really don't want to introduce different syntax for functionality that
is common between the two command sets. The user should not have to
know that driver A implements interface I and driver B implements
interface J, except that since version 2.6.y driver A implements
interface J too.
Surely it is possible to try one interface, then the other, when the
requested filter can be implemented either way?
[...]
> >> + for (i = 2; i< opt_cnt;) {
> >> + if (!strcmp(optstr[i], "tos")) {
> >> + tos = (u_int8_t)strtoul(optstr[i+1], (char **)NULL,
> >> + 0);
> >> + tm = 0xff;
> >> + fsp->h_u.tcp_ip4_spec.tos = tos;
> >> +
> >> + i += 2;
> >> + if (opt_cnt> (i+1)) {
> >> + if (!strcmp(optstr[i], "m")) {
> >> + tm = (u_int8_t)strtoul(optstr[i+1],
> >> + (char **)NULL,
> >> + 16);
> >> + i += 2;
> >> + }
> >> + }
> >> + fsp->m_u.tcp_ip4_spec.tos = tm;
> >> + } else if (!strcmp(optstr[i], "sip")) {
> > [...]
> >
> > These keyword names must be made consistent with those used for the -U
> > (--config-ntuple) option.
> >
>
> I will update the names to be consistent with the ntuple options,
> however I would prefer to keep the option of short-cutting the mask via
> the "m" value. It will not be hard to make it support both since the
> pattern would be to test for either "m" or "%s-mask".
[...]
Agreed, that would be a useful shortcut.
Ben.
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: txqueuelen has wrong units; should be time
From: Mikael Abrahamsson @ 2011-03-01 0:46 UTC (permalink / raw)
To: John Heffner
Cc: Bill Sommerfeld, Hagen Paul Pfeifer, Albert Cahalan,
Jussi Kivilinna, Eric Dumazet, linux-kernel, netdev
In-Reply-To: <AANLkTin_jY_J7tJseMLVmrQVVRezOVQTGCgB_6tefgXJ@mail.gmail.com>
On Mon, 28 Feb 2011, John Heffner wrote:
> Right... while I generally agree that a fixed-length drop-tail queue
> isn't optimal, isn't this problem what the various AQM schemes try to
> solve?
I am not an expert on exactly how Linux does this, but for Cisco and for
instance ATM interfaces, there are two stages of queuing. One is the
"hardware queue", which is a FIFO queue going into the ATM framer. If one
wants low CPU usage, then this needs to be high so multiple packets can be
put there per interrupt. Since AQM is working before this, it also means
the low-latency-queue will have a higher latency as it ends up behind
larger packets in the hw queue.
So on what level does the AQM work in Linux? Does it work similarily, that
txqueuelen is a FIFO queue to the hardware that AQM feeds packets into?
Also, when one uses WRED the thinking is generally to keep the average
queue len down, but still allow for bursts by dynamically changing the
drop probability and where it happens. When there is no queuing, allow for
big queue (so it can fill up if needed), but if the queue is large for
several seconds, start to apply WRED to bring it down.
There is generally no need at all to constantly buffer > 50 ms of data,
then it's better to just start selectively dropping it. In time of
burstyness (perhaps when re-routing traffic) there is need to buffer
200-500ms of during perhaps 1-2 seconds before things stabilize.
So one queuing scheme and one queue limit isn't going to solve this, there
need to be some dynamic built into the system for it to work well.
AQM needs to feed into a relatively short hw queue and AQM needs to exist
on output also when the traffic is sourced from the box itself, no tonly
routed. It would also help if the default would be to use let's say 25% of
the bandwidth for smaller packets (< 200 bytes or so) which generally are
for interactive uses or are ACKs.
--
Mikael Abrahamsson email: swmike@swm.pp.se
^ permalink raw reply
* pull request: sfc-next-2.6 2011-03-01
From: Ben Hutchings @ 2011-03-01 1:16 UTC (permalink / raw)
To: David Miller; +Cc: linux-net-drivers, netdev
The following changes since commit 5b2c4dd2ec12cf0e53b2bd2926f0fe2d1fbb4eda:
Jiri Pirko (1):
net: convert bonding to use rx_handler
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/bwh/sfc-next-2.6.git for-davem
Ben Hutchings (6):
sfc: Read MC firmware version when requested through ethtool
sfc: Do not read STAT1.FAULT in efx_mdio_check_mmd()
sfc: Update copyright dates
sfc: Expose TX push and TSO counters through ethtool statistics
sfc: Remove configurable FIFO thresholds for pause frame generation
sfc: Bump version to 3.1
Steve Hodgson (2):
sfc: Reduce size of efx_rx_buffer by unionising skb and page
sfc: Reduce size of efx_rx_buffer further by removing data member
drivers/net/sfc/efx.c | 2 +-
drivers/net/sfc/efx.h | 2 +-
drivers/net/sfc/ethtool.c | 27 ++++++-
drivers/net/sfc/falcon.c | 22 ++----
drivers/net/sfc/falcon_boards.c | 2 +-
drivers/net/sfc/falcon_xmac.c | 2 +-
drivers/net/sfc/io.h | 2 +-
drivers/net/sfc/mcdi.c | 23 ++----
drivers/net/sfc/mcdi.h | 4 +-
drivers/net/sfc/mcdi_mac.c | 2 +-
drivers/net/sfc/mcdi_pcol.h | 2 +-
drivers/net/sfc/mcdi_phy.c | 2 +-
drivers/net/sfc/mdio_10g.c | 34 ++--------
drivers/net/sfc/mdio_10g.h | 5 +-
drivers/net/sfc/mtd.c | 2 +-
drivers/net/sfc/net_driver.h | 14 ++--
drivers/net/sfc/nic.c | 22 +------
drivers/net/sfc/nic.h | 9 +--
drivers/net/sfc/phy.h | 2 +-
drivers/net/sfc/qt202x_phy.c | 2 +-
drivers/net/sfc/regs.h | 2 +-
drivers/net/sfc/rx.c | 144 +++++++++++++++++++-------------------
drivers/net/sfc/selftest.c | 2 +-
drivers/net/sfc/selftest.h | 2 +-
drivers/net/sfc/siena.c | 24 +------
drivers/net/sfc/spi.h | 2 +-
drivers/net/sfc/tenxpress.c | 4 +-
drivers/net/sfc/tx.c | 2 +-
drivers/net/sfc/txc43128_phy.c | 4 +-
drivers/net/sfc/workarounds.h | 2 +-
30 files changed, 150 insertions(+), 220 deletions(-)
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* [PATCH] sched: QFQ - quick fair queue scheduler (v2)
From: Stephen Hemminger @ 2011-03-01 1:17 UTC (permalink / raw)
To: David Miller, Fabio Checconi, Luigi Rizzo; +Cc: netdev
This is an implementation of the Quick Fair Queue scheduler developed
by Fabio Checconi. The same algorithm is already implemented in ipfw
in FreeBSD. Fabio had an earlier version developed on Linux, I just
cleaned it up and tested it. All bugs are mine.
This version is still experimental, do not use for production.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
v2 - Did some debugging, and rebased against net-next tree.
include/linux/pkt_sched.h | 14
net/sched/Kconfig | 11
net/sched/Makefile | 1
net/sched/sch_qfq.c | 1124 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 1150 insertions(+)
--- a/include/linux/pkt_sched.h 2011-02-28 13:28:57.763177314 -0800
+++ b/include/linux/pkt_sched.h 2011-02-28 13:29:10.466792117 -0800
@@ -588,4 +588,18 @@ struct tc_sfb_xstats {
#define SFB_MAX_PROB 0xFFFF
+/* QFQ */
+enum {
+ TCA_QFQ_WEIGHT,
+ TCA_QFQ_LMAX,
+ __TCA_QFQ_MAX
+};
+
+#define TCA_QFQ_MAX (__TCA_QFQ_MAX - 1)
+
+struct tc_qfq_stats {
+ __u32 weight;
+ __u32 lmax;
+};
+
#endif
--- a/net/sched/Kconfig 2011-02-28 13:28:57.771177070 -0800
+++ b/net/sched/Kconfig 2011-02-28 17:13:01.119718271 -0800
@@ -239,6 +239,17 @@ config NET_SCH_CHOKE
To compile this code as a module, choose M here: the
module will be called sch_choke.
+config NET_SCH_QFQ
+ tristate "Quick Fair Queueing scheduler (QFQ)"
+ help
+ Say Y here if you want to use the Quick Fair Queueing Scheduler (QFQ)
+ packet scheduling algorithm.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sch_qfq.
+
+ If unsure, say N.
+
config NET_SCH_INGRESS
tristate "Ingress Qdisc"
depends on NET_CLS_ACT
--- a/net/sched/Makefile 2011-02-28 13:28:57.783176704 -0800
+++ b/net/sched/Makefile 2011-02-28 13:29:10.470791996 -0800
@@ -35,6 +35,7 @@ obj-$(CONFIG_NET_SCH_NETEM) += sch_netem
obj-$(CONFIG_NET_SCH_DRR) += sch_drr.o
obj-$(CONFIG_NET_SCH_MQPRIO) += sch_mqprio.o
obj-$(CONFIG_NET_SCH_CHOKE) += sch_choke.o
+obj-$(CONFIG_NET_SCH_QFQ) += sch_qfq.o
obj-$(CONFIG_NET_CLS_U32) += cls_u32.o
obj-$(CONFIG_NET_CLS_ROUTE4) += cls_route.o
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ b/net/sched/sch_qfq.c 2011-02-28 17:10:48.961445894 -0800
@@ -0,0 +1,1124 @@
+/*
+ * net/sched/sch_qfq.c Quick Fair Queueing Scheduler.
+ *
+ * Copyright (c) 2009 Fabio Checconi, Luigi Rizzo, and Paolo Valente.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/pkt_sched.h>
+#include <net/sch_generic.h>
+#include <net/pkt_sched.h>
+#include <net/pkt_cls.h>
+
+
+/* Quick Fair Queueing
+ ===================
+
+ Sources:
+ Fabio Checconi and Scuola Superiore and S. Anna
+ and Paolo Valente and Luigi Riz "QFQ: Efficient Packet Scheduling
+ with Tight Bandwidth Distribution Guarantees"
+
+ See also:
+ http://retis.sssup.it/~fabio/linux/qfq/
+ */
+
+/*
+
+ Virtual time computations.
+
+ S, F and V are all computed in fixed point arithmetic with
+ FRAC_BITS decimal bits.
+
+ QFQ_MAX_INDEX is the maximum index allowed for a group. We need
+ one bit per index.
+ QFQ_MAX_WSHIFT is the maximum power of two supported as a weight.
+
+ The layout of the bits is as below:
+
+ [ MTU_SHIFT ][ FRAC_BITS ]
+ [ MAX_INDEX ][ MIN_SLOT_SHIFT ]
+ ^.__grp->index = 0
+ *.__grp->slot_shift
+
+ where MIN_SLOT_SHIFT is derived by difference from the others.
+
+ The max group index corresponds to Lmax/w_min, where
+ Lmax=1<<MTU_SHIFT, w_min = 1 .
+ From this, and knowing how many groups (MAX_INDEX) we want,
+ we can derive the shift corresponding to each group.
+
+ Because we often need to compute
+ F = S + len/w_i and V = V + len/wsum
+ instead of storing w_i store the value
+ inv_w = (1<<FRAC_BITS)/w_i
+ so we can do F = S + len * inv_w * wsum.
+ We use W_TOT in the formulas so we can easily move between
+ static and adaptive weight sum.
+
+ The per-scheduler-instance data contain all the data structures
+ for the scheduler: bitmaps and bucket lists.
+
+ */
+
+/*
+ * Maximum number of consecutive slots occupied by backlogged classes
+ * inside a group.
+ */
+#define QFQ_MAX_SLOTS 32
+
+/*
+ * Shifts used for class<->group mapping. We allow class weights that are
+ * in the range [1, 2^MAX_WSHIFT], and we try to map each class i to the
+ * group with the smallest index that can support the L_i / r_i configured
+ * for the class.
+ *
+ * grp->index is the index of the group; and grp->slot_shift
+ * is the shift for the corresponding (scaled) sigma_i.
+ */
+#define QFQ_MAX_INDEX 19
+#define QFQ_MAX_WSHIFT 16
+
+#define QFQ_MAX_WEIGHT (1<<QFQ_MAX_WSHIFT)
+#define QFQ_MAX_WSUM (2*QFQ_MAX_WEIGHT)
+
+#define FRAC_BITS 30 /* fixed point arithmetic */
+#define ONE_FP (1UL << FRAC_BITS)
+#define IWSUM (ONE_FP/QFQ_MAX_WSUM)
+
+#define QFQ_MTU_SHIFT 11
+#define QFQ_MIN_SLOT_SHIFT (FRAC_BITS + QFQ_MTU_SHIFT - QFQ_MAX_INDEX)
+
+/*
+ * Possible group states. These values are used as indexes for the bitmaps
+ * array of struct qfq_queue.
+ */
+enum qfq_state { ER, IR, EB, IB, QFQ_MAX_STATE };
+
+struct qfq_group;
+
+struct qfq_class {
+ struct Qdisc_class_common common;
+
+ unsigned int refcnt;
+ unsigned int filter_cnt;
+
+ struct gnet_stats_basic_packed bstats;
+ struct gnet_stats_queue qstats;
+ struct gnet_stats_rate_est rate_est;
+ struct Qdisc *qdisc;
+
+ struct qfq_class *next; /* Link for the slot list. */
+ u64 S, F; /* flow timestamps (exact) */
+
+ /* group we belong to. In principle we would need the index,
+ * which is log_2(lmax/weight), but we never reference it
+ * directly, only the group.
+ */
+ struct qfq_group *grp;
+
+ /* these are copied from the flowset. */
+ u32 inv_w; /* ONE_FP/weight */
+ u32 lmax; /* Max packet size for this flow. */
+};
+
+struct qfq_group {
+ u64 S, F; /* group timestamps (approx). */
+ unsigned int slot_shift; /* Slot shift. */
+ unsigned int index; /* Group index. */
+ unsigned int front; /* Index of the front slot. */
+ unsigned long full_slots; /* non-empty slots */
+
+ /* Array of RR lists of active classes. */
+ struct qfq_class *slots[QFQ_MAX_SLOTS];
+};
+
+struct qfq_sched {
+ struct tcf_proto *filter_list;
+ struct Qdisc_class_hash clhash;
+
+ u64 V; /* Precise virtual time. */
+ u32 wsum; /* weight sum */
+
+ unsigned long bitmaps[QFQ_MAX_STATE]; /* Group bitmaps. */
+ struct qfq_group groups[QFQ_MAX_INDEX + 1]; /* The groups. */
+};
+
+static struct qfq_class *qfq_find_class(struct Qdisc *sch, u32 classid)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct Qdisc_class_common *clc;
+
+ clc = qdisc_class_find(&q->clhash, classid);
+ if (clc == NULL)
+ return NULL;
+ return container_of(clc, struct qfq_class, common);
+}
+
+static void qfq_purge_queue(struct qfq_class *cl)
+{
+ unsigned int len = cl->qdisc->q.qlen;
+
+ qdisc_reset(cl->qdisc);
+ qdisc_tree_decrease_qlen(cl->qdisc, len);
+}
+
+static const struct nla_policy qfq_policy[TCA_QFQ_MAX + 1] = {
+ [TCA_QFQ_WEIGHT] = { .type = NLA_U32 },
+ [TCA_QFQ_LMAX] = { .type = NLA_U32 },
+};
+
+/*
+ * Calculate a flow index, given its weight and maximum packet length.
+ * index = log_2(maxlen/weight) but we need to apply the scaling.
+ * This is used only once at flow creation.
+ */
+static int qfq_calc_index(u32 inv_w, unsigned int maxlen)
+{
+ u64 slot_size = (u64)maxlen * inv_w;
+ unsigned long size_map;
+ int index = 0;
+
+ size_map = slot_size >> QFQ_MIN_SLOT_SHIFT;
+ if (!size_map)
+ goto out;
+
+ index = __fls(size_map) + 1; /* basically a log_2 */
+ index -= !(slot_size - (1ULL << (index + QFQ_MIN_SLOT_SHIFT - 1)));
+
+ if (index < 0)
+ index = 0;
+out:
+ pr_debug("qfq calc_index: W = %lu, L = %u, I = %d\n",
+ (unsigned long) ONE_FP/inv_w, maxlen, index);
+
+ return index;
+}
+
+static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
+ struct nlattr **tca, unsigned long *arg)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_class *cl = (struct qfq_class *)*arg;
+ struct nlattr *tb[TCA_QFQ_MAX + 1];
+ u32 weight, lmax, inv_w;
+ int i, err;
+
+ if (tca[TCA_OPTIONS] == NULL)
+ return -EINVAL;
+
+ err = nla_parse_nested(tb, TCA_QFQ_MAX, tca[TCA_OPTIONS], qfq_policy);
+ if (err < 0)
+ return err;
+
+ if (tb[TCA_QFQ_WEIGHT]) {
+ weight = nla_get_u32(tb[TCA_QFQ_WEIGHT]);
+ if (!weight || weight > (1UL << QFQ_MAX_WSHIFT)) {
+ pr_notice("qfq: invalid weight %u\n", weight);
+ return -EINVAL;
+ }
+ } else
+ weight = 1;
+
+ inv_w = ONE_FP / weight;
+ weight = ONE_FP / inv_w;
+ if (q->wsum + weight > QFQ_MAX_WSUM) {
+ pr_notice("qfq: total weight out of range (%u + %u)\n",
+ weight, q->wsum);
+ return -EINVAL;
+ }
+
+ if (tb[TCA_QFQ_LMAX]) {
+ lmax = nla_get_u32(tb[TCA_QFQ_LMAX]);
+ if (!lmax || lmax > (1UL << QFQ_MTU_SHIFT)) {
+ pr_notice("qfq: invalid max length %u\n", lmax);
+ return -EINVAL;
+ }
+ } else
+ lmax = 1UL << QFQ_MTU_SHIFT;
+
+ if (cl != NULL) {
+ if (tca[TCA_RATE]) {
+ err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
+ qdisc_root_sleeping_lock(sch),
+ tca[TCA_RATE]);
+ if (err)
+ return err;
+ }
+
+ sch_tree_lock(sch);
+ if (tb[TCA_QFQ_WEIGHT]) {
+ q->wsum = weight - ONE_FP / cl->inv_w;
+ cl->inv_w = inv_w;
+ }
+ sch_tree_unlock(sch);
+
+ return 0;
+ }
+
+ cl = kzalloc(sizeof(struct qfq_class), GFP_KERNEL);
+ if (cl == NULL)
+ return -ENOBUFS;
+
+ cl->refcnt = 1;
+ cl->common.classid = classid;
+ cl->lmax = lmax;
+ cl->inv_w = inv_w;
+ i = qfq_calc_index(cl->inv_w, cl->lmax);
+
+ cl->grp = &q->groups[i];
+ q->wsum += weight;
+
+ cl->qdisc = qdisc_create_dflt(sch->dev_queue,
+ &pfifo_qdisc_ops, classid);
+ if (cl->qdisc == NULL)
+ cl->qdisc = &noop_qdisc;
+
+ if (tca[TCA_RATE]) {
+ err = gen_new_estimator(&cl->bstats, &cl->rate_est,
+ qdisc_root_sleeping_lock(sch),
+ tca[TCA_RATE]);
+ if (err) {
+ qdisc_destroy(cl->qdisc);
+ kfree(cl);
+ return err;
+ }
+ }
+
+ sch_tree_lock(sch);
+ qdisc_class_hash_insert(&q->clhash, &cl->common);
+ sch_tree_unlock(sch);
+
+ qdisc_class_hash_grow(sch, &q->clhash);
+
+ *arg = (unsigned long)cl;
+ return 0;
+}
+
+static void qfq_destroy_class(struct Qdisc *sch, struct qfq_class *cl)
+{
+ struct qfq_sched *q = (struct qfq_sched *)sch;
+
+ if (cl->inv_w) {
+ q->wsum -= ONE_FP / cl->inv_w;
+ cl->inv_w = 0;
+ }
+
+ gen_kill_estimator(&cl->bstats, &cl->rate_est);
+ qdisc_destroy(cl->qdisc);
+ kfree(cl);
+}
+
+static int qfq_delete_class(struct Qdisc *sch, unsigned long arg)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_class *cl = (struct qfq_class *)arg;
+
+ if (cl->filter_cnt > 0)
+ return -EBUSY;
+
+ sch_tree_lock(sch);
+
+ qfq_purge_queue(cl);
+ qdisc_class_hash_remove(&q->clhash, &cl->common);
+
+ if (--cl->refcnt == 0)
+ qfq_destroy_class(sch, cl);
+
+ sch_tree_unlock(sch);
+ return 0;
+}
+
+static unsigned long qfq_get_class(struct Qdisc *sch, u32 classid)
+{
+ struct qfq_class *cl = qfq_find_class(sch, classid);
+
+ if (cl != NULL)
+ cl->refcnt++;
+
+ return (unsigned long)cl;
+}
+
+static void qfq_put_class(struct Qdisc *sch, unsigned long arg)
+{
+ struct qfq_class *cl = (struct qfq_class *)arg;
+
+ if (--cl->refcnt == 0)
+ qfq_destroy_class(sch, cl);
+}
+
+static struct tcf_proto **qfq_tcf_chain(struct Qdisc *sch, unsigned long cl)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+
+ if (cl)
+ return NULL;
+
+ return &q->filter_list;
+}
+
+static unsigned long qfq_bind_tcf(struct Qdisc *sch, unsigned long parent,
+ u32 classid)
+{
+ struct qfq_class *cl = qfq_find_class(sch, classid);
+
+ if (cl != NULL)
+ cl->filter_cnt++;
+
+ return (unsigned long)cl;
+}
+
+static void qfq_unbind_tcf(struct Qdisc *sch, unsigned long arg)
+{
+ struct qfq_class *cl = (struct qfq_class *)arg;
+
+ cl->filter_cnt--;
+}
+
+static int qfq_graft_class(struct Qdisc *sch, unsigned long arg,
+ struct Qdisc *new, struct Qdisc **old)
+{
+ struct qfq_class *cl = (struct qfq_class *)arg;
+
+ if (new == NULL) {
+ new = qdisc_create_dflt(sch->dev_queue,
+ &pfifo_qdisc_ops, cl->common.classid);
+ if (new == NULL)
+ new = &noop_qdisc;
+ }
+
+ sch_tree_lock(sch);
+ qfq_purge_queue(cl);
+ *old = cl->qdisc;
+ cl->qdisc = new;
+ sch_tree_unlock(sch);
+ return 0;
+}
+
+static struct Qdisc *qfq_class_leaf(struct Qdisc *sch, unsigned long arg)
+{
+ struct qfq_class *cl = (struct qfq_class *)arg;
+
+ return cl->qdisc;
+}
+
+static int qfq_dump_class(struct Qdisc *sch, unsigned long arg,
+ struct sk_buff *skb, struct tcmsg *tcm)
+{
+ struct qfq_class *cl = (struct qfq_class *)arg;
+ struct nlattr *nest;
+
+ tcm->tcm_parent = TC_H_ROOT;
+ tcm->tcm_handle = cl->common.classid;
+ tcm->tcm_info = cl->qdisc->handle;
+
+ nest = nla_nest_start(skb, TCA_OPTIONS);
+ if (nest == NULL)
+ goto nla_put_failure;
+ NLA_PUT_U32(skb, TCA_QFQ_WEIGHT, ONE_FP/cl->inv_w);
+ NLA_PUT_U32(skb, TCA_QFQ_LMAX, cl->lmax);
+ return nla_nest_end(skb, nest);
+
+nla_put_failure:
+ nla_nest_cancel(skb, nest);
+ return -EMSGSIZE;
+}
+
+static int qfq_dump_class_stats(struct Qdisc *sch, unsigned long arg,
+ struct gnet_dump *d)
+{
+ struct qfq_class *cl = (struct qfq_class *)arg;
+ struct tc_qfq_stats xstats;
+
+ memset(&xstats, 0, sizeof(xstats));
+
+ xstats.weight = ONE_FP/cl->inv_w;
+ xstats.lmax = cl->lmax;
+
+ if (gnet_stats_copy_basic(d, &cl->bstats) < 0 ||
+ gnet_stats_copy_rate_est(d, NULL, &cl->rate_est) < 0 ||
+ gnet_stats_copy_queue(d, &cl->qdisc->qstats) < 0)
+ return -1;
+
+ return gnet_stats_copy_app(d, &xstats, sizeof(xstats));
+}
+
+static void qfq_walk(struct Qdisc *sch, struct qdisc_walker *arg)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_class *cl;
+ struct hlist_node *n;
+ unsigned int i;
+
+ if (arg->stop)
+ return;
+
+ for (i = 0; i < q->clhash.hashsize; i++) {
+ hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode) {
+ if (arg->count < arg->skip) {
+ arg->count++;
+ continue;
+ }
+ if (arg->fn(sch, (unsigned long)cl, arg) < 0) {
+ arg->stop = 1;
+ return;
+ }
+ arg->count++;
+ }
+ }
+}
+
+static struct qfq_class *qfq_classify(struct sk_buff *skb, struct Qdisc *sch,
+ int *qerr)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_class *cl;
+ struct tcf_result res;
+ int result;
+
+ if (TC_H_MAJ(skb->priority ^ sch->handle) == 0) {
+ pr_debug("qfq_classify: found %d\n", skb->priority);
+ cl = qfq_find_class(sch, skb->priority);
+ if (cl != NULL)
+ return cl;
+ }
+
+ *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
+ result = tc_classify(skb, q->filter_list, &res);
+ if (result >= 0) {
+#ifdef CONFIG_NET_CLS_ACT
+ switch (result) {
+ case TC_ACT_QUEUED:
+ case TC_ACT_STOLEN:
+ *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
+ case TC_ACT_SHOT:
+ return NULL;
+ }
+#endif
+ cl = (struct qfq_class *)res.class;
+ if (cl == NULL)
+ cl = qfq_find_class(sch, res.classid);
+ return cl;
+ }
+
+ return NULL;
+}
+
+/* Generic comparison function, handling wraparound. */
+static inline int qfq_gt(u64 a, u64 b)
+{
+ return (s64)(a - b) > 0;
+}
+
+/* Round a precise timestamp to its slotted value. */
+static inline u64 qfq_round_down(u64 ts, unsigned int shift)
+{
+ return ts & ~((1ULL << shift) - 1);
+}
+
+/* return the pointer to the group with lowest index in the bitmap */
+static inline struct qfq_group *qfq_ffs(struct qfq_sched *q,
+ unsigned long bitmap)
+{
+ int index = __ffs(bitmap);
+ return &q->groups[index];
+}
+/* Calculate a mask to mimic what would be ffs_from(). */
+static inline unsigned long mask_from(unsigned long bitmap, int from)
+{
+ return bitmap & ~((1UL << from) - 1);
+}
+
+/*
+ * The state computation relies on ER=0, IR=1, EB=2, IB=3
+ * First compute eligibility comparing grp->S, q->V,
+ * then check if someone is blocking us and possibly add EB
+ */
+static int qfq_calc_state(struct qfq_sched *q, const struct qfq_group *grp)
+{
+ /* if S > V we are not eligible */
+ unsigned int state = qfq_gt(grp->S, q->V);
+ unsigned long mask = mask_from(q->bitmaps[ER], grp->index);
+ struct qfq_group *next;
+
+ if (mask) {
+ next = qfq_ffs(q, mask);
+ if (qfq_gt(grp->F, next->F))
+ state |= EB;
+ }
+
+ return state;
+}
+
+
+/*
+ * In principle
+ * q->bitmaps[dst] |= q->bitmaps[src] & mask;
+ * q->bitmaps[src] &= ~mask;
+ * but we should make sure that src != dst
+ */
+static inline void qfq_move_groups(struct qfq_sched *q, unsigned long mask,
+ int src, int dst)
+{
+ q->bitmaps[dst] |= q->bitmaps[src] & mask;
+ q->bitmaps[src] &= ~mask;
+}
+
+static void qfq_unblock_groups(struct qfq_sched *q, int index, u64 old_F)
+{
+ unsigned long mask = mask_from(q->bitmaps[ER], index + 1);
+ struct qfq_group *next;
+
+ if (mask) {
+ next = qfq_ffs(q, mask);
+ if (!qfq_gt(next->F, old_F))
+ return;
+ }
+
+ mask = (1UL << index) - 1;
+ qfq_move_groups(q, mask, EB, ER);
+ qfq_move_groups(q, mask, IB, IR);
+}
+
+/*
+ * perhaps
+ *
+ old_V ^= q->V;
+ old_V >>= QFQ_MIN_SLOT_SHIFT;
+ if (old_V) {
+ ...
+ }
+ *
+ */
+static void qfq_make_eligible(struct qfq_sched *q, u64 old_V)
+{
+ unsigned long vslot = q->V >> QFQ_MIN_SLOT_SHIFT;
+ unsigned long old_vslot = old_V >> QFQ_MIN_SLOT_SHIFT;
+
+ if (vslot != old_vslot) {
+ unsigned long mask = (1UL << fls(vslot ^ old_vslot)) - 1;
+ qfq_move_groups(q, mask, IR, ER);
+ qfq_move_groups(q, mask, IB, EB);
+ }
+}
+
+/*
+ * XXX we should make sure that slot becomes less than 32.
+ * This is guaranteed by the input values.
+ * roundedS is always cl->S rounded on grp->slot_shift bits.
+ */
+static void qfq_slot_insert(struct qfq_group *grp, struct qfq_class *cl,
+ u64 roundedS)
+{
+ u64 slot = (roundedS - grp->S) >> grp->slot_shift;
+ unsigned int i = (grp->front + slot) % QFQ_MAX_SLOTS;
+
+ cl->next = grp->slots[i];
+ grp->slots[i] = cl;
+ __set_bit(slot, &grp->full_slots);
+}
+
+/*
+ * remove the entry from the slot
+ */
+static void qfq_front_slot_remove(struct qfq_group *grp)
+{
+ struct qfq_class **h = &grp->slots[grp->front];
+
+ *h = (*h)->next;
+ if (!*h)
+ __clear_bit(0, &grp->full_slots);
+}
+
+/*
+ * Returns the first full queue in a group. As a side effect,
+ * adjust the bucket list so the first non-empty bucket is at
+ * position 0 in full_slots.
+ */
+static struct qfq_class *qfq_slot_scan(struct qfq_group *grp)
+{
+ unsigned int i;
+
+ pr_debug("qfq slot_scan: grp %u full %#lx\n",
+ grp->index, grp->full_slots);
+
+ if (grp->full_slots == 0)
+ return NULL;
+
+ i = __ffs(grp->full_slots); /* zero based */
+ if (i > 0) {
+ grp->front = (grp->front + i) % QFQ_MAX_SLOTS;
+ grp->full_slots >>= i;
+ }
+
+ return grp->slots[grp->front];
+}
+
+/*
+ * adjust the bucket list. When the start time of a group decreases,
+ * we move the index down (modulo QFQ_MAX_SLOTS) so we don't need to
+ * move the objects. The mask of occupied slots must be shifted
+ * because we use ffs() to find the first non-empty slot.
+ * This covers decreases in the group's start time, but what about
+ * increases of the start time ?
+ * Here too we should make sure that i is less than 32
+ */
+static void qfq_slot_rotate(struct qfq_group *grp, u64 roundedS)
+{
+ unsigned int i = (grp->S - roundedS) >> grp->slot_shift;
+
+ grp->full_slots <<= i;
+ grp->front = (grp->front - i) % QFQ_MAX_SLOTS;
+}
+
+static void qfq_update_eligible(struct qfq_sched *q, u64 old_V)
+{
+ struct qfq_group *grp;
+ unsigned long ineligible;
+
+ ineligible = q->bitmaps[IR] | q->bitmaps[IB];
+ if (ineligible) {
+ if (!q->bitmaps[ER]) {
+ grp = qfq_ffs(q, ineligible);
+ if (qfq_gt(grp->S, q->V))
+ q->V = grp->S;
+ }
+ qfq_make_eligible(q, old_V);
+ }
+}
+
+/* What is length of next packet in queue (0 if queue is empty) */
+static unsigned int qdisc_peek_len(struct Qdisc *sch)
+{
+ struct sk_buff *skb;
+
+ skb = sch->ops->peek(sch);
+ return skb ? qdisc_pkt_len(skb) : 0;
+}
+
+/*
+ * Updates the class, returns true if also the group needs to be updated.
+ */
+static bool qfq_update_class(struct qfq_group *grp, struct qfq_class *cl)
+{
+ unsigned int len = qdisc_peek_len(cl->qdisc);
+
+ cl->S = cl->F;
+ if (!len)
+ qfq_front_slot_remove(grp); /* queue is empty */
+ else {
+ u64 roundedS;
+
+ cl->F = cl->S + (u64)len * cl->inv_w;
+ roundedS = qfq_round_down(cl->S, grp->slot_shift);
+ if (roundedS == grp->S)
+ return false;
+
+ qfq_front_slot_remove(grp);
+ qfq_slot_insert(grp, cl, roundedS);
+ }
+
+ return true;
+}
+
+static struct sk_buff *qfq_dequeue(struct Qdisc *sch)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_group *grp;
+ struct qfq_class *cl;
+ struct sk_buff *skb;
+ unsigned int len;
+ u64 old_V;
+
+ if (!q->bitmaps[ER])
+ return NULL;
+
+ grp = qfq_ffs(q, q->bitmaps[ER]);
+
+ cl = grp->slots[grp->front];
+ skb = qdisc_dequeue_peeked(cl->qdisc);
+ if (!skb) {
+ WARN_ONCE(1, "qfq_dequeue: non-workconserving leaf\n");
+ return NULL;
+ }
+
+ sch->q.qlen--;
+ qdisc_bstats_update(sch, skb);
+
+ old_V = q->V;
+ len = qdisc_pkt_len(skb);
+ q->V += (u64)len * IWSUM;
+ pr_debug("qfq dequeue: len %u F %lld now %lld\n",
+ len, (unsigned long long) cl->F, (unsigned long long) q->V);
+
+ if (qfq_update_class(grp, cl)) {
+ u64 old_F = grp->F;
+
+ cl = qfq_slot_scan(grp);
+ if (!cl)
+ __clear_bit(grp->index, &q->bitmaps[ER]);
+ else {
+ u64 roundedS = qfq_round_down(cl->S, grp->slot_shift);
+ unsigned int s;
+
+ if (grp->S == roundedS)
+ goto skip_unblock;
+ grp->S = roundedS;
+ grp->F = roundedS + (2ULL << grp->slot_shift);
+ __clear_bit(grp->index, &q->bitmaps[ER]);
+ s = qfq_calc_state(q, grp);
+ __set_bit(grp->index, &q->bitmaps[s]);
+ }
+
+ qfq_unblock_groups(q, grp->index, old_F);
+ }
+
+skip_unblock:
+ qfq_update_eligible(q, old_V);
+
+ return skb;
+}
+
+/*
+ * Assign a reasonable start time for a new flow k in group i.
+ * Admissible values for \hat(F) are multiples of \sigma_i
+ * no greater than V+\sigma_i . Larger values mean that
+ * we had a wraparound so we consider the timestamp to be stale.
+ *
+ * If F is not stale and F >= V then we set S = F.
+ * Otherwise we should assign S = V, but this may violate
+ * the ordering in ER. So, if we have groups in ER, set S to
+ * the F_j of the first group j which would be blocking us.
+ * We are guaranteed not to move S backward because
+ * otherwise our group i would still be blocked.
+ */
+static void qfq_update_start(struct qfq_sched *q, struct qfq_class *cl)
+{
+ unsigned long mask;
+ uint32_t limit, roundedF;
+ int slot_shift = cl->grp->slot_shift;
+
+ roundedF = qfq_round_down(cl->F, slot_shift);
+ limit = qfq_round_down(q->V, slot_shift) + (1UL << slot_shift);
+
+ if (!qfq_gt(cl->F, q->V) || qfq_gt(roundedF, limit)) {
+ /* timestamp was stale */
+ mask = mask_from(q->bitmaps[ER], cl->grp->index);
+ if (mask) {
+ struct qfq_group *next = qfq_ffs(q, mask);
+ if (qfq_gt(roundedF, next->F)) {
+ cl->S = next->F;
+ return;
+ }
+ }
+ cl->S = q->V;
+ } else /* timestamp is not stale */
+ cl->S = cl->F;
+}
+
+static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_group *grp;
+ struct qfq_class *cl;
+ int err;
+ u64 roundedS;
+ int s;
+
+ cl = qfq_classify(skb, sch, &err);
+ if (cl == NULL) {
+ if (err & __NET_XMIT_BYPASS)
+ sch->qstats.drops++;
+ kfree_skb(skb);
+ return err;
+ }
+ pr_debug("qfq_enqueue: cl = %x\n", cl->common.classid);
+
+ err = qdisc_enqueue(skb, cl->qdisc);
+ if (unlikely(err != NET_XMIT_SUCCESS)) {
+ pr_debug("qfq_enqueue: enqueue failed %d\n", err);
+ if (net_xmit_drop_count(err)) {
+ cl->qstats.drops++;
+ sch->qstats.drops++;
+ }
+ return err;
+ }
+
+ bstats_update(&cl->bstats, skb);
+ ++sch->q.qlen;
+
+ /* If the new skb is not the head of queue, then done here. */
+ if (skb != qdisc_peek_head(cl->qdisc))
+ return err;
+
+ /* If reach this point, queue q was idle */
+ grp = cl->grp;
+ qfq_update_start(q, cl);
+
+ /* compute new finish time and rounded start. */
+ cl->F = cl->S + (u64)qdisc_pkt_len(skb) * cl->inv_w;
+ roundedS = qfq_round_down(cl->S, grp->slot_shift);
+
+ /*
+ * insert cl in the correct bucket.
+ * If cl->S >= grp->S we don't need to adjust the
+ * bucket list and simply go to the insertion phase.
+ * Otherwise grp->S is decreasing, we must make room
+ * in the bucket list, and also recompute the group state.
+ * Finally, if there were no flows in this group and nobody
+ * was in ER make sure to adjust V.
+ */
+ if (grp->full_slots) {
+ if (!qfq_gt(grp->S, cl->S))
+ goto skip_update;
+
+ /* create a slot for this cl->S */
+ qfq_slot_rotate(grp, roundedS);
+ /* group was surely ineligible, remove */
+ __clear_bit(grp->index, &q->bitmaps[IR]);
+ __clear_bit(grp->index, &q->bitmaps[IB]);
+ } else if (!q->bitmaps[ER] && qfq_gt(roundedS, q->V))
+ q->V = roundedS;
+
+ grp->S = roundedS;
+ grp->F = roundedS + (2ULL << grp->slot_shift);
+ s = qfq_calc_state(q, grp);
+ __set_bit(grp->index, &q->bitmaps[s]);
+
+ pr_debug("qfq enqueue: new state %d %#lx S %lld F %lld V %lld\n",
+ s, q->bitmaps[s],
+ (unsigned long long) cl->S,
+ (unsigned long long) cl->F,
+ (unsigned long long) q->V);
+
+skip_update:
+ qfq_slot_insert(grp, cl, roundedS);
+
+ return err;
+}
+
+
+static void qfq_slot_remove(struct qfq_sched *q, struct qfq_group *grp,
+ struct qfq_class *cl, struct qfq_class **pprev)
+{
+ unsigned int i, offset;
+ u64 roundedS;
+
+ roundedS = qfq_round_down(cl->S, grp->slot_shift);
+ offset = (roundedS - grp->S) >> grp->slot_shift;
+ i = (grp->front + offset) % QFQ_MAX_SLOTS;
+
+ if (!pprev) {
+ pprev = &grp->slots[i];
+ while (*pprev && *pprev != cl)
+ pprev = &(*pprev)->next;
+ }
+
+ *pprev = cl->next;
+ if (!grp->slots[i])
+ __clear_bit(offset, &grp->full_slots);
+}
+
+/*
+ * called to forcibly destroy a queue.
+ * If the queue is not in the front bucket, or if it has
+ * other queues in the front bucket, we can simply remove
+ * the queue with no other side effects.
+ * Otherwise we must propagate the event up.
+ */
+static void qfq_deactivate_class(struct qfq_sched *q, struct qfq_class *cl,
+ struct qfq_class **pprev)
+{
+ struct qfq_group *grp = cl->grp;
+ unsigned long mask;
+ u64 roundedS;
+ int s;
+
+ cl->F = cl->S;
+ qfq_slot_remove(q, grp, cl, pprev);
+
+ if (!grp->full_slots) {
+ __clear_bit(grp->index, &q->bitmaps[IR]);
+ __clear_bit(grp->index, &q->bitmaps[EB]);
+ __clear_bit(grp->index, &q->bitmaps[IB]);
+
+ if (test_bit(grp->index, &q->bitmaps[ER]) &&
+ !(q->bitmaps[ER] & ~((1UL << grp->index) - 1))) {
+ mask = q->bitmaps[ER] & ((1UL << grp->index) - 1);
+ if (mask)
+ mask = ~((1UL << __fls(mask)) - 1);
+ else
+ mask = ~0UL;
+ qfq_move_groups(q, mask, EB, ER);
+ qfq_move_groups(q, mask, IB, IR);
+ }
+ __clear_bit(grp->index, &q->bitmaps[ER]);
+ } else if (!grp->slots[grp->front]) {
+ cl = qfq_slot_scan(grp);
+ roundedS = qfq_round_down(cl->S, grp->slot_shift);
+ if (grp->S != roundedS) {
+ __clear_bit(grp->index, &q->bitmaps[ER]);
+ __clear_bit(grp->index, &q->bitmaps[IR]);
+ __clear_bit(grp->index, &q->bitmaps[EB]);
+ __clear_bit(grp->index, &q->bitmaps[IB]);
+ grp->S = roundedS;
+ grp->F = roundedS + (2ULL << grp->slot_shift);
+ s = qfq_calc_state(q, grp);
+ __set_bit(grp->index, &q->bitmaps[s]);
+ }
+ }
+
+ qfq_update_eligible(q, q->V);
+}
+
+static void qfq_qlen_notify(struct Qdisc *sch, unsigned long arg)
+{
+ struct qfq_sched *q = (struct qfq_sched *)sch;
+ struct qfq_class *cl = (struct qfq_class *)arg;
+
+ if (cl->qdisc->q.qlen == 0)
+ qfq_deactivate_class(q, cl, NULL);
+}
+
+static unsigned int qfq_drop(struct Qdisc *sch)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_group *grp;
+ struct qfq_class *cl, **pp;
+ unsigned int i, j, len;
+
+ for (i = 0; i <= QFQ_MAX_INDEX; i++) {
+ grp = &q->groups[i];
+ for (j = 0; j < QFQ_MAX_SLOTS; j++) {
+ for (pp = &grp->slots[j]; *pp; pp = &(*pp)->next) {
+ cl = *pp;
+ if (!cl->qdisc->ops->drop)
+ continue;
+
+ len = cl->qdisc->ops->drop(cl->qdisc);
+ if (len > 0) {
+ sch->q.qlen--;
+ if (!cl->qdisc->q.qlen)
+ qfq_deactivate_class(q, cl, pp);
+
+ return len;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int qfq_init_qdisc(struct Qdisc *sch, struct nlattr *opt)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_group *grp;
+ int i, err;
+
+ err = qdisc_class_hash_init(&q->clhash);
+ if (err < 0)
+ return err;
+
+ for (i = 0; i <= QFQ_MAX_INDEX; i++) {
+ grp = &q->groups[i];
+ grp->index = i;
+ }
+
+ return 0;
+}
+
+static void qfq_reset_qdisc(struct Qdisc *sch)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_group *grp;
+ struct qfq_class *cl, **pp;
+ struct hlist_node *n;
+ unsigned int i, j;
+
+ for (i = 0; i <= QFQ_MAX_INDEX; i++) {
+ grp = &q->groups[i];
+ for (j = 0; j < QFQ_MAX_SLOTS; j++) {
+ for (pp = &grp->slots[j]; *pp; pp = &(*pp)->next) {
+ cl = *pp;
+ if (cl->qdisc->q.qlen)
+ qfq_deactivate_class(q, cl, pp);
+ }
+ }
+ }
+
+ for (i = 0; i < q->clhash.hashsize; i++) {
+ hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode)
+ qdisc_reset(cl->qdisc);
+ }
+ sch->q.qlen = 0;
+}
+
+static void qfq_destroy_qdisc(struct Qdisc *sch)
+{
+ struct qfq_sched *q = qdisc_priv(sch);
+ struct qfq_class *cl;
+ struct hlist_node *n, *next;
+ unsigned int i;
+
+ tcf_destroy_chain(&q->filter_list);
+
+ for (i = 0; i < q->clhash.hashsize; i++) {
+ hlist_for_each_entry_safe(cl, n, next, &q->clhash.hash[i],
+ common.hnode)
+ qfq_destroy_class(sch, cl);
+ }
+ qdisc_class_hash_destroy(&q->clhash);
+}
+
+static const struct Qdisc_class_ops qfq_class_ops = {
+ .change = qfq_change_class,
+ .delete = qfq_delete_class,
+ .get = qfq_get_class,
+ .put = qfq_put_class,
+ .tcf_chain = qfq_tcf_chain,
+ .bind_tcf = qfq_bind_tcf,
+ .unbind_tcf = qfq_unbind_tcf,
+ .graft = qfq_graft_class,
+ .leaf = qfq_class_leaf,
+ .qlen_notify = qfq_qlen_notify,
+ .dump = qfq_dump_class,
+ .dump_stats = qfq_dump_class_stats,
+ .walk = qfq_walk,
+};
+
+static struct Qdisc_ops qfq_qdisc_ops __read_mostly = {
+ .cl_ops = &qfq_class_ops,
+ .id = "qfq",
+ .priv_size = sizeof(struct qfq_sched),
+ .enqueue = qfq_enqueue,
+ .dequeue = qfq_dequeue,
+ .peek = qdisc_peek_dequeued,
+ .drop = qfq_drop,
+ .init = qfq_init_qdisc,
+ .reset = qfq_reset_qdisc,
+ .destroy = qfq_destroy_qdisc,
+ .owner = THIS_MODULE,
+};
+
+static int __init qfq_init(void)
+{
+ return register_qdisc(&qfq_qdisc_ops);
+}
+
+static void __exit qfq_exit(void)
+{
+ unregister_qdisc(&qfq_qdisc_ops);
+}
+
+module_init(qfq_init);
+module_exit(qfq_exit);
+MODULE_LICENSE("GPL");
^ permalink raw reply
* [PATCH net-next-2.6] sfc: Reduce size of efx_rx_buffer by unionising skb and page
From: Ben Hutchings @ 2011-03-01 1:21 UTC (permalink / raw)
To: David Miller; +Cc: linux-net-drivers, netdev
In-Reply-To: <1298942169.3069.179.camel@localhost>
From: Steve Hodgson <shodgson@solarflare.com>
[bwh: Forward-ported to net-next-2.6.]
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/net_driver.h | 8 +++-
drivers/net/sfc/rx.c | 96 +++++++++++++++++++----------------------
2 files changed, 51 insertions(+), 53 deletions(-)
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 15b9068..59ff32a 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -216,13 +216,17 @@ struct efx_tx_queue {
* If both this and skb are %NULL, the buffer slot is currently free.
* @data: Pointer to ethernet header
* @len: Buffer length, in bytes.
+ * @is_page: Indicates if @page is valid. If false, @skb is valid.
*/
struct efx_rx_buffer {
dma_addr_t dma_addr;
- struct sk_buff *skb;
- struct page *page;
+ union {
+ struct sk_buff *skb;
+ struct page *page;
+ } u;
char *data;
unsigned int len;
+ bool is_page;
};
/**
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
index 3925fd6..bcbd2ec 100644
--- a/drivers/net/sfc/rx.c
+++ b/drivers/net/sfc/rx.c
@@ -129,6 +129,7 @@ static int efx_init_rx_buffers_skb(struct efx_rx_queue *rx_queue)
struct efx_nic *efx = rx_queue->efx;
struct net_device *net_dev = efx->net_dev;
struct efx_rx_buffer *rx_buf;
+ struct sk_buff *skb;
int skb_len = efx->rx_buffer_len;
unsigned index, count;
@@ -136,24 +137,24 @@ static int efx_init_rx_buffers_skb(struct efx_rx_queue *rx_queue)
index = rx_queue->added_count & rx_queue->ptr_mask;
rx_buf = efx_rx_buffer(rx_queue, index);
- rx_buf->skb = netdev_alloc_skb(net_dev, skb_len);
- if (unlikely(!rx_buf->skb))
+ rx_buf->u.skb = skb = netdev_alloc_skb(net_dev, skb_len);
+ if (unlikely(!skb))
return -ENOMEM;
- rx_buf->page = NULL;
/* Adjust the SKB for padding and checksum */
- skb_reserve(rx_buf->skb, NET_IP_ALIGN);
+ skb_reserve(skb, NET_IP_ALIGN);
+ rx_buf->data = (char *)skb->data;
rx_buf->len = skb_len - NET_IP_ALIGN;
- rx_buf->data = (char *)rx_buf->skb->data;
- rx_buf->skb->ip_summed = CHECKSUM_UNNECESSARY;
+ rx_buf->is_page = false;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
rx_buf->dma_addr = pci_map_single(efx->pci_dev,
rx_buf->data, rx_buf->len,
PCI_DMA_FROMDEVICE);
if (unlikely(pci_dma_mapping_error(efx->pci_dev,
rx_buf->dma_addr))) {
- dev_kfree_skb_any(rx_buf->skb);
- rx_buf->skb = NULL;
+ dev_kfree_skb_any(skb);
+ rx_buf->u.skb = NULL;
return -EIO;
}
@@ -211,10 +212,10 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)
index = rx_queue->added_count & rx_queue->ptr_mask;
rx_buf = efx_rx_buffer(rx_queue, index);
rx_buf->dma_addr = dma_addr + EFX_PAGE_IP_ALIGN;
- rx_buf->skb = NULL;
- rx_buf->page = page;
+ rx_buf->u.page = page;
rx_buf->data = page_addr + EFX_PAGE_IP_ALIGN;
rx_buf->len = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;
+ rx_buf->is_page = true;
++rx_queue->added_count;
++rx_queue->alloc_page_count;
++state->refcnt;
@@ -235,19 +236,17 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)
static void efx_unmap_rx_buffer(struct efx_nic *efx,
struct efx_rx_buffer *rx_buf)
{
- if (rx_buf->page) {
+ if (rx_buf->is_page && rx_buf->u.page) {
struct efx_rx_page_state *state;
- EFX_BUG_ON_PARANOID(rx_buf->skb);
-
- state = page_address(rx_buf->page);
+ state = page_address(rx_buf->u.page);
if (--state->refcnt == 0) {
pci_unmap_page(efx->pci_dev,
state->dma_addr,
efx_rx_buf_size(efx),
PCI_DMA_FROMDEVICE);
}
- } else if (likely(rx_buf->skb)) {
+ } else if (!rx_buf->is_page && rx_buf->u.skb) {
pci_unmap_single(efx->pci_dev, rx_buf->dma_addr,
rx_buf->len, PCI_DMA_FROMDEVICE);
}
@@ -256,12 +255,12 @@ static void efx_unmap_rx_buffer(struct efx_nic *efx,
static void efx_free_rx_buffer(struct efx_nic *efx,
struct efx_rx_buffer *rx_buf)
{
- if (rx_buf->page) {
- __free_pages(rx_buf->page, efx->rx_buffer_order);
- rx_buf->page = NULL;
- } else if (likely(rx_buf->skb)) {
- dev_kfree_skb_any(rx_buf->skb);
- rx_buf->skb = NULL;
+ if (rx_buf->is_page && rx_buf->u.page) {
+ __free_pages(rx_buf->u.page, efx->rx_buffer_order);
+ rx_buf->u.page = NULL;
+ } else if (!rx_buf->is_page && rx_buf->u.skb) {
+ dev_kfree_skb_any(rx_buf->u.skb);
+ rx_buf->u.skb = NULL;
}
}
@@ -277,7 +276,7 @@ static void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
static void efx_resurrect_rx_buffer(struct efx_rx_queue *rx_queue,
struct efx_rx_buffer *rx_buf)
{
- struct efx_rx_page_state *state = page_address(rx_buf->page);
+ struct efx_rx_page_state *state = page_address(rx_buf->u.page);
struct efx_rx_buffer *new_buf;
unsigned fill_level, index;
@@ -292,16 +291,16 @@ static void efx_resurrect_rx_buffer(struct efx_rx_queue *rx_queue,
}
++state->refcnt;
- get_page(rx_buf->page);
+ get_page(rx_buf->u.page);
index = rx_queue->added_count & rx_queue->ptr_mask;
new_buf = efx_rx_buffer(rx_queue, index);
new_buf->dma_addr = rx_buf->dma_addr ^ (PAGE_SIZE >> 1);
- new_buf->skb = NULL;
- new_buf->page = rx_buf->page;
+ new_buf->u.page = rx_buf->u.page;
new_buf->data = (void *)
((__force unsigned long)rx_buf->data ^ (PAGE_SIZE >> 1));
new_buf->len = rx_buf->len;
+ new_buf->is_page = true;
++rx_queue->added_count;
}
@@ -315,16 +314,15 @@ static void efx_recycle_rx_buffer(struct efx_channel *channel,
struct efx_rx_buffer *new_buf;
unsigned index;
- if (rx_buf->page != NULL && efx->rx_buffer_len <= EFX_RX_HALF_PAGE &&
- page_count(rx_buf->page) == 1)
+ if (rx_buf->is_page && efx->rx_buffer_len <= EFX_RX_HALF_PAGE &&
+ page_count(rx_buf->u.page) == 1)
efx_resurrect_rx_buffer(rx_queue, rx_buf);
index = rx_queue->added_count & rx_queue->ptr_mask;
new_buf = efx_rx_buffer(rx_queue, index);
memcpy(new_buf, rx_buf, sizeof(*new_buf));
- rx_buf->page = NULL;
- rx_buf->skb = NULL;
+ rx_buf->u.page = NULL;
++rx_queue->added_count;
}
@@ -428,7 +426,7 @@ static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
* data at the end of the skb will be trashed. So
* we have no choice but to leak the fragment.
*/
- *leak_packet = (rx_buf->skb != NULL);
+ *leak_packet = !rx_buf->is_page;
efx_schedule_reset(efx, RESET_TYPE_RX_RECOVERY);
} else {
if (net_ratelimit())
@@ -454,13 +452,12 @@ static void efx_rx_packet_gro(struct efx_channel *channel,
gro_result_t gro_result;
/* Pass the skb/page into the GRO engine */
- if (rx_buf->page) {
+ if (rx_buf->is_page) {
struct efx_nic *efx = channel->efx;
- struct page *page = rx_buf->page;
+ struct page *page = rx_buf->u.page;
struct sk_buff *skb;
- EFX_BUG_ON_PARANOID(rx_buf->skb);
- rx_buf->page = NULL;
+ rx_buf->u.page = NULL;
skb = napi_get_frags(napi);
if (!skb) {
@@ -487,11 +484,10 @@ static void efx_rx_packet_gro(struct efx_channel *channel,
gro_result = napi_gro_frags(napi);
} else {
- struct sk_buff *skb = rx_buf->skb;
+ struct sk_buff *skb = rx_buf->u.skb;
- EFX_BUG_ON_PARANOID(!skb);
EFX_BUG_ON_PARANOID(!checksummed);
- rx_buf->skb = NULL;
+ rx_buf->u.skb = NULL;
gro_result = napi_gro_receive(napi, skb);
}
@@ -514,8 +510,6 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
rx_buf = efx_rx_buffer(rx_queue, index);
EFX_BUG_ON_PARANOID(!rx_buf->data);
- EFX_BUG_ON_PARANOID(rx_buf->skb && rx_buf->page);
- EFX_BUG_ON_PARANOID(!(rx_buf->skb || rx_buf->page));
/* This allows the refill path to post another buffer.
* EFX_RXD_HEAD_ROOM ensures that the slot we are using
@@ -587,32 +581,32 @@ void __efx_rx_packet(struct efx_channel *channel,
return;
}
- if (rx_buf->skb) {
- prefetch(skb_shinfo(rx_buf->skb));
+ if (!rx_buf->is_page) {
+ skb = rx_buf->u.skb;
+
+ prefetch(skb_shinfo(skb));
- skb_reserve(rx_buf->skb, efx->type->rx_buffer_hash_size);
- skb_put(rx_buf->skb, rx_buf->len);
+ skb_reserve(skb, efx->type->rx_buffer_hash_size);
+ skb_put(skb, rx_buf->len);
if (efx->net_dev->features & NETIF_F_RXHASH)
- rx_buf->skb->rxhash = efx_rx_buf_hash(rx_buf);
+ skb->rxhash = efx_rx_buf_hash(rx_buf);
/* Move past the ethernet header. rx_buf->data still points
* at the ethernet header */
- rx_buf->skb->protocol = eth_type_trans(rx_buf->skb,
- efx->net_dev);
+ skb->protocol = eth_type_trans(skb, efx->net_dev);
- skb_record_rx_queue(rx_buf->skb, channel->channel);
+ skb_record_rx_queue(skb, channel->channel);
}
- if (likely(checksummed || rx_buf->page)) {
+ if (likely(checksummed || rx_buf->is_page)) {
efx_rx_packet_gro(channel, rx_buf, checksummed);
return;
}
/* We now own the SKB */
- skb = rx_buf->skb;
- rx_buf->skb = NULL;
- EFX_BUG_ON_PARANOID(!skb);
+ skb = rx_buf->u.skb;
+ rx_buf->u.skb = NULL;
/* Set the SKB flags */
skb_checksum_none_assert(skb);
--
1.5.4
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH net-next-2.6 2/8] sfc: Reduce size of efx_rx_buffer further by removing data member
From: Ben Hutchings @ 2011-03-01 1:22 UTC (permalink / raw)
To: David Miller; +Cc: linux-net-drivers, netdev
In-Reply-To: <1298942169.3069.179.camel@localhost>
From: Steve Hodgson <shodgson@solarflare.com>
Instead calculate the KVA of receive data. It's not like it's a hard sum.
[bwh: Fixed to work with GRO.]
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/net_driver.h | 2 -
drivers/net/sfc/rx.c | 50 +++++++++++++++++++++++------------------
2 files changed, 28 insertions(+), 24 deletions(-)
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 59ff32a..5b001c1 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -214,7 +214,6 @@ struct efx_tx_queue {
* If both this and page are %NULL, the buffer slot is currently free.
* @page: The associated page buffer, if any.
* If both this and skb are %NULL, the buffer slot is currently free.
- * @data: Pointer to ethernet header
* @len: Buffer length, in bytes.
* @is_page: Indicates if @page is valid. If false, @skb is valid.
*/
@@ -224,7 +223,6 @@ struct efx_rx_buffer {
struct sk_buff *skb;
struct page *page;
} u;
- char *data;
unsigned int len;
bool is_page;
};
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
index bcbd2ec..81bec87 100644
--- a/drivers/net/sfc/rx.c
+++ b/drivers/net/sfc/rx.c
@@ -89,24 +89,37 @@ static unsigned int rx_refill_limit = 95;
*/
#define EFX_RXD_HEAD_ROOM 2
-static inline unsigned int efx_rx_buf_offset(struct efx_rx_buffer *buf)
+/* Offset of ethernet header within page */
+static inline unsigned int efx_rx_buf_offset(struct efx_nic *efx,
+ struct efx_rx_buffer *buf)
{
/* Offset is always within one page, so we don't need to consider
* the page order.
*/
- return (__force unsigned long) buf->data & (PAGE_SIZE - 1);
+ return (((__force unsigned long) buf->dma_addr & (PAGE_SIZE - 1)) +
+ efx->type->rx_buffer_hash_size);
}
static inline unsigned int efx_rx_buf_size(struct efx_nic *efx)
{
return PAGE_SIZE << efx->rx_buffer_order;
}
-static inline u32 efx_rx_buf_hash(struct efx_rx_buffer *buf)
+static u8 *efx_rx_buf_eh(struct efx_nic *efx, struct efx_rx_buffer *buf)
{
+ if (buf->is_page)
+ return page_address(buf->u.page) + efx_rx_buf_offset(efx, buf);
+ else
+ return ((u8 *)buf->u.skb->data +
+ efx->type->rx_buffer_hash_size);
+}
+
+static inline u32 efx_rx_buf_hash(const u8 *eh)
+{
+ /* The ethernet header is always directly after any hash. */
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) || NET_IP_ALIGN % 4 == 0
- return __le32_to_cpup((const __le32 *)(buf->data - 4));
+ return __le32_to_cpup((const __le32 *)(eh - 4));
#else
- const u8 *data = (const u8 *)(buf->data - 4);
+ const u8 *data = eh - 4;
return ((u32)data[0] |
(u32)data[1] << 8 |
(u32)data[2] << 16 |
@@ -143,13 +156,12 @@ static int efx_init_rx_buffers_skb(struct efx_rx_queue *rx_queue)
/* Adjust the SKB for padding and checksum */
skb_reserve(skb, NET_IP_ALIGN);
- rx_buf->data = (char *)skb->data;
rx_buf->len = skb_len - NET_IP_ALIGN;
rx_buf->is_page = false;
skb->ip_summed = CHECKSUM_UNNECESSARY;
rx_buf->dma_addr = pci_map_single(efx->pci_dev,
- rx_buf->data, rx_buf->len,
+ skb->data, rx_buf->len,
PCI_DMA_FROMDEVICE);
if (unlikely(pci_dma_mapping_error(efx->pci_dev,
rx_buf->dma_addr))) {
@@ -213,7 +225,6 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)
rx_buf = efx_rx_buffer(rx_queue, index);
rx_buf->dma_addr = dma_addr + EFX_PAGE_IP_ALIGN;
rx_buf->u.page = page;
- rx_buf->data = page_addr + EFX_PAGE_IP_ALIGN;
rx_buf->len = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;
rx_buf->is_page = true;
++rx_queue->added_count;
@@ -297,8 +308,6 @@ static void efx_resurrect_rx_buffer(struct efx_rx_queue *rx_queue,
new_buf = efx_rx_buffer(rx_queue, index);
new_buf->dma_addr = rx_buf->dma_addr ^ (PAGE_SIZE >> 1);
new_buf->u.page = rx_buf->u.page;
- new_buf->data = (void *)
- ((__force unsigned long)rx_buf->data ^ (PAGE_SIZE >> 1));
new_buf->len = rx_buf->len;
new_buf->is_page = true;
++rx_queue->added_count;
@@ -446,7 +455,7 @@ static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
*/
static void efx_rx_packet_gro(struct efx_channel *channel,
struct efx_rx_buffer *rx_buf,
- bool checksummed)
+ const u8 *eh, bool checksummed)
{
struct napi_struct *napi = &channel->napi_str;
gro_result_t gro_result;
@@ -466,11 +475,11 @@ static void efx_rx_packet_gro(struct efx_channel *channel,
}
if (efx->net_dev->features & NETIF_F_RXHASH)
- skb->rxhash = efx_rx_buf_hash(rx_buf);
+ skb->rxhash = efx_rx_buf_hash(eh);
skb_shinfo(skb)->frags[0].page = page;
skb_shinfo(skb)->frags[0].page_offset =
- efx_rx_buf_offset(rx_buf);
+ efx_rx_buf_offset(efx, rx_buf);
skb_shinfo(skb)->frags[0].size = rx_buf->len;
skb_shinfo(skb)->nr_frags = 1;
@@ -509,7 +518,6 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
bool leak_packet = false;
rx_buf = efx_rx_buffer(rx_queue, index);
- EFX_BUG_ON_PARANOID(!rx_buf->data);
/* This allows the refill path to post another buffer.
* EFX_RXD_HEAD_ROOM ensures that the slot we are using
@@ -548,12 +556,12 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
/* Prefetch nice and early so data will (hopefully) be in cache by
* the time we look at it.
*/
- prefetch(rx_buf->data);
+ prefetch(efx_rx_buf_eh(efx, rx_buf));
/* Pipeline receives so that we give time for packet headers to be
* prefetched into cache.
*/
- rx_buf->len = len;
+ rx_buf->len = len - efx->type->rx_buffer_hash_size;
out:
if (channel->rx_pkt)
__efx_rx_packet(channel,
@@ -568,15 +576,13 @@ void __efx_rx_packet(struct efx_channel *channel,
{
struct efx_nic *efx = channel->efx;
struct sk_buff *skb;
-
- rx_buf->data += efx->type->rx_buffer_hash_size;
- rx_buf->len -= efx->type->rx_buffer_hash_size;
+ u8 *eh = efx_rx_buf_eh(efx, rx_buf);
/* If we're in loopback test, then pass the packet directly to the
* loopback layer, and free the rx_buf here
*/
if (unlikely(efx->loopback_selftest)) {
- efx_loopback_rx_packet(efx, rx_buf->data, rx_buf->len);
+ efx_loopback_rx_packet(efx, eh, rx_buf->len);
efx_free_rx_buffer(efx, rx_buf);
return;
}
@@ -590,7 +596,7 @@ void __efx_rx_packet(struct efx_channel *channel,
skb_put(skb, rx_buf->len);
if (efx->net_dev->features & NETIF_F_RXHASH)
- skb->rxhash = efx_rx_buf_hash(rx_buf);
+ skb->rxhash = efx_rx_buf_hash(eh);
/* Move past the ethernet header. rx_buf->data still points
* at the ethernet header */
@@ -600,7 +606,7 @@ void __efx_rx_packet(struct efx_channel *channel,
}
if (likely(checksummed || rx_buf->is_page)) {
- efx_rx_packet_gro(channel, rx_buf, checksummed);
+ efx_rx_packet_gro(channel, rx_buf, eh, checksummed);
return;
}
--
1.5.4
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH net-next-2.6 3/8] sfc: Read MC firmware version when requested through ethtool
From: Ben Hutchings @ 2011-03-01 1:22 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
In-Reply-To: <1298942169.3069.179.camel@localhost>
We currently make no use of siena_nic_data::fw_{version,build} except
to format the firmware version for ethtool_get_drvinfo(). Since we
only read the version at start of day, this information is incorrect
after an MC firmware update. Remove the cached version information
and read it via MCDI whenever it is requested.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/ethtool.c | 4 ++--
drivers/net/sfc/mcdi.c | 21 ++++++---------------
drivers/net/sfc/mcdi.h | 2 +-
drivers/net/sfc/nic.h | 6 ------
drivers/net/sfc/siena.c | 17 -----------------
5 files changed, 9 insertions(+), 41 deletions(-)
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 272cfe7..3e974b1 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -237,8 +237,8 @@ static void efx_ethtool_get_drvinfo(struct net_device *net_dev,
strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version));
if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0)
- siena_print_fwver(efx, info->fw_version,
- sizeof(info->fw_version));
+ efx_mcdi_print_fwver(efx, info->fw_version,
+ sizeof(info->fw_version));
strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info));
}
diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c
index b716e82..88e786b 100644
--- a/drivers/net/sfc/mcdi.c
+++ b/drivers/net/sfc/mcdi.c
@@ -602,7 +602,7 @@ void efx_mcdi_process_event(struct efx_channel *channel,
**************************************************************************
*/
-int efx_mcdi_fwver(struct efx_nic *efx, u64 *version, u32 *build)
+void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len)
{
u8 outbuf[ALIGN(MC_CMD_GET_VERSION_V1_OUT_LEN, 4)];
size_t outlength;
@@ -616,29 +616,20 @@ int efx_mcdi_fwver(struct efx_nic *efx, u64 *version, u32 *build)
if (rc)
goto fail;
- if (outlength == MC_CMD_GET_VERSION_V0_OUT_LEN) {
- *version = 0;
- *build = MCDI_DWORD(outbuf, GET_VERSION_OUT_FIRMWARE);
- return 0;
- }
-
if (outlength < MC_CMD_GET_VERSION_V1_OUT_LEN) {
rc = -EIO;
goto fail;
}
ver_words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_OUT_VERSION);
- *version = (((u64)le16_to_cpu(ver_words[0]) << 48) |
- ((u64)le16_to_cpu(ver_words[1]) << 32) |
- ((u64)le16_to_cpu(ver_words[2]) << 16) |
- le16_to_cpu(ver_words[3]));
- *build = MCDI_DWORD(outbuf, GET_VERSION_OUT_FIRMWARE);
-
- return 0;
+ snprintf(buf, len, "%u.%u.%u.%u",
+ le16_to_cpu(ver_words[0]), le16_to_cpu(ver_words[1]),
+ le16_to_cpu(ver_words[2]), le16_to_cpu(ver_words[3]));
+ return;
fail:
netif_err(efx, probe, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
- return rc;
+ buf[0] = 0;
}
int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
diff --git a/drivers/net/sfc/mcdi.h b/drivers/net/sfc/mcdi.h
index c792f1d..9bac250 100644
--- a/drivers/net/sfc/mcdi.h
+++ b/drivers/net/sfc/mcdi.h
@@ -93,7 +93,7 @@ extern void efx_mcdi_process_event(struct efx_channel *channel,
#define MCDI_EVENT_FIELD(_ev, _field) \
EFX_QWORD_FIELD(_ev, MCDI_EVENT_ ## _field)
-extern int efx_mcdi_fwver(struct efx_nic *efx, u64 *version, u32 *build);
+extern void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len);
extern int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
bool *was_attached_out);
extern int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address,
diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h
index eb05869..17407ea 100644
--- a/drivers/net/sfc/nic.h
+++ b/drivers/net/sfc/nic.h
@@ -142,20 +142,14 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx)
/**
* struct siena_nic_data - Siena NIC state
- * @fw_version: Management controller firmware version
- * @fw_build: Firmware build number
* @mcdi: Management-Controller-to-Driver Interface
* @wol_filter_id: Wake-on-LAN packet filter id
*/
struct siena_nic_data {
- u64 fw_version;
- u32 fw_build;
struct efx_mcdi_iface mcdi;
int wol_filter_id;
};
-extern void siena_print_fwver(struct efx_nic *efx, char *buf, size_t len);
-
extern struct efx_nic_type falcon_a1_nic_type;
extern struct efx_nic_type falcon_b0_nic_type;
extern struct efx_nic_type siena_a0_nic_type;
diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c
index bf84561..07b59a8 100644
--- a/drivers/net/sfc/siena.c
+++ b/drivers/net/sfc/siena.c
@@ -227,13 +227,6 @@ static int siena_probe_nic(struct efx_nic *efx)
if (rc)
goto fail1;
- rc = efx_mcdi_fwver(efx, &nic_data->fw_version, &nic_data->fw_build);
- if (rc) {
- netif_err(efx, probe, efx->net_dev,
- "Failed to read MCPU firmware version - rc %d\n", rc);
- goto fail1; /* MCPU absent? */
- }
-
/* Let the BMC know that the driver is now in charge of link and
* filter settings. We must do this before we reset the NIC */
rc = efx_mcdi_drv_attach(efx, true, &already_attached);
@@ -514,16 +507,6 @@ static void siena_stop_nic_stats(struct efx_nic *efx)
efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr, 0, 0, 0);
}
-void siena_print_fwver(struct efx_nic *efx, char *buf, size_t len)
-{
- struct siena_nic_data *nic_data = efx->nic_data;
- snprintf(buf, len, "%u.%u.%u.%u",
- (unsigned int)(nic_data->fw_version >> 48),
- (unsigned int)(nic_data->fw_version >> 32 & 0xffff),
- (unsigned int)(nic_data->fw_version >> 16 & 0xffff),
- (unsigned int)(nic_data->fw_version & 0xffff));
-}
-
/**************************************************************************
*
* Wake on LAN
--
1.5.4
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH net-next-2.6 4/8] sfc: Do not read STAT1.FAULT in efx_mdio_check_mmd()
From: Ben Hutchings @ 2011-03-01 1:22 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
In-Reply-To: <1298942169.3069.179.camel@localhost>
This field does not exist in all MMDs we want to check, and all
callers allow it to be set (fault_fatal = 0).
Remove the loopback condition, as STAT2.DEVPRST should be valid
regardless of any fault.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/mdio_10g.c | 32 +++++---------------------------
drivers/net/sfc/mdio_10g.h | 3 +--
drivers/net/sfc/tenxpress.c | 2 +-
drivers/net/sfc/txc43128_phy.c | 2 +-
4 files changed, 8 insertions(+), 31 deletions(-)
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
index 56b0266..6e82e5b 100644
--- a/drivers/net/sfc/mdio_10g.c
+++ b/drivers/net/sfc/mdio_10g.c
@@ -51,13 +51,10 @@ int efx_mdio_reset_mmd(struct efx_nic *port, int mmd,
return spins ? spins : -ETIMEDOUT;
}
-static int efx_mdio_check_mmd(struct efx_nic *efx, int mmd, int fault_fatal)
+static int efx_mdio_check_mmd(struct efx_nic *efx, int mmd)
{
int status;
- if (LOOPBACK_INTERNAL(efx))
- return 0;
-
if (mmd != MDIO_MMD_AN) {
/* Read MMD STATUS2 to check it is responding. */
status = efx_mdio_read(efx, mmd, MDIO_STAT2);
@@ -68,20 +65,6 @@ static int efx_mdio_check_mmd(struct efx_nic *efx, int mmd, int fault_fatal)
}
}
- /* Read MMD STATUS 1 to check for fault. */
- status = efx_mdio_read(efx, mmd, MDIO_STAT1);
- if (status & MDIO_STAT1_FAULT) {
- if (fault_fatal) {
- netif_err(efx, hw, efx->net_dev,
- "PHY MMD %d reporting fatal"
- " fault: status %x\n", mmd, status);
- return -EIO;
- } else {
- netif_dbg(efx, hw, efx->net_dev,
- "PHY MMD %d reporting status"
- " %x (expected)\n", mmd, status);
- }
- }
return 0;
}
@@ -130,8 +113,7 @@ int efx_mdio_wait_reset_mmds(struct efx_nic *efx, unsigned int mmd_mask)
return rc;
}
-int efx_mdio_check_mmds(struct efx_nic *efx,
- unsigned int mmd_mask, unsigned int fatal_mask)
+int efx_mdio_check_mmds(struct efx_nic *efx, unsigned int mmd_mask)
{
int mmd = 0, probe_mmd, devs1, devs2;
u32 devices;
@@ -161,13 +143,9 @@ int efx_mdio_check_mmds(struct efx_nic *efx,
/* Check all required MMDs are responding and happy. */
while (mmd_mask) {
- if (mmd_mask & 1) {
- int fault_fatal = fatal_mask & 1;
- if (efx_mdio_check_mmd(efx, mmd, fault_fatal))
- return -EIO;
- }
+ if ((mmd_mask & 1) && efx_mdio_check_mmd(efx, mmd))
+ return -EIO;
mmd_mask = mmd_mask >> 1;
- fatal_mask = fatal_mask >> 1;
mmd++;
}
@@ -337,7 +315,7 @@ int efx_mdio_test_alive(struct efx_nic *efx)
"no MDIO PHY present with ID %d\n", efx->mdio.prtad);
rc = -EINVAL;
} else {
- rc = efx_mdio_check_mmds(efx, efx->mdio.mmds, 0);
+ rc = efx_mdio_check_mmds(efx, efx->mdio.mmds);
}
mutex_unlock(&efx->mac_lock);
diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h
index 75791d3..44c5dee 100644
--- a/drivers/net/sfc/mdio_10g.h
+++ b/drivers/net/sfc/mdio_10g.h
@@ -68,8 +68,7 @@ extern int efx_mdio_reset_mmd(struct efx_nic *efx, int mmd,
int spins, int spintime);
/* As efx_mdio_check_mmd but for multiple MMDs */
-int efx_mdio_check_mmds(struct efx_nic *efx,
- unsigned int mmd_mask, unsigned int fatal_mask);
+int efx_mdio_check_mmds(struct efx_nic *efx, unsigned int mmd_mask);
/* Check the link status of specified mmds in bit mask */
extern bool efx_mdio_links_ok(struct efx_nic *efx, unsigned int mmd_mask);
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index f102912..581911f 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -196,7 +196,7 @@ static int tenxpress_phy_init(struct efx_nic *efx)
if (rc < 0)
return rc;
- rc = efx_mdio_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0);
+ rc = efx_mdio_check_mmds(efx, TENXPRESS_REQUIRED_DEVS);
if (rc < 0)
return rc;
}
diff --git a/drivers/net/sfc/txc43128_phy.c b/drivers/net/sfc/txc43128_phy.c
index 351794a..4e2b48a 100644
--- a/drivers/net/sfc/txc43128_phy.c
+++ b/drivers/net/sfc/txc43128_phy.c
@@ -193,7 +193,7 @@ static int txc_reset_phy(struct efx_nic *efx)
goto fail;
/* Check that all the MMDs we expect are present and responding. */
- rc = efx_mdio_check_mmds(efx, TXC_REQUIRED_DEVS, 0);
+ rc = efx_mdio_check_mmds(efx, TXC_REQUIRED_DEVS);
if (rc < 0)
goto fail;
--
1.5.4
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH net-next-2.6 5/8] sfc: Update copyright dates
From: Ben Hutchings @ 2011-03-01 1:23 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
In-Reply-To: <1298942169.3069.179.camel@localhost>
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/efx.c | 2 +-
drivers/net/sfc/efx.h | 2 +-
drivers/net/sfc/ethtool.c | 2 +-
drivers/net/sfc/falcon.c | 2 +-
drivers/net/sfc/falcon_boards.c | 2 +-
drivers/net/sfc/falcon_xmac.c | 2 +-
drivers/net/sfc/io.h | 2 +-
drivers/net/sfc/mcdi.c | 2 +-
drivers/net/sfc/mcdi.h | 2 +-
drivers/net/sfc/mcdi_mac.c | 2 +-
drivers/net/sfc/mcdi_pcol.h | 2 +-
drivers/net/sfc/mcdi_phy.c | 2 +-
drivers/net/sfc/mdio_10g.c | 2 +-
drivers/net/sfc/mdio_10g.h | 2 +-
drivers/net/sfc/mtd.c | 2 +-
drivers/net/sfc/net_driver.h | 2 +-
drivers/net/sfc/nic.c | 2 +-
drivers/net/sfc/nic.h | 2 +-
drivers/net/sfc/phy.h | 2 +-
drivers/net/sfc/qt202x_phy.c | 2 +-
drivers/net/sfc/regs.h | 2 +-
drivers/net/sfc/rx.c | 2 +-
drivers/net/sfc/selftest.c | 2 +-
drivers/net/sfc/selftest.h | 2 +-
drivers/net/sfc/siena.c | 2 +-
drivers/net/sfc/spi.h | 2 +-
drivers/net/sfc/tenxpress.c | 2 +-
drivers/net/sfc/tx.c | 2 +-
drivers/net/sfc/txc43128_phy.c | 2 +-
drivers/net/sfc/workarounds.h | 2 +-
30 files changed, 30 insertions(+), 30 deletions(-)
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 35b7bc5..d563049 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1,7 +1,7 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2005-2009 Solarflare Communications Inc.
+ * Copyright 2005-2011 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h
index cbce62b..3d83a1f 100644
--- a/drivers/net/sfc/efx.h
+++ b/drivers/net/sfc/efx.h
@@ -1,7 +1,7 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2006-2009 Solarflare Communications Inc.
+ * Copyright 2006-2010 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 3e974b1..52fa661 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -1,7 +1,7 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2006-2009 Solarflare Communications Inc.
+ * Copyright 2006-2010 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 61ddd2c..87481a6 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -1,7 +1,7 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2006-2009 Solarflare Communications Inc.
+ * Copyright 2006-2010 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c
index 2dd16f0..b9cc846 100644
--- a/drivers/net/sfc/falcon_boards.c
+++ b/drivers/net/sfc/falcon_boards.c
@@ -1,6 +1,6 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2007-2009 Solarflare Communications Inc.
+ * Copyright 2007-2010 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
index b49e843..2c9ee5d 100644
--- a/drivers/net/sfc/falcon_xmac.c
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -1,7 +1,7 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2006-2009 Solarflare Communications Inc.
+ * Copyright 2006-2010 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/io.h b/drivers/net/sfc/io.h
index 6da4ae2..dc45110 100644
--- a/drivers/net/sfc/io.h
+++ b/drivers/net/sfc/io.h
@@ -1,7 +1,7 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2006-2009 Solarflare Communications Inc.
+ * Copyright 2006-2010 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c
index 88e786b..8bba895 100644
--- a/drivers/net/sfc/mcdi.c
+++ b/drivers/net/sfc/mcdi.c
@@ -1,6 +1,6 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2008-2009 Solarflare Communications Inc.
+ * Copyright 2008-2011 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/mcdi.h b/drivers/net/sfc/mcdi.h
index 9bac250..aced2a7 100644
--- a/drivers/net/sfc/mcdi.h
+++ b/drivers/net/sfc/mcdi.h
@@ -1,6 +1,6 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2008-2009 Solarflare Communications Inc.
+ * Copyright 2008-2010 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/mcdi_mac.c b/drivers/net/sfc/mcdi_mac.c
index f88f4bf..33f7294 100644
--- a/drivers/net/sfc/mcdi_mac.c
+++ b/drivers/net/sfc/mcdi_mac.c
@@ -1,6 +1,6 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2009 Solarflare Communications Inc.
+ * Copyright 2009-2010 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/mcdi_pcol.h b/drivers/net/sfc/mcdi_pcol.h
index 90359e6..b86a15f 100644
--- a/drivers/net/sfc/mcdi_pcol.h
+++ b/drivers/net/sfc/mcdi_pcol.h
@@ -1,6 +1,6 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2009 Solarflare Communications Inc.
+ * Copyright 2009-2011 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c
index 0e97eed..ec3f740 100644
--- a/drivers/net/sfc/mcdi_phy.c
+++ b/drivers/net/sfc/mcdi_phy.c
@@ -1,6 +1,6 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2009 Solarflare Communications Inc.
+ * Copyright 2009-2010 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
index 6e82e5b..19e68c2 100644
--- a/drivers/net/sfc/mdio_10g.c
+++ b/drivers/net/sfc/mdio_10g.c
@@ -1,6 +1,6 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2006-2009 Solarflare Communications Inc.
+ * Copyright 2006-2011 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h
index 44c5dee..df07039 100644
--- a/drivers/net/sfc/mdio_10g.h
+++ b/drivers/net/sfc/mdio_10g.h
@@ -1,6 +1,6 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2006-2009 Solarflare Communications Inc.
+ * Copyright 2006-2011 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c
index d386274..e646bfc 100644
--- a/drivers/net/sfc/mtd.c
+++ b/drivers/net/sfc/mtd.c
@@ -1,7 +1,7 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2006-2009 Solarflare Communications Inc.
+ * Copyright 2006-2010 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 5b001c1..9ea6cc2 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -1,7 +1,7 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2005-2009 Solarflare Communications Inc.
+ * Copyright 2005-2011 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c
index 1d0b8b6..fb25b87 100644
--- a/drivers/net/sfc/nic.c
+++ b/drivers/net/sfc/nic.c
@@ -1,7 +1,7 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2006-2009 Solarflare Communications Inc.
+ * Copyright 2006-2011 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h
index 17407ea..1daaee6 100644
--- a/drivers/net/sfc/nic.h
+++ b/drivers/net/sfc/nic.h
@@ -1,7 +1,7 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2006-2009 Solarflare Communications Inc.
+ * Copyright 2006-2011 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h
index 1dab609..b3b7947 100644
--- a/drivers/net/sfc/phy.h
+++ b/drivers/net/sfc/phy.h
@@ -1,6 +1,6 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2007-2009 Solarflare Communications Inc.
+ * Copyright 2007-2010 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c
index ea3ae00..55f9092 100644
--- a/drivers/net/sfc/qt202x_phy.c
+++ b/drivers/net/sfc/qt202x_phy.c
@@ -1,6 +1,6 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2006-2009 Solarflare Communications Inc.
+ * Copyright 2006-2010 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/regs.h b/drivers/net/sfc/regs.h
index 8227de6..cc2c86b 100644
--- a/drivers/net/sfc/regs.h
+++ b/drivers/net/sfc/regs.h
@@ -1,7 +1,7 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2006-2009 Solarflare Communications Inc.
+ * Copyright 2006-2010 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
index 81bec87..c0fdb59 100644
--- a/drivers/net/sfc/rx.c
+++ b/drivers/net/sfc/rx.c
@@ -1,7 +1,7 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2005-2009 Solarflare Communications Inc.
+ * Copyright 2005-2011 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index f936892..a0f49b3 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -1,7 +1,7 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2006-2009 Solarflare Communications Inc.
+ * Copyright 2006-2010 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/selftest.h b/drivers/net/sfc/selftest.h
index aed495a..dba5456 100644
--- a/drivers/net/sfc/selftest.h
+++ b/drivers/net/sfc/selftest.h
@@ -1,7 +1,7 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2006-2008 Solarflare Communications Inc.
+ * Copyright 2006-2010 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c
index 07b59a8..8bd537e 100644
--- a/drivers/net/sfc/siena.c
+++ b/drivers/net/sfc/siena.c
@@ -1,7 +1,7 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2006-2009 Solarflare Communications Inc.
+ * Copyright 2006-2010 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/spi.h b/drivers/net/sfc/spi.h
index 879b7f6..71f2e3e 100644
--- a/drivers/net/sfc/spi.h
+++ b/drivers/net/sfc/spi.h
@@ -1,7 +1,7 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005 Fen Systems Ltd.
- * Copyright 2006 Solarflare Communications Inc.
+ * Copyright 2006-2010 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index 581911f..efdceb3 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -1,6 +1,6 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2007-2009 Solarflare Communications Inc.
+ * Copyright 2007-2011 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c
index 1a51653..1398019 100644
--- a/drivers/net/sfc/tx.c
+++ b/drivers/net/sfc/tx.c
@@ -1,7 +1,7 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2005-2009 Solarflare Communications Inc.
+ * Copyright 2005-2010 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/txc43128_phy.c b/drivers/net/sfc/txc43128_phy.c
index 4e2b48a..d9886ad 100644
--- a/drivers/net/sfc/txc43128_phy.c
+++ b/drivers/net/sfc/txc43128_phy.c
@@ -1,6 +1,6 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2006-2010 Solarflare Communications Inc.
+ * Copyright 2006-2011 Solarflare Communications Inc.
*
* 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
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
index e0d6308..e4dd3a7 100644
--- a/drivers/net/sfc/workarounds.h
+++ b/drivers/net/sfc/workarounds.h
@@ -1,6 +1,6 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2006-2009 Solarflare Communications Inc.
+ * Copyright 2006-2010 Solarflare Communications Inc.
*
* 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
--
1.5.4
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH net-next-2.6 6/8] sfc: Expose TX push and TSO counters through ethtool statistics
From: Ben Hutchings @ 2011-03-01 1:23 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
In-Reply-To: <1298942169.3069.179.camel@localhost>
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/ethtool.c | 21 ++++++++++++++++++++-
1 files changed, 20 insertions(+), 1 deletions(-)
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 52fa661..158d5b5 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -28,7 +28,8 @@ struct efx_ethtool_stat {
enum {
EFX_ETHTOOL_STAT_SOURCE_mac_stats,
EFX_ETHTOOL_STAT_SOURCE_nic,
- EFX_ETHTOOL_STAT_SOURCE_channel
+ EFX_ETHTOOL_STAT_SOURCE_channel,
+ EFX_ETHTOOL_STAT_SOURCE_tx_queue
} source;
unsigned offset;
u64(*get_stat) (void *field); /* Reader function */
@@ -86,6 +87,10 @@ static u64 efx_get_atomic_stat(void *field)
EFX_ETHTOOL_STAT(field, channel, n_##field, \
unsigned int, efx_get_uint_stat)
+#define EFX_ETHTOOL_UINT_TXQ_STAT(field) \
+ EFX_ETHTOOL_STAT(tx_##field, tx_queue, field, \
+ unsigned int, efx_get_uint_stat)
+
static struct efx_ethtool_stat efx_ethtool_stats[] = {
EFX_ETHTOOL_U64_MAC_STAT(tx_bytes),
EFX_ETHTOOL_U64_MAC_STAT(tx_good_bytes),
@@ -116,6 +121,10 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = {
EFX_ETHTOOL_ULONG_MAC_STAT(tx_non_tcpudp),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_mac_src_error),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_ip_src_error),
+ EFX_ETHTOOL_UINT_TXQ_STAT(tso_bursts),
+ EFX_ETHTOOL_UINT_TXQ_STAT(tso_long_headers),
+ EFX_ETHTOOL_UINT_TXQ_STAT(tso_packets),
+ EFX_ETHTOOL_UINT_TXQ_STAT(pushes),
EFX_ETHTOOL_U64_MAC_STAT(rx_bytes),
EFX_ETHTOOL_U64_MAC_STAT(rx_good_bytes),
EFX_ETHTOOL_U64_MAC_STAT(rx_bad_bytes),
@@ -470,6 +479,7 @@ static void efx_ethtool_get_stats(struct net_device *net_dev,
struct efx_mac_stats *mac_stats = &efx->mac_stats;
struct efx_ethtool_stat *stat;
struct efx_channel *channel;
+ struct efx_tx_queue *tx_queue;
struct rtnl_link_stats64 temp;
int i;
@@ -495,6 +505,15 @@ static void efx_ethtool_get_stats(struct net_device *net_dev,
data[i] += stat->get_stat((void *)channel +
stat->offset);
break;
+ case EFX_ETHTOOL_STAT_SOURCE_tx_queue:
+ data[i] = 0;
+ efx_for_each_channel(channel, efx) {
+ efx_for_each_channel_tx_queue(tx_queue, channel)
+ data[i] +=
+ stat->get_stat((void *)tx_queue
+ + stat->offset);
+ }
+ break;
}
}
}
--
1.5.4
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH net-next-2.6 7/8] sfc: Remove configurable FIFO thresholds for pause frame generation
From: Ben Hutchings @ 2011-03-01 1:23 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
In-Reply-To: <1298942169.3069.179.camel@localhost>
In Falcon we can configure the fill levels of the RX data FIFO which
trigger the generation of pause frames (if enabled), and we have
module parameters for this.
Siena does not allow the levels to be configured (or, if it does, this
is done by the MC firmware and is not configurable by drivers).
So far as I can tell, the module parameters are not used by our
internal scripts and have not been documented (with the exception of
the short parameter descriptions). Therefore, remove them and always
initialise Falcon with the default values.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/falcon.c | 20 +++++---------------
drivers/net/sfc/nic.c | 20 --------------------
drivers/net/sfc/nic.h | 1 -
drivers/net/sfc/siena.c | 5 -----
4 files changed, 5 insertions(+), 41 deletions(-)
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 87481a6..734fcfb 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -1478,36 +1478,26 @@ static void falcon_init_rx_cfg(struct efx_nic *efx)
/* RX control FIFO thresholds (32 entries) */
const unsigned ctrl_xon_thr = 20;
const unsigned ctrl_xoff_thr = 25;
- /* RX data FIFO thresholds (256-byte units; size varies) */
- int data_xon_thr = efx_nic_rx_xon_thresh >> 8;
- int data_xoff_thr = efx_nic_rx_xoff_thresh >> 8;
efx_oword_t reg;
efx_reado(efx, ®, FR_AZ_RX_CFG);
if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) {
/* Data FIFO size is 5.5K */
- if (data_xon_thr < 0)
- data_xon_thr = 512 >> 8;
- if (data_xoff_thr < 0)
- data_xoff_thr = 2048 >> 8;
EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_DESC_PUSH_EN, 0);
EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_USR_BUF_SIZE,
huge_buf_size);
- EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_MAC_TH, data_xon_thr);
- EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_MAC_TH, data_xoff_thr);
+ EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_MAC_TH, 512 >> 8);
+ EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_MAC_TH, 2048 >> 8);
EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_TX_TH, ctrl_xon_thr);
EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_TX_TH, ctrl_xoff_thr);
} else {
/* Data FIFO size is 80K; register fields moved */
- if (data_xon_thr < 0)
- data_xon_thr = 27648 >> 8; /* ~3*max MTU */
- if (data_xoff_thr < 0)
- data_xoff_thr = 54272 >> 8; /* ~80Kb - 3*max MTU */
EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_DESC_PUSH_EN, 0);
EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_USR_BUF_SIZE,
huge_buf_size);
- EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_MAC_TH, data_xon_thr);
- EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_MAC_TH, data_xoff_thr);
+ /* Send XON and XOFF at ~3 * max MTU away from empty/full */
+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_MAC_TH, 27648 >> 8);
+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_MAC_TH, 54272 >> 8);
EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_TX_TH, ctrl_xon_thr);
EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_TX_TH, ctrl_xoff_thr);
EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1);
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c
index fb25b87..e839661 100644
--- a/drivers/net/sfc/nic.c
+++ b/drivers/net/sfc/nic.c
@@ -41,26 +41,6 @@
#define RX_DC_ENTRIES 64
#define RX_DC_ENTRIES_ORDER 3
-/* RX FIFO XOFF watermark
- *
- * When the amount of the RX FIFO increases used increases past this
- * watermark send XOFF. Only used if RX flow control is enabled (ethtool -A)
- * This also has an effect on RX/TX arbitration
- */
-int efx_nic_rx_xoff_thresh = -1;
-module_param_named(rx_xoff_thresh_bytes, efx_nic_rx_xoff_thresh, int, 0644);
-MODULE_PARM_DESC(rx_xoff_thresh_bytes, "RX fifo XOFF threshold");
-
-/* RX FIFO XON watermark
- *
- * When the amount of the RX FIFO used decreases below this
- * watermark send XON. Only used if TX flow control is enabled (ethtool -A)
- * This also has an effect on RX/TX arbitration
- */
-int efx_nic_rx_xon_thresh = -1;
-module_param_named(rx_xon_thresh_bytes, efx_nic_rx_xon_thresh, int, 0644);
-MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
-
/* If EFX_MAX_INT_ERRORS internal errors occur within
* EFX_INT_ERROR_EXPIRE seconds, we consider the NIC broken and
* disable it.
diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h
index 1daaee6..d9de1b6 100644
--- a/drivers/net/sfc/nic.h
+++ b/drivers/net/sfc/nic.h
@@ -188,7 +188,6 @@ extern void efx_nic_eventq_read_ack(struct efx_channel *channel);
/* MAC/PHY */
extern void falcon_drain_tx_fifo(struct efx_nic *efx);
extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx);
-extern int efx_nic_rx_xoff_thresh, efx_nic_rx_xon_thresh;
/* Interrupts and test events */
extern int efx_nic_init_interrupt(struct efx_nic *efx);
diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c
index 8bd537e..e4dd898 100644
--- a/drivers/net/sfc/siena.c
+++ b/drivers/net/sfc/siena.c
@@ -341,11 +341,6 @@ static int siena_init_nic(struct efx_nic *efx)
FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8);
efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG3);
- if (efx_nic_rx_xoff_thresh >= 0 || efx_nic_rx_xon_thresh >= 0)
- /* No MCDI operation has been defined to set thresholds */
- netif_err(efx, hw, efx->net_dev,
- "ignoring RX flow control thresholds\n");
-
/* Enable event logging */
rc = efx_mcdi_log_ctrl(efx, true, false, 0);
if (rc)
--
1.5.4
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH net-next-2.6 8/8] sfc: Bump version to 3.1
From: Ben Hutchings @ 2011-03-01 1:23 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
In-Reply-To: <1298942169.3069.179.camel@localhost>
All features originally planned for version 3.1 (and some that
weren't) have been implemented.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/net_driver.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 9ea6cc2..215d5c5 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -41,7 +41,7 @@
*
**************************************************************************/
-#define EFX_DRIVER_VERSION "3.0"
+#define EFX_DRIVER_VERSION "3.1"
#ifdef EFX_ENABLE_DEBUG
#define EFX_BUG_ON_PARANOID(x) BUG_ON(x)
--
1.5.4
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* Re: [PATCH net-2.6] bonding: drop frames received with master's source MAC
From: Andy Gospodarek @ 2011-03-01 2:35 UTC (permalink / raw)
To: Nicolas de Pesloüan
Cc: Andy Gospodarek, netdev, David Miller, Herbert Xu, Jay Vosburgh,
Jiri Pirko
In-Reply-To: <4D6C1764.1040008@gmail.com>
On Mon, Feb 28, 2011 at 10:45:08PM +0100, Nicolas de Pesloüan wrote:
> Le 28/02/2011 17:32, Andy Gospodarek a écrit :
>> On Sat, Feb 26, 2011 at 12:08:03AM +0100, Nicolas de Pesloüan wrote:
>>> Le 25/02/2011 23:24, Andy Gospodarek a écrit :
>> [...]
>>>>
>>>> I confirmed your suspicion, this breaks ARP monitoring. I would still
>>>> welcome other opinions though as I think it would be nice to fix this as
>>>> low as possible.
>>>
>>> Why do you want to fix it earlier that in ndisc_recv_ns drop? Your
>>> original idea of silently dropping the frame there seems perfect to me.
>>>
>>
>> Maybe it's just me, but I cannot understand why we want a bunch of extra
>> packets floating up into the stack when they may only create issues for
>> the recipients of these duplicate frames.
>>
>> Clearly my original patch needs to be refined so ARP monitoring still
>> works, but I would rather fix the issue there than in a higher layer.
>
> Jay explained that the current implementation should already trap those
> frames, on inactive slaves, in modes where inactive slaves exist. I agree
> with him.
>
> What mode are you seeing this problem in? If the current "should drop"
> logic is leaking, then yes, we should fix it. But we currently don't see
> where it is leaking.
>
Use round-robin. To reproduce just take the interface down and bring it
back up. You should see the messages right away.
I've been doing some more testing on a new patch and should have
something ready tomorrow. My latest patch actually replaces the final
'return 0' with a call to a function that will return true if the sender
was the device that received it. This will hopefully prevent some of
the failures with the first patch I posted. I'll know a bit more
tomorrow if this approach seems reasonable.
^ permalink raw reply
* [PATCH] cxgb{3,4}*: improve Kconfig dependencies
From: Dimitris Michailidis @ 2011-03-01 3:34 UTC (permalink / raw)
To: netdev; +Cc: linux-scsi, JBeulich, Dimitris Michailidis
- Remove the dependency of cxgb4 and cxgb4vf on INET. cxgb3 really
depends on INET, keep it but add it directly to the driver's Kconfig
entry.
- Make the iSCSI drivers cxgb3i and cxgb4i available in the SCSI menu
without requiring any options in the net driver menu to be enabled
first. Add needed selects so the iSCSI drivers can build their
corresponding net drivers.
- Remove CHELSIO_T*_DEPENDS.
Signed-off-by: Dimitris Michailidis <dm@chelsio.com>
---
drivers/net/Kconfig | 21 +++------------------
drivers/scsi/cxgbi/cxgb3i/Kconfig | 4 +++-
drivers/scsi/cxgbi/cxgb4i/Kconfig | 4 +++-
3 files changed, 9 insertions(+), 20 deletions(-)
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index f4b3927..6e09d5f 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2595,14 +2595,9 @@ config CHELSIO_T1_1G
Enables support for Chelsio's gigabit Ethernet PCI cards. If you
are using only 10G cards say 'N' here.
-config CHELSIO_T3_DEPENDS
- tristate
- depends on PCI && INET
- default y
-
config CHELSIO_T3
tristate "Chelsio Communications T3 10Gb Ethernet support"
- depends on CHELSIO_T3_DEPENDS
+ depends on PCI && INET
select FW_LOADER
select MDIO
help
@@ -2620,14 +2615,9 @@ config CHELSIO_T3
To compile this driver as a module, choose M here: the module
will be called cxgb3.
-config CHELSIO_T4_DEPENDS
- tristate
- depends on PCI && INET
- default y
-
config CHELSIO_T4
tristate "Chelsio Communications T4 Ethernet support"
- depends on CHELSIO_T4_DEPENDS
+ depends on PCI
select FW_LOADER
select MDIO
help
@@ -2645,14 +2635,9 @@ config CHELSIO_T4
To compile this driver as a module choose M here; the module
will be called cxgb4.
-config CHELSIO_T4VF_DEPENDS
- tristate
- depends on PCI && INET
- default y
-
config CHELSIO_T4VF
tristate "Chelsio Communications T4 Virtual Function Ethernet support"
- depends on CHELSIO_T4VF_DEPENDS
+ depends on PCI
help
This driver supports Chelsio T4-based gigabit and 10Gb Ethernet
adapters with PCI-E SR-IOV Virtual Functions.
diff --git a/drivers/scsi/cxgbi/cxgb3i/Kconfig b/drivers/scsi/cxgbi/cxgb3i/Kconfig
index 5cf4e98..11dff23 100644
--- a/drivers/scsi/cxgbi/cxgb3i/Kconfig
+++ b/drivers/scsi/cxgbi/cxgb3i/Kconfig
@@ -1,6 +1,8 @@
config SCSI_CXGB3_ISCSI
tristate "Chelsio T3 iSCSI support"
- depends on CHELSIO_T3_DEPENDS
+ depends on PCI && INET
+ select NETDEVICES
+ select NETDEV_10000
select CHELSIO_T3
select SCSI_ISCSI_ATTRS
---help---
diff --git a/drivers/scsi/cxgbi/cxgb4i/Kconfig b/drivers/scsi/cxgbi/cxgb4i/Kconfig
index bb94b39..d5302c2 100644
--- a/drivers/scsi/cxgbi/cxgb4i/Kconfig
+++ b/drivers/scsi/cxgbi/cxgb4i/Kconfig
@@ -1,6 +1,8 @@
config SCSI_CXGB4_ISCSI
tristate "Chelsio T4 iSCSI support"
- depends on CHELSIO_T4_DEPENDS
+ depends on PCI && INET
+ select NETDEVICES
+ select NETDEV_10000
select CHELSIO_T4
select SCSI_ISCSI_ATTRS
---help---
--
1.7.3.4
^ permalink raw reply related
* Re: txqueuelen has wrong units; should be time
From: Albert Cahalan @ 2011-03-01 4:11 UTC (permalink / raw)
To: John Heffner
Cc: John W. Linville, Eric Dumazet, Jussi Kivilinna,
Mikael Abrahamsson, linux-kernel, netdev
In-Reply-To: <AANLkTinj5szpStmA+fZ1xggdyTS+sd8Y9jXaYquDNEjs@mail.gmail.com>
On Mon, Feb 28, 2011 at 4:45 PM, John Heffner <johnwheffner@gmail.com> wrote:
> On Mon, Feb 28, 2011 at 11:55 AM, John W. Linville
> <linville@tuxdriver.com> wrote:
>> On Mon, Feb 28, 2011 at 05:48:14PM +0100, Eric Dumazet wrote:
>>> Le lundi 28 février 2011 à 11:11 -0500, John W. Linville a écrit :
>>> > On Sun, Feb 27, 2011 at 09:07:53PM +0100, Eric Dumazet wrote:
>>> > > Qdisc should return to caller a good indication packet is queued or
>>> > > dropped at enqueue() time... not later (aka : never)
>>> > >
>>> > > Accepting a packet at t0, and dropping it later at t0+limit without
>>> > > giving any indication to caller is a problem.
>>> >
>>> > Can you elaborate on what problem this causes? Is it any worse than
>>> > if the packet is dropped at some later hop?
>>> >
>>> > Is there any API that could report the drop to the sender (at
>>> > least a local one) without having to wait for the ack timeout?
>>> > Should there be?
>>>
>>> Not all protocols have ACKS ;)
>>>
>>> dev_queue_xmit() returns an error code, some callers use it.
>>
>> Well, OK -- I agree it is best if you can return the status at
>> enqueue time. The question becomes whether or not a dropped frame
>> is worse than living with high latency. The answer, of course, still
>> seems to be a bit subjective. But, if the admin has determined that
>> a link should be low latency...?
>
> Notably, TCP is one caller that uses the error code. The error code
> is functionally equivalent to ECN, one of whose great advantages is
> reducing delay jitter. If TCP didn't get the error, that would
> effectively double the latency for a full window of data, since the
> dropped segment would not be retransmitted for an RTT.
It sounds like you need a callback or similar, so that TCP can be
informed later that the drop has occurred.
^ permalink raw reply
* Urgent Payment Information From Western Union!!
From: WESTERN UNION MONEY TRANSFER @ 2011-03-01 4:02 UTC (permalink / raw)
Good day,
I write to inform you that we have already sent you $5000.00 USD dollars
through Western Union as we have been given the mandate to transfer your
full compensation payment of $2.5Million Dollars via Western Union by the United
Nations Government.So I decided to email you the MTCN and sender's name
so you can pick up this $5000.00 USD to enable us send another $5000.00
USD by tomorrow as you know we will be sending you only $5000.00 USD per
day. Please pick up this information and run to any Western Union in your
country to pick up the $5000.00 USD and call me back to send you another
payment tomorrow. However we have noted you as a customer of western union
money transfer.
Manager: Mr Frank Amos.
Email: wumt66657@yahoo.com.hk
Tel number:+2347067137893
Call or email me once you picked up this $5,000 USD today. Here is the
western union information below.
Sender`s First Name:_______Idrus
Sender's Last Name:________Jemain
MTCN:______________________115-065-5463
Amount;=___________________$5,000, USD
Test Question;= ___________Honest?
Test Answer;= _____________Trust
Mean while i want you to give me a call if there is any problem
my telephone number is +2347067137893
Regards,
Tel number:+2347067137893
Mr Frank Amos.
^ permalink raw reply
* Re: txqueuelen has wrong units; should be time
From: David Miller @ 2011-03-01 4:18 UTC (permalink / raw)
To: acahalan
Cc: johnwheffner, linville, eric.dumazet, jussi.kivilinna, swmike,
linux-kernel, netdev
In-Reply-To: <AANLkTinFZu5AgfhO6PoA7C1NTGSfD8HH0KXq_o-mHEJF@mail.gmail.com>
From: Albert Cahalan <acahalan@gmail.com>
Date: Mon, 28 Feb 2011 23:11:13 -0500
> It sounds like you need a callback or similar, so that TCP can be
> informed later that the drop has occurred.
By that point we could have already sent an entire RTT's worth
of data, or more.
It needs to be synchronous, otherwise performance suffers.
^ permalink raw reply
* Re: txqueuelen has wrong units; should be time
From: Eric Dumazet @ 2011-03-01 5:01 UTC (permalink / raw)
To: Albert Cahalan
Cc: John Heffner, John W. Linville, Jussi Kivilinna,
Mikael Abrahamsson, linux-kernel, netdev
In-Reply-To: <AANLkTinFZu5AgfhO6PoA7C1NTGSfD8HH0KXq_o-mHEJF@mail.gmail.com>
Le lundi 28 février 2011 à 23:11 -0500, Albert Cahalan a écrit :
> It sounds like you need a callback or similar, so that TCP can be
> informed later that the drop has occurred.
There is the thing called skb destructor / skb_orphan() mess, that is
not stackable... Might extend this to something more clever, and be able
to call functions (into TCP stack for example) giving a status of skb :
Sent, or dropped somewhere in the stack...
^ permalink raw reply
* Re: [PATCH v6] net: add Faraday FTMAC100 10/100 Ethernet driver
From: Po-Yu Chuang @ 2011-03-01 5:20 UTC (permalink / raw)
To: Eric Dumazet
Cc: netdev, linux-kernel, bhutchings, joe, dilinger, mirqus, davem,
Po-Yu Chuang
In-Reply-To: <1298634040.2659.32.camel@edumazet-laptop>
Hi Eric,
On Fri, Feb 25, 2011 at 7:40 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> Le vendredi 25 février 2011 à 17:57 +0800, Po-Yu Chuang a écrit :
>> From: Po-Yu Chuang <ratbert@faraday-tech.com>
>>
>> FTMAC100 Ethernet Media Access Controller supports 10/100 Mbps and
>> MII. This driver has been working on some ARM/NDS32 SoC's including
>> Faraday A320 and Andes AG101.
>>
>> Signed-off-by: Po-Yu Chuang <ratbert@faraday-tech.com>
>
> It seems fine to me, but I have somes questions
>
> 1) On V5, the receive function ftmac100_rx_packet() was able to process
> several segments per skb. On V6 you process one frag only.
>
> Isnt this NIC able to handle large MTU (say... 9000) ?
No, it isn't. Its max supported packet size is 0x7ff (2047 bytes).
I wasn't sure when will get multi-segment packet. After confirmed with
HW designer two weeks ago, he told me that only if the rx buffer described
by the first descriptor is not big enough, another rx buffer will be used.
That means, since every rx buffer is large enough, it is impossible to
get a multi-segment packets.
So I simplified ftmac100_rx_packet().
>
> 2) ftmac100_alloc_rx_page() is called and allocate a full page for a
> rxdes.
>
> 128*4K -> 512 Kbytes of memory for RX ring
>
> In V5, you were using half pages only, so 256 kbytes of memory.
>
> If you look at other drivers (NIU, BENET), they are able to use exactly
> 128*2 kbytes (for a rxring of 128 slots, and 2Kbytes per slot)
Both NIU and BENET refill rx ring after all packets receive work done,
but I allocate rx buffer right after a packet is received. I think it
is difficult
to use a page for two rx buffers in my driver now. Can we just keep it
the way it is? I can study how to achieve that after current driver is accepted.
best regards,
Po-Yu Chuang
^ 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