Netdev List
 help / color / mirror / Atom feed
* Re: pull request: wireless-next-2.6 2009-10-28
From: David Miller @ 2009-10-29 12:15 UTC (permalink / raw)
  To: bzolnier-Re5JQEeQqe8AvxtiuMwx3w
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linville-2XuSBdqkA4R54TAoqtyWWQ
In-Reply-To: <200910291212.41656.bzolnier-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

From: Bartlomiej Zolnierkiewicz <bzolnier-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Date: Thu, 29 Oct 2009 12:12:41 +0100

> What is even more disappointing (especially after all that "working with"
> preaching) is that the patch is now in net-next-2.6..

John is the wireless maintainer, I take his tree in since the changes
in there have his blessing.

If you have a problem with some change in there, work it out with him
and he'll send the fixed up changes to me thereafterwards.

I don't really see what the big deal is, any change can be reverted.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: pull request: wireless-next-2.6 2009-10-28
From: Bartlomiej Zolnierkiewicz @ 2009-10-29 12:45 UTC (permalink / raw)
  To: David Miller
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linville-2XuSBdqkA4R54TAoqtyWWQ
In-Reply-To: <20091029.051509.119751790.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>

On Thursday 29 October 2009 13:15:09 David Miller wrote:
> From: Bartlomiej Zolnierkiewicz <bzolnier-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Date: Thu, 29 Oct 2009 12:12:41 +0100
> 
> > What is even more disappointing (especially after all that "working with"
> > preaching) is that the patch is now in net-next-2.6..
> 
> John is the wireless maintainer, I take his tree in since the changes
> in there have his blessing.
> 
> If you have a problem with some change in there, work it out with him
> and he'll send the fixed up changes to me thereafterwards.

What do you mean by that?

That *I* should be fixing the patch in question instead of the submitter?

Do some different rules apply in the networking than in other parts of
the kernel that I'm not aware of?

There were valid concerns raised on the initial rt2800pci patch submission,
yet two days later patch is in John's tree, after few more days it is in yours
tree and happily on his way into 2.6.33.

Until issues mentioned in:

	http://lkml.org/lkml/2009/10/17/81

are addressed rt2800pci shouldn't be queued for Linus' tree.

[ Please note that this driver doesn't work at all currently so the standard
  argument of having hardware support early upstream cannot be applied here. ]

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

^ permalink raw reply

* Hello,
From: cecilia_oma @ 2009-10-29 12:41 UTC (permalink / raw)


Hi,
My name is miss Cecilia Oma, i saw your profile today and became intrested in you,please i want you to send a mail to my email address so that i can give you my picture for you to know whom i am.Here is my email address(ceciliaoma2love@yahoo.com) I believe we can move from here I am waiting for your fast respond.make sure you send me a
mail so that i will know you got my message.
thanks hoping to hear from you
Cecilia..

^ permalink raw reply

* Re: Fw: [Bug 14470] New: freez in TCP stack
From: Ilpo Järvinen @ 2009-10-29 12:58 UTC (permalink / raw)
  To: Eric Dumazet, David Miller
  Cc: Andrew Morton, Stephen Hemminger, Netdev, kolo, bugzilla-daemon
In-Reply-To: <4AE9298C.1000204@gmail.com>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 10018 bytes --]

On Thu, 29 Oct 2009, Eric Dumazet wrote:

> Andrew Morton a écrit :
> > On Mon, 26 Oct 2009 08:41:32 -0700
> > Stephen Hemminger <shemminger@linux-foundation.org> wrote:
> > 
> >>
> >> Begin forwarded message:
> >>
> >> Date: Mon, 26 Oct 2009 12:47:22 GMT
> >> From: bugzilla-daemon@bugzilla.kernel.org
> >> To: shemminger@linux-foundation.org
> >> Subject: [Bug 14470] New: freez in TCP stack
> >>
> > 
> > Stephen, please retain the bugzilla and reporter email cc's when
> > forwarding a report to a mailing list.
> > 
> > 
> >> http://bugzilla.kernel.org/show_bug.cgi?id=14470
> >>
> >>            Summary: freez in TCP stack
> >>            Product: Networking
> >>            Version: 2.5
> >>     Kernel Version: 2.6.31
> >>           Platform: All
> >>         OS/Version: Linux
> >>               Tree: Mainline
> >>             Status: NEW
> >>           Severity: high
> >>           Priority: P1
> >>          Component: IPV4
> >>         AssignedTo: shemminger@linux-foundation.org
> >>         ReportedBy: kolo@albatani.cz
> >>         Regression: No
> >>
> >>
> >> We are hiting kernel panics on Dell R610 servers with e1000e NICs; it apears
> >> usualy under a high network trafic ( around 100Mbit/s) but it is not a rule it
> >> has happened even on low trafic.
> >>
> >> Servers are used as reverse http proxy (varnish).
> >>
> >> On 6 equal servers this panic happens aprox 2 times a day depending on network
> >> load. Machine completly freezes till the management watchdog reboots. 
> >>
> > 
> > Twice a day on six separate machines.  That ain't no hardware glitch.
> > 
> > Vaclav, are you able to say whether this is a regression?  Did those
> > machines run 2.6.30 (for example)?
> > 
> > Thanks.
> > 
> >> We had to put serial console on these servers to catch the oops. Is there
> >> anything else We can do to debug this?
> >> The RIP is always the same:
> >>
> >> RIP: 0010:[<ffffffff814203cc>]  [<ffffffff814203cc>]
> >> tcp_xmit_retransmit_queue+0x8c/0x290
> >>
> >> rest of the oops always differs a litle ... here is an example:
> >>
> >> RIP: 0010:[<ffffffff814203cc>]  [<ffffffff814203cc>]
> >> tcp_xmit_retransmit_queue+0x8c/0x290
> >> RSP: 0018:ffffc90000003a40  EFLAGS: 00010246
> >> RAX: ffff8807e7420678 RBX: ffff8807e74205c0 RCX: 0000000000000000
> >> RDX: 000000004598a105 RSI: 0000000000000000 RDI: ffff8807e74205c0
> >> RBP: ffffc90000003a80 R08: 0000000000000003 R09: 0000000000000000
> >> R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000
> >> R13: ffff8807e74205c0 R14: ffff8807e7420678 R15: 0000000000000000
> >> FS:  0000000000000000(0000) GS:ffffc90000000000(0000) knlGS:0000000000000000
> >> CS:  0010 DS: 0018 ES: 0018 CR0: 000000008005003b
> >> CR2: 0000000000000000 CR3: 0000000001001000 CR4: 00000000000006f0
> >> DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> >> DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
> >> Process swapper (pid: 0, threadinfo ffffffff81608000, task ffffffff81631440)
> >> Stack:
> >>  ffffc90000003a60 0000000000000000 4598a105e74205c0 000000004598a101
> >> <0> 000000000000050e ffff8807e74205c0 0000000000000003 0000000000000000
> >> <0> ffffc90000003b40 ffffffff8141ae4a ffff8807e7420678 0000000000000000
> >> Call Trace:
> >>  <IRQ>
> >>  [<ffffffff8141ae4a>] tcp_ack+0x170a/0x1dd0
> >>  [<ffffffff8141c362>] tcp_rcv_state_process+0x122/0xab0
> >>  [<ffffffff81422c6c>] tcp_v4_do_rcv+0xac/0x220
> >>  [<ffffffff813fd02f>] ? nf_iterate+0x5f/0x90
> >>  [<ffffffff81424b26>] tcp_v4_rcv+0x586/0x6b0
> >>  [<ffffffff813fd0c5>] ? nf_hook_slow+0x65/0xf0
> >>  [<ffffffff81406b70>] ? ip_local_deliver_finish+0x0/0x120
> >>  [<ffffffff81406bcf>] ip_local_deliver_finish+0x5f/0x120
> >>  [<ffffffff8140715b>] ip_local_deliver+0x3b/0x90
> >>  [<ffffffff81406971>] ip_rcv_finish+0x141/0x340
> >>  [<ffffffff8140701f>] ip_rcv+0x24f/0x350
> >>  [<ffffffff813e7ced>] netif_receive_skb+0x20d/0x2f0
> >>  [<ffffffff813e7e90>] napi_skb_finish+0x40/0x50
> >>  [<ffffffff813e82f4>] napi_gro_receive+0x34/0x40
> >>  [<ffffffff8133e0c8>] e1000_receive_skb+0x48/0x60
> >>  [<ffffffff81342342>] e1000_clean_rx_irq+0xf2/0x330
> >>  [<ffffffff813410a1>] e1000_clean+0x81/0x2a0
> >>  [<ffffffff81054ce1>] ? ktime_get+0x11/0x50
> >>  [<ffffffff813eaf1c>] net_rx_action+0x9c/0x130
> >>  [<ffffffff81046940>] ? get_next_timer_interrupt+0x1d0/0x210
> >>  [<ffffffff81041bd7>] __do_softirq+0xb7/0x160
> >>  [<ffffffff8100c27c>] call_softirq+0x1c/0x30
> >>  [<ffffffff8100e04d>] do_softirq+0x3d/0x80
> >>  [<ffffffff81041b0b>] irq_exit+0x7b/0x90
> >>  [<ffffffff8100d613>] do_IRQ+0x73/0xe0
> >>  [<ffffffff8100bb13>] ret_from_intr+0x0/0xa
> >>  <EOI>
> >>  [<ffffffff81296e6c>] ? acpi_idle_enter_bm+0x245/0x271
> >>  [<ffffffff81296e62>] ? acpi_idle_enter_bm+0x23b/0x271
> >>  [<ffffffff813c7a08>] ? cpuidle_idle_call+0x98/0xf0
> >>  [<ffffffff8100a104>] ? cpu_idle+0x94/0xd0
> >>  [<ffffffff81468db6>] ? rest_init+0x66/0x70
> >>  [<ffffffff816a082f>] ? start_kernel+0x2ef/0x340
> >>  [<ffffffff8169fd54>] ? x86_64_start_reservations+0x84/0x90
> >>  [<ffffffff8169fe32>] ? x86_64_start_kernel+0xd2/0x100
> >> Code: 00 eb 28 8b 83 d0 03 00 00 41 39 44 24 40 0f 89 00 01 00 00 41 0f b6 cd
> >> 41 bd 2f 00 00 00 83 e1 03 0f 84 fc 00 00 00 4d 8b 24 24 <49> 8b 04 24 4d 39 f4
> >> 0f 18 08 0f 84 d9 00 00 00 4c 3b a3 b8 01
> >> RIP  [<ffffffff814203cc>] tcp_xmit_retransmit_queue+0x8c/0x290
> >>  RSP <ffffc90000003a40>
> >> CR2: 0000000000000000
> >> ---[ end trace d97d99c9ae1d52cc ]---
> >> Kernel panic - not syncing: Fatal exception in interrupt
> >> Pid: 0, comm: swapper Tainted: G      D    2.6.31 #2
> >> Call Trace:
> >>  <IRQ>  [<ffffffff8103cab0>] panic+0xa0/0x170
> >>  [<ffffffff8100bb13>] ? ret_from_intr+0x0/0xa
> >>  [<ffffffff8103c74e>] ? print_oops_end_marker+0x1e/0x20
> >>  [<ffffffff8100f38e>] oops_end+0x9e/0xb0
> >>  [<ffffffff81025b9a>] no_context+0x15a/0x250
> >>  [<ffffffff81025e2b>] __bad_area_nosemaphore+0xdb/0x1c0
> >>  [<ffffffff813e89e9>] ? dev_hard_start_xmit+0x269/0x2f0
> >>  [<ffffffff81025fae>] bad_area_nosemaphore+0xe/0x10
> >>  [<ffffffff8102639f>] do_page_fault+0x17f/0x260
> >>  [<ffffffff8147eadf>] page_fault+0x1f/0x30
> >>  [<ffffffff814203cc>] ? tcp_xmit_retransmit_queue+0x8c/0x290
> >>  [<ffffffff8141ae4a>] tcp_ack+0x170a/0x1dd0
> >>  [<ffffffff8141c362>] tcp_rcv_state_process+0x122/0xab0
> >>  [<ffffffff81422c6c>] tcp_v4_do_rcv+0xac/0x220
> >>  [<ffffffff813fd02f>] ? nf_iterate+0x5f/0x90
> >>  [<ffffffff81424b26>] tcp_v4_rcv+0x586/0x6b0
> >>  [<ffffffff813fd0c5>] ? nf_hook_slow+0x65/0xf0
> >>  [<ffffffff81406b70>] ? ip_local_deliver_finish+0x0/0x120
> >>  [<ffffffff81406bcf>] ip_local_deliver_finish+0x5f/0x120
> >>  [<ffffffff8140715b>] ip_local_deliver+0x3b/0x90
> >>  [<ffffffff81406971>] ip_rcv_finish+0x141/0x340
> >>  [<ffffffff8140701f>] ip_rcv+0x24f/0x350
> >>  [<ffffffff813e7ced>] netif_receive_skb+0x20d/0x2f0
> >>  [<ffffffff813e7e90>] napi_skb_finish+0x40/0x50
> >>  [<ffffffff813e82f4>] napi_gro_receive+0x34/0x40
> >>  [<ffffffff8133e0c8>] e1000_receive_skb+0x48/0x60
> >>  [<ffffffff81342342>] e1000_clean_rx_irq+0xf2/0x330
> >>  [<ffffffff813410a1>] e1000_clean+0x81/0x2a0
> >>  [<ffffffff81054ce1>] ? ktime_get+0x11/0x50
> >>  [<ffffffff813eaf1c>] net_rx_action+0x9c/0x130
> >>  [<ffffffff81046940>] ? get_next_timer_interrupt+0x1d0/0x210
> >>  [<ffffffff81041bd7>] __do_softirq+0xb7/0x160
> >>  [<ffffffff8100c27c>] call_softirq+0x1c/0x30
> >>  [<ffffffff8100e04d>] do_softirq+0x3d/0x80
> >>  [<ffffffff81041b0b>] irq_exit+0x7b/0x90
> >>  [<ffffffff8100d613>] do_IRQ+0x73/0xe0
> >>  [<ffffffff8100bb13>] ret_from_intr+0x0/0xa
> >>  <EOI>  [<ffffffff81296e6c>] ? acpi_idle_enter_bm+0x245/0x271
> >>  [<ffffffff81296e62>] ? acpi_idle_enter_bm+0x23b/0x271
> >>  [<ffffffff813c7a08>] ? cpuidle_idle_call+0x98/0xf0
> >>  [<ffffffff8100a104>] ? cpu_idle+0x94/0xd0
> >>  [<ffffffff81468db6>] ? rest_init+0x66/0x70
> >>  [<ffffffff816a082f>] ? start_kernel+0x2ef/0x340
> >>  [<ffffffff8169fd54>] ? x86_64_start_reservations+0x84/0x90
> >>  [<ffffffff8169fe32>] ? x86_64_start_kernel+0xd2/0x100
> >>
> 
> 
> Code: 00 eb 28 8b 83 d0 03 00 00
>   41 39 44 24 40    cmp    %eax,0x40(%r12)
>   0f 89 00 01 00 00 jns ...
>   41 0f b6 cd       movzbl %r13b,%ecx
>   41 bd 2f 00 00 00 mov    $0x2f000000,%r13d
>   83 e1 03          and    $0x3,%ecx
>   0f 84 fc 00 00 00 je ...
>   4d 8b 24 24       mov    (%r12),%r12    skb = skb->next
> <>49 8b 04 24       mov    (%r12),%rax     << NULL POINTER dereference >>
>   4d 39 f4          cmp    %r14,%r12
>   0f 18 08          prefetcht0 (%rax)
>   0f 84 d9 00 00 00 je  ...
>   4c 3b a3 b8 01    cmp
> 
> 
> crash is in 
> void tcp_xmit_retransmit_queue(struct sock *sk)
> {
> 
> << HERE >> tcp_for_write_queue_from(skb, sk) {
> 
> }
> 
> 
> Some skb in sk_write_queue has a NULL ->next pointer
> 
> Strange thing is R14 and RAX =ffff8807e7420678  (&sk->sk_write_queue) 
> R14 is the stable value during the loop, while RAW is scratch register.
> 
> I dont have full disassembly for this function, but I guess we just 
> entered the loop (or RAX should be really different at this point)
> 
> So, maybe list head itself is corrupted (sk->sk_write_queue->next = NULL)

One more alternative along those lines could perhaps be:

We enter with empty write_queue there and with the hint being null, so we 
take the else branch... and skb_peek then gives us the NULL ptr. However, 
I cannot see how this could happen as all branches trap with return 
before the reach tcp_xmit_retransmit_queue.
 
> or, retransmit_skb_hint problem ? (we forget to set it to NULL in some 
> cases ?)

...I don't understand how a stale reference would yield to a consistent 
NULL ptr crash there rather than hard to track corruption for most of the 
times and random crashes then here and there. Or perhaps we were just very 
lucky to immediately get only those reports which point out to the right 
track :-).

...I tried to find what is wrong with it but sadly came up only
ah-this-is-it-oh-wait-it's-ok type of things.

-- 
 i.

^ permalink raw reply

* Re: pull request: wireless-next-2.6 2009-10-28
From: David Miller @ 2009-10-29 12:59 UTC (permalink / raw)
  To: bzolnier-Re5JQEeQqe8AvxtiuMwx3w
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linville-2XuSBdqkA4R54TAoqtyWWQ
In-Reply-To: <200910291345.05888.bzolnier-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

From: Bartlomiej Zolnierkiewicz <bzolnier-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Date: Thu, 29 Oct 2009 13:45:05 +0100

> That *I* should be fixing the patch in question instead of the
> submitter?

I'm saying that you should work with John to have him send a revert or
whatever to me.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH] Regression: e100_phy_init() isolates even selected PHY, causes 10 seconds boot delay
From: David Miller @ 2009-10-29 13:02 UTC (permalink / raw)
  To: bernhard.kaindl; +Cc: bruce.w.allan, jeffrey.t.kirsher, netdev
In-Reply-To: <4AC3C09B.3040203@gmx.net>

From: Bernhard Kaindl <bernhard.kaindl@gmx.net>
Date: Wed, 30 Sep 2009 22:33:31 +0200

> The current e100.c:e100_phy_init() electrically isolates all
> the PHYs (even the selected PHY -- for a short time!) from the MII.
> 
> This happens only for a short duration before the isolation
> of the selected PHY is reverted, but it's enough to cause a
> major disturbance in the startup of our e100-based cards:
> 
> On a number of Embedded/Industry Pentium boards which are in use,
> the result is that the initial DHCP negotiation takes more
> than 10 seconds to complete with 2.6.30 and .31, while it's
> done in a fraction of a second with 2.6.29 and earlier
> (kernels tested with no delay range from 2.6.23 to 2.6.29)
> 
> That regression was introduced on March 31 in the by a patch
> from Bruce which first appeared in 2.6.30-rc3:

Bruce, can you give some feedback on this?  I'd like to see this issue
move forward.

The only reason I haven't applied Bernhard's patch is because I
haven't seen any feedback from Intel.  But I will apply it anyways if
I don't see reasonable feedback soon.

Thanks.

^ permalink raw reply

* Re: [PATCH] udev: create empty regular files to represent net interfaces
From: Matt Domsch @ 2009-10-29 13:11 UTC (permalink / raw)
  To: Kay Sievers
  Cc: dann frazier, linux-hotplug, Narendra_K, netdev, Jordan_Hargrave,
	Charles_Rose, Ben Hutchings
In-Reply-To: <ac3eb2510910280123g3c0e3d95wb38a239238906027@mail.gmail.com>

On Wed, Oct 28, 2009 at 09:23:57AM +0100, Kay Sievers wrote:
> On Tue, Oct 27, 2009 at 21:55, Matt Domsch <Matt_Domsch@dell.com> wrote:
> > On Thu, Oct 22, 2009 at 12:36:20AM -0600, dann frazier wrote:
> >> Here's a proof of concept to further the discussion..
> >>
> >> The default filename uses the format:
> >> ?? /dev/netdev/by-ifindex/$ifindex
> >>
> >> This provides the infrastructure to permit udev rules to create aliases for
> >> network devices using symlinks, for example:
> >>
> >> ?? /dev/netdev/by-name/eth0 -> ../by-ifindex/1
> >> ?? /dev/netdev/by-biosname/LOM0 -> ../by-ifindex/3
> >>
> >> A library (such as the proposed libnetdevname) could use this information
> >> to provide an alias->realname mapping for network utilities.
>
> That all sounds very much like something which will hit us back some
> day. I'm not sure, if udev should publish such dead text files in
> /dev, it does not seem to fit the usual APIs/assumptions where /sys
> and /dev match, and libudev provides access to both.

While we could do this without any kernel changes at all, it does
still leave unresolved the concern of the in-kernel users of
netdevice-by-name - everything that uses dev_get_by_name(), and any
userspace tool that doesn't get converted to use the netdevice-by-path
concept.

Which brings us back to still looking for options.

Multiple names for the same device gives us a way out.
Users of the ethX naming convention continue unchanged, and live
with the nondeterminism; Users of other naming conventions can get
names that work for them, with needed determinism.

Netdev team - are you in agreement that having multiple names to
address the same netdevice is a worthwhile thing to add, to allow a
variety of naming schemes to exist simultaneously?  If not, this whole
discussion will be moot, and my basic problem, that the ethX naming
convention is nondeterministic, but we need determinism, remains
unresolved.

Assuming we agree it's worthwhile, I'm open to ideas for ways to solve
it.  We've proposed char devices for udev to manage, and fixing up
userspace programs, but that doesn't solve in-kernel users by name.
Dann proposed another method (above) which Kay isn't fond of, and
which has the same drawback.  I need another option then.

Thanks,
Matt

-- 
Matt Domsch
Technology Strategist, Dell Office of the CTO
linux.dell.com & www.dell.com/linux

^ permalink raw reply

* [RFC-PATCH] dhcp provisioning support in cxgb3i
From: Rakesh Ranjan @ 2009-10-29 13:16 UTC (permalink / raw)
  To: Mike Christie
  Cc: davem-fT/PcQaiUtIeIZ0/mPfg9Q, James Bottomley, Karen Xie,
	Rakesh Ranjan, open-iscsi-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org,
	LKML, linux-scsi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	netdev-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 698 bytes --]

Hi Mike,

Herein attached patches for having dhcp provisioning support in cxgb3i. 
I have added one new iscsi netlink message ISCSI_UEVENT_REQ_IPCONF. 
Please have a look and share suggestions.

Regards
Rakesh Ranjan

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "open-iscsi" group.
To post to this group, send email to open-iscsi-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
To unsubscribe from this group, send email to open-iscsi+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
For more options, visit this group at http://groups.google.com/group/open-iscsi
-~----------~----~----~----~------~----~------~--~---


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-added-one-new-netlink-message-ISCSI_UEVENT_REQ_IPCON.patch --]
[-- Type: text/x-patch, Size: 2922 bytes --]

>From 4b522723ab93b54504eeb738cc02f354635cec53 Mon Sep 17 00:00:00 2001
From: Rakesh Ranjan <rakesh-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org>
Date: Thu, 29 Oct 2009 17:41:42 +0530
Subject: [PATCH] added one new netlink message ISCSI_UEVENT_REQ_IPCONF in libiscsi to support dhcp functionality in cxgb3i


Signed-off-by: Rakesh Ranjan <rakesh-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org>
---
 drivers/scsi/scsi_transport_iscsi.c |   25 +++++++++++++++++++++++++
 include/scsi/iscsi_if.h             |    4 ++++
 include/scsi/scsi_transport_iscsi.h |    1 +
 3 files changed, 30 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index ad897df..4897a3f 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -1508,6 +1508,28 @@ iscsi_set_path(struct iscsi_transport *transport, struct iscsi_uevent *ev)
 }
 
 static int
+iscsi_req_ipconf(struct iscsi_transport *transport, struct iscsi_uevent *ev)
+{
+	struct Scsi_Host *shost;
+	int err;
+
+	if (!transport->req_ipconf)
+		return -ENOSYS;
+
+	shost = scsi_host_lookup(ev->u.req_ipconf.host_no);
+	if (!shost) {
+		printk(KERN_ERR "ipconf req could not find host no %u\n",
+				ev->u.req_ipconf.host_no);
+		return -ENODEV;
+	}
+
+	err = transport->req_ipconf(shost);
+
+	scsi_host_put(shost);
+	return err;
+}
+
+static int
 iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
 {
 	int err = 0;
@@ -1627,6 +1649,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
 	case ISCSI_UEVENT_PATH_UPDATE:
 		err = iscsi_set_path(transport, ev);
 		break;
+	case ISCSI_UEVENT_REQ_IPCONF:
+		err = iscsi_req_ipconf(transport, ev);
+		break;
 	default:
 		err = -ENOSYS;
 		break;
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index d67dda2..939b1d6 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -59,6 +59,7 @@ enum iscsi_uevent_e {
 	ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST	= UEVENT_BASE + 19,
 
 	ISCSI_UEVENT_PATH_UPDATE	= UEVENT_BASE + 20,
+	ISCSI_UEVENT_REQ_IPCONF		= UEVENT_BASE + 21,
 
 	/* up events */
 	ISCSI_KEVENT_RECV_PDU		= KEVENT_BASE + 1,
@@ -172,6 +173,9 @@ struct iscsi_uevent {
 		struct msg_set_path {
 			uint32_t	host_no;
 		} set_path;
+		struct msg_req_ipconf {
+			uint32_t	host_no;
+		} req_ipconf;
 	} u;
 	union {
 		/* messages k -> u */
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index 349c7f3..3e5fd96 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -134,6 +134,7 @@ struct iscsi_transport {
 	int (*tgt_dscvr) (struct Scsi_Host *shost, enum iscsi_tgt_dscvr type,
 			  uint32_t enable, struct sockaddr *dst_addr);
 	int (*set_path) (struct Scsi_Host *shost, struct iscsi_path *params);
+	int (*req_ipconf) (struct Scsi_Host *shost);
 };
 
 /*
-- 
1.6.0.6


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-Implemented-dhcp-client-support-in-cxgb3i.patch --]
[-- Type: text/x-patch, Size: 16591 bytes --]

>From c64cae0fc1c281159141d9e624331f00e434f056 Mon Sep 17 00:00:00 2001
From: Rakesh Ranjan <rakesh-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org>
Date: Thu, 29 Oct 2009 17:43:51 +0530
Subject: [PATCH] Implemented dhcp client support in cxgb3i


Signed-off-by: Rakesh Ranjan <rakesh-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org>
---
 drivers/scsi/cxgb3i/Kbuild            |    2 +-
 drivers/scsi/cxgb3i/cxgb3i.h          |    4 +
 drivers/scsi/cxgb3i/cxgb3i_ipconfig.c |  519 +++++++++++++++++++++++++++++++++
 drivers/scsi/cxgb3i/cxgb3i_iscsi.c    |   23 ++-
 drivers/scsi/cxgb3i/cxgb3i_offload.c  |    3 +-
 5 files changed, 548 insertions(+), 3 deletions(-)
 create mode 100644 drivers/scsi/cxgb3i/cxgb3i_ipconfig.c

diff --git a/drivers/scsi/cxgb3i/Kbuild b/drivers/scsi/cxgb3i/Kbuild
index 70d060b..b0f1a3d 100644
--- a/drivers/scsi/cxgb3i/Kbuild
+++ b/drivers/scsi/cxgb3i/Kbuild
@@ -1,4 +1,4 @@
 EXTRA_CFLAGS += -I$(srctree)/drivers/net/cxgb3
 
-cxgb3i-y := cxgb3i_init.o cxgb3i_iscsi.o cxgb3i_pdu.o cxgb3i_offload.o cxgb3i_ddp.o
+cxgb3i-y := cxgb3i_init.o cxgb3i_iscsi.o cxgb3i_pdu.o cxgb3i_offload.o cxgb3i_ddp.o cxgb3i_ipconfig.o
 obj-$(CONFIG_SCSI_CXGB3_ISCSI) += cxgb3i.o
diff --git a/drivers/scsi/cxgb3i/cxgb3i.h b/drivers/scsi/cxgb3i/cxgb3i.h
index e3133b5..37b9a0d 100644
--- a/drivers/scsi/cxgb3i/cxgb3i.h
+++ b/drivers/scsi/cxgb3i/cxgb3i.h
@@ -158,4 +158,8 @@ int cxgb3i_conn_xmit_pdu(struct iscsi_task *);
 void cxgb3i_release_itt(struct iscsi_task *task, itt_t hdr_itt);
 int cxgb3i_reserve_itt(struct iscsi_task *task, itt_t *hdr_itt);
 
+int cxgb3i_ipconfig_init(struct cxgb3i_hba *hba);
+void cxgb3i_ipconfig_exit(struct cxgb3i_hba *hba);
+int cxgb3i_do_ipconf(struct cxgb3i_hba *hba);
+
 #endif
diff --git a/drivers/scsi/cxgb3i/cxgb3i_ipconfig.c b/drivers/scsi/cxgb3i/cxgb3i_ipconfig.c
new file mode 100644
index 0000000..09eddb4
--- /dev/null
+++ b/drivers/scsi/cxgb3i/cxgb3i_ipconfig.c
@@ -0,0 +1,519 @@
+/* cxgb3i_ipconfig.c: Chelsio S3xx iSCSI dhcp client.
+ *
+ * Copyright (c) 2009 Chelsio Communications, Inc.
+ * Copyright (c) 2008 Mike Christie
+ * Copyright (c) 2008 Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Rakesh Ranjan (rakesh-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org)
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <linux/if_arp.h>
+#include <net/ip.h>
+#include <scsi/iscsi_if.h>
+
+#include "common.h"
+#include "cxgb3i.h"
+
+#define DHCP_REQUEST        1
+#define DHCP_REPLY          2
+#define DHCP_HTYPE_ETHERNET 1
+#define DHCP_HLEN_ETHERNET  6
+#define DHCP_MSG_LEN      236
+
+#define DHCPC_SERVER_PORT  67
+#define DHCPC_CLIENT_PORT  68
+
+/*  DHCP message types */
+#define DHCPDISCOVER	1
+#define DHCPOFFER	2
+#define DHCPREQUEST	3
+#define DHCPDECLINE	4
+#define DHCPACK		5
+#define DHCPNAK		6
+#define DHCPRELEASE	7
+#define DHCPINFORM	8
+
+/* DHCP options */
+#define DHCP_OPTION_SUBNET_MASK		1
+#define DHCP_OPTION_ROUTER		3
+#define DHCP_OPTION_DNS_SERVER		6
+#define	DHCP_OPTION_MTU			26
+#define DHCP_OPTION_REQ_IPADDR		50
+#define DHCP_OPTION_LEASE_TIME		51
+#define DHCP_OPTION_MSG_TYPE		53
+#define DHCP_OPTION_SERVER_ID		54
+#define DHCP_OPTION_REQ_LIST		55
+#define	DHCP_OPTION_VCID		60
+#define DHCP_OPTION_END			255
+
+enum {
+	STATE_INIT	= 0,
+	STATE_SENDING,
+	STATE_OFFER_REC,
+	STATE_CONFIG_REC,
+};
+
+struct dhcp_pkt {
+	struct iphdr iph;
+	struct udphdr udph;
+	u8 op;
+	u8 htype;
+	u8 hlen;
+	u8 hops;
+	__be32 xid;
+	__be16 secs;
+	__be16 flags;
+	__be32 cipaddr;
+	__be32 yipaddr;
+	__be32 sipaddr;
+	__be32 ripaddr;
+	u8 chwaddr[16];
+	u8 sname[64];
+	u8 bfile[128];
+	u8 options[312];
+};
+
+struct hba_client_state {
+	struct sk_buff *skb;
+	struct dhcp_pkt *pkt;
+	struct cxgb3i_hba *hba;
+	volatile __u8 state;
+
+	__u8 *mac_addr;
+	__be32 xid;
+	__be32 ltime;
+	__be32 serverid;
+	__be32 ipaddr;
+	__be32 netmask;
+	__be32 dnsaddr;
+	__be32 gipaddr;
+};
+
+
+
+static struct hba_client_state *hcstate[MAX_NPORTS];
+
+static const char *RFC2132_VENDOR_CLASS_ID = "CXGB3I_Client";
+
+static const u8 magic_cookie[4] = { 99, 130, 83, 99 };
+
+
+
+static inline u8 *add_msg_type(u8 *optptr, u8 type)
+{
+	*optptr++ = DHCP_OPTION_MSG_TYPE;
+	*optptr++ = 1;
+	*optptr++ = type;
+	return optptr;
+}
+
+static inline u8 *add_req_options(u8 *optptr)
+{
+	*optptr++ = DHCP_OPTION_REQ_LIST;
+	*optptr++ = 4;
+	*optptr++ = DHCP_OPTION_SUBNET_MASK;
+	*optptr++ = DHCP_OPTION_ROUTER;
+	*optptr++ = DHCP_OPTION_DNS_SERVER;
+	*optptr++ = DHCP_OPTION_MTU;
+	return optptr;
+}
+
+static inline u8 *add_vendor_cid(u8 *optptr)
+{
+	u8 len = strlen(RFC2132_VENDOR_CLASS_ID);
+	*optptr++ = DHCP_OPTION_VCID;
+	*optptr++ = len;
+	memcpy(optptr, RFC2132_VENDOR_CLASS_ID, len);
+	optptr += len;
+	return optptr;
+}
+
+static inline u8 *add_server_id(__be32 *sid, u8 *optptr)
+{
+	*optptr++ = DHCP_OPTION_SERVER_ID;
+	*optptr++ = 4;
+	memcpy(optptr, sid, 4);
+	return optptr + 4;
+}
+
+static inline u8 *add_req_ipaddr(__be32 *ip, u8 *optptr)
+{
+	*optptr++ = DHCP_OPTION_REQ_IPADDR;
+	*optptr++ = 4;
+	memcpy(optptr, ip, 4);
+	return optptr + 4;
+}
+
+static inline u8 *add_end(u8 *optptr)
+{
+	*optptr++ = DHCP_OPTION_END;
+	return optptr;
+}
+
+static void
+cxgb3i_process_dhcp_opts(struct hba_client_state *client, u8 *optptr, int len)
+{
+	u8 *end = optptr + len;
+	u8 type = 0;
+
+	while (optptr < end) {
+		switch (*optptr) {
+		case DHCP_OPTION_SUBNET_MASK:
+			memcpy(&client->netmask, optptr + 2, 4);
+			break;
+		case DHCP_OPTION_ROUTER:
+			memcpy(&client->gipaddr, optptr + 2, 4);
+			break;
+		case DHCP_OPTION_DNS_SERVER:
+			memcpy(&client->dnsaddr, optptr + 2, 4);
+			break;
+		case DHCP_OPTION_MSG_TYPE:
+			type = *(optptr + 2);
+			if (type == DHCPOFFER)
+				client->state = STATE_OFFER_REC;
+			else if (type == DHCPACK)
+				client->state = STATE_CONFIG_REC;
+			break;
+		case DHCP_OPTION_SERVER_ID:
+			memcpy(&client->serverid, optptr + 2, 4);
+			break;
+		case DHCP_OPTION_LEASE_TIME:
+			memcpy(&client->ltime, optptr + 2, 4);
+			break;
+		case DHCP_OPTION_END:
+			break;
+		}
+
+		optptr += optptr[1] + 2;
+	}
+}
+
+static void
+cxgb3i_process_dhcp_pack(struct hba_client_state *client, struct dhcp_pkt *pkt)
+{
+	u8 *start, *end;
+	int opt_len;
+
+	start = &pkt->options[4];
+	end = (u8 *) pkt + ntohs(pkt->iph.tot_len);
+	opt_len = end - start;
+
+	if (pkt->op == DHCP_REPLY &&
+			!memcmp(&pkt->xid, &client->xid, sizeof(client->xid)) &&
+			!memcmp(pkt->chwaddr, client->mac_addr, pkt->hlen)) {
+		memcpy(&client->ipaddr, &pkt->yipaddr, 4);
+		cxgb3i_process_dhcp_opts(client, start, opt_len);
+	}
+}
+
+static int cxgb3i_ipconfig_send(struct port_info *pi, struct sk_buff **skb)
+{
+	int rc = 0;
+	struct sk_buff *lskb = *skb;
+	struct net_device *ndev = (hcstate[pi->port_id])->hba->ndev;
+
+	lskb->dev = ndev;
+	lskb->protocol = htons(ETH_P_IP);
+
+	dev_hard_header(lskb, ndev, ntohs(lskb->protocol), ndev->broadcast,
+				pi->iscsic.mac_addr, lskb->len);
+	rc = dev_queue_xmit(lskb);
+
+	return rc;
+}
+
+static int cxgb3i_ipconfig_recv(struct port_info *pi, struct sk_buff *skb)
+{
+	struct iphdr *iph;
+	struct udphdr *udph;
+	struct ethhdr *eh;
+	struct dhcp_pkt *pkt;
+	struct sk_buff *pskb;
+	int len, opts_len;
+	struct hba_client_state *client = hcstate[pi->port_id];
+	int rc = 0;
+
+	if (unlikely(client->state == STATE_INIT))
+		goto out;
+
+	cxgb3i_log_debug("client->state : %d\n", client->state);
+
+	if (skb->pkt_type != PACKET_OTHERHOST)
+		goto out;
+
+	pskb = skb_copy(skb, GFP_ATOMIC);
+	if (!pskb) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	eh = eth_hdr(pskb);
+	if (!is_valid_ether_addr(eh->h_dest))
+		goto drop;
+
+	if (compare_ether_addr(eh->h_dest, pi->iscsic.mac_addr))
+		goto drop;
+
+	if (!pskb_may_pull(pskb, sizeof(struct iphdr) + sizeof(struct udphdr)))
+		goto drop;
+
+
+	skb_reset_network_header(pskb);
+	pkt = (struct dhcp_pkt *) skb_network_header(pskb);
+	iph = &pkt->iph;
+
+	if (iph->ihl != 5 || iph->version != 4 || iph->protocol != IPPROTO_UDP)
+		goto drop;
+
+	if (iph->frag_off & htons(IP_OFFSET | IP_MF))
+		goto drop;
+
+	if (skb->len < ntohs(iph->tot_len))
+		goto drop;
+
+	if (ip_fast_csum((u8 *)iph, iph->ihl))
+		goto drop;
+
+	udph = &pkt->udph;
+	if (udph->source != htons(67) || udph->dest != htons(68))
+		goto drop;
+
+	if (ntohs(iph->tot_len) < ntohs(udph->len) + sizeof(struct iphdr))
+		goto drop;
+
+	len = ntohs(udph->len) - sizeof(struct udphdr);
+	opts_len = len - (sizeof(*pkt) -
+			sizeof(struct iphdr) -
+			sizeof(struct udphdr) -
+			sizeof(pkt->options));
+	if (opts_len < 0)
+		goto drop;
+
+	if (memcmp(pkt->options, magic_cookie, 4)) {
+		cxgb3i_log_error("Bad DHCP cookie recieved, aborting");
+		goto drop;
+	}
+
+	cxgb3i_log_debug("Received DHCP offer, processing");
+
+	cxgb3i_process_dhcp_pack(client, pkt);
+
+drop:
+	kfree(pskb);
+out:
+	return rc;
+}
+
+static int
+cxgb3i_create_dhcp_msg(struct hba_client_state *client)
+{
+	struct iphdr *iph;
+	struct udphdr *udph;
+	struct sk_buff *skb;
+	struct dhcp_pkt *pkt;
+	int rc = 0;
+	struct port_info *pi = netdev_priv(client->hba->ndev);
+
+	skb = alloc_skb(sizeof(*pkt) +
+			LL_ALLOCATED_SPACE(client->hba->ndev) + 15,
+			GFP_ATOMIC);
+	if (!skb) {
+		rc = -ENOMEM;
+		return rc;
+	}
+
+	client->skb = skb;
+	skb_reserve(skb, LL_RESERVED_SPACE(client->hba->ndev));
+
+	pkt = (struct dhcp_pkt *) skb_put(skb, sizeof(*pkt));
+	client->pkt = pkt;
+	memset(pkt, 0, sizeof(*pkt));
+
+	skb_reset_network_header(skb);
+
+	/* construct IP header */
+	iph = &pkt->iph;
+	iph->version = 4;
+	iph->ihl = 5;
+	iph->tot_len = htons(sizeof(struct dhcp_pkt));
+	iph->frag_off = htons(IP_DF);
+	iph->ttl = 64;
+	iph->protocol = IPPROTO_UDP;
+	iph->daddr = htonl(INADDR_BROADCAST);
+	iph->check = ip_fast_csum((u8 *) iph, iph->ihl);
+
+	/* Construct UDP header */
+	udph = &pkt->udph;
+	udph->source = htons(DHCPC_CLIENT_PORT);
+	udph->dest = htons(DHCPC_SERVER_PORT);
+	udph->len = htons(sizeof(struct dhcp_pkt) - sizeof(struct iphdr));
+
+	pkt->op = DHCP_REQUEST;
+	pkt->htype = DHCP_HTYPE_ETHERNET;
+	pkt->hlen = ETH_ALEN;
+
+	memcpy(pkt->chwaddr, pi->iscsic.mac_addr, ETH_ALEN);
+	pkt->secs = htons(jiffies / HZ);
+	pkt->xid = client->xid;
+
+	memcpy(pkt->options, magic_cookie, sizeof(magic_cookie));
+
+	return rc;
+}
+
+static int cxgb3i_send_dhcp_request(struct hba_client_state *client)
+{
+	int rc = 0;
+	u8 *end;
+	struct port_info *pi = netdev_priv(client->hba->ndev);
+
+	rc = cxgb3i_create_dhcp_msg(client);
+	if (rc)
+		return rc;
+
+	end = add_msg_type(&client->pkt->options[4], DHCPREQUEST);
+	end = add_server_id(&client->serverid, end);
+	end = add_req_ipaddr(&client->ipaddr, end);
+	end = add_vendor_cid(end);
+	end = add_end(end);
+
+	rc = cxgb3i_ipconfig_send(pi, &client->skb);
+
+	return rc;
+}
+
+static int cxgb3i_send_dhcp_discover(struct hba_client_state *client)
+{
+	int rc = 0;
+	u8 *end;
+	struct port_info *pi = netdev_priv(client->hba->ndev);
+
+	rc = cxgb3i_create_dhcp_msg(client);
+	if (rc)
+		return rc;
+
+	end = add_msg_type(&client->pkt->options[4], DHCPDISCOVER);
+	end = add_req_options(end);
+	end = add_vendor_cid(end);
+	end = add_end(end);
+
+	client->state = STATE_SENDING;
+	rc = cxgb3i_ipconfig_send(pi, &client->skb);
+
+	return rc;
+}
+
+static void
+cxgb3i_wait_for_pack(struct hba_client_state *client, u8 state)
+{
+	unsigned long tout, ntout;
+
+	get_random_bytes(&tout, sizeof(tout));
+	tout = (tout % (unsigned)HZ) + (HZ * 2);
+
+	ntout = jiffies + tout;
+	while (time_before(jiffies, ntout) && (client->state != state))
+		schedule_timeout_uninterruptible(1);
+}
+
+int cxgb3i_do_ipconf(struct cxgb3i_hba *hba)
+{
+	int rc = 0;
+	int retry;
+	struct hba_client_state *client = NULL;
+	struct port_info *pi = netdev_priv(hba->ndev);
+
+	client = hcstate[pi->port_id];
+	retry = 2;
+
+	/* show time */
+	for (;;) {
+		get_random_bytes(&client->xid, sizeof(__be32));
+		cxgb3i_send_dhcp_discover(client);
+		cxgb3i_wait_for_pack(client, STATE_OFFER_REC);
+
+		if (client->state == STATE_OFFER_REC) {
+			cxgb3i_log_debug("DHCPOFFER received for hba [%p]\n",
+									hba);
+			cxgb3i_send_dhcp_request(client);
+			cxgb3i_wait_for_pack(client, STATE_CONFIG_REC);
+			if (client->state == STATE_CONFIG_REC) {
+				cxgb3i_log_info("setting ip address of hba %p "
+					"to %pI4\n", hba, &client->ipaddr);
+				cxgb3i_set_private_ipv4addr(hba->ndev,
+								client->ipaddr);
+				client->state = STATE_INIT;
+				break;
+			}
+		}
+
+		if (!--retry) {
+			cxgb3i_log_info("IPCONFIG timed out for hba [%p]\n",
+									hba);
+			rc = -ENETUNREACH;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+int cxgb3i_ipconfig_init(struct cxgb3i_hba *hba)
+{
+	int rc = 0;
+	struct hba_client_state *client = NULL;
+	struct port_info *pi = netdev_priv(hba->ndev);
+
+	client = kzalloc(sizeof(*client), GFP_KERNEL);
+	if (!client) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	client->hba = hba;
+	client->mac_addr = pi->iscsic.mac_addr;
+	client->state = STATE_INIT;
+
+	hcstate[pi->port_id] = client;
+	cxgb3i_log_debug("added hcstate[%d] : %p\n", pi->port_id,
+						hcstate[pi->port_id]);
+
+	pi->iscsic.send = cxgb3i_ipconfig_send;
+	pi->iscsic.recv = cxgb3i_ipconfig_recv;
+	pi->iscsic.flags = 1;
+
+out:
+	return rc;
+}
+
+void cxgb3i_ipconfig_exit(struct cxgb3i_hba *hba)
+{
+	struct net_device *ndev = hba->ndev;
+	struct port_info *pi = netdev_priv(ndev);
+
+	cxgb3i_set_private_ipv4addr(hba->ndev, 0);
+
+	pi->iscsic.flags = 0;
+	pi->iscsic.send = NULL;
+	pi->iscsic.recv = NULL;
+
+	if (hcstate[pi->port_id]) {
+		cxgb3i_log_info("removing hcstate[%d] : %p\n", pi->port_id,
+							hcstate[pi->port_id]);
+		kfree(hcstate[pi->port_id]);
+	}
+
+}
+
diff --git a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
index 2631bdd..2bb5e63 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
@@ -240,6 +240,13 @@ struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *snic,
 		goto pci_dev_put;
 	}
 
+	err = cxgb3i_ipconfig_init(hba);
+	if (err) {
+		cxgb3i_log_info("snic 0x%p, ndev 0x%p, host_add failed.\n",
+				snic, ndev);
+		goto pci_dev_put;
+	}
+
 	cxgb3i_api_debug("shost 0x%p, hba 0x%p, no %u.\n",
 			 shost, hba, shost->host_no);
 
@@ -259,6 +266,7 @@ void cxgb3i_hba_host_remove(struct cxgb3i_hba *hba)
 {
 	cxgb3i_api_debug("shost 0x%p, hba 0x%p, no %u.\n",
 			 hba->shost, hba, hba->shost->host_no);
+	cxgb3i_ipconfig_exit(hba);
 	iscsi_host_remove(hba->shost);
 	pci_dev_put(hba->snic->pdev);
 	iscsi_host_free(hba->shost);
@@ -737,13 +745,14 @@ static int cxgb3i_host_get_param(struct Scsi_Host *shost,
 				 enum iscsi_host_param param, char *buf)
 {
 	struct cxgb3i_hba *hba = iscsi_host_priv(shost);
+	struct port_info *pi = netdev_priv(hba->ndev);
 	int len = 0;
 
 	cxgb3i_api_debug("hba %s, param %d.\n", hba->ndev->name, param);
 
 	switch (param) {
 	case ISCSI_HOST_PARAM_HWADDRESS:
-		len = sysfs_format_mac(buf, hba->ndev->dev_addr, 6);
+		len = sysfs_format_mac(buf, pi->iscsic.mac_addr, ETH_ALEN);
 		break;
 	case ISCSI_HOST_PARAM_NETDEV_NAME:
 		len = sprintf(buf, "%s\n", hba->ndev->name);
@@ -762,6 +771,17 @@ static int cxgb3i_host_get_param(struct Scsi_Host *shost,
 	return len;
 }
 
+static int cxgb3i_req_ipconf(struct Scsi_Host *shost)
+{
+	int rc;
+
+	struct cxgb3i_hba *hba = iscsi_host_priv(shost);
+
+	rc = cxgb3i_do_ipconf(hba);
+
+	return rc;
+}
+
 /**
  * cxgb3i_conn_get_stats - returns iSCSI stats
  * @cls_conn:	pointer to iscsi cls conn
@@ -976,6 +996,7 @@ static struct iscsi_transport cxgb3i_iscsi_transport = {
 	.ep_disconnect		= cxgb3i_ep_disconnect,
 	/* Error recovery timeout call */
 	.session_recovery_timedout = iscsi_session_recovery_timedout,
+	.req_ipconf		= cxgb3i_req_ipconf,
 };
 
 int cxgb3i_iscsi_init(void)
diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.c b/drivers/scsi/cxgb3i/cxgb3i_offload.c
index c1d5be4..8fdafeb 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_offload.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_offload.c
@@ -269,7 +269,8 @@ static void make_act_open_req(struct s3_conn *c3cn, struct sk_buff *skb,
 	req->local_ip = c3cn->saddr.sin_addr.s_addr;
 	req->peer_ip = c3cn->daddr.sin_addr.s_addr;
 	req->opt0h = htonl(calc_opt0h(c3cn) | V_L2T_IDX(e->idx) |
-			   V_TX_CHANNEL(e->smt_idx));
+			   V_TX_CHANNEL(e->smt_idx) |
+			   V_SRC_MAC_SEL(SAN_MAC_IDX));
 	req->opt0l = htonl(calc_opt0l(c3cn));
 	req->params = 0;
 }
-- 
1.6.0.6


^ permalink raw reply related

* Re: [PATCH] Regression: e100_phy_init() isolates even selected PHY, causes 10 seconds boot delay
From: Jeff Kirsher @ 2009-10-29 13:19 UTC (permalink / raw)
  To: David Miller; +Cc: bernhard.kaindl, bruce.w.allan, netdev
In-Reply-To: <20091029.060239.202729106.davem@davemloft.net>

On Thu, Oct 29, 2009 at 06:02, David Miller <davem@davemloft.net> wrote:
> From: Bernhard Kaindl <bernhard.kaindl@gmx.net>
> Date: Wed, 30 Sep 2009 22:33:31 +0200
>
>> The current e100.c:e100_phy_init() electrically isolates all
>> the PHYs (even the selected PHY -- for a short time!) from the MII.
>>
>> This happens only for a short duration before the isolation
>> of the selected PHY is reverted, but it's enough to cause a
>> major disturbance in the startup of our e100-based cards:
>>
>> On a number of Embedded/Industry Pentium boards which are in use,
>> the result is that the initial DHCP negotiation takes more
>> than 10 seconds to complete with 2.6.30 and .31, while it's
>> done in a fraction of a second with 2.6.29 and earlier
>> (kernels tested with no delay range from 2.6.23 to 2.6.29)
>>
>> That regression was introduced on March 31 in the by a patch
>> from Bruce which first appeared in 2.6.30-rc3:
>
> Bruce, can you give some feedback on this?  I'd like to see this issue
> move forward.
>
> The only reason I haven't applied Bernhard's patch is because I
> haven't seen any feedback from Intel.  But I will apply it anyways if
> I don't see reasonable feedback soon.
>
> Thanks.

Bruce has been working on this and we currently have a patch in test.
We should have an updated patch submitted later today or tomorrow.

-- 
Cheers,
Jeff

^ permalink raw reply

* RE: [Pv-drivers] [PATCH] vmxnet3: remove duplicate #include
From: Bhavesh Davda @ 2009-10-29 13:35 UTC (permalink / raw)
  To: David Miller, Shreyas Bhatewara
  Cc: pv-drivers@vmware.com, netdev@vger.kernel.org,
	weiyi.huang@gmail.com
In-Reply-To: <20091028.225217.78322944.davem@davemloft.net>

> From: David Miller <davem@davemloft.net>
> Date: Wed, 28 Oct 2009 22:29:01 -0700 (PDT)
> 
> > From: Shreyas Bhatewara <sbhatewara@vmware.com>
> > Date: Wed, 28 Oct 2009 09:30:40 -0700 (PDT)
> >
> >>
> >> Remove duplicate headerfile includes from vmxnet3_int.h
> >>
> >> Signed-off-by: Shreyas Bhatewara <sbhatewara@vmware.com>
> >> Signed-off-by: Huang Weiyi <weiyi.huang@gmail.com>
> >> Signed-off-by: Bhavesh Davda <davda@vmware.com>
> >
> > Applied.
> 
> Guys, I'd like to remove the X86 Kconfig requirement for this
> driver.  There really isn't any x86 specific code in the
> driver, it uses only standard PCI and networking APIs to function.
> 
> I know the virtual hardware won't be seen on other platforms,
> but allowing the driver to get build tested on non-x86 platforms
> helps me a lot.  I do all of my build verifications on sparc64
> for example.

The driver shares in-memory data structures with the device emulation in the hypervisor, so in the VMware case since they are both on x86, we don't need any cpu_to_le32 or le32_to_cpu's when accessing them. But for correctness, if you were to compile the vmxnet3 driver for a big-endian architecture like sparc64, we will need to sprinkle those around all accesses to the shared data structures.

In other words, don't just trivially remove the X86 Kconfig requirement for this driver.

Thanks

- Bhavesh

^ permalink raw reply

* Re: pull request: wireless-next-2.6 2009-10-28
From: Bartlomiej Zolnierkiewicz @ 2009-10-29 13:35 UTC (permalink / raw)
  To: David Miller; +Cc: linux-wireless, netdev, linux-kernel, linville
In-Reply-To: <20091029.055901.24976117.davem@davemloft.net>

On Thursday 29 October 2009 13:59:01 David Miller wrote:
> From: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
> Date: Thu, 29 Oct 2009 13:45:05 +0100
> 
> > That *I* should be fixing the patch in question instead of the
> > submitter?
> 
> I'm saying that you should work with John to have him send a revert or
> whatever to me.

This is your responsibility to deal with your downstream maintainers,
not mine and since you have accepted John's patch I'm asking you to
revert rt2800pci patch from your tree.

-- 
Bartlomiej Zolnierkiewicz

^ permalink raw reply

* Re: [PATCH 4/6] vlan: Optimize multiple unregistration
From: Patrick McHardy @ 2009-10-29 13:45 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: David S. Miller, Linux Netdev List
In-Reply-To: <4AE8ADE7.1010909@gmail.com>

Eric Dumazet wrote:
> Patrick McHardy a écrit :
>>> +{
>>> +	LIST_HEAD(list);
>>> +	int i;
>>> +	struct net_device *vlandev;
>>> +	struct vlan_group save;
>>> +
>>> +	memcpy(&save, grp, sizeof(save));
>>> +	memset(&grp->vlan_devices_arrays, 0, sizeof(grp->vlan_devices_arrays));
>> This shouldn't be necessary since the lower device is already in the
>> process of being unregistered. If it was necessary, it could cause
>> crashes since the individual pointers are not set to zero atomically.
>> Or maybe I'm misunderstanding the purpose entirely :)
> 
> Very good point indeed, even if in practice memset() use long word transferts
> 
> I'll make a cleanup patch, or do you want to do it ?

I can take care of this, patch will follow shortly.


^ permalink raw reply

* Re: [Pv-drivers] [PATCH] vmxnet3: remove duplicate #include
From: David Miller @ 2009-10-29 13:50 UTC (permalink / raw)
  To: bhavesh; +Cc: sbhatewara, pv-drivers, netdev, weiyi.huang
In-Reply-To: <8B1F619C9F5F454E81D90D3C161698D7017DFAA30F@EXCH-MBX-3.vmware.com>

From: Bhavesh Davda <bhavesh@vmware.com>
Date: Thu, 29 Oct 2009 06:35:35 -0700

> In other words, don't just trivially remove the X86 Kconfig
> requirement for this driver.

Then I assume you're going to add the endianness handling
and send me a patch soon?

^ permalink raw reply

* [PATCH net-next-2.6] Driver for the Microchip MCP251x SPI CAN controllers
From: Christian Pellegrin @ 2009-10-29 13:50 UTC (permalink / raw)
  To: socketcan-core-0fE9KPoRgkgATYTw5x5z8w,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: Christian Pellegrin


Signed-off-by: Christian Pellegrin <chripell-VaTbYqLCNhc@public.gmane.org>
---
 drivers/net/can/Kconfig              |    6 +
 drivers/net/can/Makefile             |    1 +
 drivers/net/can/mcp251x.c            | 1182 ++++++++++++++++++++++++++++++++++
 include/linux/can/platform/mcp251x.h |   34 +
 4 files changed, 1223 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/can/mcp251x.c
 create mode 100644 include/linux/can/platform/mcp251x.h

diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 26d77cc..e987526 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -102,6 +102,12 @@ config CAN_TI_HECC
 	  Driver for TI HECC (High End CAN Controller) module found on many
 	  TI devices. The device specifications are available from www.ti.com
 
+config CAN_MCP251X
+	tristate "Microchip MCP251x SPI CAN controllers"
+	depends on CAN && CAN_DEV && SPI
+	---help---
+	  Driver for the Microchip MCP251x SPI CAN controllers.
+
 config CAN_DEBUG_DEVICES
 	bool "CAN devices debugging messages"
 	depends on CAN
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 31f4ab5..1489181 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -12,5 +12,6 @@ obj-y				+= usb/
 obj-$(CONFIG_CAN_SJA1000)	+= sja1000/
 obj-$(CONFIG_CAN_AT91)		+= at91_can.o
 obj-$(CONFIG_CAN_TI_HECC)	+= ti_hecc.o
+obj-$(CONFIG_CAN_MCP251X)	+= mcp251x.o
 
 ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c
new file mode 100644
index 0000000..f444cac
--- /dev/null
+++ b/drivers/net/can/mcp251x.c
@@ -0,0 +1,1182 @@
+/*
+ * CAN bus driver for Microchip 251x CAN Controller with SPI Interface
+ *
+ * MCP2510 support and bug fixes by Christian Pellegrin
+ * <chripell-LERDrqjqfvZg9hUCZPvPmw@public.gmane.org>
+ *
+ * Copyright 2007 Raymarine UK, Ltd. All Rights Reserved.
+ * Written under contract by:
+ *   Chris Elston, Katalix Systems, Ltd.
+ *
+ * Based on Microchip MCP251x CAN controller driver written by
+ * David Vrabel, Copyright 2006 Arcom Control Systems Ltd.
+ *
+ * Based on CAN bus driver for the CCAN controller written by
+ * - Sascha Hauer, Marc Kleine-Budde, Pengutronix
+ * - Simon Kallweit, intefo AG
+ * Copyright 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ *
+ * Your platform definition file should specify something like:
+ *
+ * static struct mcp251x_platform_data mcp251x_info = {
+ *         .oscillator_frequency = 8000000,
+ *         .board_specific_setup = &mcp251x_setup,
+ *         .model = CAN_MCP251X_MCP2510,
+ *         .power_enable = mcp251x_power_enable,
+ *         .transceiver_enable = NULL,
+ * };
+ *
+ * static struct spi_board_info spi_board_info[] = {
+ *         {
+ *                 .modalias      = "mcp251x",
+ *                 .platform_data = &mcp251x_info,
+ *                 .irq           = IRQ_EINT13,
+ *                 .max_speed_hz  = 2*1000*1000,
+ *                 .chip_select   = 2,
+ *         },
+ * };
+ *
+ * Please see mcp251x.h for a description of the fields in
+ * struct mcp251x_platform_data.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/can.h>
+#include <linux/spi/spi.h>
+#include <linux/can/dev.h>
+#include <linux/can/core.h>
+#include <linux/if_arp.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/freezer.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/can/platform/mcp251x.h>
+
+/* SPI interface instruction set */
+#define INSTRUCTION_WRITE	0x02
+#define INSTRUCTION_READ	0x03
+#define INSTRUCTION_BIT_MODIFY	0x05
+#define INSTRUCTION_LOAD_TXB(n)	(0x40 + 2 * (n))
+#define INSTRUCTION_READ_RXB(n)	(((n) == 0) ? 0x90 : 0x94)
+#define INSTRUCTION_RESET	0xC0
+
+/* MPC251x registers */
+#define CANSTAT	      0x0e
+#define CANCTRL	      0x0f
+#  define CANCTRL_REQOP_MASK	    0xe0
+#  define CANCTRL_REQOP_CONF	    0x80
+#  define CANCTRL_REQOP_LISTEN_ONLY 0x60
+#  define CANCTRL_REQOP_LOOPBACK    0x40
+#  define CANCTRL_REQOP_SLEEP	    0x20
+#  define CANCTRL_REQOP_NORMAL	    0x00
+#  define CANCTRL_OSM		    0x08
+#  define CANCTRL_ABAT		    0x10
+#define TEC	      0x1c
+#define REC	      0x1d
+#define CNF1	      0x2a
+#  define CNF1_SJW_SHIFT   6
+#define CNF2	      0x29
+#  define CNF2_BTLMODE	   0x80
+#  define CNF2_SAM         0x40
+#  define CNF2_PS1_SHIFT   3
+#define CNF3	      0x28
+#  define CNF3_SOF	   0x08
+#  define CNF3_WAKFIL	   0x04
+#  define CNF3_PHSEG2_MASK 0x07
+#define CANINTE	      0x2b
+#  define CANINTE_MERRE 0x80
+#  define CANINTE_WAKIE 0x40
+#  define CANINTE_ERRIE 0x20
+#  define CANINTE_TX2IE 0x10
+#  define CANINTE_TX1IE 0x08
+#  define CANINTE_TX0IE 0x04
+#  define CANINTE_RX1IE 0x02
+#  define CANINTE_RX0IE 0x01
+#define CANINTF	      0x2c
+#  define CANINTF_MERRF 0x80
+#  define CANINTF_WAKIF 0x40
+#  define CANINTF_ERRIF 0x20
+#  define CANINTF_TX2IF 0x10
+#  define CANINTF_TX1IF 0x08
+#  define CANINTF_TX0IF 0x04
+#  define CANINTF_RX1IF 0x02
+#  define CANINTF_RX0IF 0x01
+#define EFLG	      0x2d
+#  define EFLG_EWARN	0x01
+#  define EFLG_RXWAR	0x02
+#  define EFLG_TXWAR	0x04
+#  define EFLG_RXEP	0x08
+#  define EFLG_TXEP	0x10
+#  define EFLG_TXBO	0x20
+#  define EFLG_RX0OVR	0x40
+#  define EFLG_RX1OVR	0x80
+#define TXBCTRL(n)  ((n * 0x10) + 0x30)
+#  define TXBCTRL_ABTF	0x40
+#  define TXBCTRL_MLOA	0x20
+#  define TXBCTRL_TXERR 0x10
+#  define TXBCTRL_TXREQ 0x08
+#define TXBSIDH(n)  ((n * 0x10) + 0x31)
+#  define SIDH_SHIFT    3
+#define TXBSIDL(n)  ((n * 0x10) + 0x32)
+#  define SIDL_SID_MASK    7
+#  define SIDL_SID_SHIFT   5
+#  define SIDL_EXIDE_SHIFT 3
+#  define SIDL_EID_SHIFT   16
+#  define SIDL_EID_MASK    3
+#define TXBEID8(n)  ((n * 0x10) + 0x33)
+#define TXBEID0(n)  ((n * 0x10) + 0x34)
+#define TXBDLC(n)   ((n * 0x10) + 0x35)
+#  define DLC_RTR_SHIFT    6
+#define TXBCTRL_OFF 0
+#define TXBSIDH_OFF 1
+#define TXBSIDL_OFF 2
+#define TXBEID8_OFF 3
+#define TXBEID0_OFF 4
+#define TXBDLC_OFF  5
+#define TXBDAT_OFF  6
+#define RXBCTRL(n)  ((n * 0x10) + 0x60)
+#  define RXBCTRL_BUKT	0x04
+#  define RXBCTRL_RXM0	0x20
+#  define RXBCTRL_RXM1	0x40
+#define RXBSIDH(n)  ((n * 0x10) + 0x61)
+#  define RXBSIDH_SHIFT 3
+#define RXBSIDL(n)  ((n * 0x10) + 0x62)
+#  define RXBSIDL_IDE   0x08
+#  define RXBSIDL_EID   3
+#  define RXBSIDL_SHIFT 5
+#define RXBEID8(n)  ((n * 0x10) + 0x63)
+#define RXBEID0(n)  ((n * 0x10) + 0x64)
+#define RXBDLC(n)   ((n * 0x10) + 0x65)
+#  define RXBDLC_LEN_MASK  0x0f
+#  define RXBDLC_RTR       0x40
+#define RXBCTRL_OFF 0
+#define RXBSIDH_OFF 1
+#define RXBSIDL_OFF 2
+#define RXBEID8_OFF 3
+#define RXBEID0_OFF 4
+#define RXBDLC_OFF  5
+#define RXBDAT_OFF  6
+
+#define GET_BYTE(val, byte)			\
+	(((val) >> ((byte) * 8)) & 0xff)
+#define SET_BYTE(val, byte)			\
+	(((val) & 0xff) << ((byte) * 8))
+
+/*
+ * Buffer size required for the largest SPI transfer (i.e., reading a
+ * frame)
+ */
+#define CAN_FRAME_MAX_DATA_LEN	8
+#define SPI_TRANSFER_BUF_LEN	(6 + CAN_FRAME_MAX_DATA_LEN)
+#define CAN_FRAME_MAX_BITS	128
+
+#define TX_ECHO_SKB_MAX	1
+
+#define DEVICE_NAME "mcp251x"
+
+static int mcp251x_enable_dma; /* Enable SPI DMA. Default: 0 (Off) */
+module_param(mcp251x_enable_dma, int, S_IRUGO);
+MODULE_PARM_DESC(mcp251x_enable_dma, "Enable SPI DMA. Default: 0 (Off)");
+
+static struct can_bittiming_const mcp251x_bittiming_const = {
+	.name = DEVICE_NAME,
+	.tseg1_min = 3,
+	.tseg1_max = 16,
+	.tseg2_min = 2,
+	.tseg2_max = 8,
+	.sjw_max = 4,
+	.brp_min = 1,
+	.brp_max = 64,
+	.brp_inc = 1,
+};
+
+struct mcp251x_priv {
+	struct can_priv	   can;
+	struct net_device *net;
+	struct spi_device *spi;
+
+	struct mutex spi_lock; /* SPI buffer lock */
+	u8 *spi_tx_buf;
+	u8 *spi_rx_buf;
+	dma_addr_t spi_tx_dma;
+	dma_addr_t spi_rx_dma;
+
+	struct sk_buff *tx_skb;
+	int tx_len;
+	struct workqueue_struct *wq;
+	struct work_struct tx_work;
+	struct work_struct irq_work;
+	struct completion awake;
+	int wake;
+	int force_quit;
+	int after_suspend;
+#define AFTER_SUSPEND_UP 1
+#define AFTER_SUSPEND_DOWN 2
+#define AFTER_SUSPEND_POWER 4
+#define AFTER_SUSPEND_RESTART 8
+	int restart_tx;
+};
+
+static void mcp251x_clean(struct net_device *net)
+{
+	struct mcp251x_priv *priv = netdev_priv(net);
+
+	net->stats.tx_errors++;
+	if (priv->tx_skb)
+		dev_kfree_skb(priv->tx_skb);
+	if (priv->tx_len)
+		can_free_echo_skb(priv->net, 0);
+	priv->tx_skb = NULL;
+	priv->tx_len = 0;
+}
+
+/*
+ * Note about handling of error return of mcp251x_spi_trans: accessing
+ * registers via SPI is not really different conceptually than using
+ * normal I/O assembler instructions, although it's much more
+ * complicated from a practical POV. So it's not advisable to always
+ * check the return value of this function. Imagine that every
+ * read{b,l}, write{b,l} and friends would be bracketed in "if ( < 0)
+ * error();", it would be a great mess (well there are some situation
+ * when exception handling C++ like could be useful after all). So we
+ * just check that transfers are OK at the beginning of our
+ * conversation with the chip and to avoid doing really nasty things
+ * (like injecting bogus packets in the network stack).
+ */
+static int mcp251x_spi_trans(struct spi_device *spi, int len)
+{
+	struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+	struct spi_transfer t = {
+		.tx_buf = priv->spi_tx_buf,
+		.rx_buf = priv->spi_rx_buf,
+		.len = len,
+		.cs_change = 0,
+	};
+	struct spi_message m;
+	int ret;
+
+	spi_message_init(&m);
+
+	if (mcp251x_enable_dma) {
+		t.tx_dma = priv->spi_tx_dma;
+		t.rx_dma = priv->spi_rx_dma;
+		m.is_dma_mapped = 1;
+	}
+
+	spi_message_add_tail(&t, &m);
+
+	ret = spi_sync(spi, &m);
+	if (ret < 0)
+		dev_err(&spi->dev, "spi transfer failed: ret = %d\n", ret);
+	return ret;
+}
+
+static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
+{
+	struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+	u8 val = 0;
+
+	mutex_lock(&priv->spi_lock);
+
+	priv->spi_tx_buf[0] = INSTRUCTION_READ;
+	priv->spi_tx_buf[1] = reg;
+
+	mcp251x_spi_trans(spi, 3);
+	val = priv->spi_rx_buf[2];
+
+	mutex_unlock(&priv->spi_lock);
+
+	return val;
+}
+
+static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)
+{
+	struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+
+	mutex_lock(&priv->spi_lock);
+
+	priv->spi_tx_buf[0] = INSTRUCTION_WRITE;
+	priv->spi_tx_buf[1] = reg;
+	priv->spi_tx_buf[2] = val;
+
+	mcp251x_spi_trans(spi, 3);
+
+	mutex_unlock(&priv->spi_lock);
+}
+
+static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
+			       u8 mask, uint8_t val)
+{
+	struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+
+	mutex_lock(&priv->spi_lock);
+
+	priv->spi_tx_buf[0] = INSTRUCTION_BIT_MODIFY;
+	priv->spi_tx_buf[1] = reg;
+	priv->spi_tx_buf[2] = mask;
+	priv->spi_tx_buf[3] = val;
+
+	mcp251x_spi_trans(spi, 4);
+
+	mutex_unlock(&priv->spi_lock);
+}
+
+static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *data,
+				int len, int tx_buf_idx)
+{
+	struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+	struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+
+	if (pdata->model == CAN_MCP251X_MCP2510) {
+		int i;
+
+		for (i = 1; i < TXBDAT_OFF + len; i++)
+			mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + i,
+					  data[i]);
+	} else {
+		mutex_lock(&priv->spi_lock);
+		memcpy(priv->spi_tx_buf, data, TXBDAT_OFF + len);
+		mcp251x_spi_trans(spi, TXBDAT_OFF + len);
+		mutex_unlock(&priv->spi_lock);
+	}
+}
+
+static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
+			  int tx_buf_idx)
+{
+	u32 sid, eid, exide, rtr;
+	u8 buf[SPI_TRANSFER_BUF_LEN];
+
+	exide = (frame->can_id & CAN_EFF_FLAG) ? 1 : 0; /* Extended ID Enable */
+	if (exide)
+		sid = (frame->can_id & CAN_EFF_MASK) >> 18;
+	else
+		sid = frame->can_id & CAN_SFF_MASK; /* Standard ID */
+	eid = frame->can_id & CAN_EFF_MASK; /* Extended ID */
+	rtr = (frame->can_id & CAN_RTR_FLAG) ? 1 : 0; /* Remote transmission */
+
+	buf[TXBCTRL_OFF] = INSTRUCTION_LOAD_TXB(tx_buf_idx);
+	buf[TXBSIDH_OFF] = sid >> SIDH_SHIFT;
+	buf[TXBSIDL_OFF] = ((sid & SIDL_SID_MASK) << SIDL_SID_SHIFT) |
+		(exide << SIDL_EXIDE_SHIFT) |
+		((eid >> SIDL_EID_SHIFT) & SIDL_EID_MASK);
+	buf[TXBEID8_OFF] = GET_BYTE(eid, 1);
+	buf[TXBEID0_OFF] = GET_BYTE(eid, 0);
+	buf[TXBDLC_OFF]  = (rtr << DLC_RTR_SHIFT) | frame->can_dlc;
+	memcpy(buf + TXBDAT_OFF, frame->data, frame->can_dlc);
+	mcp251x_hw_tx_frame(spi, buf, frame->can_dlc, tx_buf_idx);
+	mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx), TXBCTRL_TXREQ);
+}
+
+static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *data,
+				int buf_idx)
+{
+	struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+	struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+
+	if (pdata->model == CAN_MCP251X_MCP2510) {
+		int i, len;
+
+		for (i = 1; i < RXBDAT_OFF; i++)
+			data[i] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + i);
+		len = data[RXBDLC_OFF] & RXBDLC_LEN_MASK;
+		if (len > 8)
+			len = 8;
+		for (; i < (RXBDAT_OFF + len); i++)
+			data[i] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + i);
+	} else {
+		mutex_lock(&priv->spi_lock);
+
+		priv->spi_tx_buf[RXBCTRL_OFF] = INSTRUCTION_READ_RXB(buf_idx);
+		mcp251x_spi_trans(spi, SPI_TRANSFER_BUF_LEN);
+		memcpy(data, priv->spi_rx_buf, SPI_TRANSFER_BUF_LEN);
+
+		mutex_unlock(&priv->spi_lock);
+	}
+}
+
+static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
+{
+	struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+	struct sk_buff *skb;
+	struct can_frame *frame;
+	u8 buf[SPI_TRANSFER_BUF_LEN];
+
+	skb = alloc_can_skb(priv->net, &frame);
+	if (!skb) {
+		dev_err(&spi->dev, "cannot allocate RX skb\n");
+		priv->net->stats.rx_dropped++;
+		return;
+	}
+
+	mcp251x_hw_rx_frame(spi, buf, buf_idx);
+	if (buf[RXBSIDL_OFF] & RXBSIDL_IDE) {
+		/* Extended ID format */
+		frame->can_id = CAN_EFF_FLAG;
+		frame->can_id |=
+			/* Extended ID part */
+			SET_BYTE(buf[RXBSIDL_OFF] & RXBSIDL_EID, 2) |
+			SET_BYTE(buf[RXBEID8_OFF],               1) |
+			SET_BYTE(buf[RXBEID0_OFF],               0) |
+			/* Standard ID part */
+			(((buf[RXBSIDH_OFF] << RXBSIDH_SHIFT) |
+			  (buf[RXBSIDL_OFF] >> RXBSIDL_SHIFT)) << 18);
+		if (buf[RXBDLC_OFF] & RXBDLC_RTR) {
+			/* Remote transmission request */
+			frame->can_id |= CAN_RTR_FLAG;
+		}
+	} else
+		/* Standard ID format */
+		frame->can_id =
+			(buf[RXBSIDH_OFF] << RXBSIDH_SHIFT) |
+			(buf[RXBSIDL_OFF] >> RXBSIDL_SHIFT);
+	/* Data length */
+	frame->can_dlc = buf[RXBDLC_OFF] & RXBDLC_LEN_MASK;
+	if (frame->can_dlc > 8) {
+		dev_warn(&spi->dev, "invalid frame recevied\n");
+		priv->net->stats.rx_errors++;
+		dev_kfree_skb(skb);
+		return;
+	}
+	memcpy(frame->data, buf + RXBDAT_OFF, frame->can_dlc);
+
+	priv->net->stats.rx_packets++;
+	priv->net->stats.rx_bytes += frame->can_dlc;
+	netif_rx(skb);
+}
+
+static void mcp251x_hw_sleep(struct spi_device *spi)
+{
+	mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_SLEEP);
+}
+
+static void mcp251x_hw_wakeup(struct spi_device *spi)
+{
+	struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+
+	priv->wake = 1;
+
+	/* Can only wake up by generating a wake-up interrupt. */
+	mcp251x_write_bits(spi, CANINTE, CANINTE_WAKIE, CANINTE_WAKIE);
+	mcp251x_write_bits(spi, CANINTF, CANINTF_WAKIF, CANINTF_WAKIF);
+
+	/* Wait until the device is awake */
+	if (!wait_for_completion_timeout(&priv->awake, HZ))
+		dev_err(&spi->dev, "MCP251x didn't wake-up\n");
+}
+
+static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb,
+					   struct net_device *net)
+{
+	struct mcp251x_priv *priv = netdev_priv(net);
+	struct spi_device *spi = priv->spi;
+
+	if (priv->tx_skb || priv->tx_len) {
+		dev_warn(&spi->dev, "hard_xmit called while tx busy\n");
+		netif_stop_queue(net);
+		return NETDEV_TX_BUSY;
+	}
+
+	if (skb->len != sizeof(struct can_frame)) {
+		dev_err(&spi->dev, "dropping packet - bad length\n");
+		dev_kfree_skb(skb);
+		net->stats.tx_dropped++;
+		return 0;
+	}
+
+	netif_stop_queue(net);
+	priv->tx_skb = skb;
+	net->trans_start = jiffies;
+	queue_work(priv->wq, &priv->tx_work);
+
+	return NETDEV_TX_OK;
+}
+
+static int mcp251x_do_set_mode(struct net_device *net, enum can_mode mode)
+{
+	struct mcp251x_priv *priv = netdev_priv(net);
+
+	switch (mode) {
+	case CAN_MODE_START:
+		/* We have to delay work since SPI I/O may sleep */
+		priv->can.state = CAN_STATE_ERROR_ACTIVE;
+		priv->restart_tx = 1;
+		if (priv->can.restart_ms == 0)
+			priv->after_suspend = AFTER_SUSPEND_RESTART;
+		queue_work(priv->wq, &priv->irq_work);
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static void mcp251x_set_normal_mode(struct spi_device *spi)
+{
+	struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+	unsigned long timeout;
+
+	/* Enable interrupts */
+	mcp251x_write_reg(spi, CANINTE,
+			  CANINTE_ERRIE | CANINTE_TX2IE | CANINTE_TX1IE |
+			  CANINTE_TX0IE | CANINTE_RX1IE | CANINTE_RX0IE |
+			  CANINTF_MERRF);
+
+	if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
+		/* Put device into loopback mode */
+		mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_LOOPBACK);
+	else {
+		/* Put device into normal mode */
+		mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_NORMAL);
+
+		/* Wait for the device to enter normal mode */
+		timeout = jiffies + HZ;
+		while (mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) {
+			schedule();
+			if (time_after(jiffies, timeout)) {
+				dev_err(&spi->dev, "MCP251x didn't"
+					" enter in normal mode\n");
+				return;
+			}
+		}
+	}
+	priv->can.state = CAN_STATE_ERROR_ACTIVE;
+}
+
+static int mcp251x_do_set_bittiming(struct net_device *net)
+{
+	struct mcp251x_priv *priv = netdev_priv(net);
+	struct can_bittiming *bt = &priv->can.bittiming;
+	struct spi_device *spi = priv->spi;
+	u8 state;
+
+	/* Store original mode and set mode to config */
+	state = mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK;
+	mcp251x_write_bits(spi, CANCTRL, CANCTRL_REQOP_MASK,
+			   CANCTRL_REQOP_CONF);
+
+	mcp251x_write_reg(spi, CNF1, ((bt->sjw - 1) << CNF1_SJW_SHIFT) |
+			  (bt->brp - 1));
+	mcp251x_write_reg(spi, CNF2, CNF2_BTLMODE |
+			  (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES ?
+			   CNF2_SAM : 0) |
+			  ((bt->phase_seg1 - 1) << CNF2_PS1_SHIFT) |
+			  (bt->prop_seg - 1));
+	mcp251x_write_bits(spi, CNF3, CNF3_PHSEG2_MASK,
+			   (bt->phase_seg2 - 1));
+	dev_info(&spi->dev, "CNF: 0x%02x 0x%02x 0x%02x\n",
+		 mcp251x_read_reg(spi, CNF1),
+		 mcp251x_read_reg(spi, CNF2),
+		 mcp251x_read_reg(spi, CNF3));
+	/* Restore original state */
+	mcp251x_write_bits(spi, CANCTRL, CANCTRL_REQOP_MASK, state);
+
+	return 0;
+}
+
+static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,
+			 struct spi_device *spi)
+{
+	int ret;
+
+	ret = open_candev(net);
+	if (ret) {
+		dev_err(&spi->dev, "unable to set initial baudrate!\n");
+		return ret;
+	}
+
+	/* Enable RX0->RX1 buffer roll over and disable filters */
+	mcp251x_write_bits(spi, RXBCTRL(0),
+			   RXBCTRL_BUKT | RXBCTRL_RXM0 | RXBCTRL_RXM1,
+			   RXBCTRL_BUKT | RXBCTRL_RXM0 | RXBCTRL_RXM1);
+	mcp251x_write_bits(spi, RXBCTRL(1),
+			   RXBCTRL_RXM0 | RXBCTRL_RXM1,
+			   RXBCTRL_RXM0 | RXBCTRL_RXM1);
+	return 0;
+}
+
+static void mcp251x_hw_reset(struct spi_device *spi)
+{
+	struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+	int ret;
+
+	mutex_lock(&priv->spi_lock);
+
+	priv->spi_tx_buf[0] = INSTRUCTION_RESET;
+
+	ret = spi_write(spi, priv->spi_tx_buf, 1);
+
+	mutex_unlock(&priv->spi_lock);
+
+	if (ret < 0)
+		dev_err(&spi->dev, "reset failed: ret = %d\n", ret);
+	/* Wait for reset to finish */
+	mdelay(10);
+}
+
+static int mcp251x_hw_probe(struct spi_device *spi)
+{
+	int st1, st2;
+
+	mcp251x_hw_reset(spi);
+
+	/*
+	 * Please note that these are "magic values" based on after
+	 * reset defaults taken from data sheet which allows us to see
+	 * if we really have a chip on the bus (we avoid common all
+	 * zeroes or all ones situations)
+	 */
+	st1 = mcp251x_read_reg(spi, CANSTAT) & 0xEE;
+	st2 = mcp251x_read_reg(spi, CANCTRL) & 0x17;
+
+	dev_dbg(&spi->dev, "CANSTAT 0x%02x CANCTRL 0x%02x\n", st1, st2);
+
+	/* Check for power up default values */
+	return (st1 == 0x80 && st2 == 0x07) ? 1 : 0;
+}
+
+static irqreturn_t mcp251x_can_isr(int irq, void *dev_id)
+{
+	struct net_device *net = (struct net_device *)dev_id;
+	struct mcp251x_priv *priv = netdev_priv(net);
+
+	/* Schedule bottom half */
+	if (!work_pending(&priv->irq_work))
+		queue_work(priv->wq, &priv->irq_work);
+
+	return IRQ_HANDLED;
+}
+
+static int mcp251x_open(struct net_device *net)
+{
+	struct mcp251x_priv *priv = netdev_priv(net);
+	struct spi_device *spi = priv->spi;
+	struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+	int ret;
+
+	if (pdata->transceiver_enable)
+		pdata->transceiver_enable(1);
+
+	priv->force_quit = 0;
+	priv->tx_skb = NULL;
+	priv->tx_len = 0;
+
+	ret = request_irq(spi->irq, mcp251x_can_isr,
+			  IRQF_TRIGGER_FALLING, DEVICE_NAME, net);
+	if (ret < 0) {
+		dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
+		return ret;
+	}
+
+	mcp251x_hw_wakeup(spi);
+	mcp251x_hw_reset(spi);
+	ret = mcp251x_setup(net, priv, spi);
+	if (ret < 0) {
+		disable_irq(spi->irq);
+		return ret;
+	}
+	mcp251x_set_normal_mode(spi);
+	netif_wake_queue(net);
+
+	return 0;
+}
+
+static int mcp251x_stop(struct net_device *net)
+{
+	struct mcp251x_priv *priv = netdev_priv(net);
+	struct spi_device *spi = priv->spi;
+	struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+
+	/* Disable and clear pending interrupts */
+	mcp251x_write_reg(spi, CANINTE, 0x00);
+	mcp251x_write_reg(spi, CANINTF, 0x00);
+
+	priv->force_quit = 1;
+	disable_irq(spi->irq);
+	flush_workqueue(priv->wq);
+
+	mcp251x_write_reg(spi, TXBCTRL(0), 0);
+	if (priv->tx_skb || priv->tx_len)
+		mcp251x_clean(net);
+
+	mcp251x_hw_sleep(spi);
+
+	free_irq(spi->irq, net);
+
+	if (pdata->transceiver_enable)
+		pdata->transceiver_enable(0);
+
+	priv->can.state = CAN_STATE_STOPPED;
+	close_candev(net);
+
+	return 0;
+}
+
+static void mcp251x_tx_work_handler(struct work_struct *ws)
+{
+	struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv,
+						 tx_work);
+	struct spi_device *spi = priv->spi;
+	struct net_device *net = priv->net;
+	struct can_frame *frame;
+
+	if (priv->tx_skb) {
+		frame = (struct can_frame *)priv->tx_skb->data;
+
+		if (priv->can.state == CAN_STATE_BUS_OFF) {
+			mcp251x_clean(net);
+			netif_wake_queue(net);
+			return;
+		}
+		if (frame->can_dlc > CAN_FRAME_MAX_DATA_LEN)
+			frame->can_dlc = CAN_FRAME_MAX_DATA_LEN;
+		mcp251x_hw_tx(spi, frame, 0);
+		priv->tx_len = 1 + frame->can_dlc;
+		can_put_echo_skb(priv->tx_skb, net, 0);
+		priv->tx_skb = NULL;
+	}
+}
+
+static void mcp251x_irq_work_handler(struct work_struct *ws)
+{
+	struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv,
+						 irq_work);
+	struct spi_device *spi = priv->spi;
+	struct net_device *net = priv->net;
+	u8 txbnctrl;
+	u8 intf;
+	enum can_state new_state;
+
+	if (priv->after_suspend) {
+		mdelay(10);
+		mcp251x_hw_reset(spi);
+		mcp251x_setup(net, priv, spi);
+		if (priv->after_suspend & AFTER_SUSPEND_RESTART)
+			mcp251x_set_normal_mode(spi);
+		else if (priv->after_suspend & AFTER_SUSPEND_UP) {
+			netif_device_attach(net);
+			/* Clean since we lost tx buffer */
+			if (priv->tx_skb || priv->tx_len) {
+				mcp251x_clean(net);
+				netif_wake_queue(net);
+			}
+			mcp251x_set_normal_mode(spi);
+		} else
+			mcp251x_hw_sleep(spi);
+		priv->after_suspend = 0;
+	}
+
+	if (priv->can.restart_ms == 0 && priv->can.state == CAN_STATE_BUS_OFF) {
+		while (!priv->force_quit && !freezing(current) &&
+		       (intf = mcp251x_read_reg(spi, CANINTF)))
+			mcp251x_write_bits(spi, CANINTF, intf, 0x00);
+		return;
+	}
+
+	while (!priv->force_quit && !freezing(current)) {
+		u8 eflag = mcp251x_read_reg(spi, EFLG);
+		int can_id = 0, data1 = 0;
+
+		mcp251x_write_reg(spi, EFLG, 0x00);
+
+		if (priv->restart_tx) {
+			priv->restart_tx = 0;
+			mcp251x_write_reg(spi, TXBCTRL(0), 0);
+			if (priv->tx_skb || priv->tx_len)
+				mcp251x_clean(net);
+			netif_wake_queue(net);
+			can_id |= CAN_ERR_RESTARTED;
+		}
+
+		if (priv->wake) {
+			/* Wait whilst the device wakes up */
+			mdelay(10);
+			priv->wake = 0;
+		}
+
+		intf = mcp251x_read_reg(spi, CANINTF);
+		mcp251x_write_bits(spi, CANINTF, intf, 0x00);
+
+		/* Update can state */
+		if (eflag & EFLG_TXBO) {
+			new_state = CAN_STATE_BUS_OFF;
+			can_id |= CAN_ERR_BUSOFF;
+		} else if (eflag & EFLG_TXEP) {
+			new_state = CAN_STATE_ERROR_PASSIVE;
+			can_id |= CAN_ERR_CRTL;
+			data1 |= CAN_ERR_CRTL_TX_PASSIVE;
+		} else if (eflag & EFLG_RXEP) {
+			new_state = CAN_STATE_ERROR_PASSIVE;
+			can_id |= CAN_ERR_CRTL;
+			data1 |= CAN_ERR_CRTL_RX_PASSIVE;
+		} else if (eflag & EFLG_TXWAR) {
+			new_state = CAN_STATE_ERROR_WARNING;
+			can_id |= CAN_ERR_CRTL;
+			data1 |= CAN_ERR_CRTL_TX_WARNING;
+		} else if (eflag & EFLG_RXWAR) {
+			new_state = CAN_STATE_ERROR_WARNING;
+			can_id |= CAN_ERR_CRTL;
+			data1 |= CAN_ERR_CRTL_RX_WARNING;
+		} else
+			new_state = CAN_STATE_ERROR_ACTIVE;
+
+		/* Update can state statistics */
+		switch (priv->can.state) {
+		case CAN_STATE_ERROR_ACTIVE:
+			if (new_state >= CAN_STATE_ERROR_WARNING &&
+			    new_state <= CAN_STATE_BUS_OFF)
+				priv->can.can_stats.error_warning++;
+		case CAN_STATE_ERROR_WARNING:	/* fallthrough */
+			if (new_state >= CAN_STATE_ERROR_PASSIVE &&
+			    new_state <= CAN_STATE_BUS_OFF)
+				priv->can.can_stats.error_passive++;
+			break;
+		default:
+			break;
+		}
+		priv->can.state = new_state;
+
+		if ((intf & CANINTF_ERRIF) || (can_id & CAN_ERR_RESTARTED)) {
+			struct sk_buff *skb;
+			struct can_frame *frame;
+
+			/* Create error frame */
+			skb = alloc_can_err_skb(net, &frame);
+			if (skb) {
+				/* Set error frame flags based on bus state */
+				frame->can_id = can_id;
+				frame->data[1] = data1;
+
+				/* Update net stats for overflows */
+				if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {
+					if (eflag & EFLG_RX0OVR)
+						net->stats.rx_over_errors++;
+					if (eflag & EFLG_RX1OVR)
+						net->stats.rx_over_errors++;
+					frame->can_id |= CAN_ERR_CRTL;
+					frame->data[1] |=
+						CAN_ERR_CRTL_RX_OVERFLOW;
+				}
+
+				netif_rx(skb);
+			} else
+				dev_info(&spi->dev,
+					 "cannot allocate error skb\n");
+		}
+
+		if (priv->can.state == CAN_STATE_BUS_OFF) {
+			if (priv->can.restart_ms == 0) {
+				can_bus_off(net);
+				mcp251x_hw_sleep(spi);
+				return;
+			}
+		}
+
+		if (intf == 0)
+			break;
+
+		if (intf & CANINTF_WAKIF)
+			complete(&priv->awake);
+
+		if (intf & CANINTF_MERRF) {
+			/* If there are pending Tx buffers, restart queue */
+			txbnctrl = mcp251x_read_reg(spi, TXBCTRL(0));
+			if (!(txbnctrl & TXBCTRL_TXREQ)) {
+				if (priv->tx_skb || priv->tx_len)
+					mcp251x_clean(net);
+				netif_wake_queue(net);
+			}
+		}
+
+		if (intf & (CANINTF_TX2IF | CANINTF_TX1IF | CANINTF_TX0IF)) {
+			net->stats.tx_packets++;
+			net->stats.tx_bytes += priv->tx_len - 1;
+			if (priv->tx_len) {
+				can_get_echo_skb(net, 0);
+				priv->tx_len = 0;
+			}
+			netif_wake_queue(net);
+		}
+
+		if (intf & CANINTF_RX0IF)
+			mcp251x_hw_rx(spi, 0);
+
+		if (intf & CANINTF_RX1IF)
+			mcp251x_hw_rx(spi, 1);
+	}
+}
+
+static const struct net_device_ops mcp251x_netdev_ops = {
+	.ndo_open	= mcp251x_open,
+	.ndo_stop	= mcp251x_stop,
+	.ndo_start_xmit	= mcp251x_hard_start_xmit,
+};
+
+static struct net_device
+*alloc_mcp251x_netdev(int sizeof_priv,
+		      struct mcp251x_platform_data *pdata)
+{
+	struct net_device *net;
+	struct mcp251x_priv *priv;
+
+	net = alloc_candev(sizeof_priv, TX_ECHO_SKB_MAX);
+	if (!net)
+		return NULL;
+
+	priv = netdev_priv(net);
+
+	net->netdev_ops		= &mcp251x_netdev_ops;
+	net->flags		|= IFF_ECHO;
+
+	priv->can.bittiming_const = &mcp251x_bittiming_const;
+	priv->can.do_set_mode	  = mcp251x_do_set_mode;
+	priv->can.clock.freq      = pdata->oscillator_frequency / 2;
+	priv->can.do_set_bittiming	= mcp251x_do_set_bittiming;
+
+	priv->net = net;
+
+	return net;
+}
+
+static int __devinit mcp251x_can_probe(struct spi_device *spi)
+{
+	struct net_device *net;
+	struct mcp251x_priv *priv;
+	struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+	int ret = -ENODEV;
+
+	if (!pdata)
+		/* Platform data is required for osc freq */
+		goto error_out;
+
+	/* Allocate can/net device */
+	net = alloc_mcp251x_netdev(sizeof(struct mcp251x_priv), pdata);
+	if (!net) {
+		ret = -ENOMEM;
+		goto error_alloc;
+	}
+
+	priv = netdev_priv(net);
+	dev_set_drvdata(&spi->dev, priv);
+
+	priv->spi = spi;
+	mutex_init(&priv->spi_lock);
+
+	/* If requested, allocate DMA buffers */
+	if (mcp251x_enable_dma) {
+		spi->dev.coherent_dma_mask = ~0;
+
+		/*
+		 * Minimum coherent DMA allocation is PAGE_SIZE, so allocate
+		 * that much and share it between Tx and Rx DMA buffers.
+		 */
+		priv->spi_tx_buf = dma_alloc_coherent(&spi->dev,
+						      PAGE_SIZE,
+						      &priv->spi_tx_dma,
+						      GFP_DMA);
+
+		if (priv->spi_tx_buf) {
+			priv->spi_rx_buf = (u8 *)(priv->spi_tx_buf +
+						  (PAGE_SIZE / 2));
+			priv->spi_rx_dma = (dma_addr_t)(priv->spi_tx_dma +
+							(PAGE_SIZE / 2));
+		} else
+			/* Fall back to non-DMA */
+			mcp251x_enable_dma = 0;
+	}
+
+	/* Allocate non-DMA buffers */
+	if (!mcp251x_enable_dma) {
+		priv->spi_tx_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);
+		if (!priv->spi_tx_buf) {
+			ret = -ENOMEM;
+			goto error_tx_buf;
+		}
+		priv->spi_rx_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);
+		if (!priv->spi_tx_buf) {
+			ret = -ENOMEM;
+			goto error_rx_buf;
+		}
+	}
+
+	if (pdata->power_enable)
+		pdata->power_enable(1);
+
+	/* Call out to platform specific setup */
+	if (pdata->board_specific_setup)
+		pdata->board_specific_setup(spi);
+
+	SET_NETDEV_DEV(net, &spi->dev);
+
+	priv->wq = create_freezeable_workqueue("mcp251x_wq");
+
+	INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);
+	INIT_WORK(&priv->irq_work, mcp251x_irq_work_handler);
+
+	init_completion(&priv->awake);
+
+	/* Configure the SPI bus */
+	spi->mode = SPI_MODE_0;
+	spi->bits_per_word = 8;
+	spi_setup(spi);
+
+	if (!mcp251x_hw_probe(spi)) {
+		dev_info(&spi->dev, "Probe failed\n");
+		goto error_probe;
+	}
+	mcp251x_hw_sleep(spi);
+
+	if (pdata->transceiver_enable)
+		pdata->transceiver_enable(0);
+
+	ret = register_candev(net);
+	if (ret >= 0) {
+		dev_info(&spi->dev, "probed\n");
+		return ret;
+	}
+error_probe:
+	if (!mcp251x_enable_dma)
+		kfree(priv->spi_rx_buf);
+error_rx_buf:
+	if (!mcp251x_enable_dma)
+		kfree(priv->spi_tx_buf);
+error_tx_buf:
+	free_candev(net);
+	if (mcp251x_enable_dma)
+		dma_free_coherent(&spi->dev, PAGE_SIZE,
+				  priv->spi_tx_buf, priv->spi_tx_dma);
+error_alloc:
+	dev_err(&spi->dev, "probe failed\n");
+error_out:
+	return ret;
+}
+
+static int __devexit mcp251x_can_remove(struct spi_device *spi)
+{
+	struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+	struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+	struct net_device *net = priv->net;
+
+	unregister_candev(net);
+	free_candev(net);
+
+	priv->force_quit = 1;
+	flush_workqueue(priv->wq);
+	destroy_workqueue(priv->wq);
+
+	if (mcp251x_enable_dma)
+		dma_free_coherent(&spi->dev, PAGE_SIZE,
+				  priv->spi_tx_buf, priv->spi_tx_dma);
+	else {
+		kfree(priv->spi_tx_buf);
+		kfree(priv->spi_rx_buf);
+	}
+
+	if (pdata->power_enable)
+		pdata->power_enable(0);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int mcp251x_can_suspend(struct spi_device *spi, pm_message_t state)
+{
+	struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+	struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+	struct net_device *net = priv->net;
+
+	if (netif_running(net)) {
+		netif_device_detach(net);
+
+		mcp251x_hw_sleep(spi);
+		if (pdata->transceiver_enable)
+			pdata->transceiver_enable(0);
+		priv->after_suspend = AFTER_SUSPEND_UP;
+	} else
+		priv->after_suspend = AFTER_SUSPEND_DOWN;
+
+	if (pdata->power_enable) {
+		pdata->power_enable(0);
+		priv->after_suspend |= AFTER_SUSPEND_POWER;
+	}
+
+	return 0;
+}
+
+static int mcp251x_can_resume(struct spi_device *spi)
+{
+	struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+	struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+
+	if (priv->after_suspend & AFTER_SUSPEND_POWER) {
+		pdata->power_enable(1);
+		queue_work(priv->wq, &priv->irq_work);
+	} else {
+		if (priv->after_suspend & AFTER_SUSPEND_UP) {
+			if (pdata->transceiver_enable)
+				pdata->transceiver_enable(1);
+			queue_work(priv->wq, &priv->irq_work);
+		} else
+			priv->after_suspend = 0;
+	}
+	return 0;
+}
+#else
+#define mcp251x_can_suspend NULL
+#define mcp251x_can_resume NULL
+#endif
+
+static struct spi_driver mcp251x_can_driver = {
+	.driver = {
+		.name		= DEVICE_NAME,
+		.bus		= &spi_bus_type,
+		.owner		= THIS_MODULE,
+	},
+
+	.probe		= mcp251x_can_probe,
+	.remove		= __devexit_p(mcp251x_can_remove),
+	.suspend	= mcp251x_can_suspend,
+	.resume		= mcp251x_can_resume,
+};
+
+static int __init mcp251x_can_init(void)
+{
+	return spi_register_driver(&mcp251x_can_driver);
+}
+
+static void __exit mcp251x_can_exit(void)
+{
+	spi_unregister_driver(&mcp251x_can_driver);
+}
+
+module_init(mcp251x_can_init);
+module_exit(mcp251x_can_exit);
+
+MODULE_AUTHOR("Chris Elston <celston-Bm0nJX+W7e9BDgjK7y7TUQ@public.gmane.org>, "
+	      "Christian Pellegrin <chripell-LERDrqjqfvZg9hUCZPvPmw@public.gmane.org>");
+MODULE_DESCRIPTION("Microchip 251x CAN driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/can/platform/mcp251x.h b/include/linux/can/platform/mcp251x.h
new file mode 100644
index 0000000..d217ffa
--- /dev/null
+++ b/include/linux/can/platform/mcp251x.h
@@ -0,0 +1,34 @@
+#ifndef __CAN_PLATFORM_MCP251X_H__
+#define __CAN_PLATFORM_MCP251X_H__
+
+/*
+ *
+ * CAN bus driver for Microchip 251x CAN Controller with SPI Interface
+ *
+ */
+
+/**
+ * struct mcp251x_platform_data - MCP251X SPI CAN controller platform data
+ * @oscillator_frequency:       - oscillator frequency in Hz
+ * @model:                      - actual type of chip
+ * @board_specific_setup:       - called before probing the chip (power,reset)
+ * @transceiver_enable:         - called to power on/off the transceiver
+ * @power_enable:               - called to power on/off the mcp *and* the
+ *                                transceiver
+ *
+ * Please note that you should define power_enable or transceiver_enable or
+ * none of them. Defining both of them is no use.
+ *
+ */
+
+struct mcp251x_platform_data {
+	unsigned long oscillator_frequency;
+	int model;
+#define CAN_MCP251X_MCP2510 0
+#define CAN_MCP251X_MCP2515 1
+	int (*board_specific_setup)(struct spi_device *spi);
+	int (*transceiver_enable)(int enable);
+	int (*power_enable) (int enable);
+};
+
+#endif /* __CAN_PLATFORM_MCP251X_H__ */
-- 
1.5.6.5

^ permalink raw reply related

* Re: [PATCH 2/3] net: TCP thin linear timeouts
From: Andreas Petlund @ 2009-10-29 13:50 UTC (permalink / raw)
  To: William Allen Simpson
  Cc: netdev, linux-kernel, shemminger, ilpo.jarvinen, davem
In-Reply-To: <4AE7B887.6090806@gmail.com>


Den 28. okt. 2009 kl. 04.20 skrev William Allen Simpson:

> Sorry to be too picky about the naming, but "rm_expb" really doesn't
> mean what is actually done.  Perhaps TCP_THIN_LINEAR_BACKOFF and
> sysctl_tcp_thin_linear_backoff?
>

I agree that the name should be changed. As it represents linear  
timeouts and does not back off exponentially, I suggest  
TCP_THIN_LINEAR_TIMEOUTS and sysctl_tcp_thin_linear_timeouts.

> Also, as debated on some other recent patches, shouldn't the global
> sysctl specify the default, and the per socket option specify the
> forced override?

The rationale behind the suggested model is to allow the modifications  
to be forced active in cases where the application that generates the  
thin stream is proprietary, legacy, or that the code for other reasons  
can not be modified (as is the case, for instance, for many game  
clients).

^ permalink raw reply

* Re: [PATCH 1/3] net: TCP thin-stream detection
From: Andreas Petlund @ 2009-10-29 13:51 UTC (permalink / raw)
  To: William Allen Simpson
  Cc: netdev, linux-kernel, shemminger, ilpo.jarvinen, davem
In-Reply-To: <4AE7B5D6.8070001@gmail.com>


Den 28. okt. 2009 kl. 04.09 skrev William Allen Simpson:

> Andreas Petlund wrote:
>> +/* Determines whether this is a thin stream (which may suffer from
>> + * increased latency). Used to trigger latency-reducing mechanisms.
>> + */
>> +static inline unsigned int tcp_stream_is_thin(const struct  
>> tcp_sock *tp)
>> +{
>> +	return tp->packets_out < 4;
>> +}
>> +
> This bothers me a bit.  Having just looked at your Linux presentation,
> and not (yet) read your papers, it seems much of your justification  
> was
> with 1 packet per RTT.  Here, you seem to be concentrating on 4,  
> probably
> because many implementations quickly ramp up to 4.
>

The limit of 4 packets in flight is based on the fact that less than 4  
packets in flight makes fast retransmissions impossible, thus limiting  
the retransmit options to timeout-retransmissions. The criterion is  
therefore as conservative as possible while still serving its purpose.  
If further losses occur, the exponential backoff will increase latency  
further. The concept of using this limit is also discussed in the  
Internet draft for Early Retransmit by Allman et al.:
http://www.icir.org/mallman/papers/draft-ietf-tcpm-early-rexmt-01.txt

> But there's a fair amount of experience showing that ramping to 4 is
> problematic on congested paths, especially wireless networks.  Fast
> retransmit in that case would be disastrous.

First, the modifications implemented in the patch is explicitly  
enabled only for applications where the developer knows that streams  
will be thin, thus only a small subset of the streams will apply the  
modifications. Second, experiments we have performed to try to map the  
effect on a congested bottleneck both with and without the  
modifications show that no measurable effect is recorded.

Graphs presenting results from experiments performed to analyse  
latency and fairness issues can be found here:
http://folk.uio.no/apetlund/lktmp/

> Once upon a time, I worked on a fair number of interactive games a  
> decade
> or so ago.  And agree that this can be a problem, although I've never
> been a fan of turning off the Nagle algorithm.  My solution has always
> been a heartbeat, rather than trying to shoehorn this into TCP.
>

The beginning of this patch was an analysis of game traffic from the  
Norwegian game company Funcom. They use TCP for all their MMOGs as  
does, for example, Blizzard for WoW. Our analysis showed that many  
players experienced extreme latencies, and the source of this was  
tracked to the effects that we discuss here. As long as a wide range  
of time-dependent applications choose to use TCP, and we can improve  
conditions for their needs without jeopardising other functionality,  
we think that this will add value to the TCP stack.

> Also, I've not seen any discussion on the end-to-end interest list.

It will be enlightening to have a discussion on end-to-end about this  
topic.

^ permalink raw reply

* Re: [PATCH 2/3] net: TCP thin linear timeouts
From: Andreas Petlund @ 2009-10-29 13:51 UTC (permalink / raw)
  To: Ilpo Järvinen
  Cc: Arnd Hannemann, Eric Dumazet, Netdev, LKML, shemminger,
	David Miller
In-Reply-To: <alpine.DEB.2.00.0910281618330.19761@wel-95.cs.helsinki.fi>


Den 28. okt. 2009 kl. 15.31 skrev Ilpo Järvinen:

> On Wed, 28 Oct 2009, Arnd Hannemann wrote:
>
>> Eric Dumazet schrieb:
>>> Andreas Petlund a écrit :
>>>> This patch will make TCP use only linear timeouts if the stream is
>>>> thin. This will help to avoid the very high latencies that thin
>>>> stream suffer because of exponential backoff. This mechanism is  
>>>> only
>>>> active if enabled by iocontrol or syscontrol and the stream is
>>>> identified as thin.
>
> ...I don't see how high latency is in any connection to stream being
> "thin" or not btw. If all ACKs are lost it usually requires silence  
> for
> the full RTT, which affects a stream regardless of its size. ...If  
> not all
> ACKs are lost, then the dupACK approach in the other patch should  
> cover
> it already.
>

The increased latency that we observed does not arise from lost ACKs,  
but from the lack of enough packets in flight to be able to trigger  
fast retransmits. This effectively limits the retransmission options  
to retransmission by timeout, which again will increase exponentially  
with each subsequent retransmissions. We have also found that the  
"thin" stream patterns are very often generated by applications where  
human interaction is the purpose. Such applications will give a  
degraded experience to the user if such high latencies happen often.  
In-depth discussion of these effects can be found in the papers I  
linked to.
If the application produces less than one packet per RTT, the dupACK- 
modification will be ineffective and any improved latency will be from  
linear timeouts. If the number of packets in flight are 2-4, no fast  
retransmissions may be triggered based on the 3 dupACK scheme, but a  
retransmission upon the first indication of loss will improve  
retransmission latency.

>> However, addressing the proposal:
>> I wonder how one can seriously suggest to just skip congestion  
>> response
>> during timeout-based loss recovery? I believe that in a heavily
>> congested scenarios, this would lead to a goodput disaster... Not to
>> mention that in a heavily congested scenario, suddenly every flow  
>> will
>> become "thin", so this will even amplify the problems. Or did I miss
>> something?
>
> Good point. I suppose such an under-provisioned network can  
> certainly be
> there. I have heard that at least some people who remove exponential  
> back
> off apply it later on nth retransmission as very often there really  
> isn't
> such a super heavy congestion scenario but something completely  
> unrelated
> to congestion which causes the RTO.
>
> -- 
> i.


The removal of exponential backoff on a general basis has been  
investigated and discussed already, for instance here:
http://ccr.sigcomm.org/online/?q=node/416
Such steps are, however considered drastic, and I agree that caution  
must be made to thoroughly investigate the effects of such changes.
The changes introduced by the proposed patches, however, are not  
default behaviour, but an option for applications that suffer from the  
thin-stream TCP increased retransmission latencies. They will, as  
such, not affect all streams. In addition, the changes will only be  
active for streams which are perpetually thin or in the early phase of  
expanding their cwnd. Also, experiments performed on congested  
bottlenecks with tail-drop queues show very little (if any at all)  
effect on goodput for the modified scenario compared to a scenario  
with unmodified TCP streams.

Graphs both for latency-results and fairness tests can be found here:
http://folk.uio.no/apetlund/lktmp/

-AP

^ permalink raw reply

* Re: pull request: wireless-next-2.6 2009-10-28
From: Pekka Enberg @ 2009-10-29 13:52 UTC (permalink / raw)
  To: Bartlomiej Zolnierkiewicz
  Cc: David Miller, linux-wireless, netdev, linux-kernel, linville
In-Reply-To: <200910291435.54203.bzolnier@gmail.com>

Hi Bart,

On Thu, Oct 29, 2009 at 3:35 PM, Bartlomiej Zolnierkiewicz
<bzolnier@gmail.com> wrote:
>> I'm saying that you should work with John to have him send a revert or
>> whatever to me.
>
> This is your responsibility to deal with your downstream maintainers,
> not mine and since you have accepted John's patch I'm asking you to
> revert rt2800pci patch from your tree.

So why don't you just send a patch to fix it up? I see you're doing
lots of cleanups to the staging drivers, why not direct some of that
energy to the drivers/net/wireless ones?

                         Pekka

^ permalink raw reply

* Re: pull request: wireless-next-2.6 2009-10-28
From: David Miller @ 2009-10-29 13:53 UTC (permalink / raw)
  To: bzolnier; +Cc: linux-wireless, netdev, linux-kernel, linville
In-Reply-To: <200910291435.54203.bzolnier@gmail.com>

From: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Date: Thu, 29 Oct 2009 14:35:54 +0100

> This is your responsibility to deal with your downstream maintainers,
> not mine and since you have accepted John's patch I'm asking you to
> revert rt2800pci patch from your tree.

That's not how it works Bart.  You should not be asking 'me' to do
anything on wireless bits, there is absolutely no reason to bypass
John in the workflow.

^ permalink raw reply

* Re: wanPMC-CxT1E1
From: Krzysztof Halasa @ 2009-10-29 13:54 UTC (permalink / raw)
  To: Bob Beers; +Cc: Greg KH, netdev
In-Reply-To: <4f6ba3b0910271048n10ff37fek9af191b133892e1e@mail.gmail.com>

Bob Beers <bob.beers@gmail.com> writes:

> ok, so where do I start, I have a system ready to start
>  git cloning, and creating patches. I googled for a while
>  but didn't find a nice recipe for participating in the -staging
>  process.

I can make it compile, just send me the tarball.
Not much more at the moment though.
-- 
Krzysztof Halasa

^ permalink raw reply

* [PATCH against V2]NET/KS8695: add support NAPI for Rx
From: Figo.zhang @ 2009-10-29 14:04 UTC (permalink / raw)
  To: Daniel Silverstone, David S. Miller; +Cc: netdev, Ben Dooks


Add support NAPI Rx API for KS8695NET driver.

v2, change the Rx function to NAPI.

in <KS8695X Integrated Multi-port Gateway Solution Register Description
 v1.0>:
Interrupt Enable Register (offset 0xE204)
Bit29 : WAN MAC Receive Interrupt Enable
Bit16 : LAN MAC Receive Interrupt Enable

Interrupt Status Register (Offset 0xF208)
Bit29: WAN MAC Receive Status
Bit16: LAN MAC Receive Status

see arch/arm/mach-ks8695/devices.c:
ks8695_wan_resources[] and ks8695_lan_resources[]
have IORESOURCE_IRQ , it have define the RX irq,
for wan, irq = 29; for lan ,irq = 16.
so we can do this read the interrupt status:

unsigned long mask_bit = 1 << ksp->rx_irq;
status = readl(KS8695_IRQ_VA + KS8695_INTST);

In this version is against v2, some changes that adviced by Daniel
Silverstone and Ben Dooks.

Add k8695_get_rx_enable_bit() for get Rx interrupt enable/status
bit.

Signed-off-by: Figo.zhang <figo1802@gmail.com>
--- 
drivers/net/arm/ks8695net.c |   69 ++++++++++++++++++++++++++++++++++--------
 1 files changed, 56 insertions(+), 13 deletions(-)

diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c
index ed0b0f3..b4f5994 100644
--- a/drivers/net/arm/ks8695net.c
+++ b/drivers/net/arm/ks8695net.c
@@ -41,8 +41,7 @@
 #include "ks8695net.h"
 
 #define MODULENAME	"ks8695_ether"
-#define MODULEVERSION	"1.01"
-
+#define MODULEVERSION	"1.02"
 
 /*
  * Transmit and device reset timeout, default 5 seconds.
@@ -98,6 +97,9 @@ struct ks8695_skbuff {
 #define MAX_RX_DESC 16
 #define MAX_RX_DESC_MASK 0xf
 
+/*napi_weight have better more than rx DMA buffers*/
+#define NAPI_WEIGHT   64
+
 #define MAX_RXBUF_SIZE 0x700
 
 #define TX_RING_DMA_SIZE (sizeof(struct tx_ring_desc) * MAX_TX_DESC)
@@ -123,6 +125,7 @@ enum ks8695_dtype {
  *	@dev: The platform device object for this interface
  *	@dtype: The type of this device
  *	@io_regs: The ioremapped registers for this interface
+ *      @napi : Add support NAPI for Rx
  *	@rx_irq_name: The textual name of the RX IRQ from the platform data
  *	@tx_irq_name: The textual name of the TX IRQ from the platform data
  *	@link_irq_name: The textual name of the link IRQ from the
@@ -146,6 +149,7 @@ enum ks8695_dtype {
  *	@rx_ring_dma: The DMA mapped equivalent of rx_ring
  *	@rx_buffers: The sk_buff mappings for the RX ring
  *	@next_rx_desc_read: The next RX descriptor to read from on IRQ
+ *      @rx_lock: A lock to protect Rx irq function
  *	@msg_enable: The flags for which messages to emit
  */
 struct ks8695_priv {
@@ -398,11 +402,30 @@ ks8695_tx_irq(int irq, void *dev_id)
 }
 
 /**
+ *	ks8695_get_rx_enable_bit - Get rx interrupt enable/status bit
+ *	@ksp: Private data for the KS8695 Ethernet
+ *
+ *    For KS8695 document:
+ *    Interrupt Enable Register (offset 0xE204)
+ *        Bit29 : WAN MAC Receive Interrupt Enable
+ *        Bit16 : LAN MAC Receive Interrupt Enable
+ *    Interrupt Status Register (Offset 0xF208)
+ *        Bit29: WAN MAC Receive Status
+ *        Bit16: LAN MAC Receive Status
+ *    So, this Rx interrrupt enable/status bit number is equal
+ *    as Rx IRQ number.
+ */
+static inline u32 ks8695_get_rx_enable_bit(struct ks8695_priv *ksp)
+{
+	return ksp->rx_irq;
+}
+
+/**
  *	ks8695_rx_irq - Receive IRQ handler
  *	@irq: The IRQ which went off (ignored)
  *	@dev_id: The net_device for the interrupt
  *
- *	Use NAPI to receive packets.
+ *	Inform NAPI that packet reception needs to be scheduled
  */
 
 static irqreturn_t
@@ -412,7 +435,7 @@ ks8695_rx_irq(int irq, void *dev_id)
 	struct ks8695_priv *ksp = netdev_priv(ndev);
 	unsigned long status;
 
-	unsigned long mask_bit = 1 << ksp->rx_irq;
+	unsigned long mask_bit = 1 << ks8695_get_rx_enable_bit(ksp);
 
 	spin_lock(&ksp->rx_lock);
 
@@ -434,9 +457,15 @@ ks8695_rx_irq(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static int ks8695_rx(struct net_device *ndev, int budget)
+/**
+ *	ks8695_rx - Receive packets  called by NAPI poll method
+ *	@ksp: Private data for the KS8695 Ethernet
+ *	@budget: The max packets would be receive
+ */
+
+static int ks8695_rx(struct ks8695_priv *ksp, int budget)
 {
-	struct ks8695_priv *ksp = netdev_priv(ndev);
+	struct net_device *ndev = ksp->ndev;
 	struct sk_buff *skb;
 	int buff_n;
 	u32 flags;
@@ -526,20 +555,32 @@ rx_finished:
 
 			/* And refill the buffers */
 			ks8695_refill_rxbuffers(ksp);
+
+			/* Kick the RX DMA engine, in case it became
+			 *  suspended */
+			ks8695_writereg(ksp, KS8695_DRSC, 0);
 	}
 	return received;
 }
 
+
+/**
+ *	ks8695_poll - Receive packet by NAPI poll method
+ *	@ksp: Private data for the KS8695 Ethernet
+ *	@budget: The remaining number packets for network subsystem
+ *
+ *     Invoked by the network core when it requests for new
+ *     packets from the driver
+ */
 static int ks8695_poll(struct napi_struct *napi, int budget)
 {
 	struct ks8695_priv *ksp = container_of(napi, struct ks8695_priv, napi);
-	struct net_device *dev = ksp->ndev;
-	unsigned long mask_bit = 1 << ksp->rx_irq;
-	unsigned long isr = readl(KS8695_IRQ_VA + KS8695_INTEN);
+	unsigned long  work_done;
 
-	unsigned long  work_done ;
+	unsigned long isr = readl(KS8695_IRQ_VA + KS8695_INTEN);
+	unsigned long mask_bit = 1 << ks8695_get_rx_enable_bit(ksp);
 
-	work_done = ks8695_rx(dev, budget);
+	work_done = ks8695_rx(ksp, budget);
 
 	if (work_done < budget) {
 		unsigned long flags;
@@ -1302,6 +1343,7 @@ ks8695_stop(struct net_device *ndev)
 	struct ks8695_priv *ksp = netdev_priv(ndev);
 
 	netif_stop_queue(ndev);
+	napi_disable(&ksp->napi);
 	netif_carrier_off(ndev);
 
 	ks8695_shutdown(ksp);
@@ -1335,7 +1377,8 @@ ks8695_open(struct net_device *ndev)
 		ks8695_shutdown(ksp);
 		return ret;
 	}
-
+	
+	napi_enable(&ksp->napi);
 	netif_start_queue(ndev);
 
 	return 0;
@@ -1521,7 +1564,7 @@ ks8695_probe(struct platform_device *pdev)
 	SET_ETHTOOL_OPS(ndev, &ks8695_ethtool_ops);
 	ndev->watchdog_timeo	 = msecs_to_jiffies(watchdog);
 
-	netif_napi_add(ndev, &ksp->napi, ks8695_poll, 64);
+	netif_napi_add(ndev, &ksp->napi, ks8695_poll, NAPI_WEIGHT);
 
 	/* Retrieve the default MAC addr from the chip. */
 	/* The bootloader should have left it in there for us. */



^ permalink raw reply related

* Re: [RFC-PATCH] dhcp provisioning support in cxgb3i
From: Ben Hutchings @ 2009-10-29 14:06 UTC (permalink / raw)
  To: Rakesh Ranjan
  Cc: Mike Christie, davem, James Bottomley, Karen Xie,
	open-iscsi@googlegroups.com, LKML, linux-scsi@vger.kernel.org,
	netdev
In-Reply-To: <4AE995C4.4080909@chelsio.com>

On Thu, 2009-10-29 at 18:46 +0530, Rakesh Ranjan wrote:
> Hi Mike,
> 
> Herein attached patches for having dhcp provisioning support in
> cxgb3i. 
> I have added one new iscsi netlink message ISCSI_UEVENT_REQ_IPCONF. 
> Please have a look and share suggestions.
[...]

Why does cxgb3i need its very own DHCP client?  This seems like
something that's generically useful to firmware-based iSCSI adapters.

(It would be better still if this could be left to user-space, but
although a user-space program could send out requests on the net device
using the iSCSI device's MAC address, I don't see how it would get
replies.)

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: Fw: [Bug 14470] New: freez in TCP stack
From: Eric Dumazet @ 2009-10-29 14:08 UTC (permalink / raw)
  To: Ilpo Järvinen
  Cc: David Miller, Andrew Morton, Stephen Hemminger, Netdev, kolo,
	bugzilla-daemon
In-Reply-To: <alpine.DEB.2.00.0910291316340.19761@wel-95.cs.helsinki.fi>


> ...I don't understand how a stale reference would yield to a consistent 
> NULL ptr crash there rather than hard to track corruption for most of the 
> times and random crashes then here and there. Or perhaps we were just very 
> lucky to immediately get only those reports which point out to the right 
> track :-).
> 


When a skb is freed, and re-allocated, we clear most of its fields
in __alloc_skb()

memset(skb, 0, offsetof(struct sk_buff, tail));

Then if this skb is freed again, not queued anywhere, its skb->next stays NULL

So if we have a stale reference to a freed skb, we can :

- Get a NULL pointer, or a poisonned value (if SLUB_DEBUG)


Here is a debug patch to check we dont have stale pointers, maybe this will help ?sync


[PATCH] tcp: check stale pointers in tcp_unlink_write_queue()

In order to track some obscure bug, we check in tcp_unlink_write_queue() if
we dont have stale references to unlinked skb

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 include/net/tcp.h     |    4 ++++
 net/ipv4/tcp.c        |    2 +-
 net/ipv4/tcp_input.c  |    4 ++--
 net/ipv4/tcp_output.c |    8 ++++----
 4 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/include/net/tcp.h b/include/net/tcp.h
index 740d09b..09da342 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1357,6 +1357,10 @@ static inline void tcp_insert_write_queue_before(struct sk_buff *new,
 
 static inline void tcp_unlink_write_queue(struct sk_buff *skb, struct sock *sk)
 {
+	WARN_ON(skb == tcp_sk(sk)->retransmit_skb_hint);
+	WARN_ON(skb == tcp_sk(sk)->lost_skb_hint);
+	WARN_ON(skb == tcp_sk(sk)->scoreboard_skb_hint);
+	WARN_ON(skb == sk->sk_send_head);
 	__skb_unlink(skb, &sk->sk_write_queue);
 }
 
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index e0cfa63..328bdb1 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1102,11 +1102,11 @@ out:
 
 do_fault:
 	if (!skb->len) {
-		tcp_unlink_write_queue(skb, sk);
 		/* It is the one place in all of TCP, except connection
 		 * reset, where we can be unlinking the send_head.
 		 */
 		tcp_check_send_head(sk, skb);
+		tcp_unlink_write_queue(skb, sk);
 		sk_wmem_free_skb(sk, skb);
 	}
 
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index ba0eab6..fccc6e9 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -3251,13 +3251,13 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
 		if (!fully_acked)
 			break;
 
-		tcp_unlink_write_queue(skb, sk);
-		sk_wmem_free_skb(sk, skb);
 		tp->scoreboard_skb_hint = NULL;
 		if (skb == tp->retransmit_skb_hint)
 			tp->retransmit_skb_hint = NULL;
 		if (skb == tp->lost_skb_hint)
 			tp->lost_skb_hint = NULL;
+		tcp_unlink_write_queue(skb, sk);
+		sk_wmem_free_skb(sk, skb);
 	}
 
 	if (likely(between(tp->snd_up, prior_snd_una, tp->snd_una)))
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 616c686..196171d 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -1791,6 +1791,10 @@ static void tcp_collapse_retrans(struct sock *sk, struct sk_buff *skb)
 
 	tcp_highest_sack_combine(sk, next_skb, skb);
 
+	/* changed transmit queue under us so clear hints */
+	tcp_clear_retrans_hints_partial(tp);
+	if (next_skb == tp->retransmit_skb_hint)
+		tp->retransmit_skb_hint = skb;
 	tcp_unlink_write_queue(next_skb, sk);
 
 	skb_copy_from_linear_data(next_skb, skb_put(skb, next_skb_size),
@@ -1813,10 +1817,6 @@ static void tcp_collapse_retrans(struct sock *sk, struct sk_buff *skb)
 	 */
 	TCP_SKB_CB(skb)->sacked |= TCP_SKB_CB(next_skb)->sacked & TCPCB_EVER_RETRANS;
 
-	/* changed transmit queue under us so clear hints */
-	tcp_clear_retrans_hints_partial(tp);
-	if (next_skb == tp->retransmit_skb_hint)
-		tp->retransmit_skb_hint = skb;
 
 	tcp_adjust_pcount(sk, next_skb, tcp_skb_pcount(next_skb));
 

^ permalink raw reply related

* Re: pull request: wireless-next-2.6 2009-10-28
From: Bartlomiej Zolnierkiewicz @ 2009-10-29 14:13 UTC (permalink / raw)
  To: David Miller
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linville-2XuSBdqkA4R54TAoqtyWWQ
In-Reply-To: <20091029.065336.119302168.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>

On Thursday 29 October 2009 14:53:36 David Miller wrote:
> From: Bartlomiej Zolnierkiewicz <bzolnier-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Date: Thu, 29 Oct 2009 14:35:54 +0100
> 
> > This is your responsibility to deal with your downstream maintainers,
> > not mine and since you have accepted John's patch I'm asking you to
> > revert rt2800pci patch from your tree.
> 
> That's not how it works Bart.  You should not be asking 'me' to do
> anything on wireless bits, there is absolutely no reason to bypass
> John in the workflow.

John has chosen to ignore my concerns and you are sending me back to him?

I like ping-pong but as a sport.

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

^ permalink raw reply

* Re: pull request: wireless-next-2.6 2009-10-28
From: Bartlomiej Zolnierkiewicz @ 2009-10-29 14:14 UTC (permalink / raw)
  To: Pekka Enberg; +Cc: David Miller, linux-wireless, netdev, linux-kernel, linville
In-Reply-To: <84144f020910290652n2e75827dk698b238b6bd1cbed@mail.gmail.com>


Hi,

On Thursday 29 October 2009 14:52:50 Pekka Enberg wrote:
> Hi Bart,
> 
> On Thu, Oct 29, 2009 at 3:35 PM, Bartlomiej Zolnierkiewicz
> <bzolnier@gmail.com> wrote:
> >> I'm saying that you should work with John to have him send a revert or
> >> whatever to me.
> >
> > This is your responsibility to deal with your downstream maintainers,
> > not mine and since you have accepted John's patch I'm asking you to
> > revert rt2800pci patch from your tree.
> 
> So why don't you just send a patch to fix it up? I see you're doing

"git revert a9b3a9f"

done.

Dave, if you have problems with executing the command locally I'll be
happy to supply you with the patch.

> lots of cleanups to the staging drivers, why not direct some of that
> energy to the drivers/net/wireless ones?

When did we start to apply "fix it yourself" rule instead of "submitter
should fix it" one to the _new_ code..

rt2800 drivers have their maintainers and I would like to know what they
are doing besides complaining about users and staging tree..

-- 
Bartlomiej Zolnierkiewicz

^ permalink raw reply


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