* Re: [PATCH 2/2] net: netem: always adjust now/delay when not reordering
From: Ferry Huberts @ 2013-08-21 16:14 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Johannes Naab, netdev, hagen
In-Reply-To: <1377099575.4226.120.camel@edumazet-glaptop>
On 21/08/13 17:39, Eric Dumazet wrote:
> On Wed, 2013-08-21 at 17:17 +0200, Johannes Naab wrote:
>> On 08/20/2013 05:11 PM, Ferry Huberts wrote:
>>> From: Ferry Huberts <ferry.huberts@pelagic.nl>
>>>
>>> Not doing this (current behaviour) introduces reordering.
>>>
>>> The packet_len_2_sched_time call is the only thing that logically
>>> depends on q->rate, so move the now/delay adjustment out of the if.
>>>
>>> Signed-off-by: Ferry Huberts <ferry.huberts@pelagic.nl>
>>> ---
>>
>> Hi,
>>
>> The documentation for netem does explicitly mention the reordering with
>> jitter, and gives instructions on how to avoid it. (I have not tested if
>> it works as intended).
>
>
> Yes.
>
> The user specifically adds a random delay of 0 to 510 ms to packets,
> and expect netem to not reorder packets sent every 100ms.
>
> They see netem as a single medium between two endpoints with a guarantee
> of no reordering, and cumulative delays.
Well no. We expected no reordering because reordering is not enabled.
The documentation is very confusing if you compare it to the source
code, and even incorrect.
What the code does is (when reordering is disabled):
- reorders if the rate is NOT set
- does NOT reorder if the rate is set
That is quite different, the documentation doesn't even mention the rate
nor the reordering setting in this context.
I'm confused on how to proceed now, so CC-ing Hagen Paul Pfeifer
I'll also discuss this with Teco, who asked me to write up a patch.
>
> So if you send a burst of 100 packets, they might expect the last packet
> will be send after ~50 seconds.
>
> This clearly needs a new option to netem, because this is not the
> default behavior we want.
>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Ferry Huberts
^ permalink raw reply
* Potential use-after-free in e1000_clean_tx_irq
From: Andrey Konovalov @ 2013-08-21 16:10 UTC (permalink / raw)
To: e1000-devel
Cc: netdev, Alexander Potapenko, Evgeniy Stepanov, Dmitry Vyukov,
Kostya Serebryany
[-- Attachment #1.1: Type: text/plain, Size: 10296 bytes --]
Hi,
I'm working on a memory error detector AddressSanitizer for Linux kernel (
https://code.google.com/p/address-sanitizer/wiki/AddressSanitizerForKernel),
which can detect use-after-free and buffer-overflow errors.
Currently the tool is in very early stage and it can contain bugs.
I was running a system call fuzzer and got some reports:
[ 64.143848]
=========================================================================
[ 64.144763] ERROR: AddressSanitizer: heap-use-after-free on address
ffff88002a3dae60
[ 64.145945] Stack trace:
[ 64.146302] [<ffffffff810dd1f5>] asan_report_error+0x85/0x2c0
[ 64.147112] [<ffffffff810dc700>] asan_check_region+0x30/0x40
[ 64.147966] [<ffffffff810dd4b3>] __tsan_read4+0x13/0x20
[ 64.148808] [<ffffffffa00804d0>] e1000_clean+0x1d0/0x11b0 [e1000]
[ 64.149742] [<ffffffff817f8e1a>] net_rx_action+0x1aa/0x380
[ 64.150574] [<ffffffff810ee9d2>] __do_softirq+0x182/0x3a0
[ 64.151391] [<ffffffff8192629c>] call_softirq+0x1c/0x30
[ 64.152179] [<ffffffff8108040d>] do_softirq+0x5d/0xc0
[ 64.152926] [<ffffffff810ed3d7>] local_bh_enable+0x127/0x130
[ 64.153717] [<ffffffff8185d775>] ip_finish_output+0x365/0x640
[ 64.154653] [<ffffffff8185fc79>] ip_output+0xb9/0x100
[ 64.155423] [<ffffffff8185ed1c>] ip_local_out+0x4c/0x60
[ 64.156216] [<ffffffff818611b3>] ip_send_skb+0x23/0x70
[ 64.156951] [<ffffffff818a4bf4>] udp_send_skb+0x584/0x6e0
[ 64.157761] [<ffffffff818a681c>] udp_sendmsg+0x4dc/0xfd0
[ 64.158581] [<ffffffff818b93e8>] inet_sendmsg+0x108/0x160
[ 64.159401] [<ffffffff817d0f43>] sock_sendmsg+0x133/0x170
[ 64.160143] [<ffffffff817d1669>] SYSC_sendto+0x1e9/0x2d0
[ 64.160932] [<ffffffff817d2329>] SyS_sendto+0x49/0x70
[ 64.161710] [<ffffffff81826e55>] compat_sys_socketcall+0x305/0x530
[ 64.162634] [<ffffffff81926335>] sysenter_dispatch+0x7/0x1a
[ 64.163471] [<ffffffffffffffff>] 0xffffffffffffffff
[ 64.164213] Free stack trace:
[ 64.164660] [<ffffffff810dc831>] asan_slab_free+0x61/0xb0
[ 64.165466] [<ffffffff8127f955>] kmem_cache_free+0x55/0x2e0
[ 64.166261] [<ffffffff817db68b>] kfree_skbmem+0x5b/0xd0
[ 64.167046] [<ffffffff817e003c>] consume_skb+0x4c/0xd0
[ 64.167811] [<ffffffff817f3f90>] dev_kfree_skb_any+0x60/0x70
[ 64.168710] [<ffffffffa007c6ba>]
e1000_unmap_and_free_tx_resource.isra.45+0xda/0x130 [e1000]
[ 64.169954] [<ffffffffa00804e9>] e1000_clean+0x1e9/0x11b0 [e1000]
[ 64.170859] [<ffffffff817f8e1a>] net_rx_action+0x1aa/0x380
[ 64.171685] [<ffffffff810ee9d2>] __do_softirq+0x182/0x3a0
[ 64.172491] [<ffffffff8192629c>] call_softirq+0x1c/0x30
[ 64.173276] [<ffffffff8108040d>] do_softirq+0x5d/0xc0
[ 64.174041] [<ffffffff810ed3d7>] local_bh_enable+0x127/0x130
[ 64.174868] [<ffffffff8185d775>] ip_finish_output+0x365/0x640
[ 64.175734] [<ffffffff8185fc79>] ip_output+0xb9/0x100
[ 64.176518] [<ffffffff8185ed1c>] ip_local_out+0x4c/0x60
[ 64.177315] [<ffffffff818611b3>] ip_send_skb+0x23/0x70
[ 64.178087] [<ffffffff818a4bf4>] udp_send_skb+0x584/0x6e0
[ 64.178910] [<ffffffff818a681c>] udp_sendmsg+0x4dc/0xfd0
[ 64.179713] [<ffffffff818b93e8>] inet_sendmsg+0x108/0x160
[ 64.180524] [<ffffffff817d0f43>] sock_sendmsg+0x133/0x170
[ 64.181332] [<ffffffff817d1669>] SYSC_sendto+0x1e9/0x2d0
[ 64.182001] [<ffffffff817d2329>] SyS_sendto+0x49/0x70
[ 64.182771] [<ffffffff817d238b>] SyS_send+0x3b/0x50
[ 64.183508] Shadow bytes around the buggy address:
[ 64.184258] ffff88003ba7b570: fa fa fa fa fa fa fa fa fa fa fa fa fa
fa fa fa
[ 64.185109] ffff88003ba7b580: fa fa fa fa fa fa fa fa fd fd fd fd fd
fd fd fd
[ 64.186184] ffff88003ba7b590: fd fd fd fd fd fd fd fd fd fd fd fd fd
fd fd fd
[ 64.187257] ffff88003ba7b5a0: fd fd fd fd fa fa fa fa fa fa fa fa fa
fa fa fa
[ 64.188442] ffff88003ba7b5b0: fa fa fa fa fa fa fa fa fa fa fa fa fa
fa fa fa
[ 64.189520] =>ffff88003ba7b5c0: fd fd fd fd fd fd fd fd fd fd fd
fd[fd]fd fd fd
[ 64.190600] ffff88003ba7b5d0: fd fd fd fd fd fd fd fd fd fd fd fd fa
fa fa fa
[ 64.191676] ffff88003ba7b5e0: fa fa fa fa fa fa fa fa fa fa fa fa fa
fa fa fa
[ 64.192730] ffff88003ba7b5f0: fa fa fa fa fa fa fa fa fa fa fa fa fa
fa fa fa
[ 64.193822] ffff88003ba7b600: fa fa fa fa fa fa fa fa fa fa fa fa fa
fa fa fa
[ 64.194903] ffff88003ba7b610: fa fa fa fa fa fa fa fa 00 00 00 00 fa
fa fa fa
[ 64.195954] Shadow byte legend (one shadow byte represents 8 application
bytes):
[ 64.197039] Addressable: 00
[ 64.197585] Partially addressable: 01 02 03 04 05 06 07
[ 64.198407] Heap redzone: fa
[ 64.198955] Freed heap region: fd
[ 64.199519]
=========================================================================
[ 64.200424]
=========================================================================
[ 64.201539] ERROR: AddressSanitizer: heap-use-after-free on address
ffff88002a3daedc
[ 64.202432] Stack trace:
[ 64.202814] [<ffffffff810dd1f5>] asan_report_error+0x85/0x2c0
[ 64.203636] [<ffffffff810dc700>] asan_check_region+0x30/0x40
[ 64.204481] [<ffffffff810dd4b3>] __tsan_read4+0x13/0x20
[ 64.205267] [<ffffffff817e001b>] consume_skb+0x2b/0xd0
[ 64.206066] [<ffffffff817f3f90>] dev_kfree_skb_any+0x60/0x70
[ 64.206923] [<ffffffffa007c6ba>]
e1000_unmap_and_free_tx_resource.isra.45+0xda/0x130 [e1000]
[ 64.208144] [<ffffffffa00804e9>] e1000_clean+0x1e9/0x11b0 [e1000]
[ 64.209067] [<ffffffff817f8e1a>] net_rx_action+0x1aa/0x380
[ 64.209866] [<ffffffff810ee9d2>] __do_softirq+0x182/0x3a0
[ 64.210671] [<ffffffff8192629c>] call_softirq+0x1c/0x30
[ 64.211463] [<ffffffff8108040d>] do_softirq+0x5d/0xc0
[ 64.212227] [<ffffffff810ed3d7>] local_bh_enable+0x127/0x130
[ 64.213074] [<ffffffff8185d775>] ip_finish_output+0x365/0x640
[ 64.213910] [<ffffffff8185fc79>] ip_output+0xb9/0x100
[ 64.214661] [<ffffffff8185ed1c>] ip_local_out+0x4c/0x60
[ 64.215451] [<ffffffff818611b3>] ip_send_skb+0x23/0x70
[ 64.216249] [<ffffffff818a4bf4>] udp_send_skb+0x584/0x6e0
[ 64.217064] [<ffffffff818a681c>] udp_sendmsg+0x4dc/0xfd0
[ 64.217838] [<ffffffff818b93e8>] inet_sendmsg+0x108/0x160
[ 64.218687] [<ffffffff817d0f43>] sock_sendmsg+0x133/0x170
[ 64.219496] [<ffffffff817d1669>] SYSC_sendto+0x1e9/0x2d0
[ 64.220297] [<ffffffff817d2329>] SyS_sendto+0x49/0x70
[ 64.221069] [<ffffffff81826e55>] compat_sys_socketcall+0x305/0x530
[ 64.222053] [<ffffffff81926335>] sysenter_dispatch+0x7/0x1a
[ 64.222867] [<ffffffffffffffff>] 0xffffffffffffffff
[ 64.223592] Free stack trace:
[ 64.224050] [<ffffffff810dc831>] asan_slab_free+0x61/0xb0
[ 64.224841] [<ffffffff8127f955>] kmem_cache_free+0x55/0x2e0
[ 64.225559] [<ffffffff817db68b>] kfree_skbmem+0x5b/0xd0
[ 64.226342] [<ffffffff817e003c>] consume_skb+0x4c/0xd0
[ 64.227121] [<ffffffff817f3f90>] dev_kfree_skb_any+0x60/0x70
[ 64.227958] [<ffffffffa007c6ba>]
e1000_unmap_and_free_tx_resource.isra.45+0xda/0x130 [e1000]
[ 64.229240] [<ffffffffa00804e9>] e1000_clean+0x1e9/0x11b0 [e1000]
[ 64.230149] [<ffffffff817f8e1a>] net_rx_action+0x1aa/0x380
[ 64.230947] [<ffffffff810ee9d2>] __do_softirq+0x182/0x3a0
[ 64.231706] [<ffffffff8192629c>] call_softirq+0x1c/0x30
[ 64.232451] [<ffffffff8108040d>] do_softirq+0x5d/0xc0
[ 64.233219] [<ffffffff810ed3d7>] local_bh_enable+0x127/0x130
[ 64.234012] [<ffffffff8185d775>] ip_finish_output+0x365/0x640
[ 64.234842] [<ffffffff8185fc79>] ip_output+0xb9/0x100
[ 64.235621] [<ffffffff8185ed1c>] ip_local_out+0x4c/0x60
[ 64.236431] [<ffffffff818611b3>] ip_send_skb+0x23/0x70
[ 64.237221] [<ffffffff818a4bf4>] udp_send_skb+0x584/0x6e0
[ 64.237991] [<ffffffff818a681c>] udp_sendmsg+0x4dc/0xfd0
[ 64.238788] [<ffffffff818b93e8>] inet_sendmsg+0x108/0x160
[ 64.239604] [<ffffffff817d0f43>] sock_sendmsg+0x133/0x170
[ 64.240413] [<ffffffff817d1669>] SYSC_sendto+0x1e9/0x2d0
[ 64.241213] [<ffffffff817d2329>] SyS_sendto+0x49/0x70
[ 64.241954] [<ffffffff817d238b>] SyS_send+0x3b/0x50
[ 64.242681] Shadow bytes around the buggy address:
[ 64.243422] ffff88003ba7b580: fa fa fa fa fa fa fa fa fd fd fd fd fd
fd fd fd
[ 64.244534] ffff88003ba7b590: fd fd fd fd fd fd fd fd fd fd fd fd fd
fd fd fd
[ 64.245615] ffff88003ba7b5a0: fd fd fd fd fa fa fa fa fa fa fa fa fa
fa fa fa
[ 64.246691] ffff88003ba7b5b0: fa fa fa fa fa fa fa fa fa fa fa fa fa
fa fa fa
[ 64.247768] ffff88003ba7b5c0: fd fd fd fd fd fd fd fd fd fd fd fd fd
fd fd fd
[ 64.248886] =>ffff88003ba7b5d0: fd fd fd fd fd fd fd fd fd fd fd[fd]fa
fa fa fa
[ 64.250001] ffff88003ba7b5e0: fa fa fa fa fa fa fa fa fa fa fa fa fa
fa fa fa
[ 64.251084] ffff88003ba7b5f0: fa fa fa fa fa fa fa fa fa fa fa fa fa
fa fa fa
[ 64.252162] ffff88003ba7b600: fa fa fa fa fa fa fa fa fa fa fa fa fa
fa fa fa
[ 64.253236] ffff88003ba7b610: fa fa fa fa fa fa fa fa 00 00 00 00 fa
fa fa fa
[ 64.254312] ffff88003ba7b620: fa fa fa fa fa fa fa fa fa fa fa fa fa
fa fa fa
[ 64.255431] Shadow byte legend (one shadow byte represents 8 application
bytes):
[ 64.256500] Addressable: 00
[ 64.257083] Partially addressable: 01 02 03 04 05 06 07
[ 64.257851] Heap redzone: fa
[ 64.258397] Freed heap region: fd
[ 64.258942]
=========================================================================
There were more use-after-free reports after these two.
The first use-after-free was caused by accessing 'len' field in
'buffer_info->skb' in 'e1000_clean_tx_irq' (line 3835).
Our guess is that 'buffer_info->skb' had been freed in another thread (the
bottom frames of the stack traces are different) by
'e1000_unmap_and_free_tx_resource' (line 1972) but wasn't assigned to
'NULL' yet (line 1973).
The kernel version is 3.11-rc4 (last commit:
b7bc9e7d808ba55729bd263b0210cda36965be32).
e100_clean_tx_irq:
http://lxr.free-electrons.com/source/drivers/net/ethernet/intel/e1000/e1000_main.c#L3835
e1000_unmap_and_free_tx_resource:
http://lxr.free-electrons.com/source/drivers/net/ethernet/intel/e1000/e1000_main.c#L1958
Since these reports were caused by a system call fuzzer I don't know how to
reproduce them.
Could you confirm if this is a real bug?
Thanks!
[-- Attachment #2: Type: text/plain, Size: 379 bytes --]
------------------------------------------------------------------------------
Introducing Performance Central, a new site from SourceForge and
AppDynamics. Performance Central is your source for news, insights,
analysis and resources for efficient Application Performance Management.
Visit us today!
http://pubads.g.doubleclick.net/gampad/clk?id=48897511&iu=/4140/ostg.clktrk
[-- Attachment #3: Type: text/plain, Size: 257 bytes --]
_______________________________________________
E1000-devel mailing list
E1000-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel® Ethernet, visit http://communities.intel.com/community/wired
^ permalink raw reply
* Re: [PATCH net] skge: dma_sync the whole receive buffer
From: poma @ 2013-08-21 16:04 UTC (permalink / raw)
To: Greg KH; +Cc: Stephen Hemminger, David Miller, netdev, Linus Torvalds
In-Reply-To: <5212E249.2050203@gmail.com>
On 20.08.2013 05:28, poma wrote:
> On 19.08.2013 02:49, poma wrote:
>> On 15.08.2013 17:41, Stephen Hemminger wrote:
>>> On Wed, 14 Aug 2013 20:29:06 +0200
>>> poma <pomidorabelisima@gmail.com> wrote:
>>>
>>>> On 14.08.2013 18:20, Stephen Hemminger wrote:
>>>>> On Wed, 14 Aug 2013 12:20:03 +0200
>>>>> poma <pomidorabelisima@gmail.com> wrote:
>>>>>
>>>>>> On 14.08.2013 03:00, Stephen Hemminger wrote:
>>>>>>> On Tue, 13 Aug 2013 15:09:55 -0700 (PDT)
>>>>>>> David Miller <davem@davemloft.net> wrote:
>>>>>>>
>>>>>>>> From: Stephen Hemminger <stephen@networkplumber.org>
>>>>>>>> Date: Sat, 10 Aug 2013 15:02:07 -0700
>>>>>>>>
>>>>>>>>> The DMA sync should sync the whole receive buffer, not just
>>>>>>>>> part of it. Fixes log messages dma_sync_check.
>>>>>>>>>
>>>>>>>>> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
>>>>>>>>
>>>>>>>> Applied, but I really suspect that your "check DMA mapping errors"
>>>>>>>> patch has added a serious regression. A regression much worse than
>>>>>>>> the bug you were trying to fix with that change.
>>>>>>>
>>>>>>> Argh. The problem is deeper than that. Device got broken somewhere between
>>>>>>> 3.2 and 3.4. My old Dlink card works on 3.2 but gets DMA errors on 3.4.
>>>>>>> The config's are different though so checking that as well.
>>>>>>>
>>>>>>
>>>>>> Can I help you with debugging?
>>>>>> DGE-530T is rather solid device.
>>>>>
>>>>> Don't think it is a hardware problem.
>>>>> The failure is when the board access the Receive ring PCI memory area.
>>>>> This region is allocated with pci_alloc_consistent and therefore should
>>>>> be available. Two possible issues are driver math issues, or hardware
>>>>> problems with where the region is located. Some of these cards don't
>>>>> really have full 64 bit PCI support.
>>>>>
>>>>> My board is:
>>>>> 05:01.0 Ethernet controller: D-Link System Inc Gigabit Ethernet Adapter (rev 11)
>>>>> Subsystem: D-Link System Inc DGE-530T Gigabit Ethernet Adapter
>>>>> Flags: bus master, 66MHz, medium devsel, latency 32, IRQ 18
>>>>> Memory at f7d20000 (32-bit, non-prefetchable) [size=16K]
>>>>> I/O ports at c000 [size=256]
>>>>> Expansion ROM at f7d00000 [disabled] [size=128K]
>>>>> Capabilities: [48] Power Management version 2
>>>>> Capabilities: [50] Vital Product Data
>>>>> Kernel driver in use: skge
>>>>>
>>>>>
>>>>> What is your config?
>>>>>
>>>>
>>>> 01:09.0 Ethernet controller: D-Link System Inc Gigabit Ethernet Adapter
>>>> (rev 11)
>>>> Subsystem: D-Link System Inc DGE-530T Gigabit Ethernet Adapter
>>>> Flags: bus master, 66MHz, medium devsel, latency 64, IRQ 19
>>>> Memory at fbffc000 (32-bit, non-prefetchable) [size=16K]
>>>> I/O ports at b400 [size=256]
>>>> [virtual] Expansion ROM at ec000000 [disabled] [size=128K]
>>>> Capabilities: [48] Power Management version 2
>>>> Capabilities: [50] Vital Product Data
>>>> Kernel driver in use: skge
>>>>
>>>>
>>>> poma
>>>>
>>>
>>> In the course of debugging this, I moved the card to another slot
>>> and all the problems went away. I suspect either card insertion or more likely
>>> the crap consumer motherboards don't have full PCI support on some slots.
>>>
>>> There doesn't seem to be anyway to address this in software.
>>>
>>
>>
>> DGE-530T is further tested in the 3 available slots:
>> 01:06.0 Ethernet controller: D-Link System Inc Gigabit Ethernet Adapter
>> (rev 11)
>> 01:07.0 Ethernet controller: D-Link System Inc Gigabit Ethernet Adapter
>> (rev 11)
>> 01:08.0 Ethernet controller: D-Link System Inc Gigabit Ethernet Adapter
>> (rev 11)
>> And the result is the same as in the slot:
>> 01:09.0 Ethernet controller: D-Link System Inc Gigabit Ethernet Adapter
>> (rev 11)
>> warnings, oopses and kernel crashes.
>>
>> However DGE-528T(RTL8110s) on the same bus runs without errors:
>> 01:09.0 Ethernet controller: D-Link System Inc DGE-528T Gigabit Ethernet
>> Adapter (rev 10)
>> Subsystem: D-Link System Inc DGE-528T Gigabit Ethernet Adapter
>> Flags: bus master, 66MHz, medium devsel, latency 64, IRQ 19
>> I/O ports at cc00 [size=256]
>> Memory at fbfff000 (32-bit, non-prefetchable) [size=256]
>> [virtual] Expansion ROM at fbe00000 [disabled] [size=128K]
>> Capabilities: [dc] Power Management version 2
>> Kernel driver in use: r8169
>>
>> Besides comparing the behavior of these two cards, e.g. NFS upload, I
>> noticed an obvious difference in the data flow.
>> Via DGE-528T transmission is steady, while via DGE-530T the traffic is
>> at times interrupted and unstable.
>> So it seems that the "WARNING: at lib/dma-debug.c:937 check_unmap…"
>> isn't just a fun.
>>
>
> In support of the validity of the device I made a test with the
> 2.6.32-358.14.1.el6.x86_64.debug kernel.
> And everything worked as it should.
>
> 01:08.0 Ethernet controller: D-Link System Inc Gigabit Ethernet Adapter
> (rev 11)
> Subsystem: D-Link System Inc DGE-530T Gigabit Ethernet Adapter
> Flags: bus master, 66MHz, medium devsel, latency 64, IRQ 18
> Memory at fbff8000 (32-bit, non-prefetchable) [size=16K]
> I/O ports at cc00 [size=256]
> [virtual] Expansion ROM at fbe00000 [disabled] [size=128K]
> Capabilities: [48] Power Management version 2
> Capabilities: [50] Vital Product Data
> Kernel driver in use: skge
> Kernel modules: skge
>
> filename:
> /lib/modules/2.6.32-358.14.1.el6.x86_64.debug/kernel/drivers/net/skge.ko
> version: 1.13
> license: GPL
> author: Stephen Hemminger <shemminger@linux-foundation.org>
> description: SysKonnect Gigabit Ethernet driver
> srcversion: ADF6781C2E0D2D895F86279
> alias: pci:v00001737d00001032sv*sd00000015bc*sc*i*
> alias: pci:v00001737d00001064sv*sd*bc*sc*i*
> alias: pci:v00001371d0000434Esv*sd*bc*sc*i*
> alias: pci:v000011ABd00005005sv*sd*bc*sc*i*
> alias: pci:v000011ABd00004320sv*sd*bc*sc*i*
> alias: pci:v00001186d00004B01sv*sd*bc*sc*i*
> alias: pci:v00001186d00004C00sv*sd*bc*sc*i*
> alias: pci:v00001148d00004320sv*sd*bc*sc*i*
> alias: pci:v00001148d00004300sv*sd*bc*sc*i*
> alias: pci:v000010B7d000080EBsv*sd*bc*sc*i*
> alias: pci:v000010B7d00001700sv*sd*bc*sc*i*
> depends:
> vermagic: 2.6.32-358.14.1.el6.x86_64.debug SMP mod_unload modversions
> parm: debug:Debug level (0=none,...,16=all) (int)
>
>
> Given all the tests and all written, something isn't right, at all.
> Should I quote Shakespeare. :)
>
Additionally, I have researched the history of the event and made a few
more tests.
The last kernel that worked flawlessly is from the 3.7.10 series.
I tested with the 3.7.10-400.fc19.x86_64.debug kernel.
The first kernel afterwards - the 3.8 series - introduced problems with
DMA-API, "… device driver failed to check map error".
An example that follows shows the skge module brokenness in its current
state.
The only thing that is produced is a timeout.
The same result was achieved with the 3.11.0-0.rc6.git1.1.fc20.i686 kernel.
[CLIENT]
$ lspci -knn -d 1186:4c00
01:08.0 Ethernet controller [0200]: D-Link System Inc Gigabit Ethernet
Adapter [1186:4c00] (rev 11)
Subsystem: D-Link System Inc DGE-530T Gigabit Ethernet Adapter [1186:4c00]
Kernel driver in use: skge
$ modinfo skge
filename:
/lib/modules/3.11.0-0.rc6.git1.1.fc20.x86_64/kernel/drivers/net/ethernet/marvell/skge.ko
version: 1.14
license: GPL
author: Stephen Hemminger <shemminger@linux-foundation.org>
description: SysKonnect Gigabit Ethernet driver
srcversion: BF56B39CFC55B011E27DAB9
alias: pci:v00001737d00001032sv*sd00000015bc*sc*i*
alias: pci:v00001737d00001064sv*sd*bc*sc*i*
alias: pci:v00001371d0000434Esv*sd*bc*sc*i*
alias: pci:v000011ABd00005005sv*sd*bc*sc*i*
alias: pci:v000011ABd00004320sv*sd*bc*sc*i*
alias: pci:v00001186d00004302sv*sd*bc*sc*i*
alias: pci:v00001186d00004C00sv*sd*bc*sc*i*
alias: pci:v00001186d00004B01sv*sd*bc*sc*i*
alias: pci:v00001148d00004320sv*sd*bc*sc*i*
alias: pci:v00001148d00004300sv*sd*bc*sc*i*
alias: pci:v000010B7d000080EBsv*sd*bc*sc*i*
alias: pci:v000010B7d00001700sv*sd*bc*sc*i*
depends:
intree: Y
vermagic: 3.11.0-0.rc6.git1.1.fc20.x86_64 SMP mod_unload
signer: Fedora kernel signing key
sig_key: B1:4E:0F:25:52:6B:EE:0B:8B:66:BA:D6:38:99:D2:21:5D:37:E1:C1
sig_hashalgo: sha256
parm: debug:Debug level (0=none,...,16=all) (int)
$ time ssh -vvv <SERVER_IP>
OpenSSH_6.2p2, OpenSSL 1.0.1e-fips 11 Feb 2013
debug1: Reading configuration data $HOME/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 51: Applying options for *
debug2: ssh_connect: needpriv 0
debug1: Connecting to <SERVER_IP> [<SERVER_IP>] port 22.
debug1: Connection established.
debug1: identity file $HOME/.ssh/id_rsa type -1
debug1: identity file $HOME/.ssh/id_rsa-cert type -1
debug3: Incorrect RSA1 identifier
debug3: Could not load "$HOME/.ssh/id_dsa" as a RSA1 public key
debug1: identity file $HOME/.ssh/id_dsa type 2
debug1: identity file $HOME/.ssh/id_dsa-cert type -1
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_6.2
debug1: Remote protocol version 2.0, remote software version OpenSSH_6.2
debug1: match: OpenSSH_6.2 pat OpenSSH*
debug2: fd 3 setting O_NONBLOCK
debug3: load_hostkeys: loading entries for host "<SERVER_IP>" from file
"$HOME/.ssh/known_hosts"
debug3: load_hostkeys: found key type RSA in file $HOME/.ssh/known_hosts:1
debug3: load_hostkeys: loaded 1 keys
debug3: order_hostkeyalgs: prefer hostkeyalgs:
ssh-rsa-cert-v01@openssh.com,ssh-rsa-cert-v00@openssh.com,ssh-rsa
debug1: SSH2_MSG_KEXINIT sent
Connection to <SERVER_IP> timed out while waiting to read
real 1m0.133s
user 0m0.006s
sys 0m0.036s
# tcptrack -i enp1s8 port 22
Client Server State Idle A Speed
<CLIENT_IP>:53602 <SERVER_IP>:22 ESTABLISHED 1m 0 B/s
[\CLIENT]
.
.
[SERVER]
/var/log/secure
<DATE> <SERVER> sshd[25248]: Connection closed by <CLIENT_IP> [preauth]
[\SERVER]
Signor Greg you are supposed to be very resourceful guy, especially in
matters concerning the hardware, so please if you can set aside your
valuable time and help us finally resolve this issue.
poma
A complete thread:
http://www.spinics.net/lists/netdev/msg245381.html
^ permalink raw reply
* [PATCH net-next 5/5] qlcnic: Update version to 5.3.48
From: Himanshu Madhani @ 2013-08-21 15:24 UTC (permalink / raw)
To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Himanshu Madhani
In-Reply-To: <cover.1377122994.git.himanshu.madhani@qlogic.com>
From: Himanshu Madhani <himanshu.madhani@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index 9d8f80e..3f03856 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -37,8 +37,8 @@
#define _QLCNIC_LINUX_MAJOR 5
#define _QLCNIC_LINUX_MINOR 3
-#define _QLCNIC_LINUX_SUBVERSION 47
-#define QLCNIC_LINUX_VERSIONID "5.3.47"
+#define _QLCNIC_LINUX_SUBVERSION 48
+#define QLCNIC_LINUX_VERSIONID "5.3.48"
#define QLCNIC_DRV_IDC_VER 0x01
#define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\
(_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
--
1.8.1.4
^ permalink raw reply related
* [PATCH net-next 3/5] qlcnic: Enable diagnostic test for multiple Tx queues.
From: Himanshu Madhani @ 2013-08-21 15:24 UTC (permalink / raw)
To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Himanshu Madhani
In-Reply-To: <cover.1377122994.git.himanshu.madhani@qlogic.com>
From: Himanshu Madhani <himanshu.madhani@qlogic.com>
o Enable diagnostic test via ethtool and QConvergeConsole
application when Multiple Tx queues are enabled on 82xx
series adapters.
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 2 ++
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c | 23 +++++++++++++---------
.../net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c | 2 ++
drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c | 3 ++-
drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | 13 ++++++++----
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 5 +++++
6 files changed, 34 insertions(+), 14 deletions(-)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index 101b538..45a5a2a 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -1990,6 +1990,7 @@ static inline void qlcnic_disable_int(struct qlcnic_host_sds_ring *sds_ring)
struct qlcnic_adapter *adapter = sds_ring->adapter;
if (qlcnic_check_multi_tx(adapter) &&
+ !adapter->ahw->diag_test &&
(adapter->flags & QLCNIC_MSIX_ENABLED))
writel(0x1, sds_ring->crb_intr_mask);
else
@@ -2004,6 +2005,7 @@ static inline void qlcnic_enable_int(struct qlcnic_host_sds_ring *sds_ring)
struct qlcnic_adapter *adapter = sds_ring->adapter;
if (qlcnic_check_multi_tx(adapter) &&
+ !adapter->ahw->diag_test &&
(adapter->flags & QLCNIC_MSIX_ENABLED))
writel(0, sds_ring->crb_intr_mask);
else
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
index b8d9750..2b68779 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
@@ -295,7 +295,8 @@ int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
| QLCNIC_CAP0_VALIDOFF);
cap |= (QLCNIC_CAP0_JUMBO_CONTIGUOUS | QLCNIC_CAP0_LRO_CONTIGUOUS);
- if (qlcnic_check_multi_tx(adapter)) {
+ if (qlcnic_check_multi_tx(adapter) &&
+ !adapter->ahw->diag_test) {
cap |= QLCNIC_CAP0_TX_MULTI;
} else {
temp_u16 = offsetof(struct qlcnic_hostrq_rx_ctx, msix_handler);
@@ -338,7 +339,8 @@ int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
memset(sds_ring->desc_head, 0, STATUS_DESC_RINGSIZE(sds_ring));
prq_sds[i].host_phys_addr = cpu_to_le64(sds_ring->phys_addr);
prq_sds[i].ring_size = cpu_to_le32(sds_ring->num_desc);
- if (qlcnic_check_multi_tx(adapter))
+ if (qlcnic_check_multi_tx(adapter) &&
+ !adapter->ahw->diag_test)
prq_sds[i].msi_index = cpu_to_le16(ahw->intr_tbl[i].id);
else
prq_sds[i].msi_index = cpu_to_le16(i);
@@ -374,7 +376,7 @@ int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
for (i = 0; i < le16_to_cpu(prsp->num_sds_rings); i++) {
sds_ring = &recv_ctx->sds_rings[i];
reg = le32_to_cpu(prsp_sds[i].host_consumer_crb);
- if (qlcnic_check_multi_tx(adapter))
+ if (qlcnic_check_multi_tx(adapter) && !adapter->ahw->diag_test)
reg2 = ahw->intr_tbl[i].src;
else
reg2 = le32_to_cpu(prsp_sds[i].interrupt_crb);
@@ -464,13 +466,13 @@ int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter,
temp = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN |
QLCNIC_CAP0_LSO);
- if (qlcnic_check_multi_tx(adapter))
+ if (qlcnic_check_multi_tx(adapter) && !adapter->ahw->diag_test)
temp |= QLCNIC_CAP0_TX_MULTI;
prq->capabilities[0] = cpu_to_le32(temp);
if (qlcnic_check_multi_tx(adapter) &&
- (adapter->max_drv_tx_rings > 1)) {
+ !adapter->ahw->diag_test) {
temp_nsds_rings = adapter->max_sds_rings;
index = temp_nsds_rings + ring;
msix_id = ahw->intr_tbl[index].id;
@@ -506,6 +508,7 @@ int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter,
tx_ring->crb_cmd_producer = adapter->ahw->pci_base0 + temp;
tx_ring->ctx_id = le16_to_cpu(prsp->context_id);
if (qlcnic_check_multi_tx(adapter) &&
+ !adapter->ahw->diag_test &&
(adapter->flags & QLCNIC_MSIX_ENABLED)) {
index = adapter->max_sds_rings + ring;
intr_mask = ahw->intr_tbl[index].src;
@@ -681,13 +684,14 @@ int qlcnic_fw_create_ctx(struct qlcnic_adapter *dev)
err_out:
if (qlcnic_82xx_check(dev) && (dev->flags & QLCNIC_MSIX_ENABLED) &&
- qlcnic_check_multi_tx(dev))
- qlcnic_82xx_config_intrpt(dev, 0);
+ qlcnic_check_multi_tx(dev) && !dev->ahw->diag_test)
+ qlcnic_82xx_config_intrpt(dev, 0);
if (qlcnic_83xx_check(dev) && (dev->flags & QLCNIC_MSIX_ENABLED)) {
if (dev->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
qlcnic_83xx_config_intrpt(dev, 0);
}
+
return err;
}
@@ -703,8 +707,9 @@ void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter)
if (qlcnic_82xx_check(adapter) &&
(adapter->flags & QLCNIC_MSIX_ENABLED) &&
- qlcnic_check_multi_tx(adapter))
- qlcnic_82xx_config_intrpt(adapter, 0);
+ qlcnic_check_multi_tx(adapter) &&
+ !adapter->ahw->diag_test)
+ qlcnic_82xx_config_intrpt(adapter, 0);
if (qlcnic_83xx_check(adapter) &&
(adapter->flags & QLCNIC_MSIX_ENABLED)) {
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
index 583dc2b..7b0c90e 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
@@ -984,6 +984,7 @@ int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ int max_drv_tx_rings = adapter->max_drv_tx_rings;
int max_sds_rings = adapter->max_sds_rings;
struct qlcnic_host_sds_ring *sds_ring;
struct qlcnic_hardware_context *ahw = adapter->ahw;
@@ -1043,6 +1044,7 @@ int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
clear_it:
adapter->max_sds_rings = max_sds_rings;
+ adapter->max_drv_tx_rings = max_drv_tx_rings;
clear_bit(__QLCNIC_RESETTING, &adapter->state);
return ret;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
index 240b49f..66c26cf 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
@@ -242,7 +242,8 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
sds_ring->adapter = adapter;
sds_ring->num_desc = adapter->num_rxd;
if (qlcnic_82xx_check(adapter)) {
- if (qlcnic_check_multi_tx(adapter))
+ if (qlcnic_check_multi_tx(adapter) &&
+ !adapter->ahw->diag_test)
sds_ring->tx_ring = &adapter->tx_ring[ring];
else
sds_ring->tx_ring = &adapter->tx_ring[0];
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
index f4b09f4..89f6dff 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -130,7 +130,8 @@ struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *,
inline void qlcnic_enable_tx_intr(struct qlcnic_adapter *adapter,
struct qlcnic_host_tx_ring *tx_ring)
{
- if (qlcnic_check_multi_tx(adapter))
+ if (qlcnic_check_multi_tx(adapter) &&
+ !adapter->ahw->diag_test)
writel(0x0, tx_ring->crb_intr_mask);
}
@@ -138,7 +139,8 @@ inline void qlcnic_enable_tx_intr(struct qlcnic_adapter *adapter,
static inline void qlcnic_disable_tx_int(struct qlcnic_adapter *adapter,
struct qlcnic_host_tx_ring *tx_ring)
{
- if (qlcnic_check_multi_tx(adapter))
+ if (qlcnic_check_multi_tx(adapter) &&
+ !adapter->ahw->diag_test)
writel(1, tx_ring->crb_intr_mask);
}
@@ -1466,6 +1468,7 @@ int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter,
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
if (qlcnic_check_multi_tx(adapter) &&
+ !adapter->ahw->diag_test &&
(adapter->max_drv_tx_rings > 1)) {
netif_napi_add(netdev, &sds_ring->napi, qlcnic_rx_poll,
QLCNIC_NETDEV_WEIGHT * 2);
@@ -1487,7 +1490,7 @@ int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter,
return -ENOMEM;
}
- if (qlcnic_check_multi_tx(adapter)) {
+ if (qlcnic_check_multi_tx(adapter) && !adapter->ahw->diag_test) {
for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
tx_ring = &adapter->tx_ring[ring];
netif_napi_add(netdev, &tx_ring->napi, qlcnic_tx_poll,
@@ -1512,7 +1515,7 @@ void qlcnic_82xx_napi_del(struct qlcnic_adapter *adapter)
qlcnic_free_sds_rings(adapter->recv_ctx);
- if (qlcnic_check_multi_tx(adapter)) {
+ if (qlcnic_check_multi_tx(adapter) && !adapter->ahw->diag_test) {
for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
tx_ring = &adapter->tx_ring[ring];
netif_napi_del(&tx_ring->napi);
@@ -1540,6 +1543,7 @@ void qlcnic_82xx_napi_enable(struct qlcnic_adapter *adapter)
if (qlcnic_check_multi_tx(adapter) &&
(adapter->flags & QLCNIC_MSIX_ENABLED) &&
+ !adapter->ahw->diag_test &&
(adapter->max_drv_tx_rings > 1)) {
for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
tx_ring = &adapter->tx_ring[ring];
@@ -1567,6 +1571,7 @@ void qlcnic_82xx_napi_disable(struct qlcnic_adapter *adapter)
}
if ((adapter->flags & QLCNIC_MSIX_ENABLED) &&
+ !adapter->ahw->diag_test &&
qlcnic_check_multi_tx(adapter)) {
for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
tx_ring = &adapter->tx_ring[ring];
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 94b3e82..25a858f 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -581,6 +581,7 @@ int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
} else {
adapter->ahw->num_msix = num_msix;
if (qlcnic_check_multi_tx(adapter) &&
+ !adapter->ahw->diag_test &&
(adapter->max_drv_tx_rings > 1))
max_sds_rings = num_msix - max_tx_rings;
else
@@ -697,6 +698,7 @@ int qlcnic_82xx_mq_intrpt(struct qlcnic_adapter *adapter, int op_type)
int err, i;
if (qlcnic_check_multi_tx(adapter) &&
+ !ahw->diag_test &&
(adapter->flags & QLCNIC_MSIX_ENABLED)) {
ahw->intr_tbl = vzalloc(ahw->num_msix *
sizeof(struct qlcnic_intrpt_config));
@@ -1752,6 +1754,7 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_host_sds_ring *sds_ring;
+ int max_tx_rings = adapter->max_drv_tx_rings;
int ring;
clear_bit(__QLCNIC_DEV_UP, &adapter->state);
@@ -1768,6 +1771,7 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings)
adapter->ahw->diag_test = 0;
adapter->max_sds_rings = max_sds_rings;
+ adapter->max_drv_tx_rings = max_tx_rings;
if (qlcnic_attach(adapter))
goto out;
@@ -1836,6 +1840,7 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
adapter->max_sds_rings = 1;
adapter->ahw->diag_test = test;
adapter->ahw->linkup = 0;
+ adapter->max_drv_tx_rings = 1;
ret = qlcnic_attach(adapter);
if (ret) {
--
1.8.1.4
^ permalink raw reply related
* [PATCH net-next 1/5] qlcnic: Multi Tx queue support for 82xx Series adapter.
From: Himanshu Madhani @ 2013-08-21 15:24 UTC (permalink / raw)
To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Himanshu Madhani
In-Reply-To: <cover.1377122994.git.himanshu.madhani@qlogic.com>
From: Himanshu Madhani <himanshu.madhani@qlogic.com>
o 82xx firmware allows support for multiple Tx queues. This
patch will enable multi Tx queue support for 82xx series
adapter. Max number of Tx queues supported will be 8.
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 74 +++++++-
.../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 6 +-
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c | 196 +++++++++++++++------
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c | 2 +-
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h | 3 +
drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c | 11 +-
drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | 140 ++++++++++++---
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 167 +++++++++++++++---
8 files changed, 487 insertions(+), 112 deletions(-)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index 3dcc666..2f9985f 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -97,6 +97,9 @@
#define TX_STOP_THRESH ((MAX_SKB_FRAGS >> 2) + MAX_TSO_HEADER_DESC \
+ MGMT_CMD_DESC_RESV)
#define QLCNIC_MAX_TX_TIMEOUTS 2
+#define QLCNIC_MAX_TX_RINGS 8
+#define QLCNIC_MAX_SDS_RINGS 8
+
/*
* Following are the states of the Phantom. Phantom will set them and
* Host will read to check if the fields are correct.
@@ -515,6 +518,7 @@ struct qlcnic_host_sds_ring {
u32 num_desc;
void __iomem *crb_sts_consumer;
+ struct qlcnic_host_tx_ring *tx_ring;
struct status_desc *desc_head;
struct qlcnic_adapter *adapter;
struct napi_struct napi;
@@ -532,9 +536,17 @@ struct qlcnic_host_tx_ring {
void __iomem *crb_intr_mask;
char name[IFNAMSIZ + 12];
u16 ctx_id;
+
+ u32 state;
u32 producer;
u32 sw_consumer;
u32 num_desc;
+
+ u64 xmit_on;
+ u64 xmit_off;
+ u64 xmit_called;
+ u64 xmit_finished;
+
void __iomem *crb_cmd_producer;
struct cmd_desc_type0 *desc_head;
struct qlcnic_adapter *adapter;
@@ -559,7 +571,6 @@ struct qlcnic_recv_context {
u32 state;
u16 context_id;
u16 virt_port;
-
};
/* HW context creation */
@@ -604,6 +615,7 @@ struct qlcnic_recv_context {
#define QLCNIC_CAP0_LRO_CONTIGUOUS (1 << 8)
#define QLCNIC_CAP0_VALIDOFF (1 << 11)
#define QLCNIC_CAP0_LRO_MSS (1 << 21)
+#define QLCNIC_CAP0_TX_MULTI (1 << 22)
/*
* Context state
@@ -631,7 +643,7 @@ struct qlcnic_hostrq_rds_ring {
struct qlcnic_hostrq_rx_ctx {
__le64 host_rsp_dma_addr; /* Response dma'd here */
- __le32 capabilities[4]; /* Flag bit vector */
+ __le32 capabilities[4]; /* Flag bit vector */
__le32 host_int_crb_mode; /* Interrupt crb usage */
__le32 host_rds_crb_mode; /* RDS crb usage */
/* These ring offsets are relative to data[0] below */
@@ -814,6 +826,7 @@ struct qlcnic_mac_list_s {
#define QLCNIC_FW_CAPABILITY_BDG BIT_8
#define QLCNIC_FW_CAPABILITY_FVLANTX BIT_9
#define QLCNIC_FW_CAPABILITY_HW_LRO BIT_10
+#define QLCNIC_FW_CAPABILITY_2_MULTI_TX BIT_4
#define QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK BIT_27
#define QLCNIC_FW_CAPABILITY_MORE_CAPS BIT_31
@@ -922,6 +935,7 @@ struct qlcnic_ipaddr {
#define QLCNIC_BEACON_DISABLE 0xD
#define QLCNIC_DEF_NUM_STS_DESC_RINGS 4
+#define QLCNIC_DEF_NUM_TX_RINGS 4
#define QLCNIC_MSIX_TBL_SPACE 8192
#define QLCNIC_PCI_REG_MSIX_TBL 0x44
#define QLCNIC_MSIX_TBL_PGSIZE 4096
@@ -937,6 +951,7 @@ struct qlcnic_ipaddr {
#define __QLCNIC_DIAG_RES_ALLOC 6
#define __QLCNIC_LED_ENABLE 7
#define __QLCNIC_ELB_INPROGRESS 8
+#define __QLCNIC_MULTI_TX_UNIQUE 9
#define __QLCNIC_SRIOV_ENABLE 10
#define __QLCNIC_SRIOV_CAPABLE 11
#define __QLCNIC_MBX_POLL_ENABLE 12
@@ -1482,7 +1497,8 @@ void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter);
void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *adapter);
void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter);
-void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter);
+void qlcnic_release_tx_buffers(struct qlcnic_adapter *,
+ struct qlcnic_host_tx_ring *);
int qlcnic_check_fw_status(struct qlcnic_adapter *adapter);
void qlcnic_watchdog_task(struct work_struct *work);
@@ -1543,6 +1559,7 @@ void qlcnic_free_sds_rings(struct qlcnic_recv_context *);
void qlcnic_advert_link_change(struct qlcnic_adapter *, int);
void qlcnic_free_tx_rings(struct qlcnic_adapter *);
int qlcnic_alloc_tx_rings(struct qlcnic_adapter *, struct net_device *);
+void qlcnic_dump_mbx(struct qlcnic_adapter *, struct qlcnic_cmd_args *);
void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter);
void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter);
@@ -1605,6 +1622,26 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring)
tx_ring->producer;
}
+static inline int qlcnic_set_real_num_queues(struct qlcnic_adapter *adapter,
+ struct net_device *netdev)
+{
+ int err, tx_q;
+
+ tx_q = adapter->max_drv_tx_rings;
+
+ netdev->num_tx_queues = tx_q;
+ netdev->real_num_tx_queues = tx_q;
+
+ err = netif_set_real_num_tx_queues(netdev, tx_q);
+ if (err)
+ dev_err(&adapter->pdev->dev, "failed to set %d Tx queues\n",
+ tx_q);
+ else
+ dev_info(&adapter->pdev->dev, "set %d Tx queues\n", tx_q);
+
+ return err;
+}
+
struct qlcnic_nic_template {
int (*config_bridged_mode) (struct qlcnic_adapter *, u32);
int (*config_led) (struct qlcnic_adapter *, u32, u32);
@@ -1932,16 +1969,43 @@ static inline void qlcnic_config_ipaddr(struct qlcnic_adapter *adapter,
adapter->nic_ops->config_ipaddr(adapter, ip, cmd);
}
+static inline bool qlcnic_check_multi_tx(struct qlcnic_adapter *adapter)
+{
+ return test_bit(__QLCNIC_MULTI_TX_UNIQUE, &adapter->state);
+}
+
+static inline void qlcnic_disable_multi_tx(struct qlcnic_adapter *adapter)
+{
+ test_and_clear_bit(__QLCNIC_MULTI_TX_UNIQUE, &adapter->state);
+ adapter->max_drv_tx_rings = 1;
+}
+
+/* When operating in a muti tx mode, driver needs to write 0x1
+ * to src register, instead of 0x0 to disable receiving interrupt.
+ */
static inline void qlcnic_disable_int(struct qlcnic_host_sds_ring *sds_ring)
{
- writel(0, sds_ring->crb_intr_mask);
+ struct qlcnic_adapter *adapter = sds_ring->adapter;
+
+ if (qlcnic_check_multi_tx(adapter) &&
+ (adapter->flags & QLCNIC_MSIX_ENABLED))
+ writel(0x1, sds_ring->crb_intr_mask);
+ else
+ writel(0, sds_ring->crb_intr_mask);
}
+/* When operating in a muti tx mode, driver needs to write 0x0
+ * to src register, instead of 0x1 to enable receiving interrupts.
+ */
static inline void qlcnic_enable_int(struct qlcnic_host_sds_ring *sds_ring)
{
struct qlcnic_adapter *adapter = sds_ring->adapter;
- writel(0x1, sds_ring->crb_intr_mask);
+ if (qlcnic_check_multi_tx(adapter) &&
+ (adapter->flags & QLCNIC_MSIX_ENABLED))
+ writel(0, sds_ring->crb_intr_mask);
+ else
+ writel(0x1, sds_ring->crb_intr_mask);
if (!QLCNIC_IS_MSI_FAMILY(adapter))
writel(0xfbff, adapter->tgt_mask_reg);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index c5daf78..f0dc5d4 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -695,8 +695,8 @@ static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter,
static void qlcnic_83xx_handle_idc_comp_aen(struct qlcnic_adapter *adapter,
u32 data[]);
-static void qlcnic_dump_mbx(struct qlcnic_adapter *adapter,
- struct qlcnic_cmd_args *cmd)
+void qlcnic_dump_mbx(struct qlcnic_adapter *adapter,
+ struct qlcnic_cmd_args *cmd)
{
int i;
@@ -1691,7 +1691,7 @@ int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode)
/* Make sure carrier is off and queue is stopped during loopback */
if (netif_running(netdev)) {
netif_carrier_off(netdev);
- netif_stop_queue(netdev);
+ netif_tx_stop_all_queues(netdev);
}
ret = qlcnic_do_lb_test(adapter, mode);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
index d09389b..b8d9750 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
@@ -38,6 +38,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_mbx_tbl[] = {
{QLCNIC_CMD_GET_TEMP_HDR, 4, 1},
{QLCNIC_CMD_82XX_SET_DRV_VER, 4, 1},
{QLCNIC_CMD_GET_LED_STATUS, 4, 2},
+ {QLCNIC_CMD_MQ_TX_CONFIG_INTR, 2, 3},
};
static inline u32 qlcnic_get_cmd_signature(struct qlcnic_hardware_context *ahw)
@@ -171,6 +172,7 @@ int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
break;
}
dev_err(&pdev->dev, fmt, cmd->rsp.arg[0]);
+ qlcnic_dump_mbx(adapter, cmd);
} else if (rsp == QLCNIC_CDRP_RSP_OK)
cmd->rsp.arg[0] = QLCNIC_RCODE_SUCCESS;
@@ -243,40 +245,38 @@ qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu)
int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
{
- void *addr;
- struct qlcnic_hostrq_rx_ctx *prq;
- struct qlcnic_cardrsp_rx_ctx *prsp;
- struct qlcnic_hostrq_rds_ring *prq_rds;
- struct qlcnic_hostrq_sds_ring *prq_sds;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ dma_addr_t hostrq_phys_addr, cardrsp_phys_addr;
+ struct net_device *netdev = adapter->netdev;
+ u32 temp_intr_crb_mode, temp_rds_crb_mode;
struct qlcnic_cardrsp_rds_ring *prsp_rds;
struct qlcnic_cardrsp_sds_ring *prsp_sds;
+ struct qlcnic_hostrq_rds_ring *prq_rds;
+ struct qlcnic_hostrq_sds_ring *prq_sds;
struct qlcnic_host_rds_ring *rds_ring;
struct qlcnic_host_sds_ring *sds_ring;
- struct qlcnic_cmd_args cmd;
-
- dma_addr_t hostrq_phys_addr, cardrsp_phys_addr;
- u64 phys_addr;
-
+ struct qlcnic_cardrsp_rx_ctx *prsp;
+ struct qlcnic_hostrq_rx_ctx *prq;
u8 i, nrds_rings, nsds_rings;
- u16 temp_u16;
+ struct qlcnic_cmd_args cmd;
size_t rq_size, rsp_size;
u32 cap, reg, val, reg2;
+ u64 phys_addr;
+ u16 temp_u16;
+ void *addr;
int err;
- struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
-
nrds_rings = adapter->max_rds_rings;
nsds_rings = adapter->max_sds_rings;
- rq_size =
- SIZEOF_HOSTRQ_RX(struct qlcnic_hostrq_rx_ctx, nrds_rings,
- nsds_rings);
- rsp_size =
- SIZEOF_CARDRSP_RX(struct qlcnic_cardrsp_rx_ctx, nrds_rings,
- nsds_rings);
+ rq_size = SIZEOF_HOSTRQ_RX(struct qlcnic_hostrq_rx_ctx, nrds_rings,
+ nsds_rings);
+ rsp_size = SIZEOF_CARDRSP_RX(struct qlcnic_cardrsp_rx_ctx, nrds_rings,
+ nsds_rings);
addr = dma_alloc_coherent(&adapter->pdev->dev, rq_size,
- &hostrq_phys_addr, GFP_KERNEL);
+ &hostrq_phys_addr, GFP_KERNEL);
if (addr == NULL)
return -ENOMEM;
prq = addr;
@@ -295,15 +295,19 @@ int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
| QLCNIC_CAP0_VALIDOFF);
cap |= (QLCNIC_CAP0_JUMBO_CONTIGUOUS | QLCNIC_CAP0_LRO_CONTIGUOUS);
- temp_u16 = offsetof(struct qlcnic_hostrq_rx_ctx, msix_handler);
- prq->valid_field_offset = cpu_to_le16(temp_u16);
- prq->txrx_sds_binding = nsds_rings - 1;
+ if (qlcnic_check_multi_tx(adapter)) {
+ cap |= QLCNIC_CAP0_TX_MULTI;
+ } else {
+ temp_u16 = offsetof(struct qlcnic_hostrq_rx_ctx, msix_handler);
+ prq->valid_field_offset = cpu_to_le16(temp_u16);
+ prq->txrx_sds_binding = nsds_rings - 1;
+ temp_intr_crb_mode = QLCNIC_HOST_INT_CRB_MODE_SHARED;
+ prq->host_int_crb_mode = cpu_to_le32(temp_intr_crb_mode);
+ temp_rds_crb_mode = QLCNIC_HOST_RDS_CRB_MODE_UNIQUE;
+ prq->host_rds_crb_mode = cpu_to_le32(temp_rds_crb_mode);
+ }
prq->capabilities[0] = cpu_to_le32(cap);
- prq->host_int_crb_mode =
- cpu_to_le32(QLCNIC_HOST_INT_CRB_MODE_SHARED);
- prq->host_rds_crb_mode =
- cpu_to_le32(QLCNIC_HOST_RDS_CRB_MODE_UNIQUE);
prq->num_rds_rings = cpu_to_le16(nrds_rings);
prq->num_sds_rings = cpu_to_le16(nsds_rings);
@@ -317,10 +321,8 @@ int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
le32_to_cpu(prq->rds_ring_offset));
for (i = 0; i < nrds_rings; i++) {
-
rds_ring = &recv_ctx->rds_rings[i];
rds_ring->producer = 0;
-
prq_rds[i].host_phys_addr = cpu_to_le64(rds_ring->phys_addr);
prq_rds[i].ring_size = cpu_to_le32(rds_ring->num_desc);
prq_rds[i].ring_kind = cpu_to_le32(i);
@@ -331,14 +333,15 @@ int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
le32_to_cpu(prq->sds_ring_offset));
for (i = 0; i < nsds_rings; i++) {
-
sds_ring = &recv_ctx->sds_rings[i];
sds_ring->consumer = 0;
memset(sds_ring->desc_head, 0, STATUS_DESC_RINGSIZE(sds_ring));
-
prq_sds[i].host_phys_addr = cpu_to_le64(sds_ring->phys_addr);
prq_sds[i].ring_size = cpu_to_le32(sds_ring->num_desc);
- prq_sds[i].msi_index = cpu_to_le16(i);
+ if (qlcnic_check_multi_tx(adapter))
+ prq_sds[i].msi_index = cpu_to_le16(ahw->intr_tbl[i].id);
+ else
+ prq_sds[i].msi_index = cpu_to_le16(i);
}
phys_addr = hostrq_phys_addr;
@@ -361,9 +364,8 @@ int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
for (i = 0; i < le16_to_cpu(prsp->num_rds_rings); i++) {
rds_ring = &recv_ctx->rds_rings[i];
-
reg = le32_to_cpu(prsp_rds[i].host_producer_crb);
- rds_ring->crb_rcv_producer = adapter->ahw->pci_base0 + reg;
+ rds_ring->crb_rcv_producer = ahw->pci_base0 + reg;
}
prsp_sds = ((struct qlcnic_cardrsp_sds_ring *)
@@ -371,24 +373,30 @@ int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
for (i = 0; i < le16_to_cpu(prsp->num_sds_rings); i++) {
sds_ring = &recv_ctx->sds_rings[i];
-
reg = le32_to_cpu(prsp_sds[i].host_consumer_crb);
- reg2 = le32_to_cpu(prsp_sds[i].interrupt_crb);
+ if (qlcnic_check_multi_tx(adapter))
+ reg2 = ahw->intr_tbl[i].src;
+ else
+ reg2 = le32_to_cpu(prsp_sds[i].interrupt_crb);
- sds_ring->crb_sts_consumer = adapter->ahw->pci_base0 + reg;
- sds_ring->crb_intr_mask = adapter->ahw->pci_base0 + reg2;
+ sds_ring->crb_intr_mask = ahw->pci_base0 + reg2;
+ sds_ring->crb_sts_consumer = ahw->pci_base0 + reg;
}
recv_ctx->state = le32_to_cpu(prsp->host_ctx_state);
recv_ctx->context_id = le16_to_cpu(prsp->context_id);
recv_ctx->virt_port = prsp->virt_port;
+ netdev_info(netdev, "Rx Context[%d] Created, state 0x%x\n",
+ recv_ctx->context_id, recv_ctx->state);
qlcnic_free_mbx_args(&cmd);
+
out_free_rsp:
dma_free_coherent(&adapter->pdev->dev, rsp_size, prsp,
cardrsp_phys_addr);
out_free_rq:
dma_free_coherent(&adapter->pdev->dev, rq_size, prq, hostrq_phys_addr);
+
return err;
}
@@ -416,16 +424,19 @@ int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter,
struct qlcnic_host_tx_ring *tx_ring,
int ring)
{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ struct net_device *netdev = adapter->netdev;
struct qlcnic_hostrq_tx_ctx *prq;
struct qlcnic_hostrq_cds_ring *prq_cds;
struct qlcnic_cardrsp_tx_ctx *prsp;
- void *rq_addr, *rsp_addr;
- size_t rq_size, rsp_size;
- u32 temp;
struct qlcnic_cmd_args cmd;
- int err;
- u64 phys_addr;
- dma_addr_t rq_phys_addr, rsp_phys_addr;
+ u32 temp, intr_mask, temp_int_crb_mode;
+ dma_addr_t rq_phys_addr, rsp_phys_addr;
+ int temp_nsds_rings, index, err;
+ void *rq_addr, *rsp_addr;
+ size_t rq_size, rsp_size;
+ u64 phys_addr;
+ u16 msix_id;
/* reset host resources */
tx_ring->producer = 0;
@@ -447,18 +458,28 @@ int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter,
}
prq = rq_addr;
-
prsp = rsp_addr;
prq->host_rsp_dma_addr = cpu_to_le64(rsp_phys_addr);
temp = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN |
- QLCNIC_CAP0_LSO);
+ QLCNIC_CAP0_LSO);
+ if (qlcnic_check_multi_tx(adapter))
+ temp |= QLCNIC_CAP0_TX_MULTI;
+
prq->capabilities[0] = cpu_to_le32(temp);
- prq->host_int_crb_mode =
- cpu_to_le32(QLCNIC_HOST_INT_CRB_MODE_SHARED);
- prq->msi_index = 0;
+ if (qlcnic_check_multi_tx(adapter) &&
+ (adapter->max_drv_tx_rings > 1)) {
+ temp_nsds_rings = adapter->max_sds_rings;
+ index = temp_nsds_rings + ring;
+ msix_id = ahw->intr_tbl[index].id;
+ prq->msi_index = cpu_to_le16(msix_id);
+ } else {
+ temp_int_crb_mode = QLCNIC_HOST_INT_CRB_MODE_SHARED;
+ prq->host_int_crb_mode = cpu_to_le32(temp_int_crb_mode);
+ prq->msi_index = 0;
+ }
prq->interrupt_ctl = 0;
prq->cmd_cons_dma_addr = cpu_to_le64(tx_ring->hw_cons_phys_addr);
@@ -480,15 +501,24 @@ int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter,
err = qlcnic_issue_cmd(adapter, &cmd);
if (err == QLCNIC_RCODE_SUCCESS) {
+ tx_ring->state = le32_to_cpu(prsp->host_ctx_state);
temp = le32_to_cpu(prsp->cds_ring.host_producer_crb);
tx_ring->crb_cmd_producer = adapter->ahw->pci_base0 + temp;
tx_ring->ctx_id = le16_to_cpu(prsp->context_id);
+ if (qlcnic_check_multi_tx(adapter) &&
+ (adapter->flags & QLCNIC_MSIX_ENABLED)) {
+ index = adapter->max_sds_rings + ring;
+ intr_mask = ahw->intr_tbl[index].src;
+ tx_ring->crb_intr_mask = ahw->pci_base0 + intr_mask;
+ }
+
+ netdev_info(netdev, "Tx Context[0x%x] Created, state 0x%x\n",
+ tx_ring->ctx_id, tx_ring->state);
} else {
- dev_err(&adapter->pdev->dev,
- "Failed to create tx ctx in firmware%d\n", err);
+ netdev_err(netdev, "Failed to create tx ctx in firmware%d\n",
+ err);
err = -EIO;
}
-
qlcnic_free_mbx_args(&cmd);
out_free_rsp:
@@ -618,6 +648,13 @@ int qlcnic_fw_create_ctx(struct qlcnic_adapter *dev)
}
}
+ if (qlcnic_82xx_check(dev) && (dev->flags & QLCNIC_MSIX_ENABLED) &&
+ qlcnic_check_multi_tx(dev) && !dev->ahw->diag_test) {
+ err = qlcnic_82xx_mq_intrpt(dev, 1);
+ if (err)
+ return err;
+ }
+
err = qlcnic_fw_cmd_create_rx_ctx(dev);
if (err)
goto err_out;
@@ -639,9 +676,14 @@ int qlcnic_fw_create_ctx(struct qlcnic_adapter *dev)
}
set_bit(__QLCNIC_FW_ATTACHED, &dev->state);
+
return 0;
err_out:
+ if (qlcnic_82xx_check(dev) && (dev->flags & QLCNIC_MSIX_ENABLED) &&
+ qlcnic_check_multi_tx(dev))
+ qlcnic_82xx_config_intrpt(dev, 0);
+
if (qlcnic_83xx_check(dev) && (dev->flags & QLCNIC_MSIX_ENABLED)) {
if (dev->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
qlcnic_83xx_config_intrpt(dev, 0);
@@ -659,6 +701,11 @@ void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter)
qlcnic_fw_cmd_del_tx_ctx(adapter,
&adapter->tx_ring[ring]);
+ if (qlcnic_82xx_check(adapter) &&
+ (adapter->flags & QLCNIC_MSIX_ENABLED) &&
+ qlcnic_check_multi_tx(adapter))
+ qlcnic_82xx_config_intrpt(adapter, 0);
+
if (qlcnic_83xx_check(adapter) &&
(adapter->flags & QLCNIC_MSIX_ENABLED)) {
if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
@@ -723,6 +770,51 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
}
}
+int qlcnic_82xx_config_intrpt(struct qlcnic_adapter *adapter, u8 op_type)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ struct net_device *netdev = adapter->netdev;
+ struct qlcnic_cmd_args cmd;
+ u32 type, val;
+ int i, err = 0;
+
+ for (i = 0; i < ahw->num_msix; i++) {
+ qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_MQ_TX_CONFIG_INTR);
+ type = op_type ? QLCNIC_INTRPT_ADD : QLCNIC_INTRPT_DEL;
+ val = type | (ahw->intr_tbl[i].type << 4);
+ if (ahw->intr_tbl[i].type == QLCNIC_INTRPT_MSIX)
+ val |= (ahw->intr_tbl[i].id << 16);
+ cmd.req.arg[1] = val;
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err) {
+ netdev_err(netdev, "Failed to %s interrupts %d\n",
+ op_type == QLCNIC_INTRPT_ADD ? "Add" :
+ "Delete", err);
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+ }
+ val = cmd.rsp.arg[1];
+ if (LSB(val)) {
+ netdev_info(netdev,
+ "failed to configure interrupt for %d\n",
+ ahw->intr_tbl[i].id);
+ continue;
+ }
+ if (op_type) {
+ ahw->intr_tbl[i].id = MSW(val);
+ ahw->intr_tbl[i].enabled = 1;
+ ahw->intr_tbl[i].src = cmd.rsp.arg[2];
+ } else {
+ ahw->intr_tbl[i].id = i;
+ ahw->intr_tbl[i].enabled = 0;
+ ahw->intr_tbl[i].src = 0;
+ }
+ qlcnic_free_mbx_args(&cmd);
+ }
+
+ return err;
+}
int qlcnic_82xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
{
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
index 4d5f59b..9e49c15 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -387,7 +387,7 @@ qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter,
if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
return -EIO;
- tx_ring = adapter->tx_ring;
+ tx_ring = &adapter->tx_ring[0];
__netif_tx_lock_bh(tx_ring->txq);
producer = tx_ring->producer;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
index 4a71b28..e9a2225 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
@@ -87,6 +87,7 @@ enum qlcnic_regs {
#define QLCNIC_CMD_CONFIG_VPORT 0x32
#define QLCNIC_CMD_GET_MAC_STATS 0x37
#define QLCNIC_CMD_82XX_SET_DRV_VER 0x38
+#define QLCNIC_CMD_MQ_TX_CONFIG_INTR 0x39
#define QLCNIC_CMD_GET_LED_STATUS 0x3C
#define QLCNIC_CMD_CONFIGURE_RSS 0x41
#define QLCNIC_CMD_CONFIG_INTR_COAL 0x43
@@ -177,6 +178,8 @@ int qlcnic_82xx_setup_intr(struct qlcnic_adapter *, u8);
irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *);
int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
struct qlcnic_cmd_args *);
+int qlcnic_82xx_mq_intrpt(struct qlcnic_adapter *, int);
+int qlcnic_82xx_config_intrpt(struct qlcnic_adapter *, u8);
int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *);
int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *,
struct qlcnic_host_tx_ring *tx_ring, int);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
index 974d626..240b49f 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
@@ -127,12 +127,12 @@ void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *adapter)
}
}
-void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter)
+void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_tx_ring *tx_ring)
{
struct qlcnic_cmd_buffer *cmd_buf;
struct qlcnic_skb_frag *buffrag;
int i, j;
- struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
cmd_buf = tx_ring->cmd_buf_arr;
for (i = 0; i < tx_ring->num_desc; i++) {
@@ -241,7 +241,12 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
sds_ring->irq = adapter->msix_entries[ring].vector;
sds_ring->adapter = adapter;
sds_ring->num_desc = adapter->num_rxd;
-
+ if (qlcnic_82xx_check(adapter)) {
+ if (qlcnic_check_multi_tx(adapter))
+ sds_ring->tx_ring = &adapter->tx_ring[ring];
+ else
+ sds_ring->tx_ring = &adapter->tx_ring[0];
+ }
for (i = 0; i < NUM_RCV_DESC_RINGS; i++)
INIT_LIST_HEAD(&sds_ring->free_list[i]);
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
index cec0908..f4b09f4 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -127,6 +127,21 @@
struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *,
struct qlcnic_host_rds_ring *, u16, u16);
+inline void qlcnic_enable_tx_intr(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_tx_ring *tx_ring)
+{
+ if (qlcnic_check_multi_tx(adapter))
+ writel(0x0, tx_ring->crb_intr_mask);
+}
+
+
+static inline void qlcnic_disable_tx_int(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_tx_ring *tx_ring)
+{
+ if (qlcnic_check_multi_tx(adapter))
+ writel(1, tx_ring->crb_intr_mask);
+}
+
inline void qlcnic_83xx_enable_tx_intr(struct qlcnic_adapter *adapter,
struct qlcnic_host_tx_ring *tx_ring)
{
@@ -354,14 +369,14 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
}
static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter,
- struct cmd_desc_type0 *first_desc, struct sk_buff *skb)
+ struct cmd_desc_type0 *first_desc, struct sk_buff *skb,
+ struct qlcnic_host_tx_ring *tx_ring)
{
u8 l4proto, opcode = 0, hdr_len = 0;
u16 flags = 0, vlan_tci = 0;
int copied, offset, copy_len, size;
struct cmd_desc_type0 *hwdesc;
struct vlan_ethhdr *vh;
- struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
u16 protocol = ntohs(skb->protocol);
u32 producer = tx_ring->producer;
@@ -544,7 +559,7 @@ static inline void qlcnic_clear_cmddesc(u64 *desc)
netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
- struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
+ struct qlcnic_host_tx_ring *tx_ring;
struct qlcnic_cmd_buffer *pbuf;
struct qlcnic_skb_frag *buffrag;
struct cmd_desc_type0 *hwdesc, *first_desc;
@@ -553,10 +568,8 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
int i, k, frag_count, delta = 0;
u32 producer, num_txd;
- num_txd = tx_ring->num_desc;
-
if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
- netif_stop_queue(netdev);
+ netif_tx_stop_all_queues(netdev);
return NETDEV_TX_BUSY;
}
@@ -566,7 +579,14 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
goto drop_packet;
}
+ if (qlcnic_check_multi_tx(adapter))
+ tx_ring = &adapter->tx_ring[skb_get_queue_mapping(skb)];
+ else
+ tx_ring = &adapter->tx_ring[0];
+ num_txd = tx_ring->num_desc;
+
frag_count = skb_shinfo(skb)->nr_frags + 1;
+
/* 14 frags supported for normal packet and
* 32 frags supported for TSO packet
*/
@@ -581,11 +601,12 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
}
if (unlikely(qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH)) {
- netif_stop_queue(netdev);
+ netif_tx_stop_queue(tx_ring->txq);
if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
- netif_start_queue(netdev);
+ netif_tx_start_queue(tx_ring->txq);
} else {
adapter->stats.xmit_off++;
+ tx_ring->xmit_off++;
return NETDEV_TX_BUSY;
}
}
@@ -640,7 +661,7 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
tx_ring->producer = get_next_index(producer, num_txd);
smp_mb();
- if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb)))
+ if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb, tx_ring)))
goto unwind_buff;
if (adapter->drv_mac_learn)
@@ -648,6 +669,7 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
adapter->stats.txbytes += skb->len;
adapter->stats.xmitcalled++;
+ tx_ring->xmit_called++;
qlcnic_update_cmd_producer(tx_ring);
@@ -670,7 +692,7 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup)
adapter->ahw->linkup = 0;
if (netif_running(netdev)) {
netif_carrier_off(netdev);
- netif_stop_queue(netdev);
+ netif_tx_stop_all_queues(netdev);
}
} else if (!adapter->ahw->linkup && linkup) {
netdev_info(netdev, "NIC Link is up\n");
@@ -765,9 +787,6 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,
struct net_device *netdev = adapter->netdev;
struct qlcnic_skb_frag *frag;
- if (!spin_trylock(&adapter->tx_clean_lock))
- return 1;
-
sw_consumer = tx_ring->sw_consumer;
hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
@@ -785,6 +804,7 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,
frag->dma = 0ULL;
}
adapter->stats.xmitfinished++;
+ tx_ring->xmit_finished++;
dev_kfree_skb_any(buffer->skb);
buffer->skb = NULL;
}
@@ -797,10 +817,12 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,
if (count && netif_running(netdev)) {
tx_ring->sw_consumer = sw_consumer;
smp_mb();
- if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) {
+ if (netif_tx_queue_stopped(tx_ring->txq) &&
+ netif_carrier_ok(netdev)) {
if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
- netif_wake_queue(netdev);
+ netif_tx_wake_queue(tx_ring->txq);
adapter->stats.xmit_on++;
+ tx_ring->xmit_on++;
}
}
adapter->tx_timeo_cnt = 0;
@@ -820,7 +842,6 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,
*/
hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
done = (sw_consumer == hw_consumer);
- spin_unlock(&adapter->tx_clean_lock);
return done;
}
@@ -830,16 +851,40 @@ static int qlcnic_poll(struct napi_struct *napi, int budget)
int tx_complete, work_done;
struct qlcnic_host_sds_ring *sds_ring;
struct qlcnic_adapter *adapter;
+ struct qlcnic_host_tx_ring *tx_ring;
sds_ring = container_of(napi, struct qlcnic_host_sds_ring, napi);
adapter = sds_ring->adapter;
- tx_complete = qlcnic_process_cmd_ring(adapter, adapter->tx_ring,
+ tx_ring = sds_ring->tx_ring;
+
+ tx_complete = qlcnic_process_cmd_ring(adapter, tx_ring,
budget);
work_done = qlcnic_process_rcv_ring(sds_ring, budget);
if ((work_done < budget) && tx_complete) {
napi_complete(&sds_ring->napi);
- if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
+ if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
qlcnic_enable_int(sds_ring);
+ qlcnic_enable_tx_intr(adapter, tx_ring);
+ }
+ }
+
+ return work_done;
+}
+
+static int qlcnic_tx_poll(struct napi_struct *napi, int budget)
+{
+ struct qlcnic_host_tx_ring *tx_ring;
+ struct qlcnic_adapter *adapter;
+ int work_done;
+
+ tx_ring = container_of(napi, struct qlcnic_host_tx_ring, napi);
+ adapter = tx_ring->adapter;
+
+ work_done = qlcnic_process_cmd_ring(adapter, tx_ring, budget);
+ if (work_done) {
+ napi_complete(&tx_ring->napi);
+ if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
+ qlcnic_enable_tx_intr(adapter, tx_ring);
}
return work_done;
@@ -1411,6 +1456,7 @@ int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter,
int ring, max_sds_rings;
struct qlcnic_host_sds_ring *sds_ring;
struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+ struct qlcnic_host_tx_ring *tx_ring;
if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings))
return -ENOMEM;
@@ -1419,12 +1465,21 @@ int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter,
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
- if (ring == adapter->max_sds_rings - 1)
- netif_napi_add(netdev, &sds_ring->napi, qlcnic_poll,
- QLCNIC_NETDEV_WEIGHT / max_sds_rings);
- else
+ if (qlcnic_check_multi_tx(adapter) &&
+ (adapter->max_drv_tx_rings > 1)) {
netif_napi_add(netdev, &sds_ring->napi, qlcnic_rx_poll,
- QLCNIC_NETDEV_WEIGHT*2);
+ QLCNIC_NETDEV_WEIGHT * 2);
+ } else {
+ if (ring == (adapter->max_sds_rings - 1))
+ netif_napi_add(netdev, &sds_ring->napi,
+ qlcnic_poll,
+ QLCNIC_NETDEV_WEIGHT /
+ max_sds_rings);
+ else
+ netif_napi_add(netdev, &sds_ring->napi,
+ qlcnic_rx_poll,
+ QLCNIC_NETDEV_WEIGHT * 2);
+ }
}
if (qlcnic_alloc_tx_rings(adapter, netdev)) {
@@ -1432,6 +1487,14 @@ int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter,
return -ENOMEM;
}
+ if (qlcnic_check_multi_tx(adapter)) {
+ for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+ tx_ring = &adapter->tx_ring[ring];
+ netif_napi_add(netdev, &tx_ring->napi, qlcnic_tx_poll,
+ QLCNIC_NETDEV_WEIGHT);
+ }
+ }
+
return 0;
}
@@ -1440,6 +1503,7 @@ void qlcnic_82xx_napi_del(struct qlcnic_adapter *adapter)
int ring;
struct qlcnic_host_sds_ring *sds_ring;
struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+ struct qlcnic_host_tx_ring *tx_ring;
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
@@ -1447,6 +1511,14 @@ void qlcnic_82xx_napi_del(struct qlcnic_adapter *adapter)
}
qlcnic_free_sds_rings(adapter->recv_ctx);
+
+ if (qlcnic_check_multi_tx(adapter)) {
+ for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+ tx_ring = &adapter->tx_ring[ring];
+ netif_napi_del(&tx_ring->napi);
+ }
+ }
+
qlcnic_free_tx_rings(adapter);
}
@@ -1454,6 +1526,7 @@ void qlcnic_82xx_napi_enable(struct qlcnic_adapter *adapter)
{
int ring;
struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_host_tx_ring *tx_ring;
struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
@@ -1464,12 +1537,23 @@ void qlcnic_82xx_napi_enable(struct qlcnic_adapter *adapter)
napi_enable(&sds_ring->napi);
qlcnic_enable_int(sds_ring);
}
+
+ if (qlcnic_check_multi_tx(adapter) &&
+ (adapter->flags & QLCNIC_MSIX_ENABLED) &&
+ (adapter->max_drv_tx_rings > 1)) {
+ for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+ tx_ring = &adapter->tx_ring[ring];
+ napi_enable(&tx_ring->napi);
+ qlcnic_enable_tx_intr(adapter, tx_ring);
+ }
+ }
}
void qlcnic_82xx_napi_disable(struct qlcnic_adapter *adapter)
{
int ring;
struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_host_tx_ring *tx_ring;
struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
@@ -1481,6 +1565,16 @@ void qlcnic_82xx_napi_disable(struct qlcnic_adapter *adapter)
napi_synchronize(&sds_ring->napi);
napi_disable(&sds_ring->napi);
}
+
+ if ((adapter->flags & QLCNIC_MSIX_ENABLED) &&
+ qlcnic_check_multi_tx(adapter)) {
+ for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+ tx_ring = &adapter->tx_ring[ring];
+ qlcnic_disable_tx_int(adapter, tx_ring);
+ napi_synchronize(&tx_ring->napi);
+ napi_disable(&tx_ring->napi);
+ }
+ }
}
#define QLC_83XX_NORMAL_LB_PKT (1ULL << 36)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 1f97a73..af2b2e2 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -261,7 +261,6 @@ static const struct qlcnic_board_info qlcnic_boards[] = {
};
#define NUM_SUPPORTED_BOARDS ARRAY_SIZE(qlcnic_boards)
-#define QLC_MAX_SDS_RINGS 8
static const
struct qlcnic_legacy_intr_set legacy_intr[] = QLCNIC_LEGACY_INTR_CONFIG;
@@ -523,11 +522,30 @@ static struct qlcnic_hardware_ops qlcnic_hw_ops = {
.free_mac_list = qlcnic_82xx_free_mac_list,
};
+static void qlcnic_get_multiq_capability(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ int num_tx_q;
+
+ if (ahw->msix_supported &&
+ (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_2_MULTI_TX)) {
+ num_tx_q = min_t(int, QLCNIC_DEF_NUM_TX_RINGS,
+ num_online_cpus());
+ if (num_tx_q > 1) {
+ test_and_set_bit(__QLCNIC_MULTI_TX_UNIQUE,
+ &adapter->state);
+ adapter->max_drv_tx_rings = num_tx_q;
+ }
+ } else {
+ adapter->max_drv_tx_rings = 1;
+ }
+}
+
int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
{
struct pci_dev *pdev = adapter->pdev;
+ int max_tx_rings, max_sds_rings, tx_vector;
int err = -1, i;
- int max_tx_rings, tx_vector;
if (adapter->flags & QLCNIC_TX_INTR_SHARED) {
max_tx_rings = 0;
@@ -561,7 +579,14 @@ int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
adapter->max_sds_rings = num_msix -
max_tx_rings - 1;
} else {
- adapter->max_sds_rings = num_msix;
+ adapter->ahw->num_msix = num_msix;
+ if (qlcnic_check_multi_tx(adapter) &&
+ (adapter->max_drv_tx_rings > 1))
+ max_sds_rings = num_msix - max_tx_rings;
+ else
+ max_sds_rings = num_msix;
+
+ adapter->max_sds_rings = max_sds_rings;
}
dev_info(&pdev->dev, "using msi-x interrupts\n");
return err;
@@ -577,6 +602,8 @@ int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
num_msix += (max_tx_rings + 1);
} else {
num_msix = rounddown_pow_of_two(err);
+ if (qlcnic_check_multi_tx(adapter))
+ num_msix += max_tx_rings;
}
if (num_msix) {
@@ -612,6 +639,7 @@ static int qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
adapter->msix_entries[0].vector = pdev->irq;
return err;
}
+
if (qlcnic_use_msi || qlcnic_use_msi_x)
return -EOPNOTSUPP;
@@ -630,26 +658,63 @@ static int qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
int num_msix, err = 0;
if (!num_intr)
num_intr = QLCNIC_DEF_NUM_STS_DESC_RINGS;
- if (adapter->ahw->msix_supported)
+ if (ahw->msix_supported) {
num_msix = rounddown_pow_of_two(min_t(int, num_online_cpus(),
num_intr));
- else
+ if (qlcnic_check_multi_tx(adapter))
+ num_msix += adapter->max_drv_tx_rings;
+ } else {
num_msix = 1;
+ }
err = qlcnic_enable_msix(adapter, num_msix);
- if (err == -ENOMEM || !err)
+ if (err == -ENOMEM)
return err;
- err = qlcnic_enable_msi_legacy(adapter);
- if (!err)
+ if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) {
+ qlcnic_disable_multi_tx(adapter);
+
+ err = qlcnic_enable_msi_legacy(adapter);
+ if (!err)
+ return err;
+ }
+
+ return 0;
+}
+
+int qlcnic_82xx_mq_intrpt(struct qlcnic_adapter *adapter, int op_type)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ int err, i;
+
+ if (qlcnic_check_multi_tx(adapter) &&
+ (adapter->flags & QLCNIC_MSIX_ENABLED)) {
+ ahw->intr_tbl = vzalloc(ahw->num_msix *
+ sizeof(struct qlcnic_intrpt_config));
+ if (!ahw->intr_tbl)
+ return -ENOMEM;
+
+ for (i = 0; i < ahw->num_msix; i++) {
+ ahw->intr_tbl[i].type = QLCNIC_INTRPT_MSIX;
+ ahw->intr_tbl[i].id = i;
+ ahw->intr_tbl[i].src = 0;
+ }
+
+ err = qlcnic_82xx_config_intrpt(adapter, 1);
+ if (err)
+ dev_err(&adapter->pdev->dev,
+ "Failed to configure Interrupt for %d vector\n",
+ ahw->num_msix);
return err;
+ }
- return -EIO;
+ return 0;
}
void qlcnic_teardown_intr(struct qlcnic_adapter *adapter)
@@ -1422,6 +1487,7 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
for (ring = 0; ring < num_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
if (qlcnic_82xx_check(adapter) &&
+ !qlcnic_check_multi_tx(adapter) &&
(ring == (num_sds_rings - 1))) {
if (!(adapter->flags &
QLCNIC_MSIX_ENABLED))
@@ -1445,9 +1511,11 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
return err;
}
}
- if (qlcnic_83xx_check(adapter) &&
- (adapter->flags & QLCNIC_MSIX_ENABLED) &&
- !(adapter->flags & QLCNIC_TX_INTR_SHARED)) {
+ if ((qlcnic_82xx_check(adapter) &&
+ qlcnic_check_multi_tx(adapter)) ||
+ (qlcnic_83xx_check(adapter) &&
+ (adapter->flags & QLCNIC_MSIX_ENABLED) &&
+ !(adapter->flags & QLCNIC_TX_INTR_SHARED))) {
handler = qlcnic_msix_tx_intr;
for (ring = 0; ring < adapter->max_drv_tx_rings;
ring++) {
@@ -1482,8 +1550,10 @@ qlcnic_free_irq(struct qlcnic_adapter *adapter)
free_irq(sds_ring->irq, sds_ring);
}
}
- if (qlcnic_83xx_check(adapter) &&
- !(adapter->flags & QLCNIC_TX_INTR_SHARED)) {
+ if ((qlcnic_83xx_check(adapter) &&
+ !(adapter->flags & QLCNIC_TX_INTR_SHARED)) ||
+ (qlcnic_82xx_check(adapter) &&
+ qlcnic_check_multi_tx(adapter))) {
for (ring = 0; ring < adapter->max_drv_tx_rings;
ring++) {
tx_ring = &adapter->tx_ring[ring];
@@ -1519,8 +1589,10 @@ int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
return 0;
+
if (qlcnic_set_eswitch_port_config(adapter))
return -EIO;
+
qlcnic_get_lro_mss_capability(adapter);
if (qlcnic_fw_create_ctx(adapter))
@@ -1567,6 +1639,8 @@ int qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
void __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
{
+ int ring;
+
if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
return;
@@ -1576,7 +1650,6 @@ void __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
if (qlcnic_sriov_vf_check(adapter))
qlcnic_sriov_cleanup_async_list(&adapter->ahw->sriov->bc);
smp_mb();
- spin_lock(&adapter->tx_clean_lock);
netif_carrier_off(netdev);
adapter->ahw->linkup = 0;
netif_tx_disable(netdev);
@@ -1594,8 +1667,9 @@ void __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
adapter->flags &= ~QLCNIC_FW_LRO_MSS_CAP;
qlcnic_reset_rx_buffers_list(adapter);
- qlcnic_release_tx_buffers(adapter);
- spin_unlock(&adapter->tx_clean_lock);
+
+ for (ring = 0; ring < adapter->max_drv_tx_rings; ring++)
+ qlcnic_release_tx_buffers(adapter, &adapter->tx_ring[ring]);
}
/* Usage: During suspend and firmware recovery module */
@@ -1916,6 +1990,12 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,
netdev->priv_flags |= IFF_UNICAST_FLT;
netdev->irq = adapter->msix_entries[0].vector;
+ if (qlcnic_82xx_check(adapter) && qlcnic_check_multi_tx(adapter)) {
+ err = qlcnic_set_real_num_queues(adapter, netdev);
+ if (err)
+ return err;
+ }
+
err = register_netdev(netdev);
if (err) {
dev_err(&pdev->dev, "failed to register net device\n");
@@ -1984,7 +2064,8 @@ int qlcnic_alloc_tx_rings(struct qlcnic_adapter *adapter,
tx_ring->cmd_buf_arr = cmd_buf_arr;
}
- if (qlcnic_83xx_check(adapter)) {
+ if (qlcnic_83xx_check(adapter) ||
+ (qlcnic_82xx_check(adapter) && qlcnic_check_multi_tx(adapter))) {
for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
tx_ring = &adapter->tx_ring[ring];
tx_ring->adapter = adapter;
@@ -1995,6 +2076,7 @@ int qlcnic_alloc_tx_rings(struct qlcnic_adapter *adapter,
}
}
}
+
return 0;
}
@@ -2072,7 +2154,8 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto err_out_free_hw_res;
- netdev = alloc_etherdev(sizeof(struct qlcnic_adapter));
+ netdev = alloc_etherdev_mq(sizeof(struct qlcnic_adapter),
+ QLCNIC_MAX_TX_RINGS);
if (!netdev) {
err = -ENOMEM;
goto err_out_iounmap;
@@ -2102,12 +2185,10 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->fdb_mac_learn = true;
else if (qlcnic_mac_learn == DRV_MAC_LEARN)
adapter->drv_mac_learn = true;
- adapter->max_drv_tx_rings = 1;
rwlock_init(&adapter->ahw->crb_lock);
mutex_init(&adapter->ahw->mem_lock);
- spin_lock_init(&adapter->tx_clean_lock);
INIT_LIST_HEAD(&adapter->mac_list);
if (qlcnic_82xx_check(adapter)) {
@@ -2119,12 +2200,27 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_free_hw;
}
+ qlcnic_get_multiq_capability(adapter);
+
+ if ((adapter->ahw->act_pci_func > 2) &&
+ qlcnic_check_multi_tx(adapter)) {
+ adapter->max_drv_tx_rings = QLCNIC_DEF_NUM_TX_RINGS;
+ dev_info(&adapter->pdev->dev,
+ "vNIC mode enabled, Set max TX rings = %d\n",
+ adapter->max_drv_tx_rings);
+ }
+
+ if (!qlcnic_check_multi_tx(adapter)) {
+ clear_bit(__QLCNIC_MULTI_TX_UNIQUE, &adapter->state);
+ adapter->max_drv_tx_rings = 1;
+ }
err = qlcnic_setup_idc_param(adapter);
if (err)
goto err_out_free_hw;
adapter->flags |= QLCNIC_NEED_FLR;
} else if (qlcnic_83xx_check(adapter)) {
+ adapter->max_drv_tx_rings = 1;
qlcnic_83xx_check_vf(adapter, ent);
adapter->portnum = adapter->ahw->pci_func;
err = qlcnic_83xx_init(adapter, pci_using_dac);
@@ -2345,7 +2441,7 @@ static int qlcnic_open(struct net_device *netdev)
if (err)
goto err_out;
- netif_start_queue(netdev);
+ netif_tx_start_all_queues(netdev);
return 0;
@@ -2477,6 +2573,8 @@ int qlcnic_check_temp(struct qlcnic_adapter *adapter)
static void qlcnic_tx_timeout(struct net_device *netdev)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_host_tx_ring *tx_ring;
+ int ring;
if (test_bit(__QLCNIC_RESETTING, &adapter->state))
return;
@@ -2490,6 +2588,25 @@ static void qlcnic_tx_timeout(struct net_device *netdev)
QLCNIC_FORCE_FW_DUMP_KEY);
} else {
netdev_info(netdev, "Tx timeout, reset adapter context.\n");
+ if (qlcnic_82xx_check(adapter)) {
+ for (ring = 0; ring < adapter->max_drv_tx_rings;
+ ring++) {
+ tx_ring = &adapter->tx_ring[ring];
+ dev_info(&netdev->dev, "ring=%d\n", ring);
+ dev_info(&netdev->dev, "crb_intr_mask=%d\n",
+ readl(tx_ring->crb_intr_mask));
+ dev_info(&netdev->dev, "producer=%d\n",
+ readl(tx_ring->crb_cmd_producer));
+ dev_info(&netdev->dev, "sw_consumer = %d\n",
+ tx_ring->sw_consumer);
+ dev_info(&netdev->dev, "hw_consumer = %d\n",
+ le32_to_cpu(*(tx_ring->hw_consumer)));
+ dev_info(&netdev->dev, "xmit-on=%llu\n",
+ tx_ring->xmit_on);
+ dev_info(&netdev->dev, "xmit-off=%llu\n",
+ tx_ring->xmit_off);
+ }
+ }
adapter->ahw->reset_context = 1;
}
}
@@ -3380,15 +3497,15 @@ qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
}
int qlcnic_validate_max_rss(struct qlcnic_adapter *adapter,
- __u32 val)
+ __u32 val)
{
struct net_device *netdev = adapter->netdev;
u8 max_hw = adapter->ahw->max_rx_ques;
u32 max_allowed;
- if (val > QLC_MAX_SDS_RINGS) {
+ if (val > QLCNIC_MAX_SDS_RINGS) {
netdev_err(netdev, "RSS value should not be higher than %u\n",
- QLC_MAX_SDS_RINGS);
+ QLCNIC_MAX_SDS_RINGS);
return -EINVAL;
}
--
1.8.1.4
^ permalink raw reply related
* [PATCH net-next 4/5] qlcnic: Implement ndo_get_phys_port_id for 82xx adapter
From: Himanshu Madhani @ 2013-08-21 15:24 UTC (permalink / raw)
To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Shahed Shaikh, himanshu.madhani
In-Reply-To: <cover.1377122994.git.himanshu.madhani@qlogic.com>
From: Shahed Shaikh <shahed.shaikh@qlogic.com>
Each function driver instance uses the MAC address of the
lowest function belonging to that physical port as a unique
port identifier. This port identifier is read and cached in
driver during probe and provided to user space through
ndo_get_phys_port_id()
Signed-off-by: Shahed Shaikh <shahed.shaikh@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 17 ++++++++++---
.../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 4 +++-
.../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | 2 +-
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c | 5 ++--
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c | 16 +++++++++++++
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h | 2 +-
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 28 +++++++++++++++++++---
7 files changed, 63 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index 45a5a2a..9d8f80e 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -471,6 +471,7 @@ struct qlcnic_hardware_context {
u32 mbox_reg[4];
struct qlcnic_mailbox *mailbox;
u8 extend_lb_time;
+ u8 phys_port_id[ETH_ALEN];
};
struct qlcnic_adapter_stats {
@@ -926,6 +927,8 @@ struct qlcnic_ipaddr {
#define QLCNIC_FW_LRO_MSS_CAP 0x8000
#define QLCNIC_TX_INTR_SHARED 0x10000
#define QLCNIC_APP_CHANGED_FLAGS 0x20000
+#define QLCNIC_HAS_PHYS_PORT_ID 0x40000
+
#define QLCNIC_IS_MSI_FAMILY(adapter) \
((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
#define QLCNIC_IS_TSO_CAPABLE(adapter) \
@@ -1510,6 +1513,7 @@ void __qlcnic_set_multi(struct net_device *, u16);
int qlcnic_nic_add_mac(struct qlcnic_adapter *, const u8 *, u16);
int qlcnic_nic_del_mac(struct qlcnic_adapter *, const u8 *);
void qlcnic_82xx_free_mac_list(struct qlcnic_adapter *adapter);
+int qlcnic_82xx_read_phys_port_id(struct qlcnic_adapter *);
int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu);
int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *, u32);
@@ -1679,7 +1683,7 @@ struct qlcnic_hardware_ops {
int (*read_reg) (struct qlcnic_adapter *, ulong, int *);
int (*write_reg) (struct qlcnic_adapter *, ulong, u32);
void (*get_ocm_win) (struct qlcnic_hardware_context *);
- int (*get_mac_address) (struct qlcnic_adapter *, u8 *);
+ int (*get_mac_address) (struct qlcnic_adapter *, u8 *, u8);
int (*setup_intr) (struct qlcnic_adapter *, u8, int);
int (*alloc_mbx_args)(struct qlcnic_cmd_args *,
struct qlcnic_adapter *, u32);
@@ -1713,6 +1717,7 @@ struct qlcnic_hardware_ops {
int (*get_board_info) (struct qlcnic_adapter *);
void (*set_mac_filter_count) (struct qlcnic_adapter *);
void (*free_mac_list) (struct qlcnic_adapter *);
+ int (*read_phys_port_id) (struct qlcnic_adapter *);
};
extern struct qlcnic_nic_template qlcnic_vf_ops;
@@ -1741,9 +1746,9 @@ static inline int qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter,
}
static inline int qlcnic_get_mac_address(struct qlcnic_adapter *adapter,
- u8 *mac)
+ u8 *mac, u8 function)
{
- return adapter->ahw->hw_ops->get_mac_address(adapter, mac);
+ return adapter->ahw->hw_ops->get_mac_address(adapter, mac, function);
}
static inline int qlcnic_setup_intr(struct qlcnic_adapter *adapter,
@@ -1940,6 +1945,12 @@ static inline void qlcnic_set_mac_filter_count(struct qlcnic_adapter *adapter)
adapter->ahw->hw_ops->set_mac_filter_count(adapter);
}
+static inline void qlcnic_read_phys_port_id(struct qlcnic_adapter *adapter)
+{
+ if (adapter->ahw->hw_ops->read_phys_port_id)
+ adapter->ahw->hw_ops->read_phys_port_id(adapter);
+}
+
static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter,
u32 key)
{
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index ea44828..6c059f9 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -2037,12 +2037,14 @@ void qlcnic_83xx_configure_mac(struct qlcnic_adapter *adapter, u8 *mac,
cmd->req.arg[1] = type;
}
-int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
+int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac,
+ u8 function)
{
int err, i;
struct qlcnic_cmd_args cmd;
u32 mac_low, mac_high;
+ function = 0;
err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_MAC_ADDRESS);
if (err)
return err;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
index bfd2741..0fc5616 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
@@ -564,7 +564,7 @@ int qlcnic_83xx_setup_link_event(struct qlcnic_adapter *, int);
void qlcnic_83xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *);
int qlcnic_83xx_config_intrpt(struct qlcnic_adapter *, bool);
int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *, u8 *, u16, u8);
-int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *, u8 *);
+int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *, u8 *, u8);
void qlcnic_83xx_configure_mac(struct qlcnic_adapter *, u8 *, u8,
struct qlcnic_cmd_args *);
int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *,
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
index 2b68779..d4f0e95 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
@@ -821,7 +821,8 @@ int qlcnic_82xx_config_intrpt(struct qlcnic_adapter *adapter, u8 op_type)
return err;
}
-int qlcnic_82xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
+int qlcnic_82xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac,
+ u8 function)
{
int err, i;
struct qlcnic_cmd_args cmd;
@@ -831,7 +832,7 @@ int qlcnic_82xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
if (err)
return err;
- cmd.req.arg[1] = adapter->ahw->pci_func | BIT_8;
+ cmd.req.arg[1] = function | BIT_8;
err = qlcnic_issue_cmd(adapter, &cmd);
if (err == QLCNIC_RCODE_SUCCESS) {
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
index 9e49c15..f8adc7b 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -740,6 +740,22 @@ int qlcnic_82xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
return 0;
}
+int qlcnic_82xx_read_phys_port_id(struct qlcnic_adapter *adapter)
+{
+ u8 mac[ETH_ALEN];
+ int ret;
+
+ ret = qlcnic_get_mac_address(adapter, mac,
+ adapter->ahw->physical_port);
+ if (ret)
+ return ret;
+
+ memcpy(adapter->ahw->phys_port_id, mac, ETH_ALEN);
+ adapter->flags |= QLCNIC_HAS_PHYS_PORT_ID;
+
+ return 0;
+}
+
/*
* Send the interrupt coalescing parameter set by ethtool to the card.
*/
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
index cf35220..786366c 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
@@ -186,7 +186,7 @@ void qlcnic_82xx_fw_cmd_del_rx_ctx(struct qlcnic_adapter *);
void qlcnic_82xx_fw_cmd_del_tx_ctx(struct qlcnic_adapter *,
struct qlcnic_host_tx_ring *);
int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *, u8 *, u16, u8);
-int qlcnic_82xx_get_mac_address(struct qlcnic_adapter *, u8*);
+int qlcnic_82xx_get_mac_address(struct qlcnic_adapter *, u8*, u8);
int qlcnic_82xx_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8);
int qlcnic_82xx_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info*);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 25a858f..8321d1a 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -284,12 +284,15 @@ void qlcnic_free_sds_rings(struct qlcnic_recv_context *recv_ctx)
int qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
{
- u8 mac_addr[ETH_ALEN];
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
+ u8 mac_addr[ETH_ALEN];
+ int ret;
- if (qlcnic_get_mac_address(adapter, mac_addr) != 0)
- return -EIO;
+ ret = qlcnic_get_mac_address(adapter, mac_addr,
+ adapter->ahw->pci_func);
+ if (ret)
+ return ret;
memcpy(netdev->dev_addr, mac_addr, ETH_ALEN);
memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len);
@@ -431,6 +434,21 @@ static void qlcnic_82xx_cancel_idc_work(struct qlcnic_adapter *adapter)
cancel_delayed_work_sync(&adapter->fw_work);
}
+static int qlcnic_get_phys_port_id(struct net_device *netdev,
+ struct netdev_phys_port_id *ppid)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ if (!(adapter->flags & QLCNIC_HAS_PHYS_PORT_ID))
+ return -EOPNOTSUPP;
+
+ ppid->id_len = sizeof(ahw->phys_port_id);
+ memcpy(ppid->id, ahw->phys_port_id, ppid->id_len);
+
+ return 0;
+}
+
static const struct net_device_ops qlcnic_netdev_ops = {
.ndo_open = qlcnic_open,
.ndo_stop = qlcnic_close,
@@ -448,6 +466,7 @@ static const struct net_device_ops qlcnic_netdev_ops = {
.ndo_fdb_add = qlcnic_fdb_add,
.ndo_fdb_del = qlcnic_fdb_del,
.ndo_fdb_dump = qlcnic_fdb_dump,
+ .ndo_get_phys_port_id = qlcnic_get_phys_port_id,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = qlcnic_poll_controller,
#endif
@@ -520,6 +539,7 @@ static struct qlcnic_hardware_ops qlcnic_hw_ops = {
.get_board_info = qlcnic_82xx_get_board_info,
.set_mac_filter_count = qlcnic_82xx_set_mac_filter_count,
.free_mac_list = qlcnic_82xx_free_mac_list,
+ .read_phys_port_id = qlcnic_82xx_read_phys_port_id,
};
static void qlcnic_get_multiq_capability(struct qlcnic_adapter *adapter)
@@ -2245,6 +2265,8 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (qlcnic_read_mac_addr(adapter))
dev_warn(&pdev->dev, "failed to read mac addr\n");
+ qlcnic_read_phys_port_id(adapter);
+
if (adapter->portnum == 0) {
qlcnic_get_board_name(adapter, board_name);
--
1.8.1.4
^ permalink raw reply related
* [PATCH net-next 0/5] qlcnic: Implement Multi Tx queues and ndo_get_phys_port support for 82xx.
From: Himanshu Madhani @ 2013-08-21 15:24 UTC (permalink / raw)
To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Himanshu Madhani
From: Himanshu Madhani <himanshu.madhani@qlogic.com>
This patch series contains following updates
o Patches for enabling multiple Tx queues for 82xx series adapter
o Patch to implement ndo_get_phys_port support for 82xx series adapter.
Please apply to net-next.
Thanks,
Himanshu
Himanshu Madhani (4):
qlcnic: Multi Tx queue support for 82xx Series adapter.
qlcnic: Enable Tx queue changes using ethtool for 82xx Series adapter.
qlcnic: Enable diagnostic test for multiple Tx queues.
qlcnic: Update version to 5.3.48
Shahed Shaikh (1):
qlcnic: Implement ndo_get_phys_port_id for 82xx adapter
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 107 +++++++-
.../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 12 +-
.../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | 4 +-
.../net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | 2 +-
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c | 206 +++++++++++----
.../net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c | 65 ++++-
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c | 18 +-
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h | 8 +-
drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c | 12 +-
drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | 145 +++++++++--
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 284 ++++++++++++++++++---
.../ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | 2 +-
12 files changed, 711 insertions(+), 154 deletions(-)
--
1.8.1.4
^ permalink raw reply
* [PATCH net-next 2/5] qlcnic: Enable Tx queue changes using ethtool for 82xx Series adapter.
From: Himanshu Madhani @ 2013-08-21 15:24 UTC (permalink / raw)
To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Himanshu Madhani
In-Reply-To: <cover.1377122994.git.himanshu.madhani@qlogic.com>
From: Himanshu Madhani <himanshu.madhani@qlogic.com>
o using ethtool {set|get}_channel option, user can change number
of Tx queues for 82xx Series adapter.
o updated ethtool -S <ethX> option to display stats from each Tx queue.
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 10 ++-
.../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 2 +-
.../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | 2 +-
.../net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | 2 +-
.../net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c | 63 +++++++++++---
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h | 3 +-
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 96 +++++++++++++++++++---
.../ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | 2 +-
8 files changed, 145 insertions(+), 35 deletions(-)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index 2f9985f..101b538 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -1531,8 +1531,9 @@ int qlcnic_reset_context(struct qlcnic_adapter *);
void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings);
int qlcnic_diag_alloc_res(struct net_device *netdev, int test);
netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
-int qlcnic_set_max_rss(struct qlcnic_adapter *, u8, size_t);
+int qlcnic_set_max_rss(struct qlcnic_adapter *, u8, int);
int qlcnic_validate_max_rss(struct qlcnic_adapter *, __u32);
+int qlcnic_validate_max_tx_rings(struct qlcnic_adapter *, int);
void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter);
void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *);
int qlcnic_enable_msix(struct qlcnic_adapter *, u32);
@@ -1679,7 +1680,7 @@ struct qlcnic_hardware_ops {
int (*write_reg) (struct qlcnic_adapter *, ulong, u32);
void (*get_ocm_win) (struct qlcnic_hardware_context *);
int (*get_mac_address) (struct qlcnic_adapter *, u8 *);
- int (*setup_intr) (struct qlcnic_adapter *, u8);
+ int (*setup_intr) (struct qlcnic_adapter *, u8, int);
int (*alloc_mbx_args)(struct qlcnic_cmd_args *,
struct qlcnic_adapter *, u32);
int (*mbx_cmd) (struct qlcnic_adapter *, struct qlcnic_cmd_args *);
@@ -1745,9 +1746,10 @@ static inline int qlcnic_get_mac_address(struct qlcnic_adapter *adapter,
return adapter->ahw->hw_ops->get_mac_address(adapter, mac);
}
-static inline int qlcnic_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
+static inline int qlcnic_setup_intr(struct qlcnic_adapter *adapter,
+ u8 num_intr, int txq)
{
- return adapter->ahw->hw_ops->setup_intr(adapter, num_intr);
+ return adapter->ahw->hw_ops->setup_intr(adapter, num_intr, txq);
}
static inline int qlcnic_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index f0dc5d4..ea44828 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -261,7 +261,7 @@ int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *adapter, ulong addr,
}
}
-int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
+int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr, int txq)
{
int err, i, num_msix;
struct qlcnic_hardware_context *ahw = adapter->ahw;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
index d4c58c6..bfd2741 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
@@ -523,7 +523,7 @@ enum qlc_83xx_ext_regs {
/* 83xx funcitons */
int qlcnic_83xx_get_fw_version(struct qlcnic_adapter *);
int qlcnic_83xx_issue_cmd(struct qlcnic_adapter *, struct qlcnic_cmd_args *);
-int qlcnic_83xx_setup_intr(struct qlcnic_adapter *, u8);
+int qlcnic_83xx_setup_intr(struct qlcnic_adapter *, u8, int);
void qlcnic_83xx_get_func_no(struct qlcnic_adapter *);
int qlcnic_83xx_cam_lock(struct qlcnic_adapter *);
void qlcnic_83xx_cam_unlock(struct qlcnic_adapter *);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
index f23e667..fb0ef36 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -2201,7 +2201,7 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
if (err)
goto detach_mbx;
- err = qlcnic_setup_intr(adapter, 0);
+ err = qlcnic_setup_intr(adapter, 0, 0);
if (err) {
dev_err(&adapter->pdev->dev, "Failed to setup interrupt\n");
goto disable_intr;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
index 79a5855..583dc2b 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
@@ -125,6 +125,14 @@ static const char qlcnic_83xx_mac_stats_strings[][ETH_GSTRING_LEN] = {
};
#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
+
+static const char qlcnic_tx_ring_stats_strings[][ETH_GSTRING_LEN] = {
+ "xmit_on",
+ "xmit_off",
+ "xmit_called",
+ "xmit_finished",
+};
+
static const char qlcnic_83xx_rx_stats_strings[][ETH_GSTRING_LEN] = {
"ctx_rx_bytes",
"ctx_rx_pkts",
@@ -630,15 +638,15 @@ qlcnic_set_ringparam(struct net_device *dev,
static void qlcnic_get_channels(struct net_device *dev,
struct ethtool_channels *channel)
{
- int min;
struct qlcnic_adapter *adapter = netdev_priv(dev);
+ int min;
min = min_t(int, adapter->ahw->max_rx_ques, num_online_cpus());
channel->max_rx = rounddown_pow_of_two(min);
- channel->max_tx = adapter->ahw->max_tx_ques;
+ channel->max_tx = min_t(int, QLCNIC_MAX_TX_RINGS, num_online_cpus());
channel->rx_count = adapter->max_sds_rings;
- channel->tx_count = adapter->ahw->max_tx_ques;
+ channel->tx_count = adapter->max_drv_tx_rings;
}
static int qlcnic_set_channels(struct net_device *dev,
@@ -646,18 +654,27 @@ static int qlcnic_set_channels(struct net_device *dev,
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
int err;
+ int txq = 0;
- if (channel->other_count || channel->combined_count ||
- channel->tx_count != channel->max_tx)
+ if (channel->other_count || channel->combined_count)
return -EINVAL;
- err = qlcnic_validate_max_rss(adapter, channel->rx_count);
- if (err)
- return err;
+ if (channel->rx_count) {
+ err = qlcnic_validate_max_rss(adapter, channel->rx_count);
+ if (err)
+ return err;
+ }
+
+ if (channel->tx_count) {
+ err = qlcnic_validate_max_tx_rings(adapter, channel->tx_count);
+ if (err)
+ return err;
+ txq = channel->tx_count;
+ }
- err = qlcnic_set_max_rss(adapter, channel->rx_count, 0);
- netdev_info(dev, "allocated 0x%x sds rings\n",
- adapter->max_sds_rings);
+ err = qlcnic_set_max_rss(adapter, channel->rx_count, txq);
+ netdev_info(dev, "allocated 0x%x sds rings and 0x%x tx rings\n",
+ adapter->max_sds_rings, adapter->max_drv_tx_rings);
return err;
}
@@ -893,6 +910,7 @@ free_diag_res:
clear_diag_irq:
adapter->max_sds_rings = max_sds_rings;
clear_bit(__QLCNIC_RESETTING, &adapter->state);
+
return ret;
}
@@ -1077,11 +1095,21 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
QLCNIC_TEST_LEN * ETH_GSTRING_LEN);
break;
case ETH_SS_STATS:
+ num_stats = ARRAY_SIZE(qlcnic_tx_ring_stats_strings);
+ for (i = 0; i < adapter->max_drv_tx_rings; i++) {
+ for (index = 0; index < num_stats; index++) {
+ sprintf(data, "tx_ring_%d %s", i,
+ qlcnic_tx_ring_stats_strings[index]);
+ data += ETH_GSTRING_LEN;
+ }
+ }
+
for (index = 0; index < QLCNIC_STATS_LEN; index++) {
memcpy(data + index * ETH_GSTRING_LEN,
qlcnic_gstrings_stats[index].stat_string,
ETH_GSTRING_LEN);
}
+
if (qlcnic_83xx_check(adapter)) {
num_stats = ARRAY_SIZE(qlcnic_83xx_tx_stats_strings);
for (i = 0; i < num_stats; i++, index++)
@@ -1173,11 +1201,22 @@ static void qlcnic_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *data)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
+ struct qlcnic_host_tx_ring *tx_ring;
struct qlcnic_esw_statistics port_stats;
struct qlcnic_mac_statistics mac_stats;
- int index, ret, length, size;
+ int index, ret, length, size, ring;
char *p;
+ memset(data, 0, adapter->max_drv_tx_rings * 4 * sizeof(u64));
+ for (ring = 0, index = 0; ring < adapter->max_drv_tx_rings; ring++) {
+ if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
+ tx_ring = &adapter->tx_ring[ring];
+ *data++ = tx_ring->xmit_on;
+ *data++ = tx_ring->xmit_off;
+ *data++ = tx_ring->xmit_called;
+ *data++ = tx_ring->xmit_finished;
+ }
+ }
memset(data, 0, stats->n_stats * sizeof(u64));
length = QLCNIC_STATS_LEN;
for (index = 0; index < length; index++) {
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
index e9a2225..cf35220 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
@@ -150,7 +150,6 @@ struct ethtool_stats;
struct pci_device_id;
struct qlcnic_host_sds_ring;
struct qlcnic_host_tx_ring;
-struct qlcnic_host_tx_ring;
struct qlcnic_hardware_context;
struct qlcnic_adapter;
@@ -174,7 +173,7 @@ int qlcnic_82xx_set_lb_mode(struct qlcnic_adapter *, u8);
void qlcnic_82xx_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
void qlcnic_82xx_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *, u32);
-int qlcnic_82xx_setup_intr(struct qlcnic_adapter *, u8);
+int qlcnic_82xx_setup_intr(struct qlcnic_adapter *, u8, int);
irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *);
int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
struct qlcnic_cmd_args *);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index af2b2e2..94b3e82 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -656,7 +656,7 @@ static int qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
return err;
}
-int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
+int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr, int txq)
{
struct qlcnic_hardware_context *ahw = adapter->ahw;
int num_msix, err = 0;
@@ -667,8 +667,11 @@ int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
if (ahw->msix_supported) {
num_msix = rounddown_pow_of_two(min_t(int, num_online_cpus(),
num_intr));
- if (qlcnic_check_multi_tx(adapter))
+ if (qlcnic_check_multi_tx(adapter)) {
+ if (txq)
+ adapter->max_drv_tx_rings = txq;
num_msix += adapter->max_drv_tx_rings;
+ }
} else {
num_msix = 1;
}
@@ -1990,11 +1993,9 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,
netdev->priv_flags |= IFF_UNICAST_FLT;
netdev->irq = adapter->msix_entries[0].vector;
- if (qlcnic_82xx_check(adapter) && qlcnic_check_multi_tx(adapter)) {
- err = qlcnic_set_real_num_queues(adapter, netdev);
- if (err)
- return err;
- }
+ err = qlcnic_set_real_num_queues(adapter, netdev);
+ if (err)
+ return err;
err = register_netdev(netdev);
if (err) {
@@ -2253,7 +2254,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
"Device does not support MSI interrupts\n");
if (qlcnic_82xx_check(adapter)) {
- err = qlcnic_setup_intr(adapter, 0);
+ err = qlcnic_setup_intr(adapter, 0, 0);
if (err) {
dev_err(&pdev->dev, "Failed to setup interrupt\n");
goto err_out_disable_msi;
@@ -3371,7 +3372,7 @@ static int qlcnic_attach_func(struct pci_dev *pdev)
qlcnic_clr_drv_state(adapter);
kfree(adapter->msix_entries);
adapter->msix_entries = NULL;
- err = qlcnic_setup_intr(adapter, 0);
+ err = qlcnic_setup_intr(adapter, 0, 0);
if (err) {
kfree(adapter->msix_entries);
@@ -3496,6 +3497,49 @@ qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
return err;
}
+int qlcnic_validate_max_tx_rings(struct qlcnic_adapter *adapter, int txq)
+{
+ struct net_device *netdev = adapter->netdev;
+ u8 max_hw = QLCNIC_MAX_TX_RINGS;
+ u32 max_allowed;
+
+ if (!qlcnic_82xx_check(adapter)) {
+ netdev_err(netdev, "No Multi TX-Q support\n");
+ return -EINVAL;
+ }
+
+ if (!qlcnic_use_msi_x && !qlcnic_use_msi) {
+ netdev_err(netdev, "No Multi TX-Q support in INT-x mode\n");
+ return -EINVAL;
+ }
+
+ if (!qlcnic_check_multi_tx(adapter)) {
+ netdev_err(netdev, "No Multi TX-Q support\n");
+ return -EINVAL;
+ }
+
+ if (txq > QLCNIC_MAX_TX_RINGS) {
+ netdev_err(netdev, "Invalid ring count\n");
+ return -EINVAL;
+ }
+
+ max_allowed = rounddown_pow_of_two(min_t(int, max_hw,
+ num_online_cpus()));
+ if ((txq > max_allowed) || !is_power_of_2(txq)) {
+ if (!is_power_of_2(txq))
+ netdev_err(netdev,
+ "TX queue should be a power of 2\n");
+ if (txq > num_online_cpus())
+ netdev_err(netdev,
+ "Tx queue should not be higher than [%u], number of online CPUs in the system\n",
+ num_online_cpus());
+ netdev_err(netdev, "Unable to configure %u Tx rings\n", txq);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
int qlcnic_validate_max_rss(struct qlcnic_adapter *adapter,
__u32 val)
{
@@ -3503,6 +3547,12 @@ int qlcnic_validate_max_rss(struct qlcnic_adapter *adapter,
u8 max_hw = adapter->ahw->max_rx_ques;
u32 max_allowed;
+ if (qlcnic_82xx_check(adapter) && !qlcnic_use_msi_x &&
+ !qlcnic_use_msi) {
+ netdev_err(netdev, "No RSS support in INT-x mode\n");
+ return -EINVAL;
+ }
+
if (val > QLCNIC_MAX_SDS_RINGS) {
netdev_err(netdev, "RSS value should not be higher than %u\n",
QLCNIC_MAX_SDS_RINGS);
@@ -3535,27 +3585,48 @@ int qlcnic_validate_max_rss(struct qlcnic_adapter *adapter,
return 0;
}
-int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data, size_t len)
+int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data, int txq)
{
int err;
struct net_device *netdev = adapter->netdev;
+ int num_msix;
if (test_bit(__QLCNIC_RESETTING, &adapter->state))
return -EBUSY;
+ if (qlcnic_82xx_check(adapter) && !qlcnic_use_msi_x &&
+ !qlcnic_use_msi) {
+ netdev_err(netdev, "No RSS support in INT-x mode\n");
+ return -EINVAL;
+ }
+
netif_device_detach(netdev);
if (netif_running(netdev))
__qlcnic_down(adapter, netdev);
qlcnic_detach(adapter);
+ if (qlcnic_82xx_check(adapter)) {
+ if (txq != 0)
+ adapter->max_drv_tx_rings = txq;
+
+ if (qlcnic_check_multi_tx(adapter) &&
+ (txq > adapter->max_drv_tx_rings))
+ num_msix = adapter->max_drv_tx_rings;
+ else
+ num_msix = data;
+ }
+
if (qlcnic_83xx_check(adapter)) {
qlcnic_83xx_free_mbx_intr(adapter);
qlcnic_83xx_enable_mbx_poll(adapter);
}
+ netif_set_real_num_tx_queues(netdev, adapter->max_drv_tx_rings);
+
qlcnic_teardown_intr(adapter);
- err = qlcnic_setup_intr(adapter, data);
+
+ err = qlcnic_setup_intr(adapter, data, txq);
if (err) {
kfree(adapter->msix_entries);
netdev_err(netdev, "failed to setup interrupt\n");
@@ -3583,8 +3654,7 @@ int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data, size_t len)
goto done;
qlcnic_restore_indev_addr(netdev, NETDEV_UP);
}
- err = len;
- done:
+done:
netif_device_attach(netdev);
clear_bit(__QLCNIC_RESETTING, &adapter->state);
return err;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
index b2fbefc..2f79ec5 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
@@ -512,7 +512,7 @@ static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter,
dev_warn(&adapter->pdev->dev,
"Device does not support MSI interrupts\n");
- err = qlcnic_setup_intr(adapter, 1);
+ err = qlcnic_setup_intr(adapter, 1, 0);
if (err) {
dev_err(&adapter->pdev->dev, "Failed to setup interrupt\n");
goto err_out_disable_msi;
--
1.8.1.4
^ permalink raw reply related
* Re: [PATCH 2/2] net: netem: always adjust now/delay when not reordering
From: Eric Dumazet @ 2013-08-21 15:39 UTC (permalink / raw)
To: Johannes Naab; +Cc: mailings, netdev
In-Reply-To: <5214D9F2.90900@stusta.de>
On Wed, 2013-08-21 at 17:17 +0200, Johannes Naab wrote:
> On 08/20/2013 05:11 PM, Ferry Huberts wrote:
> > From: Ferry Huberts <ferry.huberts@pelagic.nl>
> >
> > Not doing this (current behaviour) introduces reordering.
> >
> > The packet_len_2_sched_time call is the only thing that logically
> > depends on q->rate, so move the now/delay adjustment out of the if.
> >
> > Signed-off-by: Ferry Huberts <ferry.huberts@pelagic.nl>
> > ---
>
> Hi,
>
> The documentation for netem does explicitly mention the reordering with
> jitter, and gives instructions on how to avoid it. (I have not tested if
> it works as intended).
Yes.
The user specifically adds a random delay of 0 to 510 ms to packets,
and expect netem to not reorder packets sent every 100ms.
They see netem as a single medium between two endpoints with a guarantee
of no reordering, and cumulative delays.
So if you send a burst of 100 packets, they might expect the last packet
will be send after ~50 seconds.
This clearly needs a new option to netem, because this is not the
default behavior we want.
^ permalink raw reply
* Re: [PATCH 2/2] net: netem: always adjust now/delay when not reordering
From: Johannes Naab @ 2013-08-21 15:17 UTC (permalink / raw)
To: mailings; +Cc: netdev, eric.dumazet
In-Reply-To: <1377011469-26151-2-git-send-email-mailings@hupie.com>
On 08/20/2013 05:11 PM, Ferry Huberts wrote:
> From: Ferry Huberts <ferry.huberts@pelagic.nl>
>
> Not doing this (current behaviour) introduces reordering.
>
> The packet_len_2_sched_time call is the only thing that logically
> depends on q->rate, so move the now/delay adjustment out of the if.
>
> Signed-off-by: Ferry Huberts <ferry.huberts@pelagic.nl>
> ---
Hi,
The documentation for netem does explicitly mention the reordering with
jitter, and gives instructions on how to avoid it. (I have not tested if
it works as intended).
http://www.linuxfoundation.org/collaborate/workgroups/networking/netem#How_to_reorder_packets_based_on_jitter.3F
Could you test if that fixes your problem already?
Assuming that the documentation is right:
For the sake of stability I strongly oppose changing existing and
documented behavior without opt-in. (Then again I'm not involved in
kernel development.)
If the documentation turns out to be wrong:
The netem rate extension (with all the reordering changes for that case,
which are needed for proper rate emulation in that model) was introduced
in 3.3 by Hagen Paul Pfeifer
http://marc.info/?l=linux-netdev&m=132215646820338&w=2. You could ping
him, and try to get his input/Acked-by on your patch. I only did some
bug fixing in 3.8 http://marc.info/?l=linux-netdev&m=135897762224399&w=2.
Best regards,
Johannes
--
^ permalink raw reply
* Re: [PATCH RFC net-next] net: epoll support for busy poll
From: Eliezer Tamir @ 2013-08-21 15:09 UTC (permalink / raw)
To: Eric Dumazet
Cc: David Miller, linux-kernel, netdev, e1000-devel, Eilon Greenstein,
Amir Vadai, Willem de Bruijn, Eliezer Tamir
In-Reply-To: <1377093188.4226.108.camel@edumazet-glaptop>
On 21/08/2013 16:53, Eric Dumazet wrote:
> On Wed, 2013-08-21 at 13:39 +0300, Eliezer Tamir wrote:
>
>>
>> Instead of remembering the napi_id for all the sockets in an epoll,
>> we only track the first socket we see with any unique napi_id.
>> The rational for this is that while there may be many thousands of
>> sockets tracked by a single epoll, we expect to only see a handful
>> of unique napi_ids in most cases.
>
> This looks buggy assumption to me.
>
> We use epoll() with in the order of millions of fds per epoller, and
> typically one napi_id per cpu.
>
> With your model, we would have to use nr_cpu epollers and make sure that
> sockets are properly placed on those epollers by their napi_ids.
There is no assumption here on how the user configures epoll.
All we are doing is reducing the list of sockets monitored
by an epoll instance to a smaller subset where each NAPI_ID
appears only once.
The user is free to have an epoll monitor sockets from queues
associated to any CPU.
^ permalink raw reply
* Re: [PATCH] be2net: fix disabling TX in be_close()
From: Sergei Shtylyov @ 2013-08-21 14:48 UTC (permalink / raw)
To: Sathya Perla; +Cc: netdev
In-Reply-To: <1377080534-19509-1-git-send-email-sathya.perla@emulex.com>
Hello.
On 21-08-2013 14:22, Sathya Perla wrote:
> commit fba875591 disabled TX in be_close() to protect be_xmit() from
Please also specify that commit's summary line in parens.
> touching freed up queues in the AER recovery flow.
> But, TX must be disabled *before* cleaning up TX completions in the
> close() path, not after. This allows be_tx_compl_clean() to free up
> all TX-req skbs that were notified to the HW.
> Signed-off-by: Sathya Perla <sathya.perla@emulex.com>
WBR, Sergei
^ permalink raw reply
* Re: [PATCH 1/2] SH7619: fix Ether support
From: Sergei Shtylyov @ 2013-08-21 14:20 UTC (permalink / raw)
To: netdev; +Cc: lethal, linux-sh, davem
In-Reply-To: <201308180215.43063.sergei.shtylyov@cogentembedded.com>
Hello.
On 18-08-2013 2:15, Sergei Shtylyov wrote:
> The 'sh_eth' driver's probe will crash as the platform code is hopelessly behind
> the platform data -- it passes PHY ID instead of 'struct sh_eth_plat_data *'.
> Strangely, both commit d88a3ea6fa4c (SH7619 add ethernet controler support) that
> added the platform code and commit 71557a37adb5 ([netdrvr] sh_eth: Add SH7619
> support) were done in about the same time, yet the latter one added 'struct
> sh_eth_plat_data' and the platform code didn't ever get updated...
>
> Add the proper platform data and fix off-by-one memory resource end error, while
> at it...
> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
> Cc: stable@vger.kernel.org
> ---
> arch/sh/kernel/cpu/sh2/setup-sh7619.c | 12 ++++++++++--
> 1 file changed, 10 insertions(+), 2 deletions(-)
> Index: net/arch/sh/kernel/cpu/sh2/setup-sh7619.c
> ===================================================================
> --- net.orig/arch/sh/kernel/cpu/sh2/setup-sh7619.c
> +++ net/arch/sh/kernel/cpu/sh2/setup-sh7619.c
[...]
> @@ -110,10 +111,17 @@ static struct platform_device scif2_devi
> },
> };
>
> +static struct sh_eth_plat_data eth_platform_data = {
> + .phy = 1,
> + .edmac_endian = EDMAC_LITTLE_ENDIAN,
> + .register_type = SH_ETH_REG_FAST_SH3_SH2,
> + .phy_interace = PHY_INTERFACE_MODE_MII,
Grr, I forgot to compile test this patch as the kbuild test robot just
told me... s/phy_interace/phy_interface/. I'll send a fix today.
WBR, Sergei
^ permalink raw reply
* Re: [PATCH v2 2/2] net: netem: always adjust now/delay when not reordering
From: mailings @ 2013-08-21 14:10 UTC (permalink / raw)
To: mailings; +Cc: Eric Dumazet, Ferry Huberts, netdev
In-Reply-To: <59065.80.101.237.101.1377093746.squirrel@hupie.dyndns.org>
>> On Wed, 2013-08-21 at 09:04 +0200, Ferry Huberts wrote:
>>> On 21/08/13 08:14, Eric Dumazet wrote:
>>> > On Wed, 2013-08-21 at 07:59 +0200, Ferry Huberts wrote:
>>> >> From: Ferry Huberts <ferry.huberts@pelagic.nl>
>>> >>
>>> >> Not doing this (current behaviour) introduces reordering.
>>> >>
>>> >> The packet_len_2_sched_time call is the only thing that logically
> depends on q->rate, so move the now/delay adjustment out of the if.
>>> >>
>>> >> How to test:
>>> >> -----------
>>> >
>>> > I ask again :
>>> >
>>> > Did you test a config with both rate limiting and delay.
>>> (sorry for missing that question)
>>> Just did so and with rate limiting I get no reordering, which is
> logical
>>> looking at the code.
>>> The thing is, the evaluation q->rate is within the 'no-reordering'
> block
>>> and in the current situation you can get reordering (with that
> 'strange'
>>> command). My patch makes sure that no reordering will occur, and
> effectively 'clamps' the realised delay, which currently isn't done.
>>
>>
>> OK, let me be very clear.
>>
>> I would like you post the results of regression tests, to make sure that
> you do not add a new regression.
>>
>
> Since I'm new to netdev development and therefore the processes attached
> to it, let me ask where I can find such regression tests?
>
> I'm happy to run them once I know about them... ;-)
>
>
>> It seems that you want _us_ to check all this for you.
>>
>> With "rate 1Mbits delay 100ms 10ms", and ping probes sent every 100ms,
> the pong reply of _all_ probes should be between 90ms and 110ms
>>
>> Is it still the case after your patch ?
>>
>
> Yes it is.
>
> In the script I described in the commit message I replaced the line
> tc qdisc add dev "${fields[1]}" handle 1 root netem delay 10ms 500ms
> with the line (1Mbit gave 'Illegal "rate"')
> tc qdisc add dev "${fields[1]}" handle 1 root netem rate 1024000 delay
> 100ms 10ms
>
> The output then was (tried a 10 times):
> # ./netemreordering
> PING 192.168.160.1 (192.168.160.1) 56(84) bytes of data.
> 64 bytes from 192.168.160.1: icmp_seq=1 ttl=254 time=114 ms
Wow. And of course Murphy would do this.
This is the _only_ deviation there was and I copy&pasted it...
I re-checked and it really is the only one.
I re-ran 20 more times and all were ok.
Must have been a busy router I guess.
> 64 bytes from 192.168.160.1: icmp_seq=2 ttl=254 time=109 ms
> 64 bytes from 192.168.160.1: icmp_seq=3 ttl=254 time=106 ms
> 64 bytes from 192.168.160.1: icmp_seq=4 ttl=254 time=100 ms
> 64 bytes from 192.168.160.1: icmp_seq=5 ttl=254 time=111 ms
> 64 bytes from 192.168.160.1: icmp_seq=6 ttl=254 time=92.2 ms
> 64 bytes from 192.168.160.1: icmp_seq=7 ttl=254 time=99.8 ms
> 64 bytes from 192.168.160.1: icmp_seq=8 ttl=254 time=91.4 ms
> 64 bytes from 192.168.160.1: icmp_seq=9 ttl=254 time=97.4 ms
> 64 bytes from 192.168.160.1: icmp_seq=10 ttl=254 time=95.5 ms
>
> --- 192.168.160.1 ping statistics ---
> 10 packets transmitted, 10 received, 0% packet loss, time 910ms
> rtt min/avg/max/mdev = 91.413/101.879/114.534/7.723 ms, pipe 2
>
>
> Is this enough?
> Please let me know, I'm happy to oblige.
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* [PATCH 0/2] fix generic netlink locking issue(s)
From: Johannes Berg @ 2013-08-21 14:08 UTC (permalink / raw)
To: netdev; +Cc: Thomas Graf
Here's another attempt at fixing the genetlink locking issue,
hopefully better tested this time. Sorry about the mess the
previous version caused.
I really didn't find a way to "simply" add locking, no matter
which way I turn genetlink is special because it would then use
the same locks "inside" and "outside" the generic netlink family;
"inside" because I'm trying to protect the otherwise unlocked
dump call, and "outside" because it itself is a generic netlink
family so needs to protect things there.
As a result, I've turned to RCU and (hopefully) made it safe.
The unregistration can get fairly expensive with all the calls
to synchronize_rcu(), but I don't see any better way, and it's
hopefully really rare.
The only place that now uses RCU is ctrl_dumpfamily(), but it'd
be possible to use it in other places. I didn't want to do it
in this patch, but I also don't see any candidates where that
would really make sense.
The first patch should obviously go into 3.11, I'll let you
decide about the second. This one might actually be easier to
backport than the original one, but it'd still have to be done
carefully.
johannes
^ permalink raw reply
* [PATCH 2/2] genetlink: convert family dump code to use RCU
From: Johannes Berg @ 2013-08-21 14:08 UTC (permalink / raw)
To: netdev; +Cc: Thomas Graf, Johannes Berg
In-Reply-To: <1377094083-8122-1-git-send-email-johannes@sipsolutions.net>
From: Johannes Berg <johannes.berg@intel.com>
In my previous commit 58ad436fcf49810aa006016107f494c9ac9013db
("genetlink: fix family dump race") I attempted to solve an
issue in generic netlink that could lead to crashes, but it
turns out that this introduced a possibility for deadlock. As
I haven't found a way to actually add locking without causing
that, convert the family, family ops/mcast group lists all to
use RCU, so the family dump code can simply use RCU protection
instead of locking.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/netlink/genetlink.c | 25 ++++++++++++++++---------
1 file changed, 16 insertions(+), 9 deletions(-)
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 512718a..2027964 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -222,7 +222,7 @@ int genl_register_mc_group(struct genl_family *family,
grp->id = id;
set_bit(id, mc_groups);
- list_add_tail(&grp->list, &family->mcast_groups);
+ list_add_tail_rcu(&grp->list, &family->mcast_groups);
grp->family = family;
genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, grp);
@@ -246,7 +246,7 @@ static void __genl_unregister_mc_group(struct genl_family *family,
netlink_table_ungrab();
clear_bit(grp->id, mc_groups);
- list_del(&grp->list);
+ list_del_rcu(&grp->list);
genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp);
grp->id = 0;
grp->family = NULL;
@@ -272,6 +272,7 @@ void genl_unregister_mc_group(struct genl_family *family,
genl_lock_all();
__genl_unregister_mc_group(family, grp);
genl_unlock_all();
+ synchronize_rcu();
}
EXPORT_SYMBOL(genl_unregister_mc_group);
@@ -281,6 +282,7 @@ static void genl_unregister_mc_groups(struct genl_family *family)
list_for_each_entry_safe(grp, tmp, &family->mcast_groups, list)
__genl_unregister_mc_group(family, grp);
+ synchronize_rcu();
}
/**
@@ -318,7 +320,7 @@ int genl_register_ops(struct genl_family *family, struct genl_ops *ops)
ops->flags |= GENL_CMD_CAP_HASPOL;
genl_lock_all();
- list_add_tail(&ops->ops_list, &family->ops_list);
+ list_add_tail_rcu(&ops->ops_list, &family->ops_list);
genl_unlock_all();
genl_ctrl_event(CTRL_CMD_NEWOPS, ops);
@@ -351,9 +353,10 @@ int genl_unregister_ops(struct genl_family *family, struct genl_ops *ops)
genl_lock_all();
list_for_each_entry(rc, &family->ops_list, ops_list) {
if (rc == ops) {
- list_del(&ops->ops_list);
+ list_del_rcu(&ops->ops_list);
genl_unlock_all();
genl_ctrl_event(CTRL_CMD_DELOPS, ops);
+ synchronize_rcu();
return 0;
}
}
@@ -418,7 +421,7 @@ int genl_register_family(struct genl_family *family)
} else
family->attrbuf = NULL;
- list_add_tail(&family->family_list, genl_family_chain(family->id));
+ list_add_tail_rcu(&family->family_list, genl_family_chain(family->id));
genl_unlock_all();
genl_ctrl_event(CTRL_CMD_NEWFAMILY, family);
@@ -498,7 +501,8 @@ int genl_unregister_family(struct genl_family *family)
if (family->id != rc->id || strcmp(rc->name, family->name))
continue;
- list_del(&rc->family_list);
+ list_del_rcu(&rc->family_list);
+ synchronize_rcu();
INIT_LIST_HEAD(&family->ops_list);
genl_unlock_all();
@@ -692,7 +696,7 @@ static int ctrl_fill_info(struct genl_family *family, u32 portid, u32 seq,
if (nla_ops == NULL)
goto nla_put_failure;
- list_for_each_entry(ops, &family->ops_list, ops_list) {
+ list_for_each_entry_rcu(ops, &family->ops_list, ops_list) {
struct nlattr *nest;
nest = nla_nest_start(skb, idx++);
@@ -718,7 +722,7 @@ static int ctrl_fill_info(struct genl_family *family, u32 portid, u32 seq,
if (nla_grps == NULL)
goto nla_put_failure;
- list_for_each_entry(grp, &family->mcast_groups, list) {
+ list_for_each_entry_rcu(grp, &family->mcast_groups, list) {
struct nlattr *nest;
nest = nla_nest_start(skb, idx++);
@@ -790,9 +794,10 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
int chains_to_skip = cb->args[0];
int fams_to_skip = cb->args[1];
+ rcu_read_lock();
for (i = chains_to_skip; i < GENL_FAM_TAB_SIZE; i++) {
n = 0;
- list_for_each_entry(rt, genl_family_chain(i), family_list) {
+ list_for_each_entry_rcu(rt, genl_family_chain(i), family_list) {
if (!rt->netnsok && !net_eq(net, &init_net))
continue;
if (++n < fams_to_skip)
@@ -807,6 +812,8 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
}
errout:
+ rcu_read_unlock();
+
cb->args[0] = i;
cb->args[1] = n;
--
1.8.4.rc2
^ permalink raw reply related
* [PATCH 1/2] Revert "genetlink: fix family dump race"
From: Johannes Berg @ 2013-08-21 14:08 UTC (permalink / raw)
To: netdev; +Cc: Thomas Graf, Johannes Berg
In-Reply-To: <1377094083-8122-1-git-send-email-johannes@sipsolutions.net>
From: Johannes Berg <johannes.berg@intel.com>
This reverts commit 58ad436fcf49810aa006016107f494c9ac9013db.
It turns out that the change introduced a potential deadlock
by causing a locking dependency with netlink's cb_mutex. I
can't seem to find a way to resolve this without doing major
changes to the locking, so revert this.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/netlink/genetlink.c | 7 -------
1 file changed, 7 deletions(-)
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index f85f8a2..512718a 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -789,10 +789,6 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
struct net *net = sock_net(skb->sk);
int chains_to_skip = cb->args[0];
int fams_to_skip = cb->args[1];
- bool need_locking = chains_to_skip || fams_to_skip;
-
- if (need_locking)
- genl_lock();
for (i = chains_to_skip; i < GENL_FAM_TAB_SIZE; i++) {
n = 0;
@@ -814,9 +810,6 @@ errout:
cb->args[0] = i;
cb->args[1] = n;
- if (need_locking)
- genl_unlock();
-
return skb->len;
}
--
1.8.4.rc2
^ permalink raw reply related
* Re: [PATCH v2 2/2] net: netem: always adjust now/delay when not reordering
From: mailings @ 2013-08-21 14:02 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Ferry Huberts, netdev
In-Reply-To: <1377091824.4226.102.camel@edumazet-glaptop>
> On Wed, 2013-08-21 at 09:04 +0200, Ferry Huberts wrote:
>> On 21/08/13 08:14, Eric Dumazet wrote:
>> > On Wed, 2013-08-21 at 07:59 +0200, Ferry Huberts wrote:
>> >> From: Ferry Huberts <ferry.huberts@pelagic.nl>
>> >>
>> >> Not doing this (current behaviour) introduces reordering.
>> >>
>> >> The packet_len_2_sched_time call is the only thing that logically
depends on q->rate, so move the now/delay adjustment out of the if.
>> >>
>> >> How to test:
>> >> -----------
>> >
>> > I ask again :
>> >
>> > Did you test a config with both rate limiting and delay.
>> (sorry for missing that question)
>> Just did so and with rate limiting I get no reordering, which is
logical
>> looking at the code.
>> The thing is, the evaluation q->rate is within the 'no-reordering'
block
>> and in the current situation you can get reordering (with that
'strange'
>> command). My patch makes sure that no reordering will occur, and
effectively 'clamps' the realised delay, which currently isn't done.
>
>
> OK, let me be very clear.
>
> I would like you post the results of regression tests, to make sure that
you do not add a new regression.
>
Since I'm new to netdev development and therefore the processes attached
to it, let me ask where I can find such regression tests?
I'm happy to run them once I know about them... ;-)
> It seems that you want _us_ to check all this for you.
>
> With "rate 1Mbits delay 100ms 10ms", and ping probes sent every 100ms,
the pong reply of _all_ probes should be between 90ms and 110ms
>
> Is it still the case after your patch ?
>
Yes it is.
In the script I described in the commit message I replaced the line
tc qdisc add dev "${fields[1]}" handle 1 root netem delay 10ms 500ms
with the line (1Mbit gave 'Illegal "rate"')
tc qdisc add dev "${fields[1]}" handle 1 root netem rate 1024000 delay
100ms 10ms
The output then was (tried a 10 times):
# ./netemreordering
PING 192.168.160.1 (192.168.160.1) 56(84) bytes of data.
64 bytes from 192.168.160.1: icmp_seq=1 ttl=254 time=114 ms
64 bytes from 192.168.160.1: icmp_seq=2 ttl=254 time=109 ms
64 bytes from 192.168.160.1: icmp_seq=3 ttl=254 time=106 ms
64 bytes from 192.168.160.1: icmp_seq=4 ttl=254 time=100 ms
64 bytes from 192.168.160.1: icmp_seq=5 ttl=254 time=111 ms
64 bytes from 192.168.160.1: icmp_seq=6 ttl=254 time=92.2 ms
64 bytes from 192.168.160.1: icmp_seq=7 ttl=254 time=99.8 ms
64 bytes from 192.168.160.1: icmp_seq=8 ttl=254 time=91.4 ms
64 bytes from 192.168.160.1: icmp_seq=9 ttl=254 time=97.4 ms
64 bytes from 192.168.160.1: icmp_seq=10 ttl=254 time=95.5 ms
--- 192.168.160.1 ping statistics ---
10 packets transmitted, 10 received, 0% packet loss, time 910ms
rtt min/avg/max/mdev = 91.413/101.879/114.534/7.723 ms, pipe 2
Is this enough?
Please let me know, I'm happy to oblige.
^ permalink raw reply
* BUG: MARK in OUTPUT + ip_tunnel causes kernel panic
From: Kristian Evensen @ 2013-08-21 14:00 UTC (permalink / raw)
To: netdev
Hello,
When trying to tunnel traffic originating from the same machine as the
tunnel endpoint, I am experiencing kernel panics for some types of
traffic (ICMP and UDP). TCP seems not to be affected by this, at least
I have not been able to trigger the panic.
I have one tunnel (without an IP address) and use policy routing to
steer some traffic through the tunnels. For my example, I use the
following commands to configure the tunnel and the routing:
ip tunnel add tun0 mode ipip remote 10.110.112.2 local 10.110.112.1
ip link set dev tun0 up
ip rule add fwmark 0x1 lookup 101
ip ro add default via tun0 table 101
iptables -A OUTPUT -t mangle -d 8.8.8.8 -j MARK --set-mark 0x1
The remote address of the tunnel does not matter, as the packets never
get that far. I then run ping 8.8.8.8/nc -u 8.8.8.8 9999, which
triggers the panic:
With ICMP:
skbuff: skb_under_panic: text:ffffffff815f9baf len:118 put:14
head:ffff880100cff800 data:ffff880100cff7ee tail:0x64 end:0xc0
dev:eth4
With UDP:
skbuff: skb_under_panic: text:ffffffff815f9baf len:71 put:14
head:ffff880118554c00 data:ffff880118554bee tail:0x35 end:0xc0
dev:eth4
Stack trace is the same:
[ 304.217036] ------------[ cut here ]------------
[ 304.217106] Kernel BUG at ffffffff816b75cc [verbose debug info unavailable]
[ 304.217195] invalid opcode: 0000 [#1] SMP
[ 304.217278] Modules linked in: iptable_mangle xt_mark ip_tables
x_tables ipip tunnel4 ip_tunnel netconsole configfs asix usbnet mii
i915 snd_hda_codec_hdmi snd_hda_intel joydev snd_hda_codec hid_generic
drm_kms_helper snd_hwdep drm usbhid hid snd_pcm video snd_page_alloc
mac_hid snd_timer snd lpc_ich soundcore i2c_algo_bit lp parport e1000e
ahci libahci ptp pps_core [last unloaded: netconsole]
[ 304.218140] CPU: 3 PID: 1437 Comm: nc Not tainted 3.11.0-rc5 #33
[ 304.218221] Hardware name: /D33217GKE, BIOS
GKPPT10H.86A.0020.2012.0919.2135 09/19/2012
[ 304.218325] task: ffff880110555d40 ti: ffff88011ef4c000 task.ti:
ffff88011ef4c000
[ 304.218411] RIP: 0010:[<ffffffff816b75cc>] [<ffffffff816b75cc>]
skb_panic+0x63/0x65
[ 304.218528] RSP: 0018:ffff88011ef4d8d0 EFLAGS: 00010292
[ 304.218595] RAX: 0000000000000084 RBX: ffff88011f1e8f00 RCX: 0000000000000006
[ 304.218677] RDX: 0000000000000007 RSI: 0000000000000046 RDI: ffff88011f38d490
[ 304.218759] RBP: ffff88011ef4d8f0 R08: 0000000002000000 R09: 0000000000000300
[ 304.218841] R10: ffff88002ed6b880 R11: 0000000000000000 R12: ffff8801104f72d8
[ 304.218923] R13: 000000000000000e R14: ffff8801104f72e8 R15: 0000000000000000
[ 304.219005] FS: 00007f49f196d740(0000) GS:ffff88011f380000(0000)
knlGS:0000000000000000
[ 304.219095] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 304.219164] CR2: 00007f49f10799d0 CR3: 00000001184ed000 CR4: 00000000001407e0
[ 304.219245] Stack:
[ 304.219273] ffff880118554bee 0000000000000035 00000000000000c0
ffff8801193d7000
[ 304.219411] ffff88011ef4d900 ffffffff815b183a ffff88011ef4d948
ffffffff815f9baf
[ 304.219544] ffff8801193d7000 02706e0a81d00380 ffff88011f1e8f00
0000000000000000
[ 304.219672] Call Trace:
[ 304.219724] [<ffffffff815b183a>] skb_push+0x3a/0x40
[ 304.219794] [<ffffffff815f9baf>] ip_finish_output+0x2af/0x3d0
[ 304.219873] [<ffffffff815fa5d5>] ip_output+0x55/0x90
[ 304.219941] [<ffffffff815f9d85>] ip_local_out+0x25/0x30
[ 304.220014] [<ffffffff8163be77>] iptunnel_xmit+0x1a7/0x1e0
[ 304.220095] [<ffffffffa0284d49>] ip_tunnel_xmit+0x2e9/0x15a0 [ip_tunnel]
[ 304.220181] [<ffffffffa028a6a1>] ipip_tunnel_xmit+0x61/0x80 [ipip]
[ 304.220264] [<ffffffff815c3138>] dev_hard_start_xmit+0x338/0x510
[ 304.220342] [<ffffffffa02a710b>] ? iptable_mangle_hook+0x7b/0x13c
[iptable_mangle]
[ 304.220435] [<ffffffff815c363f>] dev_queue_xmit+0x32f/0x490
[ 304.220512] [<ffffffff815c9401>] neigh_direct_output+0x11/0x20
[ 304.220589] [<ffffffff815f9aaf>] ip_finish_output+0x1af/0x3d0
[ 304.220665] [<ffffffff815fa5d5>] ip_output+0x55/0x90
[ 304.220735] [<ffffffff815f9d85>] ip_local_out+0x25/0x30
[ 304.220806] [<ffffffff815fb075>] ip_send_skb+0x15/0x50
[ 304.220880] [<ffffffff816201f7>] udp_send_skb+0x227/0x2b0
[ 304.220953] [<ffffffff815f82d0>] ? ip_copy_metadata+0x1a0/0x1a0
[ 304.221034] [<ffffffff81621c14>] udp_sendmsg+0x2c4/0x9e0
[ 304.221108] [<ffffffff81128f00>] ? __page_cache_alloc+0xc0/0xd0
[ 304.221186] [<ffffffff8112af2d>] ? filemap_fault+0xbd/0x470
[ 304.221259] [<ffffffff81129443>] ? unlock_page+0x23/0x30
[ 304.221335] [<ffffffff8114dc39>] ? __do_fault+0x3a9/0x4c0
[ 304.221407] [<ffffffff8162ce73>] inet_sendmsg+0x63/0xb0
[ 304.221481] [<ffffffff815aa36f>] sock_aio_write+0x13f/0x160
[ 304.221555] [<ffffffff81402e32>] ? n_tty_set_room+0x12/0xc0
[ 304.221634] [<ffffffff8118def0>] do_sync_write+0x80/0xb0
[ 304.221707] [<ffffffff8118edc5>] vfs_write+0x1b5/0x1e0
[ 304.221778] [<ffffffff8118f1c2>] SyS_write+0x52/0xa0
[ 304.221850] [<ffffffff816c4346>] system_call_fastpath+0x1a/0x1f
[ 304.221924] Code: 00 00 48 89 44 24 10 8b 87 d0 00 00 00 48 89 44
24 08 48 8b 87 e0 00 00 00 48 c7 c7 58 14 ad 81 48 89 04 24 31 c0 e8
d9 97 ff ff <0f> 0b 0f 1f 44 00 00 55 48 89 e5 41 56 41 55 41 54 53 48
89 fb
[ 304.222830] RIP [<ffffffff816b75cc>] skb_panic+0x63/0x65
[ 304.222910] RSP <ffff88011ef4d8d0>
[ 304.222993] ---[ end trace e19b480453293c10 ]---
[ 304.223086] Kernel panic - not syncing: Fatal exception in interrupt
[ 304.223221] drm_kms_helper: panic occurred, switching back to text console
An interesting thing is that I have seen different kernel panics being
triggered. The other one I have seen has RIP pointing to
e1000_xmit_frame() and the message "protocol 0800 is buggy". However,
the one I have posted is by far the most common.
What puzzles me is this additional skb_push()-call. I have not been
able to trace its origin. As far as I can see, the skb data is not
touched after iptunnel_xmit(). It is clear that some bogus data is
introduced to the head of the packet at some point after
iptunnel_xmit():
[ 500.537604] ip_tunnel_core: Len before push: 84 (size of iphdr struct 20)
[ 500.541096] ip_tunnel_core: Len after push: 104
[ 500.650000] ip_tunnel_core: 4 5 2706e0a 1706e0a (protocol, header
length, dst, src ip)
[ 500.735787] rawpost: IN= OUT=eth4 SRC=236.168.107.243
DST=138.226.8.0 LEN=0 TOS=0x00 PREC=0x00 TTL=1 ID=180 DF FRAG:7704
PROTO=UDPLITE MARK=0x1
The three first lines is debug-output I added to iptunnel_xmit(),
while the last line is from iptables' LOG target used in rawpost
(combined with a DROP to avoid triggering the panic).
I do not see this kernel panic when I mangle in PREROUTING, give the
interface an address or don't mangle at all (for example ping -I tun0
8.8.8.8). The machine this occurs on is an Intel NUC with the Intel
82579 Gigabit Ethernet Controller. I have tested this against latest
net-next (pulled this morning).
Thanks in advance for any help,
Kristian
^ permalink raw reply
* Re: [PATCH RFC net-next] net: epoll support for busy poll
From: Eric Dumazet @ 2013-08-21 13:53 UTC (permalink / raw)
To: Eliezer Tamir
Cc: David Miller, linux-kernel, netdev, e1000-devel, Eilon Greenstein,
Amir Vadai, Willem de Bruijn, Eliezer Tamir
In-Reply-To: <20130821103954.30607.6819.stgit@ladj378.jer.intel.com>
On Wed, 2013-08-21 at 13:39 +0300, Eliezer Tamir wrote:
>
> Instead of remembering the napi_id for all the sockets in an epoll,
> we only track the first socket we see with any unique napi_id.
> The rational for this is that while there may be many thousands of
> sockets tracked by a single epoll, we expect to only see a handful
> of unique napi_ids in most cases.
This looks buggy assumption to me.
We use epoll() with in the order of millions of fds per epoller, and
typically one napi_id per cpu.
With your model, we would have to use nr_cpu epollers and make sure that
sockets are properly placed on those epollers by their napi_ids.
^ permalink raw reply
* Re: [PATCH] VMXNET3: Add support for virtual IOMMU
From: Andy King @ 2013-08-21 13:37 UTC (permalink / raw)
To: David Miller; +Cc: pv-drivers, netdev, Greg KH, linux-kernel, virtualization
In-Reply-To: <20130821.000255.1258155583733908892.davem@davemloft.net>
Adding Greg, since this will apply to a similar patchset I sent out
for VMCI.
----- Original Message -----
> From: Andy King <acking@vmware.com>
> Date: Tue, 20 Aug 2013 10:33:32 -0700
>
> > We can't just do virt_to_phys() on memory that we pass to the device and
> > expect it to work in presence of a virtual IOMMU. We need to add IOMMU
> > mappings for such DMAs to work correctly. Fix that with
> > pci_alloc_consistent() where possible, or pci_map_single() where the
> > mapping is short-lived or we don't control the allocation (netdev).
>
> Please use dma_alloc_coherent() (or in fact dma_zalloc_coherent()),
> dma_map_single() et al., because they are preferred and in particular
> allow specification of GFP_* flags
Sorry about that, I'll fix that and send out a new patch.
Thanks!
- Andy
^ permalink raw reply
* Re: [PATCH v2 2/2] net: netem: always adjust now/delay when not reordering
From: Eric Dumazet @ 2013-08-21 13:30 UTC (permalink / raw)
To: Ferry Huberts; +Cc: netdev
In-Reply-To: <5214668E.504@hupie.com>
On Wed, 2013-08-21 at 09:04 +0200, Ferry Huberts wrote:
>
> On 21/08/13 08:14, Eric Dumazet wrote:
> > On Wed, 2013-08-21 at 07:59 +0200, Ferry Huberts wrote:
> >> From: Ferry Huberts <ferry.huberts@pelagic.nl>
> >>
> >> Not doing this (current behaviour) introduces reordering.
> >>
> >> The packet_len_2_sched_time call is the only thing that logically
> >> depends on q->rate, so move the now/delay adjustment out of the if.
> >>
> >> How to test:
> >> -----------
> >
> > I ask again :
> >
> > Did you test a config with both rate limiting and delay.
>
> (sorry for missing that question)
>
> Just did so and with rate limiting I get no reordering, which is logical
> looking at the code.
>
> The thing is, the evaluation q->rate is within the 'no-reordering' block
> and in the current situation you can get reordering (with that 'strange'
> command). My patch makes sure that no reordering will occur, and
> effectively 'clamps' the realised delay, which currently isn't done.
OK, let me be very clear.
I would like you post the results of regression tests, to make sure that
you do not add a new regression.
It seems that you want _us_ to check all this for you.
With "rate 1Mbits delay 100ms 10ms", and ping probes sent every 100ms,
the pong reply of _all_ probes should be between 90ms and 110ms
Is it still the case after your patch ?
Thanks
^ permalink raw reply
* Re: [PATCH 2/2] sh_eth: remove 'register_type' field from 'struct sh_eth_plat_data'
From: Laurent Pinchart @ 2013-08-21 12:58 UTC (permalink / raw)
To: Sergei Shtylyov; +Cc: netdev, davem, lethal, linux-sh
In-Reply-To: <5214B770.5000807@cogentembedded.com>
Hi Sergei,
On Wednesday 21 August 2013 16:49:52 Sergei Shtylyov wrote:
> On 21-08-2013 4:39, Laurent Pinchart wrote:
> >>>>>>> Now that the 'register_type' field of the 'sh_eth' driver's platform
> >>>>>>> data is not used by the driver anymore, it's time to remove it and
> >>>>>>> its initializers from the SH platform code. Also move *enum*
> >>>>>>> declaring values for this field from <linux/sh_eth.h> to the
> >>>>>>> local driver's header file as they're only needed by the driver
> >>>>>>> itself now...
> >>>>>>>
> >>>>>>> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
> >>>>
> >>>> [...]
> >>>>
> >>>>>>> /* Driver's parameters */
> >>>>>>> #if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
> >>>>>>> #define SH4_SKB_RX_ALIGN 32
> >>>>>>>
> >>>>>>> Index: net-next/include/linux/sh_eth.h
> >>>>>>> ===================================================================
> >>>>>>> --- net-next.orig/include/linux/sh_eth.h
> >>>>>>> +++ net-next/include/linux/sh_eth.h
> >>>>>>> @@ -5,17 +5,10 @@
> >>>>>>>
> >>>>>>> #include <linux/if_ether.h>
> >>>>>>>
> >>>>>>> enum {EDMAC_LITTLE_ENDIAN, EDMAC_BIG_ENDIAN};
> >>>>>>>
> >>>>>>> -enum {
> >>>>>>> - SH_ETH_REG_GIGABIT,
> >>>>>>> - SH_ETH_REG_FAST_RCAR,
> >>>>>>> - SH_ETH_REG_FAST_SH4,
> >>>>>>> - SH_ETH_REG_FAST_SH3_SH2
> >>>>>>> -};
> >>>>>>>
> >>>>>>> struct sh_eth_plat_data {
> >>>>>>>
> >>>>>>> int phy;
> >>>>>>> int edmac_endian;
> >>>>>>
> >>>>>> Wouldn't it make sense to move the edmac_endian field to
> >>>>>> sh_eth_cpu_data as well ?
> >>>>>
> >>>>> No, it depends on the SoC endianness which is determined by power-on
> >>>>> pin strapping -- which is board specific.
> >>>
> >>> Does SoC endianness affect the ARM core endianness, the ethernet
> >>> registers endianness, or both ?
> >>
> >> Both, AFAIK.
> >>
> >>> If it affects the ARM core endianness only, the kernel needs to be
> >>> compiled in little-endian or big-endian mode anyway, and the sh_eth
> >>> driver should use cpu_to_le32() unconditionally. If it affects both the
> >>> ARM core and the ethernet controller there's not need to care about the
> >>> endianness, as it will always be good.
> >>
> >> No, it won't unless you're using __raw_{readl|writel}() accessors. The
> >> driver doesn't do it. {readl|writel}() and io{read|write}32() that use
> >> them always assume LE ordering of memory.
> >>
> >>> We only need to care about it if it affects the ethernet controller
> >>> registers only, which would seem weird to me.
> >>
> >> Unfortunately, you are wrong.
> >
> > Care to explain *why* ? There might be bugs in the driver (such as using
> > the wrong I/O accessors), but I don't see why we need to configure the
> > endianness through platform data.
>
> Re-read my reply about the power-on pin strapping please. The SoC endianness
> setting gets read from the external source to the SoC, i.e. it's determined
> by the board.
Unless that pin doesn't affect the CPU core (in which case I wonder what it's
used for), the kernel will need to be compiled for the specified endianness
anyway. Endianness conversion can thus be performed with cpu_to_* (if the
registers endianness is fixed) or skipped completely (if the registers
endianness is also configured by the bootstrap pin) by using raw I/O
accessors. Modifications will be need in the sh_eth driver, but I don't see
why the driver would need to receive endianness information from platform data
or DT.
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH 2/2] sh_eth: remove 'register_type' field from 'struct sh_eth_plat_data'
From: Sergei Shtylyov @ 2013-08-21 12:49 UTC (permalink / raw)
To: Laurent Pinchart; +Cc: netdev, davem, lethal, linux-sh
In-Reply-To: <20555348.Y63SQY2deS@avalon>
Hello.
On 21-08-2013 4:39, Laurent Pinchart wrote:
>>>>>>> Now that the 'register_type' field of the 'sh_eth' driver's platform
>>>>>>> data is not used by the driver anymore, it's time to remove it and
>>>>>>> its initializers from the SH platform code. Also move *enum*
>>>>>>> declaring values for this field from <linux/sh_eth.h> to the local
>>>>>>> driver's header file as they're only needed by the driver itself
>>>>>>> now...
>>>>>>> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
>>>> [...]
>>>>>>> /* Driver's parameters */
>>>>>>> #if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
>>>>>>> #define SH4_SKB_RX_ALIGN 32
>>>>>>>
>>>>>>> Index: net-next/include/linux/sh_eth.h
>>>>>>> ===================================================================
>>>>>>> --- net-next.orig/include/linux/sh_eth.h
>>>>>>> +++ net-next/include/linux/sh_eth.h
>>>>>>> @@ -5,17 +5,10 @@
>>>>>>>
>>>>>>> #include <linux/if_ether.h>
>>>>>>>
>>>>>>> enum {EDMAC_LITTLE_ENDIAN, EDMAC_BIG_ENDIAN};
>>>>>>>
>>>>>>> -enum {
>>>>>>> - SH_ETH_REG_GIGABIT,
>>>>>>> - SH_ETH_REG_FAST_RCAR,
>>>>>>> - SH_ETH_REG_FAST_SH4,
>>>>>>> - SH_ETH_REG_FAST_SH3_SH2
>>>>>>> -};
>>>>>>>
>>>>>>> struct sh_eth_plat_data {
>>>>>>>
>>>>>>> int phy;
>>>>>>> int edmac_endian;
>>>>>> Wouldn't it make sense to move the edmac_endian field to
>>>>>> sh_eth_cpu_data as well ?
>>>>> No, it depends on the SoC endianness which is determined by power-on pin
>>>>> strapping -- which is board specific.
>>> Does SoC endianness affect the ARM core endianness, the ethernet registers
>>> endianness, or both ?
>> Both, AFAIK.
>>> If it affects the ARM core endianness only, the kernel needs to be
>>> compiled in little-endian or big-endian mode anyway, and the sh_eth driver
>>> should use cpu_to_le32() unconditionally. If it affects both the ARM core
>>> and the ethernet controller there's not need to care about the endianness,
>>> as it will always be good.
>> No, it won't unless you're using __raw_{readl|writel}() accessors. The
>> driver doesn't do it. {readl|writel}() and io{read|write}32() that use them
>> always assume LE ordering of memory.
>>> We only need to care about it if it affects the ethernet controller
>>> registers only, which would seem weird to me.
>> Unfortunately, you are wrong.
> Care to explain *why* ? There might be bugs in the driver (such as using the
> wrong I/O accessors), but I don't see why we need to configure the endianness
> through platform data.
Re-read my reply about the power-on pin strapping please. The SoC
endianness setting gets read from the external source to the SoC, i.e. it's
determined by the board.
WBR, Sergei
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox