Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [PATCH] ath10k: unify rx processing in napi_poll
From: Peter Oh @ 2017-11-29 22:03 UTC (permalink / raw)
  To: Rajkumar Manoharan, ath10k; +Cc: linux-wireless, rmanohar
In-Reply-To: <1511991212-4837-1-git-send-email-rmanohar@qti.qualcomm.com>

Hi Rajkumar,

I'm wondering if this patch is related to kernel crash due to ath10k napi.

Do you think this patch helps the crash below?

This crash happened ath10k v4.14 (10/04/2017, commit id c09dbd7) + 
3.14.43 kernel backports.


[ 6866.655419] ------------[ cut here ]------------
[ 6866.659029] kernel BUG at /net/core/dev.c:4301!
[ 6866.666404] Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM
[ 6866.672206] Modules linked in: asix essedma qca_ssdk ath9k 
ath9k_common ath9k_hw ath10k_pci ath10k_core mac80211 qca_nss_drv 
qca_nss_gmac ath cfg80211 skcipher compat nvram
[ 6866.687576] CPU: 0 PID: 1228 Comm: kworker/0:0 Tainted: G        W    
3.14.43 #1
[ 6866.694962] Workqueue: events_power_efficient phy_state_machine
[ 6866.700853] task: d88252c0 ti: d8cd2000 task.ti: d8cd2000
[ 6866.706239] PC is at __napi_complete+0x10/0x50
[ 6866.710663] LR is at napi_complete+0x2c/0x34
[ 6866.714919] pc : [<c0635a6c>]    lr : [<c0636710>]    psr: 60050093
[ 6866.714919] sp : d8cd3d88  ip : dfbc5d10  fp : c09dd6e4
[ 6866.726374] r10: dfbc5e88  r9 : 000a04de  r8 : 00000001
[ 6866.731582] r7 : 00000040  r6 : 00000001  r5 : 60050013  r4 : de7a5d60
[ 6866.738092] r3 : 00000000  r2 : 00000100  r1 : de7a5d60  r0 : de7a5d60
[ 6866.744606] Flags: nZCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  
Segment kernel
[ 6866.751982] Control: 10c5387d  Table: 9b4f406a  DAC: 00000015
[ 6866.757708]
[ 6866.757708] PC: 0xc06359ec:
[ 6866.761960] 59ec  e8bd8010 e3a00001 e8bd8010 e1a00003 e8bd8010 
e3a00000 e8bd8010 c08b1fb9
[ 6866.770119] 5a0c  c089e498 c0888b00 e5903120 e3130001 012fff1e 
e92d4037 e1a04000 e3a05000
[ 6866.778280] 5a2c  e1a0200d e1a01000 e3a00004 e58d5004 ebfff5f2 
e3a030d0 e1a02005 e1a01004
[ 6866.786439] 5a4c  e3a00010 eb003b52 e28dd00c e8bd8030 e5903008 
e1a01000 e3130001 1a000000
[ 6866.794599] 5a6c  e7f001f2 e590001c e3500000 0a000000 e7f001f2 
e891000c e5823004 e5832000
[ 6866.802759] 5a8c  e59f2010 e59f3010 e881000c f57ff05b e2811008 
eaef51ef 00100100 00200200
[ 6866.810919] 5aac  e92d4070 e1a04000 e5903110 e5932020 e3520000 
0a000013 e2803f4d e1d1c0b0
[ 6866.819078] 5acc  e1d330b0 e15c0003 1a000010 e590302c e3130002 
0a00000f e12fff32 e2505000
[ 6866.827239]
[ 6866.827239] LR: 0xc0636690:
[ 6866.831490] 6690  e59f7048 e1a04003 e3500000 0a00000d e3560000 
e5804000 0a000003 e5973000
[ 6866.839651] 66b0  e590202c e1520003 08bd81f0 e5908004 ebffffb4 
e5953010 e1a00008 e2433001
[ 6866.847810] 66d0  e5853010 eaffffef e585001c e8bd81f0 c09ce0c0 
e5901008 e7e01151 e3510000
[ 6866.855970] 66f0  112fff1e e92d4070 e1a04000 ebffffd9 e10f5000 
f10c0080 e1a00004 ebfffcd2
[ 6866.864130] 6710  e121f005 e8bd8070 e92d4ff0 e1a04001 e1d1b6b6 
e3a09000 e5911014 e24dd014
[ 6866.872289] 6730  e1c127d0 e2028901 e1983009 1a000001 e3a05003 
ea0000a4 e59430a8 e1d320b2
[ 6866.880450] 6750  e3520000 1afffff9 e5937008 e3570000 1afffff6 
e3003136 e590501c e19180b3
[ 6866.888609] 6770  e1a06000 e5949078 e3550000 0a000037 e5953078 
e1c572b4 e1590003 15c5702a
[ 6866.896771]
[ 6866.896771] SP: 0xd8cd3d08:
[ 6866.901023] 3d08  d8cd3d34 c024ed60 00000001 de7fcb00 de7fc300 
de7a41a4 00000000 00000004
[ 6866.909182] 3d28  d8cd2000 c0635a70 00000000 c0209858 00000000 
c02095ec de7a5d60 de7a5d60
[ 6866.917342] 3d48  00000100 00000000 de7a5d60 60050013 00000001 
00000040 00000001 000a04de
[ 6866.925501] 3d68  dfbc5e88 c09dd6e4 dfbc5d10 d8cd3d88 c0636710 
c0635a6c 60050093 ffffffff
[ 6866.933661] 3d88  de7a15e0 de7a5d60 00000001 bf1a38f8 de7a5d60 
dfbc5e80 00000001 00000040
[ 6866.941821] 3da8  0000012c c0637328 c09ce08c c09ce0c0 c0637280 
40000003 d8cd2020 00000008
[ 6866.949981] 3dc8  c0a34c80 0000000a c09ce08c d8cd2000 00000100 
c022fcac 00000080 00000001
[ 6866.958141] 3de8  c09dd5f0 04208060 000a04dd 00000000 00000004 
c09ce0c0 c09ce080 00000003
[ 6866.966304]
[ 6866.966304] IP: 0xdfbc5c90:
[ 6866.970554] 5c90  c09ddbd0 df49a1c0 000a04e3 00000000 c50baadf 
0000063e acc26c21 000005c9
[ 6866.978713] 5cb0  00000000 df40dc00 df484b80 000003d3 00000000 
00000000 00000000 00000003
[ 6866.986872] 5cd0  dfbc5cd0 dfbc5cd0 c0254544 dfbc5840 00000000 
00000000 00000001 d882531c
[ 6866.995033] 5cf0  d882405c 00000000 01b8e867 00000000 bb4b1900 
0000063e 00000000 00000000
[ 6867.003192] 5d10  000dbc97 00000000 0007a120 00000000 18493ebe 
00000075 000a05e7 fffffef9
[ 6867.011353] 5d30  00000000 00000000 00000000 c024aef0 dfbc5840 
00000000 dfbc5d48 00000000
[ 6867.019512] 5d50  00000000 00000000 00000000 00000000 00000000 
00000000 c024bee8 dfbc41f0
[ 6867.027672] 5d70  00000000 00000000 db651a54 00000000 00002846 
0000b728 acc26c21 000005c9
[ 6867.035833]
[ 6867.035833] FP: 0xc09dd664:
[ 6867.040084] d664  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.048245] d684  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.056404] d6a4  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.064564] d6c4  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.072723] d6e4  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 c08443a7
[ 6867.080884] d704  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.089043] d724  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.097203] d744  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.105365]
[ 6867.105365] R0: 0xde7a5ce0:
[ 6867.109617] 5ce0  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.117776] 5d00  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.125936] 5d20  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.134095] 5d40  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.142255] 5d60  00100100 00200200 00000000 00000040 00000000 
bf1a38bc de7a58a0 00000000
[ 6867.150415] 5d80  00000000 de7a58d8 de7a58d8 00000000 00000000 
00000000 ffffffe0 de7a5d9c
[ 6867.158574] 5da0  de7a5d9c bf135954 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.166734] 5dc0  000f9032 de7a5fd8 00000100 de7a5dcc de7a5dcc 
bf154244 de7a5dd8 de7a5dd8
[ 6867.174895]
[ 6867.174895] R1: 0xde7a5ce0:
[ 6867.179147] 5ce0  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.187306] 5d00  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.195466] 5d20  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.203627] 5d40  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.211787] 5d60  00100100 00200200 00000000 00000040 00000000 
bf1a38bc de7a58a0 00000000
[ 6867.219945] 5d80  00000000 de7a58d8 de7a58d8 00000000 00000000 
00000000 ffffffe0 de7a5d9c
[ 6867.228106] 5da0  de7a5d9c bf135954 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.236265] 5dc0  000f9032 de7a5fd8 00000100 de7a5dcc de7a5dcc 
bf154244 de7a5dd8 de7a5dd8
[ 6867.244427]
[ 6867.244427] R4: 0xde7a5ce0:
[ 6867.248679] 5ce0  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.256839] 5d00  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.264998] 5d20  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.273158] 5d40  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.281317] 5d60  00100100 00200200 00000000 00000040 00000000 
bf1a38bc de7a58a0 00000000
[ 6867.289477] 5d80  00000000 de7a58d8 de7a58d8 00000000 00000000 
00000000 ffffffe0 de7a5d9c
[ 6867.297636] 5da0  de7a5d9c bf135954 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.305797] 5dc0  000f9032 de7a5fd8 00000100 de7a5dcc de7a5dcc 
bf154244 de7a5dd8 de7a5dd8
[ 6867.313960]
[ 6867.313960] R10: 0xdfbc5e08:
[ 6867.318295] 5e08  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.326456] 5e28  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.334617] 5e48  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.342776] 5e68  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 dfbc5e80
[ 6867.350936] 5e88  dfbc5e88 dfbc5e88 00000000 dfbc5e94 dfbc5e94 
00000000 00000000 00368e2a
[ 6867.359096] 5ea8  00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.367254] 5ec8  c0633af4 dfbc5e80 00000000 00000000 00000000 
0000483c 0000483c 00000000
[ 6867.375415] 5ee8  dfbc5ee8 dfbc5ee8 00000000 81048104 00100100 
00200200 00000000 00000040
[ 6867.383579] Process kworker/0:0 (pid: 1228, stack limit = 0xd8cd2238)
[ 6867.390002] Stack: (0xd8cd3d88 to 0xd8cd4000)
[ 6867.394348] 3d80:                   de7a15e0 de7a5d60 00000001 
bf1a38f8 de7a5d60 dfbc5e80
[ 6867.402511] 3da0: 00000001 00000040 0000012c c0637328 c09ce08c 
c09ce0c0 c0637280 40000003
[ 6867.410671] 3dc0: d8cd2020 00000008 c0a34c80 0000000a c09ce08c 
d8cd2000 00000100 c022fcac
[ 6867.418831] 3de0: 00000080 00000001 c09dd5f0 04208060 000a04dd 
00000000 00000004 c09ce0c0
[ 6867.426990] 3e00: c09ce080 00000003 d8cd2000 d8cd2030 d8cd2000 
00000000 d8cd3e94 c04fd548
[ 6867.435151] 3e20: d8979398 d8cd2000 00000000 c0230068 c09c9c38 
000000c8 00000000 c02190f0
[ 6867.443309] 3e40: e0802000 c09d4818 d8cd3e60 c02084c4 c04fd504 
20050013 ffffffff c0209540
[ 6867.451468] 3e60: 00010000 0000004c fff95200 e0a60000 000003da 
dedaf9d0 c09e6b20 00000000
[ 6867.459628] 3e80: c04fd548 d8979398 d8cd2000 00000000 00000000 
d8cd3ea8 c021e288 c04fd504
[ 6867.467787] 3ea0: 20050013 ffffffff dedaf9d0 00000400 00000004 
c04fd604 dedcf000 dedc9800
[ 6867.475947] 3ec0: dedcdc00 c04f8978 dedcf1e0 dedcf1e0 dfbc5440 
dedcf000 dedcf218 c04f55ec
[ 6867.484108] 3ee0: d8979380 dedcf1e0 dfbc5440 00000000 dfbc8b00 
d8979398 d8cd2000 c023ef40
[ 6867.492268] 3f00: d8cd3f34 c020ff1c dfbc5440 d8cd2038 d8cd2000 
d8979380 dfbc5440 dfbc5440
[ 6867.500427] 3f20: d8cd2038 d8cd2000 d8979398 dfbc5454 00000009 
c023feac d8979380 d8cd3f6c
[ 6867.508584] 3f40: 00000000 dc2e5600 00000000 d8979380 c023fc88 
00000000 00000000 00000000
[ 6867.516746] 3f60: 00000000 c0244b6c 00000000 00000000 00000000 
d8979380 00000000 00000000
[ 6867.524905] 3f80: d8cd3f80 d8cd3f80 00000000 00000000 d8cd3f90 
d8cd3f90 d8cd3fac dc2e5600
[ 6867.533063] 3fa0: c0244aa4 00000000 00000000 c0208cd8 00000000 
00000000 00000000 00000000
[ 6867.541222] 3fc0: 00000000 00000000 00000000 00000000 00000000 
00000000 00000000 00000000
[ 6867.549385] 3fe0: 00000000 00000000 00000000 00000000 00000013 
00000000 00000000 00000000
[ 6867.557554] [<c0635a6c>] (__napi_complete) from [<c0636710>] 
(napi_complete+0x2c/0x34)
[ 6867.565457] [<c0636710>] (napi_complete) from [<bf1a38f8>] 
(ath10k_pci_napi_poll+0x3c/0xec [ath10k_pci])
[ 6867.574917] [<bf1a38f8>] (ath10k_pci_napi_poll [ath10k_pci]) from 
[<c0637328>] (net_rx_action+0xa8/0x158)
[ 6867.584458] [<c0637328>] (net_rx_action) from [<c022fcac>] 
(__do_softirq+0xec/0x218)
[ 6867.592182] [<c022fcac>] (__do_softirq) from [<c0230068>] 
(irq_exit+0x8c/0xe8)
[ 6867.599386] [<c0230068>] (irq_exit) from [<c02190f0>] 
(handle_IRQ+0x6c/0x90)
[ 6867.606419] [<c02190f0>] (handle_IRQ) from [<c02084c4>] 
(gic_handle_irq+0x3c/0x5c)
[ 6867.613968] [<c02084c4>] (gic_handle_irq) from [<c0209540>] 
(__irq_svc+0x40/0x70)
[ 6867.621427] Exception stack(0xd8cd3e60 to 0xd8cd3ea8)
[ 6867.626469] 3e60: 00010000 0000004c fff95200 e0a60000 000003da 
dedaf9d0 c09e6b20 00000000
[ 6867.634628] 3e80: c04fd548 d8979398 d8cd2000 00000000 00000000 
d8cd3ea8 c021e288 c04fd504
[ 6867.642781] 3ea0: 20050013 ffffffff
[ 6867.646263] [<c0209540>] (__irq_svc) from [<c04fd504>] 
(ipq40xx_mdio_wait_busy+0x24/0x68)
[ 6867.654424] [<c04fd504>] (ipq40xx_mdio_wait_busy) from [<c04fd604>] 
(ipq40xx_mdio_read+0x50/0x68)
[ 6867.663276] [<c04fd604>] (ipq40xx_mdio_read) from [<c04f8978>] 
(rtl8306_read_status+0x7c/0x1c0)
[ 6867.671958] [<c04f8978>] (rtl8306_read_status) from [<c04f55ec>] 
(phy_state_machine+0x118/0x3b0)
[ 6867.680727] [<c04f55ec>] (phy_state_machine) from [<c023ef40>] 
(process_one_work+0x208/0x328)
[ 6867.689234] [<c023ef40>] (process_one_work) from [<c023feac>] 
(worker_thread+0x224/0x348)
[ 6867.697393] [<c023feac>] (worker_thread) from [<c0244b6c>] 
(kthread+0xc8/0xdc)
[ 6867.704594] [<c0244b6c>] (kthread) from [<c0208cd8>] 
(ret_from_fork+0x14/0x3c)
[ 6867.711797] Code: e5903008 e1a01000 e3130001 1a000000 (e7f001f2)
[ 6867.717871] ---[ end trace 5bbbaa9d0273b80c ]---
[ 6867.722470] Kernel panic - not syncing: Fatal exception in interrupt
[ 6867.728812] CPU1: stopping
[ 6867.731501] CPU: 1 PID: 0 Comm: swapper/1 Tainted: G      D W    
3.14.43 #1
[ 6867.738460] [<c021e7d8>] (unwind_backtrace) from [<c021b930>] 
(show_stack+0x10/0x14)
[ 6867.746178] [<c021b930>] (show_stack) from [<c03de238>] 
(dump_stack+0x78/0xbc)
[ 6867.753383] [<c03de238>] (dump_stack) from [<c021dc58>] 
(handle_IPI+0xb8/0x140)
[ 6867.760671] [<c021dc58>] (handle_IPI) from [<c02084dc>] 
(gic_handle_irq+0x54/0x5c)
[ 6867.768221] [<c02084dc>] (gic_handle_irq) from [<c0209540>] 
(__irq_svc+0x40/0x70)
[ 6867.775680] Exception stack(0xdf4c1fa0 to 0xdf4c1fe8)
[ 6867.780723] 1fa0: ffffffed 00000000 1f203000 00000000 df4c0030 
df4c0000 10c0387d c0a322c8
[ 6867.788881] 1fc0: 8020406a 410fc075 00000000 00000000 00000001 
df4c1fe8 c02194b8 c02194bc
[ 6867.797035] 1fe0: 600e0013 ffffffff
[ 6867.800515] [<c0209540>] (__irq_svc) from [<c02194bc>] 
(arch_cpu_idle+0x30/0x50)
[ 6867.807897] [<c02194bc>] (arch_cpu_idle) from [<c0261538>] 
(cpu_startup_entry+0xa4/0x108)
[ 6867.816058] [<c0261538>] (cpu_startup_entry) from [<80208584>] 
(0x80208584)
[ 6867.822990] CPU3: stopping
[ 6867.825685] CPU: 3 PID: 0 Comm: swapper/3 Tainted: G      D W    
3.14.43 #1
[ 6867.832639] [<c021e7d8>] (unwind_backtrace) from [<c021b930>] 
(show_stack+0x10/0x14)
[ 6867.840358] [<c021b930>] (show_stack) from [<c03de238>] 
(dump_stack+0x78/0xbc)
[ 6867.847567] [<c03de238>] (dump_stack) from [<c021dc58>] 
(handle_IPI+0xb8/0x140)
[ 6867.854854] [<c021dc58>] (handle_IPI) from [<c02084dc>] 
(gic_handle_irq+0x54/0x5c)
[ 6867.862405] [<c02084dc>] (gic_handle_irq) from [<c0209540>] 
(__irq_svc+0x40/0x70)
[ 6867.869862] Exception stack(0xdf4c5fa0 to 0xdf4c5fe8)
[ 6867.874907] 5fa0: ffffffed 00000000 1f213000 00000000 df4c4030 
df4c4000 10c0387d c0a322c8
[ 6867.883066] 5fc0: 8020406a 410fc075 00000000 00000000 00000001 
df4c5fe8 c02194b8 c02194bc
[ 6867.891219] 5fe0: 60070013 ffffffff
[ 6867.894699] [<c0209540>] (__irq_svc) from [<c02194bc>] 
(arch_cpu_idle+0x30/0x50)
[ 6867.902077] [<c02194bc>] (arch_cpu_idle) from [<c0261538>] 
(cpu_startup_entry+0xa4/0x108)
[ 6867.910238] [<c0261538>] (cpu_startup_entry) from [<80208584>] 
(0x80208584)
[ 6867.917175] CPU2: stopping
[ 6867.919869] CPU: 2 PID: 0 Comm: swapper/2 Tainted: G      D W    
3.14.43 #1
[ 6867.926823] [<c021e7d8>] (unwind_backtrace) from [<c021b930>] 
(show_stack+0x10/0x14)
[ 6867.934542] [<c021b930>] (show_stack) from [<c03de238>] 
(dump_stack+0x78/0xbc)
[ 6867.941748] [<c03de238>] (dump_stack) from [<c021dc58>] 
(handle_IPI+0xb8/0x140)
[ 6867.949037] [<c021dc58>] (handle_IPI) from [<c02084dc>] 
(gic_handle_irq+0x54/0x5c)
[ 6867.956587] [<c02084dc>] (gic_handle_irq) from [<c0209540>] 
(__irq_svc+0x40/0x70)
[ 6867.964048] Exception stack(0xdf4c3fa0 to 0xdf4c3fe8)
[ 6867.969090] 3fa0: ffffffed 00000000 1f20b000 00000000 df4c2030 
df4c2000 10c0387d c0a322c8
[ 6867.977251] 3fc0: 8020406a 410fc075 00000000 00000000 00000001 
df4c3fe8 c02194b8 c02194bc
[ 6867.985401] 3fe0: 60000013 ffffffff
[ 6867.988882] [<c0209540>] (__irq_svc) from [<c02194bc>] 
(arch_cpu_idle+0x30/0x50)
[ 6867.996262] [<c02194bc>] (arch_cpu_idle) from [<c0261538>] 
(cpu_startup_entry+0xa4/0x108)
[ 6868.004421] [<c0261538>] (cpu_startup_entry) from [<80208584>] 
(0x80208584)
[ 6868.011402] Rebooting in 3 seconds..



On 11/29/2017 01:33 PM, Rajkumar Manoharan wrote:
> With current NAPI implementation, NAPI poll can deliver more frames
> to net core than allotted budget. This may cause warning in napi_poll.
> Remaining quota is not accounted, while processing amsdus in
> rx_in_ord_ind and rx_ind queue. Adding num_msdus at last can not
> prevent delivering more frames to net core. With this change,
> all amdus from both in_ord_ind and rx_ind queues are processed and
> enqueued into common skb list instead of delivering into mac80211.
> Later msdus from common queue are dequeued and delivered depends on
> quota availability. This change also simplifies the rx processing in
> napi poll routine.
>
> Signed-off-by: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
> ---
>   drivers/net/wireless/ath/ath10k/core.h   |   1 -
>   drivers/net/wireless/ath/ath10k/htt.h    |   2 +-
>   drivers/net/wireless/ath/ath10k/htt_rx.c | 121 ++++++++++++++++---------------
>   3 files changed, 63 insertions(+), 61 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
> index 643041ef3271..6ecc58811656 100644
> --- a/drivers/net/wireless/ath/ath10k/core.h
> +++ b/drivers/net/wireless/ath/ath10k/core.h
> @@ -67,7 +67,6 @@
>   
>   /* NAPI poll budget */
>   #define ATH10K_NAPI_BUDGET      64
> -#define ATH10K_NAPI_QUOTA_LIMIT 60
>   
>   /* SMBIOS type containing Board Data File Name Extension */
>   #define ATH10K_SMBIOS_BDF_EXT_TYPE 0xF8
> diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
> index 6305308422c4..7d6143523634 100644
> --- a/drivers/net/wireless/ath/ath10k/htt.h
> +++ b/drivers/net/wireless/ath/ath10k/htt.h
> @@ -1695,7 +1695,7 @@ struct ath10k_htt {
>   	/* This is used to group tx/rx completions separately and process them
>   	 * in batches to reduce cache stalls
>   	 */
> -	struct sk_buff_head rx_compl_q;
> +	struct sk_buff_head rx_msdus_q;
>   	struct sk_buff_head rx_in_ord_compl_q;
>   	struct sk_buff_head tx_fetch_ind_q;
>   
> diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
> index e31438541ee1..d82f26dbba44 100644
> --- a/drivers/net/wireless/ath/ath10k/htt_rx.c
> +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
> @@ -227,7 +227,7 @@ void ath10k_htt_rx_free(struct ath10k_htt *htt)
>   {
>   	del_timer_sync(&htt->rx_ring.refill_retry_timer);
>   
> -	skb_queue_purge(&htt->rx_compl_q);
> +	skb_queue_purge(&htt->rx_msdus_q);
>   	skb_queue_purge(&htt->rx_in_ord_compl_q);
>   	skb_queue_purge(&htt->tx_fetch_ind_q);
>   
> @@ -515,7 +515,7 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
>   	htt->rx_ring.sw_rd_idx.msdu_payld = 0;
>   	hash_init(htt->rx_ring.skb_table);
>   
> -	skb_queue_head_init(&htt->rx_compl_q);
> +	skb_queue_head_init(&htt->rx_msdus_q);
>   	skb_queue_head_init(&htt->rx_in_ord_compl_q);
>   	skb_queue_head_init(&htt->tx_fetch_ind_q);
>   	atomic_set(&htt->num_mpdus_ready, 0);
> @@ -951,16 +951,25 @@ static char *ath10k_get_tid(struct ieee80211_hdr *hdr, char *out, size_t size)
>   	return out;
>   }
>   
> -static void ath10k_process_rx(struct ath10k *ar,
> -			      struct ieee80211_rx_status *rx_status,
> -			      struct sk_buff *skb)
> +static void ath10k_htt_rx_h_queue_msdu(struct ath10k *ar,
> +				       struct ieee80211_rx_status *rx_status,
> +				       struct sk_buff *skb)
> +{
> +	struct ieee80211_rx_status *status;
> +
> +	status = IEEE80211_SKB_RXCB(skb);
> +	*status = *rx_status;
> +
> +	__skb_queue_tail(&ar->htt.rx_msdus_q, skb);
> +}
> +
> +static void ath10k_process_rx(struct ath10k *ar, struct sk_buff *skb)
>   {
>   	struct ieee80211_rx_status *status;
>   	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
>   	char tid[32];
>   
>   	status = IEEE80211_SKB_RXCB(skb);
> -	*status = *rx_status;
>   
>   	ath10k_dbg(ar, ATH10K_DBG_DATA,
>   		   "rx skb %pK len %u peer %pM %s %s sn %u %s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
> @@ -1492,7 +1501,7 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
>   	}
>   }
>   
> -static void ath10k_htt_rx_h_deliver(struct ath10k *ar,
> +static void ath10k_htt_rx_h_enqueue(struct ath10k *ar,
>   				    struct sk_buff_head *amsdu,
>   				    struct ieee80211_rx_status *status)
>   {
> @@ -1515,7 +1524,7 @@ static void ath10k_htt_rx_h_deliver(struct ath10k *ar,
>   			status->flag |= RX_FLAG_ALLOW_SAME_PN;
>   		}
>   
> -		ath10k_process_rx(ar, status, msdu);
> +		ath10k_htt_rx_h_queue_msdu(ar, status, msdu);
>   	}
>   }
>   
> @@ -1627,7 +1636,7 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
>   	struct ath10k *ar = htt->ar;
>   	struct ieee80211_rx_status *rx_status = &htt->rx_status;
>   	struct sk_buff_head amsdu;
> -	int ret, num_msdus;
> +	int ret;
>   
>   	__skb_queue_head_init(&amsdu);
>   
> @@ -1649,7 +1658,6 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
>   		return ret;
>   	}
>   
> -	num_msdus = skb_queue_len(&amsdu);
>   	ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
>   
>   	/* only for ret = 1 indicates chained msdus */
> @@ -1658,9 +1666,9 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
>   
>   	ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
>   	ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true);
> -	ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
> +	ath10k_htt_rx_h_enqueue(ar, &amsdu, rx_status);
>   
> -	return num_msdus;
> +	return 0;
>   }
>   
>   static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt,
> @@ -1868,15 +1876,14 @@ static void ath10k_htt_rx_h_rx_offload_prot(struct ieee80211_rx_status *status,
>   			RX_FLAG_MMIC_STRIPPED;
>   }
>   
> -static int ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
> -				      struct sk_buff_head *list)
> +static void ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
> +				       struct sk_buff_head *list)
>   {
>   	struct ath10k_htt *htt = &ar->htt;
>   	struct ieee80211_rx_status *status = &htt->rx_status;
>   	struct htt_rx_offload_msdu *rx;
>   	struct sk_buff *msdu;
>   	size_t offset;
> -	int num_msdu = 0;
>   
>   	while ((msdu = __skb_dequeue(list))) {
>   		/* Offloaded frames don't have Rx descriptor. Instead they have
> @@ -1915,10 +1922,8 @@ static int ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
>   
>   		ath10k_htt_rx_h_rx_offload_prot(status, msdu);
>   		ath10k_htt_rx_h_channel(ar, status, NULL, rx->vdev_id);
> -		ath10k_process_rx(ar, status, msdu);
> -		num_msdu++;
> +		ath10k_htt_rx_h_queue_msdu(ar, status, msdu);
>   	}
> -	return num_msdu;
>   }
>   
>   static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
> @@ -1934,7 +1939,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
>   	u8 tid;
>   	bool offload;
>   	bool frag;
> -	int ret, num_msdus = 0;
> +	int ret;
>   
>   	lockdep_assert_held(&htt->rx_ring.lock);
>   
> @@ -1976,7 +1981,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
>   	 * separately.
>   	 */
>   	if (offload)
> -		num_msdus = ath10k_htt_rx_h_rx_offload(ar, &list);
> +		ath10k_htt_rx_h_rx_offload(ar, &list);
>   
>   	while (!skb_queue_empty(&list)) {
>   		__skb_queue_head_init(&amsdu);
> @@ -1989,11 +1994,10 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
>   			 * better to report something than nothing though. This
>   			 * should still give an idea about rx rate to the user.
>   			 */
> -			num_msdus += skb_queue_len(&amsdu);
>   			ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id);
>   			ath10k_htt_rx_h_filter(ar, &amsdu, status);
>   			ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false);
> -			ath10k_htt_rx_h_deliver(ar, &amsdu, status);
> +			ath10k_htt_rx_h_enqueue(ar, &amsdu, status);
>   			break;
>   		case -EAGAIN:
>   			/* fall through */
> @@ -2005,7 +2009,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
>   			return -EIO;
>   		}
>   	}
> -	return num_msdus;
> +	return ret;
>   }
>   
>   static void ath10k_htt_rx_tx_fetch_resp_id_confirm(struct ath10k *ar,
> @@ -2606,6 +2610,24 @@ void ath10k_htt_rx_pktlog_completion_handler(struct ath10k *ar,
>   }
>   EXPORT_SYMBOL(ath10k_htt_rx_pktlog_completion_handler);
>   
> +static int ath10k_htt_rx_deliver_msdu(struct ath10k *ar, int quota, int budget)
> +{
> +	struct sk_buff *skb;
> +
> +	while (quota < budget) {
> +		if (skb_queue_empty(&ar->htt.rx_msdus_q))
> +			break;
> +
> +		skb = __skb_dequeue(&ar->htt.rx_msdus_q);
> +		if (!skb)
> +			break;
> +		ath10k_process_rx(ar, skb);
> +		quota++;
> +	}
> +
> +	return quota;
> +}
> +
>   int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget)
>   {
>   	struct ath10k_htt *htt = &ar->htt;
> @@ -2613,63 +2635,44 @@ int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget)
>   	struct sk_buff_head tx_ind_q;
>   	struct sk_buff *skb;
>   	unsigned long flags;
> -	int quota = 0, done, num_rx_msdus;
> +	int quota = 0, done, ret;
>   	bool resched_napi = false;
>   
>   	__skb_queue_head_init(&tx_ind_q);
>   
> -	/* Since in-ord-ind can deliver more than 1 A-MSDU in single event,
> -	 * process it first to utilize full available quota.
> +	/* Process pending frames before dequeuing more data
> +	 * from hardware.
>   	 */
> -	while (quota < budget) {
> -		if (skb_queue_empty(&htt->rx_in_ord_compl_q))
> -			break;
> -
> -		skb = __skb_dequeue(&htt->rx_in_ord_compl_q);
> -		if (!skb) {
> -			resched_napi = true;
> -			goto exit;
> -		}
> +	quota = ath10k_htt_rx_deliver_msdu(ar, quota, budget);
> +	if (quota == budget) {
> +		resched_napi = true;
> +		goto exit;
> +	}
>   
> +	while ((skb = __skb_dequeue(&htt->rx_in_ord_compl_q))) {
>   		spin_lock_bh(&htt->rx_ring.lock);
> -		num_rx_msdus = ath10k_htt_rx_in_ord_ind(ar, skb);
> +		ret = ath10k_htt_rx_in_ord_ind(ar, skb);
>   		spin_unlock_bh(&htt->rx_ring.lock);
> -		if (num_rx_msdus < 0) {
> -			resched_napi = true;
> -			goto exit;
> -		}
>   
>   		dev_kfree_skb_any(skb);
> -		if (num_rx_msdus > 0)
> -			quota += num_rx_msdus;
> -
> -		if ((quota > ATH10K_NAPI_QUOTA_LIMIT) &&
> -		    !skb_queue_empty(&htt->rx_in_ord_compl_q)) {
> +		if (ret == -EIO) {
>   			resched_napi = true;
>   			goto exit;
>   		}
>   	}
>   
> -	while (quota < budget) {
> -		/* no more data to receive */
> -		if (!atomic_read(&htt->num_mpdus_ready))
> -			break;
> -
> -		num_rx_msdus = ath10k_htt_rx_handle_amsdu(htt);
> -		if (num_rx_msdus < 0) {
> +	while (atomic_read(&htt->num_mpdus_ready)) {
> +		ret = ath10k_htt_rx_handle_amsdu(htt);
> +		if (ret == -EIO) {
>   			resched_napi = true;
>   			goto exit;
>   		}
> -
> -		quota += num_rx_msdus;
>   		atomic_dec(&htt->num_mpdus_ready);
> -		if ((quota > ATH10K_NAPI_QUOTA_LIMIT) &&
> -		    atomic_read(&htt->num_mpdus_ready)) {
> -			resched_napi = true;
> -			goto exit;
> -		}
>   	}
>   
> +	/* Deliver received data after processing data from hardware */
> +	quota = ath10k_htt_rx_deliver_msdu(ar, quota, budget);
> +
>   	/* From NAPI documentation:
>   	 *  The napi poll() function may also process TX completions, in which
>   	 *  case if it processes the entire TX ring then it should count that

^ permalink raw reply

* [PATCH] ath10k: unify rx processing in napi_poll
From: Rajkumar Manoharan @ 2017-11-29 21:33 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, rmanohar, Rajkumar Manoharan

With current NAPI implementation, NAPI poll can deliver more frames
to net core than allotted budget. This may cause warning in napi_poll.
Remaining quota is not accounted, while processing amsdus in
rx_in_ord_ind and rx_ind queue. Adding num_msdus at last can not
prevent delivering more frames to net core. With this change,
all amdus from both in_ord_ind and rx_ind queues are processed and
enqueued into common skb list instead of delivering into mac80211.
Later msdus from common queue are dequeued and delivered depends on
quota availability. This change also simplifies the rx processing in
napi poll routine.

Signed-off-by: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/core.h   |   1 -
 drivers/net/wireless/ath/ath10k/htt.h    |   2 +-
 drivers/net/wireless/ath/ath10k/htt_rx.c | 121 ++++++++++++++++---------------
 3 files changed, 63 insertions(+), 61 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 643041ef3271..6ecc58811656 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -67,7 +67,6 @@
 
 /* NAPI poll budget */
 #define ATH10K_NAPI_BUDGET      64
-#define ATH10K_NAPI_QUOTA_LIMIT 60
 
 /* SMBIOS type containing Board Data File Name Extension */
 #define ATH10K_SMBIOS_BDF_EXT_TYPE 0xF8
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 6305308422c4..7d6143523634 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -1695,7 +1695,7 @@ struct ath10k_htt {
 	/* This is used to group tx/rx completions separately and process them
 	 * in batches to reduce cache stalls
 	 */
-	struct sk_buff_head rx_compl_q;
+	struct sk_buff_head rx_msdus_q;
 	struct sk_buff_head rx_in_ord_compl_q;
 	struct sk_buff_head tx_fetch_ind_q;
 
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index e31438541ee1..d82f26dbba44 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -227,7 +227,7 @@ void ath10k_htt_rx_free(struct ath10k_htt *htt)
 {
 	del_timer_sync(&htt->rx_ring.refill_retry_timer);
 
-	skb_queue_purge(&htt->rx_compl_q);
+	skb_queue_purge(&htt->rx_msdus_q);
 	skb_queue_purge(&htt->rx_in_ord_compl_q);
 	skb_queue_purge(&htt->tx_fetch_ind_q);
 
@@ -515,7 +515,7 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
 	htt->rx_ring.sw_rd_idx.msdu_payld = 0;
 	hash_init(htt->rx_ring.skb_table);
 
-	skb_queue_head_init(&htt->rx_compl_q);
+	skb_queue_head_init(&htt->rx_msdus_q);
 	skb_queue_head_init(&htt->rx_in_ord_compl_q);
 	skb_queue_head_init(&htt->tx_fetch_ind_q);
 	atomic_set(&htt->num_mpdus_ready, 0);
@@ -951,16 +951,25 @@ static char *ath10k_get_tid(struct ieee80211_hdr *hdr, char *out, size_t size)
 	return out;
 }
 
-static void ath10k_process_rx(struct ath10k *ar,
-			      struct ieee80211_rx_status *rx_status,
-			      struct sk_buff *skb)
+static void ath10k_htt_rx_h_queue_msdu(struct ath10k *ar,
+				       struct ieee80211_rx_status *rx_status,
+				       struct sk_buff *skb)
+{
+	struct ieee80211_rx_status *status;
+
+	status = IEEE80211_SKB_RXCB(skb);
+	*status = *rx_status;
+
+	__skb_queue_tail(&ar->htt.rx_msdus_q, skb);
+}
+
+static void ath10k_process_rx(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct ieee80211_rx_status *status;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	char tid[32];
 
 	status = IEEE80211_SKB_RXCB(skb);
-	*status = *rx_status;
 
 	ath10k_dbg(ar, ATH10K_DBG_DATA,
 		   "rx skb %pK len %u peer %pM %s %s sn %u %s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
@@ -1492,7 +1501,7 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
 	}
 }
 
-static void ath10k_htt_rx_h_deliver(struct ath10k *ar,
+static void ath10k_htt_rx_h_enqueue(struct ath10k *ar,
 				    struct sk_buff_head *amsdu,
 				    struct ieee80211_rx_status *status)
 {
@@ -1515,7 +1524,7 @@ static void ath10k_htt_rx_h_deliver(struct ath10k *ar,
 			status->flag |= RX_FLAG_ALLOW_SAME_PN;
 		}
 
-		ath10k_process_rx(ar, status, msdu);
+		ath10k_htt_rx_h_queue_msdu(ar, status, msdu);
 	}
 }
 
@@ -1627,7 +1636,7 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
 	struct ath10k *ar = htt->ar;
 	struct ieee80211_rx_status *rx_status = &htt->rx_status;
 	struct sk_buff_head amsdu;
-	int ret, num_msdus;
+	int ret;
 
 	__skb_queue_head_init(&amsdu);
 
@@ -1649,7 +1658,6 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
 		return ret;
 	}
 
-	num_msdus = skb_queue_len(&amsdu);
 	ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
 
 	/* only for ret = 1 indicates chained msdus */
@@ -1658,9 +1666,9 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
 
 	ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
 	ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true);
-	ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
+	ath10k_htt_rx_h_enqueue(ar, &amsdu, rx_status);
 
-	return num_msdus;
+	return 0;
 }
 
 static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt,
@@ -1868,15 +1876,14 @@ static void ath10k_htt_rx_h_rx_offload_prot(struct ieee80211_rx_status *status,
 			RX_FLAG_MMIC_STRIPPED;
 }
 
-static int ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
-				      struct sk_buff_head *list)
+static void ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
+				       struct sk_buff_head *list)
 {
 	struct ath10k_htt *htt = &ar->htt;
 	struct ieee80211_rx_status *status = &htt->rx_status;
 	struct htt_rx_offload_msdu *rx;
 	struct sk_buff *msdu;
 	size_t offset;
-	int num_msdu = 0;
 
 	while ((msdu = __skb_dequeue(list))) {
 		/* Offloaded frames don't have Rx descriptor. Instead they have
@@ -1915,10 +1922,8 @@ static int ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
 
 		ath10k_htt_rx_h_rx_offload_prot(status, msdu);
 		ath10k_htt_rx_h_channel(ar, status, NULL, rx->vdev_id);
-		ath10k_process_rx(ar, status, msdu);
-		num_msdu++;
+		ath10k_htt_rx_h_queue_msdu(ar, status, msdu);
 	}
-	return num_msdu;
 }
 
 static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
@@ -1934,7 +1939,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
 	u8 tid;
 	bool offload;
 	bool frag;
-	int ret, num_msdus = 0;
+	int ret;
 
 	lockdep_assert_held(&htt->rx_ring.lock);
 
@@ -1976,7 +1981,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
 	 * separately.
 	 */
 	if (offload)
-		num_msdus = ath10k_htt_rx_h_rx_offload(ar, &list);
+		ath10k_htt_rx_h_rx_offload(ar, &list);
 
 	while (!skb_queue_empty(&list)) {
 		__skb_queue_head_init(&amsdu);
@@ -1989,11 +1994,10 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
 			 * better to report something than nothing though. This
 			 * should still give an idea about rx rate to the user.
 			 */
-			num_msdus += skb_queue_len(&amsdu);
 			ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id);
 			ath10k_htt_rx_h_filter(ar, &amsdu, status);
 			ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false);
-			ath10k_htt_rx_h_deliver(ar, &amsdu, status);
+			ath10k_htt_rx_h_enqueue(ar, &amsdu, status);
 			break;
 		case -EAGAIN:
 			/* fall through */
@@ -2005,7 +2009,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
 			return -EIO;
 		}
 	}
-	return num_msdus;
+	return ret;
 }
 
 static void ath10k_htt_rx_tx_fetch_resp_id_confirm(struct ath10k *ar,
@@ -2606,6 +2610,24 @@ void ath10k_htt_rx_pktlog_completion_handler(struct ath10k *ar,
 }
 EXPORT_SYMBOL(ath10k_htt_rx_pktlog_completion_handler);
 
+static int ath10k_htt_rx_deliver_msdu(struct ath10k *ar, int quota, int budget)
+{
+	struct sk_buff *skb;
+
+	while (quota < budget) {
+		if (skb_queue_empty(&ar->htt.rx_msdus_q))
+			break;
+
+		skb = __skb_dequeue(&ar->htt.rx_msdus_q);
+		if (!skb)
+			break;
+		ath10k_process_rx(ar, skb);
+		quota++;
+	}
+
+	return quota;
+}
+
 int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget)
 {
 	struct ath10k_htt *htt = &ar->htt;
@@ -2613,63 +2635,44 @@ int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget)
 	struct sk_buff_head tx_ind_q;
 	struct sk_buff *skb;
 	unsigned long flags;
-	int quota = 0, done, num_rx_msdus;
+	int quota = 0, done, ret;
 	bool resched_napi = false;
 
 	__skb_queue_head_init(&tx_ind_q);
 
-	/* Since in-ord-ind can deliver more than 1 A-MSDU in single event,
-	 * process it first to utilize full available quota.
+	/* Process pending frames before dequeuing more data
+	 * from hardware.
 	 */
-	while (quota < budget) {
-		if (skb_queue_empty(&htt->rx_in_ord_compl_q))
-			break;
-
-		skb = __skb_dequeue(&htt->rx_in_ord_compl_q);
-		if (!skb) {
-			resched_napi = true;
-			goto exit;
-		}
+	quota = ath10k_htt_rx_deliver_msdu(ar, quota, budget);
+	if (quota == budget) {
+		resched_napi = true;
+		goto exit;
+	}
 
+	while ((skb = __skb_dequeue(&htt->rx_in_ord_compl_q))) {
 		spin_lock_bh(&htt->rx_ring.lock);
-		num_rx_msdus = ath10k_htt_rx_in_ord_ind(ar, skb);
+		ret = ath10k_htt_rx_in_ord_ind(ar, skb);
 		spin_unlock_bh(&htt->rx_ring.lock);
-		if (num_rx_msdus < 0) {
-			resched_napi = true;
-			goto exit;
-		}
 
 		dev_kfree_skb_any(skb);
-		if (num_rx_msdus > 0)
-			quota += num_rx_msdus;
-
-		if ((quota > ATH10K_NAPI_QUOTA_LIMIT) &&
-		    !skb_queue_empty(&htt->rx_in_ord_compl_q)) {
+		if (ret == -EIO) {
 			resched_napi = true;
 			goto exit;
 		}
 	}
 
-	while (quota < budget) {
-		/* no more data to receive */
-		if (!atomic_read(&htt->num_mpdus_ready))
-			break;
-
-		num_rx_msdus = ath10k_htt_rx_handle_amsdu(htt);
-		if (num_rx_msdus < 0) {
+	while (atomic_read(&htt->num_mpdus_ready)) {
+		ret = ath10k_htt_rx_handle_amsdu(htt);
+		if (ret == -EIO) {
 			resched_napi = true;
 			goto exit;
 		}
-
-		quota += num_rx_msdus;
 		atomic_dec(&htt->num_mpdus_ready);
-		if ((quota > ATH10K_NAPI_QUOTA_LIMIT) &&
-		    atomic_read(&htt->num_mpdus_ready)) {
-			resched_napi = true;
-			goto exit;
-		}
 	}
 
+	/* Deliver received data after processing data from hardware */
+	quota = ath10k_htt_rx_deliver_msdu(ar, quota, budget);
+
 	/* From NAPI documentation:
 	 *  The napi poll() function may also process TX completions, in which
 	 *  case if it processes the entire TX ring then it should count that
-- 
1.9.1

^ permalink raw reply related

* [PATCH v3 31/36] mac80211_hwsim: Replace hrtimer tasklet with softirq hrtimer
From: Anna-Maria Gleixner @ 2017-11-29 15:30 UTC (permalink / raw)
  To: LKML
  Cc: Thomas Gleixner, Peter Zijlstra, Ingo Molnar, keescook,
	Christoph Hellwig, John Stultz, Anna-Maria Gleixner,
	linux-wireless, Johannes Berg, Kalle Valo
In-Reply-To: <20171129153101.27297-1-anna-maria@linutronix.de>

From: Thomas Gleixner <tglx@linutronix.de>

Switch the timer to HRTIMER_MODE_SOFT, which executed the timer
callback in softirq context and remove the hrtimer_tasklet.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de>
Cc: linux-wireless@vger.kernel.org
Cc: Johannes Berg <johannes@sipsolutions.net>
Cc: Kalle Valo <kvalo@codeaurora.org>
---
 drivers/net/wireless/mac80211_hwsim.c | 44 ++++++++++++++++-------------------
 1 file changed, 20 insertions(+), 24 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 10b075a46b26..d3f1861398a7 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -537,7 +537,7 @@ struct mac80211_hwsim_data {
 	unsigned int rx_filter;
 	bool started, idle, scanning;
 	struct mutex mutex;
-	struct tasklet_hrtimer beacon_timer;
+	struct hrtimer beacon_timer;
 	enum ps_mode {
 		PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL
 	} ps;
@@ -1418,7 +1418,7 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
 {
 	struct mac80211_hwsim_data *data = hw->priv;
 	data->started = false;
-	tasklet_hrtimer_cancel(&data->beacon_timer);
+	hrtimer_cancel(&data->beacon_timer);
 	wiphy_dbg(hw->wiphy, "%s\n", __func__);
 }
 
@@ -1541,14 +1541,12 @@ static enum hrtimer_restart
 mac80211_hwsim_beacon(struct hrtimer *timer)
 {
 	struct mac80211_hwsim_data *data =
-		container_of(timer, struct mac80211_hwsim_data,
-			     beacon_timer.timer);
+		container_of(timer, struct mac80211_hwsim_data, beacon_timer);
 	struct ieee80211_hw *hw = data->hw;
 	u64 bcn_int = data->beacon_int;
-	ktime_t next_bcn;
 
 	if (!data->started)
-		goto out;
+		return HRTIMER_NORESTART;
 
 	ieee80211_iterate_active_interfaces_atomic(
 		hw, IEEE80211_IFACE_ITER_NORMAL,
@@ -1560,11 +1558,9 @@ mac80211_hwsim_beacon(struct hrtimer *timer)
 		data->bcn_delta = 0;
 	}
 
-	next_bcn = ktime_add(hrtimer_get_expires(timer),
-			     ns_to_ktime(bcn_int * 1000));
-	tasklet_hrtimer_start(&data->beacon_timer, next_bcn, HRTIMER_MODE_ABS);
-out:
-	return HRTIMER_NORESTART;
+	hrtimer_forward(&data->beacon_timer, hrtimer_get_expires(timer),
+			ns_to_ktime(bcn_int * NSEC_PER_USEC));
+	return HRTIMER_RESTART;
 }
 
 static const char * const hwsim_chanwidths[] = {
@@ -1638,15 +1634,15 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
 	mutex_unlock(&data->mutex);
 
 	if (!data->started || !data->beacon_int)
-		tasklet_hrtimer_cancel(&data->beacon_timer);
-	else if (!hrtimer_is_queued(&data->beacon_timer.timer)) {
+		hrtimer_cancel(&data->beacon_timer);
+	else if (!hrtimer_is_queued(&data->beacon_timer)) {
 		u64 tsf = mac80211_hwsim_get_tsf(hw, NULL);
 		u32 bcn_int = data->beacon_int;
 		u64 until_tbtt = bcn_int - do_div(tsf, bcn_int);
 
-		tasklet_hrtimer_start(&data->beacon_timer,
-				      ns_to_ktime(until_tbtt * 1000),
-				      HRTIMER_MODE_REL);
+		hrtimer_start(&data->beacon_timer,
+			      ns_to_ktime(until_tbtt * 1000),
+			      HRTIMER_MODE_REL_SOFT);
 	}
 
 	return 0;
@@ -1709,7 +1705,7 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
 			  info->enable_beacon, info->beacon_int);
 		vp->bcn_en = info->enable_beacon;
 		if (data->started &&
-		    !hrtimer_is_queued(&data->beacon_timer.timer) &&
+		    !hrtimer_is_queued(&data->beacon_timer) &&
 		    info->enable_beacon) {
 			u64 tsf, until_tbtt;
 			u32 bcn_int;
@@ -1717,9 +1713,9 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
 			tsf = mac80211_hwsim_get_tsf(hw, vif);
 			bcn_int = data->beacon_int;
 			until_tbtt = bcn_int - do_div(tsf, bcn_int);
-			tasklet_hrtimer_start(&data->beacon_timer,
-					      ns_to_ktime(until_tbtt * 1000),
-					      HRTIMER_MODE_REL);
+			hrtimer_start(&data->beacon_timer,
+				      ns_to_ktime(until_tbtt * 1000),
+				      HRTIMER_MODE_REL_SOFT);
 		} else if (!info->enable_beacon) {
 			unsigned int count = 0;
 			ieee80211_iterate_active_interfaces_atomic(
@@ -1728,7 +1724,7 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
 			wiphy_dbg(hw->wiphy, "  beaconing vifs remaining: %u",
 				  count);
 			if (count == 0) {
-				tasklet_hrtimer_cancel(&data->beacon_timer);
+				hrtimer_cancel(&data->beacon_timer);
 				data->beacon_int = 0;
 			}
 		}
@@ -2720,9 +2716,9 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
 				    data->debugfs,
 				    data, &hwsim_simulate_radar);
 
-	tasklet_hrtimer_init(&data->beacon_timer,
-			     mac80211_hwsim_beacon,
-			     CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+	hrtimer_init(&data->beacon_timer, CLOCK_MONOTONIC,
+		     HRTIMER_MODE_REL_SOFT);
+	data->beacon_timer.function = mac80211_hwsim_beacon;
 
 	spin_lock_bh(&hwsim_radio_lock);
 	list_add_tail(&data->list, &hwsim_radios);
-- 
2.11.0

^ permalink raw reply related

* Re: [PATCH] ath10k: handling qos at STA side based on AP WMM enable/disable
From: Sebastian Gottschall @ 2017-11-29 13:38 UTC (permalink / raw)
  To: Balaji Pothunoori, ath10k@lists.infradead.org
  Cc: linux-wireless@vger.kernel.org
In-Reply-To: <8f027afc7c094e6d84ff4205384eb66d@aptaiexm02b.ap.qualcomm.com>

Am 29.11.2017 um 11:12 schrieb Balaji Pothunoori:
>>> Hi Sebastian,
>>>
>>> If I am not wrong you are seeing the issue with WRT3200ACM (Marvell 88W8964) as client + QCA9984 (FW : 10.4-3.5.3-00038) as AP with below change you are seeing the crash while running traffic between the WRT3200ACM + QCA9984 ?
>>> Do you used  any other client in place of WRT3200ACM ?
>> there is not much  traffic required. as it seems the firmware crashes immediatly after association. the issue is also not present in 10.4-3.4-0082ww
> Still my question is not cleared,  firmware crash is due to this patch ? Also let me know do you observed same behavior with any other chipset ?

no. its unrelated to this patch but since you're working for qca i 
thought it would make sense to tell you this since saw that you're using 
ath10k firmwares which arent published officiall but based on the

qca firmwares which are published on chipcode. since i was testing  
these firmwares too some weeks ago i found its a good idea to tell you this

>
>   
> Regards,
> Balaji.
>
>> Sebastian
>
>>> Regards,
>>> Balaji.
> -----Original Message-----
> From: Sebastian Gottschall [mailto:s.gottschall@dd-wrt.com]
> Sent: Wednesday, November 29, 2017 2:04 PM
> To: Balaji Pothunoori <bpothuno@qti.qualcomm.com>; ath10k@lists.infradead.org
> Cc: linux-wireless@vger.kernel.org
> Subject: Re: [PATCH] ath10k: handling qos at STA side based on AP WMM enable/disable
>
> Am 29.11.2017 um 07:58 schrieb Balaji Pothunoori:
>> Hi Sebastian,
>>
>> If I am not wrong you are seeing the issue with WRT3200ACM (Marvell 88W8964) as client + QCA9984 (FW : 10.4-3.5.3-00038) as AP with below change you are seeing the crash while running traffic between the WRT3200ACM + QCA9984 ?
>> Do you used  any other client in place of WRT3200ACM ?
> there is not much  traffic required. as it seems the firmware crashes immediatly after association. the issue is also not present in 10.4-3.4-0082ww
>
>> Can you share the more details on firmware crash ?
> so a firmware crashdump from log? i'll try to get it within the next hours. just need to resetup the test scenario
>
>
> Sebastian
>
>
>> Regards,
>> Balaji.
>>
>> -----Original Message-----
>> From: Sebastian Gottschall [mailto:s.gottschall@dd-wrt.com]
>> Sent: Wednesday, November 29, 2017 8:28 AM
>> To: Balaji Pothunoori <bpothuno@qti.qualcomm.com>; ath10k@lists.infradead.org
>> Cc: linux-wireless@vger.kernel.org
>> Subject: Re: [PATCH] ath10k: handling qos at STA side based on AP WMM enable/disable
>>
>> did you notice  that Marvell 88W8964 based clients will crash 10.4-3.5.3 firmwares?  (tested with 9984 and 10.4-3.5.3-00038) client device was a linksys wrt3200acm running dd-wrt for testing
>>
>> Am 28.11.2017 um 11:07 schrieb bpothuno@qti.qualcomm.com:
>>> From: Balaji Pothunoori <bpothuno@qti.qualcomm.com>
>>>
>>> Data packets are not sent by STA in case of STA joined to non QOS AP
>>> (WMM disabled AP). This is happening because of STA is sending data
>>> packets to firmware from host with qos enabled along with non qos
>>> queue value(TID = 16).
>>> Due to qos enabled, firmware is discarding the packet.
>>>
>>> This patch fixes this issue by updating the qos based on station WME
>>> capability field if WMM is disabled in AP.
>>>
>>> This patch is required by 10.4 family chipsets like
>>> QCA4019/QCA9888/QCA9884/QCA99X0.
>>> Firmware Versoin : 10.4-3.5.1-00018.
>>>
>>> For 10.2.4 family chipsets QCA988X/QCA9887 and QCA6174 this patch has
>>> no effect.
>>>
>>> Signed-off-by: Balaji Pothunoori <bpothuno@qti.qualcomm.com>
>>> ---
>>>     drivers/net/wireless/ath/ath10k/mac.c |    2 +-
>>>     1 file changed, 1 insertion(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/net/wireless/ath/ath10k/mac.c
>>> b/drivers/net/wireless/ath/ath10k/mac.c
>>> index 0a947ee..2616b99 100644
>>> --- a/drivers/net/wireless/ath/ath10k/mac.c
>>> +++ b/drivers/net/wireless/ath/ath10k/mac.c
>>> @@ -2563,7 +2563,7 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
>>>     		}
>>>     		break;
>>>     	case WMI_VDEV_TYPE_STA:
>>> -		if (vif->bss_conf.qos)
>>> +		if (sta->wme)
>>>     			arg->peer_flags |= arvif->ar->wmi.peer_flags->qos;
>>>     		break;
>>>     	case WMI_VDEV_TYPE_IBSS:
>> --
>> Mit freundlichen Grüssen / Regards
>>
>> Sebastian Gottschall / CTO
>>
>> NewMedia-NET GmbH - DD-WRT
>> Firmensitz:  Stubenwaldallee 21a, 64625 Bensheim
>> Registergericht: Amtsgericht Darmstadt, HRB 25473
>> Geschäftsführer: Peter Steinhäuser, Christian Scheele http://www.dd-wrt.com
>> email: s.gottschall@dd-wrt.com
>> Tel.: +496251-582650 / Fax: +496251-5826565
>>

-- 
Mit freundlichen Grüssen / Regards

Sebastian Gottschall / CTO

NewMedia-NET GmbH - DD-WRT
Firmensitz:  Stubenwaldallee 21a, 64625 Bensheim
Registergericht: Amtsgericht Darmstadt, HRB 25473
Geschäftsführer: Peter Steinhäuser, Christian Scheele
http://www.dd-wrt.com
email: s.gottschall@dd-wrt.com
Tel.: +496251-582650 / Fax: +496251-5826565

^ permalink raw reply

* Re: [PATCH 5/8] Bluetooth: btrsi: add new rsi bluetooth driver
From: Marcel Holtmann @ 2017-11-29 13:33 UTC (permalink / raw)
  To: Amitkumar Karwar
  Cc: Kalle Valo, linux-wireless, Amitkumar Karwar,
	Prameela Rani Garnepudi, open list:BLUETOOTH DRIVERS,
	Siva Rebbagondla
In-Reply-To: <CAEhWJF=pvMSz5XRp0vPyej6KBnD-frDYFggy55jEJv3ciXim_Q@mail.gmail.com>

Hi Amitkumar,

>>> Redpine bluetooth driver is a thin driver which depends on
>>> 'rsi_91x' driver for transmitting and receiving packets
>>> to/from device. It creates hci interface when attach() is
>>> called from 'rsi_91x' module.
>>> 
>>> Signed-off-by: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>
>>> Signed-off-by: Siva Rebbagondla <siva.rebbagondla@redpinesignals.com>
>>> Signed-off-by: Amitkumar Karwar <amit.karwar@redpinesignals.com>
>>> ---
>>> drivers/bluetooth/Kconfig   |  12 ++
>>> drivers/bluetooth/Makefile  |   2 +
>>> drivers/bluetooth/btrsi.c   | 268 ++++++++++++++++++++++++++++++++++++++++++++
>>> drivers/bluetooth/rsi_hci.h |  51 +++++++++
>>> 4 files changed, 333 insertions(+)
>>> create mode 100644 drivers/bluetooth/btrsi.c
>>> create mode 100644 drivers/bluetooth/rsi_hci.h
>>> 
>>> diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
>>> index 60e1c7d..ca58d74 100644
>>> --- a/drivers/bluetooth/Kconfig
>>> +++ b/drivers/bluetooth/Kconfig
>>> @@ -378,4 +378,16 @@ config BT_QCOMSMD
>>>        Say Y here to compile support for HCI over Qualcomm SMD into the
>>>        kernel or say M to compile as a module.
>>> 
>>> +config BT_RSI
>>> +     tristate "Redpine HCI support"
>>> +     depends on BT && BT_RFCOMM
>> 
>> the depends on BT_RFCOMM is wrong. And even the depends on BT is unneeded since that is already covered with the above menu clause.
>> 
>> 
>>> +     default m
>> 
>> No. New drivers are by default off.
> 
> We made it by default on, as RSI core module depends on this.
> 
>> 
>>> +     help
>>> +       Redpine BT driver.
>>> +       This driver handles BT traffic from upper layers and pass
>>> +       to the RSI_91x coex module for further scheduling to device
>>> +
>>> +       Say Y here to compile support for HCI over Qualcomm SMD into the
>>> +       kernel or say M to compile as a module.
>>> +
>> 
>> What I am missing is the depends on the RSI core piece that is needed.
> 
> Actually RSI core module depends on RSI BT module as per our design.
> As soon as firmware is downloaded by RSI core module, we get WLAN and
> BT card ready frames from firmware. BT initialization has to happen at
> this point. So btrsi module should be loaded first.

that should be solved by the dependencies and not by a default m.

> 
>> 
>>> endmenu
>>> diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
>>> index 4e4e44d..712af83a 100644
>>> --- a/drivers/bluetooth/Makefile
>>> +++ b/drivers/bluetooth/Makefile
>>> @@ -28,6 +28,8 @@ obj-$(CONFIG_BT_QCA)                += btqca.o
>>> 
>>> obj-$(CONFIG_BT_HCIUART_NOKIA)        += hci_nokia.o
>>> 
>>> +obj-$(CONFIG_BT_RSI)         += btrsi.o
>>> +
>>> btmrvl-y                      := btmrvl_main.o
>>> btmrvl-$(CONFIG_DEBUG_FS)     += btmrvl_debugfs.o
>>> 
>>> diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c
>>> new file mode 100644
>>> index 0000000..c52f418
>>> --- /dev/null
>>> +++ b/drivers/bluetooth/btrsi.c
>>> @@ -0,0 +1,268 @@
>>> +/**
>>> + * Copyright (c) 2017 Redpine Signals Inc.
>>> + *
>>> + * Permission to use, copy, modify, and/or distribute this software for any
>>> + * purpose with or without fee is hereby granted, provided that the above
>>> + * copyright notice and this permission notice appear in all copies.
>>> + *
>>> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
>>> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
>>> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
>>> +e* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
>>> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
>>> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
>>> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>>> + */
>>> +#include <linux/version.h>
>>> +#include <linux/module.h>
>>> +#include <linux/kernel.h>
>>> +#include "rsi_hci.h"
>>> +
>>> +static struct rsi_mod_ops rsi_bt_ops = {
>>> +     .attach = rsi_hci_attach,
>>> +     .detach = rsi_hci_detach,
>>> +     .recv_pkt = rsi_hci_recv_pkt,
>>> +};
>>> +
>>> +static int rsi_hci_open(struct hci_dev *hdev)
>>> +{
>>> +     BT_INFO("%s open\n", hdev->name);
>> 
>> No BT_INFO here. We are not spamming dmesg with pointless information. And this applies to all of these.
>> 
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +static int rsi_hci_close(struct hci_dev *hdev)
>>> +{
>>> +     BT_INFO("%s closed\n", hdev->name);
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +static int rsi_hci_flush(struct hci_dev *hdev)
>>> +{
>>> +     BT_ERR("%s flush\n", hdev->name);
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +static int rsi_hci_send_pkt(struct hci_dev *hdev, struct sk_buff *skb)
>>> +{
>>> +     struct rsi_hci_adapter *h_adapter;
>> 
>>                                        = hci_get_drvdata(dev);
>> 
>> There is no need to do that separate.
>> 
>>> +     struct sk_buff *new_skb = NULL;
>>> +
>>> +     int status = 0;
>>> +
>>> +     h_adapter = hci_get_drvdata(hdev);
>>> +     if (!h_adapter) {
>>> +             status = -EFAULT;
>>> +             goto fail;
>>> +     }
>> 
>> And this error check seems unneeded since the Bluetooth core will never call ->send unless it is all correctly set up.
>> 
>>> +
>>> +     if (h_adapter->fsm_state != RSI_BT_FSM_DEVICE_READY) {
>>> +             BT_INFO("BT Device not ready\n");
>>> +             status = -ENODEV;
>>> +             goto fail;
>>> +     }
>> 
>> Why are we registering a HCI device that might not be ready. This will be a massive bug in the whole system. Also one that is not recoverable. If something goes wrong, then lets unregister the HCI device.
>> 
>>> +
>>> +     if (!test_bit(HCI_RUNNING, &hdev->flags)) {
>>> +             status = -EBUSY;
>>> +             goto fail;
>>> +     }
>> 
>> This should no longer be needed. We moved this into the core and besides some old USB drivers, nobody is using this anymore.
>> 
>>> +
>>> +     switch (bt_cb(skb)->pkt_type) {
>>> +     case HCI_COMMAND_PKT:
>>> +             hdev->stat.cmd_tx++;
>>> +             break;
>>> +
>>> +     case HCI_ACLDATA_PKT:
>>> +             hdev->stat.acl_tx++;
>>> +             break;
>>> +
>>> +     case HCI_SCODATA_PKT:
>>> +             hdev->stat.sco_tx++;
>>> +             break;
>>> +
>>> +     default:
>>> +             dev_kfree_skb(skb);
>> 
>> Don’t use dev_kfree_skb() here. I think the Bluetooth subsystem is not ready for that.
>> 
>>> +             status = -EILSEQ;
>>> +             goto fail;
>>> +     }
>>> +
>>> +     if (skb_headroom(skb) < RSI_HEADROOM_FOR_BT_HAL) {
>>> +             /* Re-allocate one more skb with sufficent headroom */
>>> +             /* Space for Descriptor (16 bytes) is required in head room */
>>> +             u16 new_len = skb->len + RSI_HEADROOM_FOR_BT_HAL;
>>> +
>>> +             new_skb = dev_alloc_skb(new_len);
>>> +             if (!new_skb) {
>>> +                     dev_kfree_skb(skb);
>>> +                     return -ENOMEM;
>>> +             }
>>> +             skb_reserve(new_skb, RSI_HEADROOM_FOR_BT_HAL);
>>> +             skb_put(new_skb, skb->len);
>>> +             memcpy(new_skb->data, skb->data, skb->len);
>>> +             bt_cb(new_skb)->pkt_type = bt_cb(skb)->pkt_type;
>>> +             dev_kfree_skb(skb);
>>> +             skb = new_skb;
>> 
>> Just allocate a new skb with proper headroom. The data part can be shared. Doing this fully manual is just a bad idea.
>> 
>> I also get the feeling that long term we want to change the Bluetooth drivers to specify the required SKB headroom so that they always get SKBs that are large enough for their needs.
>> 
>>> +     }
>>> +     if (h_adapter->proto_ops->coex_send_pkt)
>>> +             return h_adapter->proto_ops->coex_send_pkt(h_adapter->priv, skb,
>>> +                                                       RSI_BT_Q);
>> 
>> This is worrisome. You need to send. If this callback is not available, then better not register the HCI device at all.
>> 
>>> +
>>> +fail:
>>> +     dev_kfree_skb(skb);
>>> +     return status;
>>> +}
>>> +
>>> +int rsi_hci_recv_pkt(void *priv, u8 *pkt)
>>> +{
>>> +     struct rsi_hci_adapter *h_adapter = (struct rsi_hci_adapter *)priv;
>>> +     struct hci_dev *hdev = NULL;
>>> +     struct sk_buff *skb;
>>> +     int pkt_len = (le16_to_cpu(*(__le16 *)pkt)) & 0x0fff;
>>> +     u8 queue_no = (le16_to_cpu(*(__le16 *)pkt) & 0x7000) >> 12;
>> 
>> We have get_unaligned_le16 helpers for this.
>> 
>>> +
>>> +     if (h_adapter->fsm_state != RSI_BT_FSM_DEVICE_READY) {
>>> +             BT_INFO("BT Device not ready\n");
>>> +             return 0;
>>> +     }
>> 
>> Why call this function if the device is not ready? Can that not be checked and the HCI device not be registered.
>> 
>>> +
>>> +     if (queue_no == RSI_BT_MGMT_Q) {
>>> +             u8 msg_type = pkt[14] & 0xFF;
>>> +
>>> +             switch (msg_type) {
>>> +             case RSI_RESULT_CONFIRM:
>>> +                     BT_INFO("BT Result Confirm\n");
>>> +                     return 0;
>>> +             case RSI_BT_BER:
>>> +                     BT_INFO("BT Ber\n");
>>> +                     return 0;
>>> +             case RSI_BT_CW:
>>> +                     BT_INFO("BT CW\n");
>>> +                     return 0;
>>> +             default:
>>> +                     break;
>>> +             }
>>> +     }
>> 
>> How noisy is this? Also no \n required for the BT_INFO functions. And here bt_dev_info is preferred anyway.
>> 
>>> +
>>> +     skb = dev_alloc_skb(pkt_len);
>>> +     if (!skb)
>>> +             return -ENOMEM;
>>> +
>>> +     hdev = h_adapter->hdev;
>>> +     memcpy(skb->data, pkt + RSI_FRAME_DESC_SIZE, pkt_len);
>>> +     skb_put(skb, pkt_len);
>>> +     h_adapter->hdev->stat.byte_rx += skb->len;
>>> +
>>> +     skb->dev = (void *)hdev;
>>> +     bt_cb(skb)->pkt_type = pkt[14];
>>> +
>>> +     return hci_recv_frame(hdev, skb);
>>> +}
>>> +EXPORT_SYMBOL_GPL(rsi_hci_recv_pkt);
>>> +
>>> +int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops)
>>> +{
>>> +     struct rsi_hci_adapter *h_adapter = NULL;
>>> +     struct hci_dev *hdev;
>>> +     int status = 0;
>>> +
>>> +     h_adapter = kzalloc(sizeof(*h_adapter), GFP_KERNEL);
>>> +     if (!h_adapter)
>>> +             return -ENOMEM;
>>> +
>>> +     h_adapter->priv = priv;
>>> +     ops->set_bt_context(priv, h_adapter);
>>> +     h_adapter->proto_ops = ops;
>>> +     ops->bt_ops = &rsi_bt_ops;
>>> +     h_adapter->fsm_state = RSI_BT_FSM_DEVICE_READY;
>>> +
>>> +     hdev = hci_alloc_dev();
>>> +     if (!hdev) {
>>> +             BT_ERR("Failed to alloc HCI device\n");
>>> +             goto err;
>>> +     }
>>> +     h_adapter->hdev = hdev;
>>> +
>>> +     if (ops->get_host_intf(priv) == RSI_HOST_INTF_SDIO)
>>> +             hdev->bus = HCI_SDIO;
>>> +     else
>>> +             hdev->bus = HCI_USB;
>>> +
>>> +     hci_set_drvdata(hdev, h_adapter);
>>> +     hdev->dev_type = HCI_PRIMARY;
>>> +     hdev->open = rsi_hci_open;
>>> +     hdev->close = rsi_hci_close;
>>> +     hdev->flush = rsi_hci_flush;
>>> +     hdev->send = rsi_hci_send_pkt;
>>> +
>>> +     status = hci_register_dev(hdev);
>>> +     if (status < 0) {
>>> +             BT_ERR("%s: HCI registration failed with errcode %d\n",
>>> +                    __func__, status);
>>> +             goto err;
>>> +     }
>>> +
>>> +     BT_INFO("%s interface created\n", hdev->name);
>>> +
>>> +     h_adapter->fsm_state = RSI_BT_FSM_DEVICE_READY;
>>> +
>>> +     return 0;
>>> +
>>> +err:
>>> +     if (hdev) {
>>> +             hci_unregister_dev(hdev);
>>> +             hci_free_dev(hdev);
>>> +             h_adapter->hdev = NULL;
>>> +     }
>>> +     kfree(h_adapter);
>>> +
>>> +     return -EINVAL;
>>> +}
>>> +
>>> +void rsi_hci_detach(void *priv)
>>> +{
>>> +     struct rsi_hci_adapter *h_adapter = (struct rsi_hci_adapter *)priv;
>>> +     struct hci_dev *hdev;
>>> +
>>> +     if (!h_adapter)
>>> +             return;
>>> +
>>> +     hdev = h_adapter->hdev;
>>> +
>>> +     BT_INFO("Detaching %s\n", hdev->name);
>>> +
>>> +     if (hdev) {
>>> +             hci_unregister_dev(hdev);
>>> +             hci_free_dev(hdev);
>>> +             h_adapter->hdev = NULL;
>>> +     }
>>> +
>>> +     kfree(h_adapter);
>>> +     h_adapter->fsm_state = RSI_BT_FSM_DEVICE_NOT_READY;
>>> +}
>>> +
>>> +struct rsi_mod_ops *rsi_get_hci_ops(void)
>>> +{
>>> +     return &rsi_bt_ops;
>>> +};
>>> +EXPORT_SYMBOL_GPL(rsi_get_hci_ops);
>>> +
>>> +static int rsi_91x_bt_module_init(void)
>>> +{
>>> +     BT_INFO("%s: BT Module init called\n", __func__);
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +static void rsi_91x_bt_module_exit(void)
>>> +{
>>> +     BT_INFO("%s: BT Module exit called\n", __func__);
>>> +}
>>> +
>>> +module_init(rsi_91x_bt_module_init);
>>> +module_exit(rsi_91x_bt_module_exit);
>>> +MODULE_AUTHOR("Redpine Signals Inc");
>>> +MODULE_DESCRIPTION("RSI BT driver");
>>> +MODULE_SUPPORTED_DEVICE("RSI-BT");
>>> +MODULE_LICENSE("Dual BSD/GPL");
>>> diff --git a/drivers/bluetooth/rsi_hci.h b/drivers/bluetooth/rsi_hci.h
>>> new file mode 100644
>>> index 0000000..6f44231
>>> --- /dev/null
>>> +++ b/drivers/bluetooth/rsi_hci.h
>>> @@ -0,0 +1,51 @@
>>> +/**
>>> + * Copyright (c) 2017 Redpine Signals Inc.
>>> + *
>>> + * Permission to use, copy, modify, and/or distribute this software for any
>>> + * purpose with or without fee is hereby granted, provided that the above
>>> + * copyright notice and this permission notice appear in all copies.
>>> + *
>>> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
>>> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
>>> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
>>> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
>>> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
>>> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
>>> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>>> + */
>>> +
>>> +#ifndef __RSI_HCI_H__
>>> +#define __RSI_HCI_H__
>>> +
>>> +#include <net/bluetooth/bluetooth.h>
>>> +#include <net/bluetooth/hci_core.h>
>>> +#include <linux/rsi_header.h>
>>> +#include <net/genetlink.h>
>>> +
>>> +/* RX frame types */
>>> +#define RSI_RESULT_CONFIRM                   0x80
>>> +#define RSI_BT_PER                           0x10
>>> +#define RSI_BT_BER                           0x11
>>> +#define RSI_BT_CW                            0x12
>>> +
>>> +#define RSI_HEADROOM_FOR_BT_HAL      16
>>> +
>>> +enum bt_fsm_state {
>>> +     RSI_BT_FSM_DEVICE_NOT_READY = 0,
>>> +     RSI_BT_FSM_DEVICE_READY,
>>> +};
>>> +
>>> +struct rsi_hci_adapter {
>>> +     void *priv;
>>> +     struct rsi_proto_ops *proto_ops;
>>> +     enum bt_fsm_state fsm_state;
>>> +     struct hci_dev *hdev;
>>> +};
>> 
>> If they are btrsi.c specific, they should be in btrsi.c and not in a header file.
>> 
>>> +
>>> +#define RSI_FRAME_DESC_SIZE          16
>>> +
>>> +int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops);
>>> +void rsi_hci_detach(void *priv);
>>> +int rsi_hci_recv_pkt(void *data, u8 *pkt);
>> 
>> And this is the part I do not get. What is the deal with the rsi_bt_ops. Having both exported is pointless.
> 
> rsi core module initializes rsi_bt_ops by calling exported function
> rsi_get_hci_ops().

Still exporting both is pointless. There are a few too many exports / public functions here. Make as much static as possible.

Regards

Marcel

^ permalink raw reply

* [v2 8/8] rsi: sdio changes to support BT
From: Amitkumar Karwar @ 2017-11-29 12:45 UTC (permalink / raw)
  To: Kalle Valo, marcel
  Cc: linux-wireless, Amitkumar Karwar, Prameela Rani Garnepudi,
	linux-bluetooth
In-Reply-To: <1511959513-3902-1-git-send-email-amitkarwar@gmail.com>

From: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>

Queue number is correctly updated for BT traffic. Also, kzalloc
instead of kmalloc is used for Rx packet allocation.

Signed-off-by: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>
Signed-off-by: Amitkumar Karwar <amit.karwar@redpinesignals.com>
---
 drivers/net/wireless/rsi/rsi_91x_sdio.c     | 2 ++
 drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
index 5722736..beb18d0 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -763,6 +763,8 @@ static int rsi_sdio_host_intf_write_pkt(struct rsi_hw *adapter,
 	int status;
 
 	queueno = ((pkt[1] >> 4) & 0xf);
+	if (queueno == RSI_BT_MGMT_Q || queueno == RSI_BT_DATA_Q)
+		queueno = RSI_BT_Q;
 
 	num_blocks = len / block_size;
 
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
index 26abe51..83652bd 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
@@ -103,7 +103,7 @@ static int rsi_process_pkt(struct rsi_common *common)
 
 	rcv_pkt_len = (num_blks * 256);
 
-	common->rx_data_pkt = kmalloc(rcv_pkt_len, GFP_KERNEL);
+	common->rx_data_pkt = kzalloc(rcv_pkt_len, GFP_KERNEL);
 	if (!common->rx_data_pkt) {
 		rsi_dbg(ERR_ZONE, "%s: Failed in memory allocation\n",
 			__func__);
-- 
2.7.4

^ permalink raw reply related

* [v2 7/8] rsi: add module parameter operating mode
From: Amitkumar Karwar @ 2017-11-29 12:45 UTC (permalink / raw)
  To: Kalle Valo, marcel
  Cc: linux-wireless, Amitkumar Karwar, Prameela Rani Garnepudi,
	linux-bluetooth, Siva Rebbagondla
In-Reply-To: <1511959513-3902-1-git-send-email-amitkarwar@gmail.com>

From: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>

Operating mode determines the support for other protocols.
This is made as module parameter for better usage.

Signed-off-by: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>
Signed-off-by: Siva Rebbagondla <siva.rebbagondla@redpinesignals.com>
Signed-off-by: Amitkumar Karwar <amit.karwar@redpinesignals.com>
---
 drivers/net/wireless/rsi/rsi_91x_main.c | 58 ++++++++++++++++++++++++++++-----
 drivers/net/wireless/rsi/rsi_91x_sdio.c | 10 +++++-
 drivers/net/wireless/rsi/rsi_91x_usb.c  | 10 +++++-
 drivers/net/wireless/rsi/rsi_common.h   |  2 +-
 drivers/net/wireless/rsi/rsi_hal.h      | 11 +++++++
 5 files changed, 80 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c
index 00f54c5..084b779 100644
--- a/drivers/net/wireless/rsi/rsi_91x_main.c
+++ b/drivers/net/wireless/rsi/rsi_91x_main.c
@@ -69,8 +69,24 @@ EXPORT_SYMBOL_GPL(rsi_dbg);
 static char *opmode_str(int oper_mode)
 {
 	switch (oper_mode) {
-	case RSI_DEV_OPMODE_WIFI_ALONE:
+	case DEV_OPMODE_WIFI_ALONE:
 		return "Wi-Fi alone";
+	case DEV_OPMODE_BT_ALONE:
+		return "BT EDR alone";
+	case DEV_OPMODE_BT_LE_ALONE:
+		return "BT LE alone";
+	case DEV_OPMODE_BT_DUAL:
+		return "BT Dual";
+	case DEV_OPMODE_STA_BT:
+		return "Wi-Fi STA + BT EDR";
+	case DEV_OPMODE_STA_BT_LE:
+		return "Wi-Fi STA + BT LE";
+	case DEV_OPMODE_STA_BT_DUAL:
+		return "Wi-Fi STA + BT DUAL";
+	case DEV_OPMODE_AP_BT:
+		return "Wi-Fi AP + BT EDR";
+	case DEV_OPMODE_AP_BT_DUAL:
+		return "Wi-Fi AP + BT DUAL";
 	}
 
 	return "Unknown";
@@ -278,7 +294,7 @@ void *rsi_get_bt_context(void *priv)
  *
  * Return: Pointer to the adapter structure on success, NULL on failure .
  */
-struct rsi_hw *rsi_91x_init(void)
+struct rsi_hw *rsi_91x_init(u16 oper_mode)
 {
 	struct rsi_hw *adapter = NULL;
 	struct rsi_common *common = NULL;
@@ -320,11 +336,34 @@ struct rsi_hw *rsi_91x_init(void)
 	spin_lock_init(&adapter->ps_lock);
 	timer_setup(&common->roc_timer, rsi_roc_timeout, 0);
 	init_completion(&common->wlan_init_completion);
+	common->oper_mode = oper_mode;
 	common->init_done = true;
-
-	common->coex_mode = RSI_DEV_COEX_MODE_WIFI_ALONE;
-	common->oper_mode = RSI_DEV_OPMODE_WIFI_ALONE;
 	adapter->device_model = RSI_DEV_9113;
+
+	/* Determine coex mode */
+	switch (common->oper_mode) {
+	case DEV_OPMODE_STA_BT_DUAL:
+	case DEV_OPMODE_STA_BT:
+	case DEV_OPMODE_STA_BT_LE:
+	case DEV_OPMODE_BT_ALONE:
+	case DEV_OPMODE_BT_LE_ALONE:
+	case DEV_OPMODE_BT_DUAL:
+		common->coex_mode = 2;
+		break;
+	case DEV_OPMODE_AP_BT_DUAL:
+	case DEV_OPMODE_AP_BT:
+		common->coex_mode = 4;
+		break;
+	case DEV_OPMODE_WIFI_ALONE:
+		common->coex_mode = 1;
+		break;
+	default:
+		common->oper_mode = 1;
+		common->coex_mode = 1;
+	}
+	rsi_dbg(INFO_ZONE, "%s: oper_mode = %d, coex_mode = %d\n",
+		__func__, common->oper_mode, common->coex_mode);
+
 	if (common->coex_mode > 1) {
 		if (rsi_coex_attach(common)) {
 			rsi_dbg(ERR_ZONE, "Failed to init coex module\n");
@@ -359,10 +398,13 @@ void rsi_91x_deinit(struct rsi_hw *adapter)
 	for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
 		skb_queue_purge(&common->tx_queue[ii]);
 
-	common->init_done = false;
-
-	if (common->coex_mode > 1)
+	if (common->coex_mode > 1) {
 		rsi_coex_detach(common);
+		if (g_proto_ops.bt_ops->detach)
+			g_proto_ops.bt_ops->detach(common->bt_adapter);
+	}
+
+	common->init_done = false;
 
 	kfree(common);
 	kfree(adapter->rsi_dev);
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
index ba38c6d..5722736 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -21,6 +21,14 @@
 #include "rsi_coex.h"
 #include "rsi_hal.h"
 
+/* Default operating mode is wlan STA + BT */
+static u16 dev_oper_mode = DEV_OPMODE_STA_BT_DUAL;
+module_param(dev_oper_mode, ushort, 0444);
+MODULE_PARM_DESC(dev_oper_mode,
+		 "1[Wi-Fi], 4[BT], 8[BT LE], 5[Wi-Fi STA + BT classic]\n"
+		 "9[Wi-Fi STA + BT LE], 13[Wi-Fi STA + BT classic + BT LE]\n"
+		 "6[AP + BT classic], 14[AP + BT classic + BT LE]");
+
 /**
  * rsi_sdio_set_cmd52_arg() - This function prepares cmd 52 read/write arg.
  * @rw: Read/write
@@ -926,7 +934,7 @@ static int rsi_probe(struct sdio_func *pfunction,
 
 	rsi_dbg(INIT_ZONE, "%s: Init function called\n", __func__);
 
-	adapter = rsi_91x_init();
+	adapter = rsi_91x_init(dev_oper_mode);
 	if (!adapter) {
 		rsi_dbg(ERR_ZONE, "%s: Failed to init os intf ops\n",
 			__func__);
diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c
index b09c7da..a30305e 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb.c
@@ -21,6 +21,14 @@
 #include "rsi_hal.h"
 #include "rsi_coex.h"
 
+/* Default operating mode is wlan STA + BT */
+static u16 dev_oper_mode = DEV_OPMODE_STA_BT_DUAL;
+module_param(dev_oper_mode, ushort, 0444);
+MODULE_PARM_DESC(dev_oper_mode,
+		 "1[Wi-Fi], 4[BT], 8[BT LE], 5[Wi-Fi STA + BT classic]\n"
+		 "9[Wi-Fi STA + BT LE], 13[Wi-Fi STA + BT classic + BT LE]\n"
+		 "6[AP + BT classic], 14[AP + BT classic + BT LE]");
+
 /**
  * rsi_usb_card_write() - This function writes to the USB Card.
  * @adapter: Pointer to the adapter structure.
@@ -708,7 +716,7 @@ static int rsi_probe(struct usb_interface *pfunction,
 
 	rsi_dbg(INIT_ZONE, "%s: Init function called\n", __func__);
 
-	adapter = rsi_91x_init();
+	adapter = rsi_91x_init(dev_oper_mode);
 	if (!adapter) {
 		rsi_dbg(ERR_ZONE, "%s: Failed to init os intf ops\n",
 			__func__);
diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h
index 4616585..d9ff3b8 100644
--- a/drivers/net/wireless/rsi/rsi_common.h
+++ b/drivers/net/wireless/rsi/rsi_common.h
@@ -81,7 +81,7 @@ static inline int rsi_kill_thread(struct rsi_thread *handle)
 
 void rsi_mac80211_detach(struct rsi_hw *hw);
 u16 rsi_get_connected_channel(struct ieee80211_vif *vif);
-struct rsi_hw *rsi_91x_init(void);
+struct rsi_hw *rsi_91x_init(u16 oper_mode);
 void rsi_91x_deinit(struct rsi_hw *adapter);
 int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len);
 #ifdef CONFIG_PM
diff --git a/drivers/net/wireless/rsi/rsi_hal.h b/drivers/net/wireless/rsi/rsi_hal.h
index e712223..a7d3011 100644
--- a/drivers/net/wireless/rsi/rsi_hal.h
+++ b/drivers/net/wireless/rsi/rsi_hal.h
@@ -17,6 +17,17 @@
 #ifndef __RSI_HAL_H__
 #define __RSI_HAL_H__
 
+/* Device Operating modes */
+#define DEV_OPMODE_WIFI_ALONE		1
+#define DEV_OPMODE_BT_ALONE		4
+#define DEV_OPMODE_BT_LE_ALONE		8
+#define DEV_OPMODE_BT_DUAL		12
+#define DEV_OPMODE_STA_BT		5
+#define DEV_OPMODE_STA_BT_LE		9
+#define DEV_OPMODE_STA_BT_DUAL		13
+#define DEV_OPMODE_AP_BT		6
+#define DEV_OPMODE_AP_BT_DUAL		14
+
 #define FLASH_WRITE_CHUNK_SIZE		(4 * 1024)
 #define FLASH_SECTOR_SIZE		(4 * 1024)
 
-- 
2.7.4

^ permalink raw reply related

* [v2 6/8] rsi: handle BT traffic in driver
From: Amitkumar Karwar @ 2017-11-29 12:45 UTC (permalink / raw)
  To: Kalle Valo, marcel
  Cc: linux-wireless, Amitkumar Karwar, Prameela Rani Garnepudi,
	linux-bluetooth, Siva Rebbagondla
In-Reply-To: <1511959513-3902-1-git-send-email-amitkarwar@gmail.com>

From: Siva Rebbagondla <siva.rebbagondla@redpinesignals.com>

BT frames are passed through coex and hal modules to BUS.
After firmware is loaded, based on the operating mode CARD
READY frame comes for each protocol. When BT card ready is
received, BT attach is called.
Protocol operations are exchanged between the modules
at initialization time.

Signed-off-by: Siva Rebbagondla <siva.rebbagondla@redpinesignals.com>
Signed-off-by: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>
Signed-off-by: Amitkumar Karwar <amit.karwar@redpinesignals.com>
---
v2: WLAN module depends on BT module. Updated in Kconfig
---
 drivers/net/wireless/rsi/Kconfig            |  2 +-
 drivers/net/wireless/rsi/rsi_91x_coex.c     |  4 ++-
 drivers/net/wireless/rsi/rsi_91x_core.c     | 16 +++++++---
 drivers/net/wireless/rsi/rsi_91x_hal.c      | 39 ++++++++++++++++++++++++
 drivers/net/wireless/rsi/rsi_91x_main.c     | 47 +++++++++++++++++++++++++++++
 drivers/net/wireless/rsi/rsi_91x_sdio_ops.c |  1 +
 drivers/net/wireless/rsi/rsi_common.h       |  1 +
 drivers/net/wireless/rsi/rsi_hal.h          | 10 ++++++
 drivers/net/wireless/rsi/rsi_main.h         |  5 +++
 include/linux/rsi_header.h                  |  2 ++
 10 files changed, 120 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/rsi/Kconfig b/drivers/net/wireless/rsi/Kconfig
index 7c5e4ca..ad72c80 100644
--- a/drivers/net/wireless/rsi/Kconfig
+++ b/drivers/net/wireless/rsi/Kconfig
@@ -13,7 +13,7 @@ if WLAN_VENDOR_RSI
 
 config RSI_91X
 	tristate "Redpine Signals Inc 91x WLAN driver support"
-	depends on MAC80211
+	depends on MAC80211 && BT_RSI
 	---help---
 	  This option enabes support for RSI 1x1 devices.
 	  Select M (recommended), if you have a RSI 1x1 wireless module.
diff --git a/drivers/net/wireless/rsi/rsi_91x_coex.c b/drivers/net/wireless/rsi/rsi_91x_coex.c
index 914a0c5..f502cf9 100644
--- a/drivers/net/wireless/rsi/rsi_91x_coex.c
+++ b/drivers/net/wireless/rsi/rsi_91x_coex.c
@@ -48,8 +48,10 @@ static void rsi_coex_sched_tx_pkts(struct rsi_coex_ctrl_block *coex_cb)
 			break;
 		}
 
-		if (coex_q == RSI_COEX_Q_BT)
+		if (coex_q == RSI_COEX_Q_BT) {
 			skb = skb_dequeue(&coex_cb->coex_tx_qs[RSI_COEX_Q_BT]);
+			rsi_send_bt_pkt(coex_cb->priv, skb);
+		}
 	}
 }
 
diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c
index d0d2201..046ace8 100644
--- a/drivers/net/wireless/rsi/rsi_91x_core.c
+++ b/drivers/net/wireless/rsi/rsi_91x_core.c
@@ -17,6 +17,7 @@
 #include "rsi_mgmt.h"
 #include "rsi_common.h"
 #include "rsi_hal.h"
+#include "rsi_coex.h"
 
 /**
  * rsi_determine_min_weight_queue() - This function determines the queue with
@@ -301,14 +302,19 @@ void rsi_core_qos_processor(struct rsi_common *common)
 			mutex_unlock(&common->tx_lock);
 			break;
 		}
-
-		if (q_num == MGMT_SOFT_Q) {
-			status = rsi_send_mgmt_pkt(common, skb);
-		} else if (q_num == MGMT_BEACON_Q) {
+		if (q_num == MGMT_BEACON_Q) {
 			status = rsi_send_pkt_to_bus(common, skb);
 			dev_kfree_skb(skb);
 		} else {
-			status = rsi_send_data_pkt(common, skb);
+			if (common->coex_mode > 1) {
+				status = rsi_coex_send_pkt(common, skb,
+							   RSI_WLAN_Q);
+			} else {
+				if (q_num == MGMT_SOFT_Q)
+					status = rsi_send_mgmt_pkt(common, skb);
+				else
+					status = rsi_send_data_pkt(common, skb);
+			}
 		}
 
 		if (status) {
diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c
index 8b30448..883dba1 100644
--- a/drivers/net/wireless/rsi/rsi_91x_hal.c
+++ b/drivers/net/wireless/rsi/rsi_91x_hal.c
@@ -15,6 +15,7 @@
  */
 
 #include <linux/firmware.h>
+#include <net/bluetooth/bluetooth.h>
 #include "rsi_mgmt.h"
 #include "rsi_hal.h"
 #include "rsi_sdio.h"
@@ -24,6 +25,7 @@
 static struct ta_metadata metadata_flash_content[] = {
 	{"flash_content", 0x00010000},
 	{"rsi/rs9113_wlan_qspi.rps", 0x00010000},
+	{"rsi/rs9113_wlan_bt_dual_mode.rps", 0x00010000},
 };
 
 int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb)
@@ -357,6 +359,43 @@ int rsi_send_mgmt_pkt(struct rsi_common *common,
 	return status;
 }
 
+int rsi_send_bt_pkt(struct rsi_common *common, struct sk_buff *skb)
+{
+	int status = -EINVAL;
+	u8 header_size = 0;
+	struct rsi_bt_desc *bt_desc;
+	u8 queueno = ((skb->data[1] >> 4) & 0xf);
+
+	if (queueno == RSI_BT_MGMT_Q) {
+		status = rsi_send_pkt_to_bus(common, skb);
+		if (status)
+			rsi_dbg(ERR_ZONE, "%s: Failed to write bt mgmt pkt\n",
+				__func__);
+		goto out;
+	}
+	header_size = FRAME_DESC_SZ;
+	if (header_size > skb_headroom(skb)) {
+		rsi_dbg(ERR_ZONE, "%s: Not enough headroom\n", __func__);
+		status = -ENOSPC;
+		goto out;
+	}
+	skb_push(skb, header_size);
+	memset(skb->data, 0, header_size);
+	bt_desc = (struct rsi_bt_desc *)skb->data;
+
+	rsi_set_len_qno(&bt_desc->len_qno, (skb->len - FRAME_DESC_SZ),
+			RSI_BT_DATA_Q);
+	bt_desc->bt_pkt_type = cpu_to_le16(bt_cb(skb)->pkt_type);
+
+	status = rsi_send_pkt_to_bus(common, skb);
+	if (status)
+		rsi_dbg(ERR_ZONE, "%s: Failed to write bt pkt\n", __func__);
+
+out:
+	dev_kfree_skb(skb);
+	return status;
+}
+
 int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb)
 {
 	struct rsi_hw *adapter = (struct rsi_hw *)common->priv;
diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c
index 7dce533..00f54c5 100644
--- a/drivers/net/wireless/rsi/rsi_91x_main.c
+++ b/drivers/net/wireless/rsi/rsi_91x_main.c
@@ -18,6 +18,7 @@
 
 #include <linux/module.h>
 #include <linux/firmware.h>
+#include <linux/rsi_header.h>
 #include "rsi_mgmt.h"
 #include "rsi_common.h"
 #include "rsi_coex.h"
@@ -35,6 +36,13 @@ u32 rsi_zone_enabled = /* INFO_ZONE |
 			0;
 EXPORT_SYMBOL_GPL(rsi_zone_enabled);
 
+static struct rsi_proto_ops g_proto_ops = {
+	.coex_send_pkt = rsi_coex_send_pkt,
+	.get_host_intf = rsi_get_host_intf,
+	.set_bt_context = rsi_set_bt_context,
+	.get_bt_context = rsi_get_bt_context,
+};
+
 /**
  * rsi_dbg() - This function outputs informational messages.
  * @zone: Zone of interest for output message.
@@ -144,6 +152,8 @@ int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
 	u32 index, length = 0, queueno = 0;
 	u16 actual_length = 0, offset;
 	struct sk_buff *skb = NULL;
+	struct rsi_mod_ops *bt_ops = g_proto_ops.bt_ops;
+	u8 bt_pkt_type;
 
 	index = 0;
 	do {
@@ -183,6 +193,24 @@ int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
 			rsi_mgmt_pkt_recv(common, (frame_desc + offset));
 			break;
 
+		case RSI_BT_MGMT_Q:
+		case RSI_BT_DATA_Q:
+#define BT_RX_PKT_TYPE_OFST	14
+#define BT_CARD_READY_IND	0x89
+			bt_pkt_type = frame_desc[offset + BT_RX_PKT_TYPE_OFST];
+			if (bt_pkt_type == BT_CARD_READY_IND &&
+			    bt_ops && bt_ops->attach) {
+				rsi_dbg(INFO_ZONE, "BT Card ready recvd\n");
+				if (bt_ops->attach(common, &g_proto_ops))
+					rsi_dbg(ERR_ZONE,
+						"Failed to attach BT module\n");
+			} else {
+				if (bt_ops && bt_ops->recv_pkt)
+					bt_ops->recv_pkt(common->bt_adapter,
+							 frame_desc + offset);
+			}
+			break;
+
 		default:
 			rsi_dbg(ERR_ZONE, "%s: pkt from invalid queue: %d\n",
 				__func__,   queueno);
@@ -230,6 +258,20 @@ enum rsi_host_intf rsi_get_host_intf(void *priv)
 	return common->priv->rsi_host_intf;
 }
 
+void rsi_set_bt_context(void *priv, void *bt_context)
+{
+	struct rsi_common *common = (struct rsi_common *)priv;
+
+	common->bt_adapter = bt_context;
+}
+
+void *rsi_get_bt_context(void *priv)
+{
+	struct rsi_common *common = (struct rsi_common *)priv;
+
+	return common->bt_adapter;
+}
+
 /**
  * rsi_91x_init() - This function initializes os interface operations.
  * @void: Void.
@@ -339,6 +381,11 @@ EXPORT_SYMBOL_GPL(rsi_91x_deinit);
 static int rsi_91x_hal_module_init(void)
 {
 	rsi_dbg(INIT_ZONE, "%s: Module init called\n", __func__);
+
+	g_proto_ops.bt_ops = rsi_get_hci_ops();
+	if (!g_proto_ops.bt_ops)
+		rsi_dbg(ERR_ZONE, "Failed to get BT ops\n");
+
 	return 0;
 }
 
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
index 9fbc0ef..26abe51 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
@@ -16,6 +16,7 @@
  */
 
 #include <linux/firmware.h>
+#include <linux/rsi_header.h>
 #include "rsi_sdio.h"
 #include "rsi_common.h"
 
diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h
index 1d8af41..4616585 100644
--- a/drivers/net/wireless/rsi/rsi_common.h
+++ b/drivers/net/wireless/rsi/rsi_common.h
@@ -62,6 +62,7 @@ static inline int rsi_create_kthread(struct rsi_common *common,
 				     u8 *name)
 {
 	init_completion(&thread->completion);
+	atomic_set(&thread->thread_done, 0);
 	thread->task = kthread_run(func_ptr, common, "%s", name);
 	if (IS_ERR(thread->task))
 		return (int)PTR_ERR(thread->task);
diff --git a/drivers/net/wireless/rsi/rsi_hal.h b/drivers/net/wireless/rsi/rsi_hal.h
index a09d36b..e712223 100644
--- a/drivers/net/wireless/rsi/rsi_hal.h
+++ b/drivers/net/wireless/rsi/rsi_hal.h
@@ -145,8 +145,18 @@ struct rsi_data_desc {
 	u8 sta_id;
 } __packed;
 
+struct rsi_bt_desc {
+	__le16 len_qno;
+	__le16 reserved1;
+	__le32 reserved2;
+	__le32 reserved3;
+	__le16 reserved4;
+	__le16 bt_pkt_type;
+} __packed;
+
 int rsi_hal_device_init(struct rsi_hw *adapter);
 int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb);
 int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb);
+int rsi_send_bt_pkt(struct rsi_common *common, struct sk_buff *skb);
 
 #endif
diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
index e1c1dc8..033cc8c 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -290,6 +290,9 @@ struct rsi_common {
 	bool p2p_enabled;
 	struct timer_list roc_timer;
 	struct ieee80211_vif *roc_vif;
+
+	/* BT params */
+	void *bt_adapter;
 };
 
 struct eepromrw_info {
@@ -363,5 +366,7 @@ struct rsi_host_intf_ops {
 };
 
 enum rsi_host_intf rsi_get_host_intf(void *priv);
+void rsi_set_bt_context(void *priv, void *bt_context);
+void *rsi_get_bt_context(void *priv);
 
 #endif
diff --git a/include/linux/rsi_header.h b/include/linux/rsi_header.h
index 277f748..8e87d55 100644
--- a/include/linux/rsi_header.h
+++ b/include/linux/rsi_header.h
@@ -53,4 +53,6 @@ struct rsi_mod_ops {
 	void (*detach)(void *priv);
 	int (*recv_pkt)(void *priv, u8 *msg);
 };
+
+struct rsi_mod_ops *rsi_get_hci_ops(void);
 #endif
-- 
2.7.4

^ permalink raw reply related

* [v2 5/8] Bluetooth: btrsi: add new rsi bluetooth driver
From: Amitkumar Karwar @ 2017-11-29 12:45 UTC (permalink / raw)
  To: Kalle Valo, marcel
  Cc: linux-wireless, Amitkumar Karwar, Prameela Rani Garnepudi,
	linux-bluetooth, Siva Rebbagondla
In-Reply-To: <1511959513-3902-1-git-send-email-amitkarwar@gmail.com>

From: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>

Redpine bluetooth driver is a thin driver which depends on
'rsi_91x' driver for transmitting and receiving packets
to/from device. It creates hci interface when attach() is
called from 'rsi_91x' module.

Signed-off-by: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>
Signed-off-by: Siva Rebbagondla <siva.rebbagondla@redpinesignals.com>
Signed-off-by: Amitkumar Karwar <amit.karwar@redpinesignals.com>
---
v2: Addressed review comments from Marcel
    Removed unnecessary 'depends on BT && BT_RFOMM' line in Kconfig
    Removed redundant BT_INFO messages
    h_adapter initialization and declaration in a single line.
    Removed unnecessary error checks for HCI_RUNNING and fsm_state
    Allocated new skb with skb_realloc_headroom() API if headroom is not sufficient
    Used get_unaligned_le16 helpers
    Moved a structure and union from header file to btrsi.c file
---
 drivers/bluetooth/Kconfig   |  11 +++
 drivers/bluetooth/Makefile  |   2 +
 drivers/bluetooth/btrsi.c   | 216 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/bluetooth/rsi_hci.h |  40 ++++++++
 4 files changed, 269 insertions(+)
 create mode 100644 drivers/bluetooth/btrsi.c
 create mode 100644 drivers/bluetooth/rsi_hci.h

diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 60e1c7d..56c0e16 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -378,4 +378,15 @@ config BT_QCOMSMD
 	  Say Y here to compile support for HCI over Qualcomm SMD into the
 	  kernel or say M to compile as a module.
 
+config BT_RSI
+	tristate "Redpine HCI support"
+	default m
+	help
+	  Redpine BT driver.
+	  This driver handles BT traffic from upper layers and pass
+	  to the RSI_91x coex module for further scheduling to device
+
+	  Say Y here to compile support for HCI over Redpine into the
+	  kernel or say M to compile as a module.
+
 endmenu
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 4e4e44d..712af83a 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -28,6 +28,8 @@ obj-$(CONFIG_BT_QCA)		+= btqca.o
 
 obj-$(CONFIG_BT_HCIUART_NOKIA)	+= hci_nokia.o
 
+obj-$(CONFIG_BT_RSI)		+= btrsi.o
+
 btmrvl-y			:= btmrvl_main.o
 btmrvl-$(CONFIG_DEBUG_FS)	+= btmrvl_debugfs.o
 
diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c
new file mode 100644
index 0000000..db33482
--- /dev/null
+++ b/drivers/bluetooth/btrsi.c
@@ -0,0 +1,216 @@
+/**
+ * Copyright (c) 2017 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+e* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include "rsi_hci.h"
+
+struct rsi_hci_adapter {
+	void *priv;
+	struct rsi_proto_ops *proto_ops;
+	struct hci_dev *hdev;
+};
+
+static struct rsi_mod_ops rsi_bt_ops = {
+	.attach	= rsi_hci_attach,
+	.detach	= rsi_hci_detach,
+	.recv_pkt = rsi_hci_recv_pkt,
+};
+
+static int rsi_hci_open(struct hci_dev *hdev)
+{
+	return 0;
+}
+
+static int rsi_hci_close(struct hci_dev *hdev)
+{
+	return 0;
+}
+
+static int rsi_hci_flush(struct hci_dev *hdev)
+{
+	return 0;
+}
+
+static int rsi_hci_send_pkt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct rsi_hci_adapter *h_adapter = hci_get_drvdata(hdev);
+	struct sk_buff *new_skb = NULL;
+
+	switch (bt_cb(skb)->pkt_type) {
+	case HCI_COMMAND_PKT:
+		hdev->stat.cmd_tx++;
+		break;
+
+	case HCI_ACLDATA_PKT:
+		hdev->stat.acl_tx++;
+		break;
+
+	case HCI_SCODATA_PKT:
+		hdev->stat.sco_tx++;
+		break;
+	}
+
+	if (skb_headroom(skb) < RSI_HEADROOM_FOR_BT_HAL) {
+		/* Insufficient skb headroom - allocate a new skb */
+		new_skb = skb_realloc_headroom(skb, RSI_HEADROOM_FOR_BT_HAL);
+		if (unlikely(!new_skb))
+			return -ENOMEM;
+		bt_cb(new_skb)->pkt_type = bt_cb(skb)->pkt_type;
+		kfree_skb(skb);
+		skb = new_skb;
+	}
+
+	return h_adapter->proto_ops->coex_send_pkt(h_adapter->priv, skb,
+						   RSI_BT_Q);
+}
+
+int rsi_hci_recv_pkt(void *priv, u8 *pkt)
+{
+	struct rsi_hci_adapter *h_adapter = (struct rsi_hci_adapter *)priv;
+	struct hci_dev *hdev = h_adapter->hdev;
+	struct sk_buff *skb;
+
+	int pkt_len = get_unaligned_le16(pkt) & 0x0fff;
+	u8 queue_no = (get_unaligned_le16(pkt) & 0x7000) >> 12;
+
+	if (queue_no == RSI_BT_MGMT_Q) {
+		u8 msg_type = pkt[14] & 0xFF;
+
+		switch (msg_type) {
+		case RSI_RESULT_CONFIRM:
+			bt_dev_info(hdev, "BT Result Confirm");
+			return 0;
+		case RSI_BT_BER:
+			bt_dev_info(hdev, "BT Ber");
+			return 0;
+		case RSI_BT_CW:
+			bt_dev_info(hdev, "BT CW");
+			return 0;
+		default:
+			break;
+		}
+	}
+
+	skb = dev_alloc_skb(pkt_len);
+	if (!skb)
+		return -ENOMEM;
+
+	memcpy(skb->data, pkt + RSI_FRAME_DESC_SIZE, pkt_len);
+	skb_put(skb, pkt_len);
+	h_adapter->hdev->stat.byte_rx += skb->len;
+
+	skb->dev = (void *)hdev;
+	bt_cb(skb)->pkt_type = pkt[14];
+
+	return hci_recv_frame(hdev, skb);
+}
+
+int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops)
+{
+	struct rsi_hci_adapter *h_adapter = NULL;
+	struct hci_dev *hdev;
+	int status = 0;
+
+	h_adapter = kzalloc(sizeof(*h_adapter), GFP_KERNEL);
+	if (!h_adapter)
+		return -ENOMEM;
+
+	h_adapter->priv = priv;
+	ops->set_bt_context(priv, h_adapter);
+	h_adapter->proto_ops = ops;
+
+	hdev = hci_alloc_dev();
+	if (!hdev) {
+		BT_ERR("Failed to alloc HCI device\n");
+		goto err;
+	}
+
+	h_adapter->hdev = hdev;
+
+	if (ops->get_host_intf(priv) == RSI_HOST_INTF_SDIO)
+		hdev->bus = HCI_SDIO;
+	else
+		hdev->bus = HCI_USB;
+
+	hci_set_drvdata(hdev, h_adapter);
+	hdev->dev_type = HCI_PRIMARY;
+	hdev->open = rsi_hci_open;
+	hdev->close = rsi_hci_close;
+	hdev->flush = rsi_hci_flush;
+	hdev->send = rsi_hci_send_pkt;
+
+	status = hci_register_dev(hdev);
+	if (status < 0) {
+		BT_ERR("%s: HCI registration failed with errcode %d\n",
+		       __func__, status);
+		goto err;
+	}
+
+	return 0;
+err:
+	if (hdev) {
+		hci_unregister_dev(hdev);
+		hci_free_dev(hdev);
+		h_adapter->hdev = NULL;
+	}
+	kfree(h_adapter);
+
+	return -EINVAL;
+}
+
+void rsi_hci_detach(void *priv)
+{
+	struct rsi_hci_adapter *h_adapter = (struct rsi_hci_adapter *)priv;
+	struct hci_dev *hdev;
+
+	if (!h_adapter)
+		return;
+
+	hdev = h_adapter->hdev;
+	if (hdev) {
+		hci_unregister_dev(hdev);
+		hci_free_dev(hdev);
+		h_adapter->hdev = NULL;
+	}
+
+	kfree(h_adapter);
+}
+
+struct rsi_mod_ops *rsi_get_hci_ops(void)
+{
+	return &rsi_bt_ops;
+};
+EXPORT_SYMBOL_GPL(rsi_get_hci_ops);
+
+static int rsi_91x_bt_module_init(void)
+{
+	BT_INFO("%s: BT Module init called\n", __func__);
+
+	return 0;
+}
+
+static void rsi_91x_bt_module_exit(void)
+{
+	BT_INFO("%s: BT Module exit called\n", __func__);
+}
+
+module_init(rsi_91x_bt_module_init);
+module_exit(rsi_91x_bt_module_exit);
+MODULE_AUTHOR("Redpine Signals Inc");
+MODULE_DESCRIPTION("RSI BT driver");
+MODULE_SUPPORTED_DEVICE("RSI-BT");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/bluetooth/rsi_hci.h b/drivers/bluetooth/rsi_hci.h
new file mode 100644
index 0000000..6fc7757
--- /dev/null
+++ b/drivers/bluetooth/rsi_hci.h
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2017 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __RSI_HCI_H__
+#define __RSI_HCI_H__
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <linux/unaligned/le_byteshift.h>
+#include <linux/rsi_header.h>
+#include <net/genetlink.h>
+
+/* RX frame types */
+#define RSI_RESULT_CONFIRM			0x80
+#define RSI_BT_PER				0x10
+#define RSI_BT_BER				0x11
+#define RSI_BT_CW				0x12
+
+#define RSI_HEADROOM_FOR_BT_HAL	16
+
+#define RSI_FRAME_DESC_SIZE		16
+
+int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops);
+void rsi_hci_detach(void *priv);
+int rsi_hci_recv_pkt(void *data, u8 *pkt);
+
+#endif
-- 
2.7.4

^ permalink raw reply related

* [v2 4/8] rsi: add coex support
From: Amitkumar Karwar @ 2017-11-29 12:45 UTC (permalink / raw)
  To: Kalle Valo, marcel
  Cc: linux-wireless, Amitkumar Karwar, Prameela Rani Garnepudi,
	linux-bluetooth, Siva Rebbagondla
In-Reply-To: <1511959513-3902-1-git-send-email-amitkarwar@gmail.com>

From: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>

With BT support, driver has to handle two streams of data
(i.e. wlan and BT). Actual coex implementation is in firmware.
Coex module just schedule the packets to firmware by taking them
from the corresponding paths.

Structures for module and protocol operations are introduced for
this purpose. Protocol operations structure is global structure
which can be shared among different modules. Initialization of
coex and operating mode values is moved to rsi_91x_init().

Signed-off-by: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>
Signed-off-by: Siva Rebbagondla <siva.rebbagondla@redpinesignals.com>
Signed-off-by: Amitkumar Karwar <amit.karwar@redpinesignals.com>
---
 drivers/net/wireless/rsi/Makefile       |   1 +
 drivers/net/wireless/rsi/rsi_91x_coex.c | 182 ++++++++++++++++++++++++++++++++
 drivers/net/wireless/rsi/rsi_91x_hal.c  |  17 +--
 drivers/net/wireless/rsi/rsi_91x_main.c |  30 +++++-
 drivers/net/wireless/rsi/rsi_91x_mgmt.c |   2 +-
 drivers/net/wireless/rsi/rsi_91x_sdio.c |   1 +
 drivers/net/wireless/rsi/rsi_91x_usb.c  |   2 +
 drivers/net/wireless/rsi/rsi_coex.h     |  38 +++++++
 drivers/net/wireless/rsi/rsi_main.h     |   5 +
 drivers/net/wireless/rsi/rsi_mgmt.h     |   3 +
 include/linux/rsi_header.h              |  22 ++++
 11 files changed, 293 insertions(+), 10 deletions(-)
 create mode 100644 drivers/net/wireless/rsi/rsi_91x_coex.c
 create mode 100644 drivers/net/wireless/rsi/rsi_coex.h

diff --git a/drivers/net/wireless/rsi/Makefile b/drivers/net/wireless/rsi/Makefile
index 47c4590..fda827b 100644
--- a/drivers/net/wireless/rsi/Makefile
+++ b/drivers/net/wireless/rsi/Makefile
@@ -5,6 +5,7 @@ rsi_91x-y			+= rsi_91x_mac80211.o
 rsi_91x-y			+= rsi_91x_mgmt.o
 rsi_91x-y			+= rsi_91x_hal.o
 rsi_91x-y			+= rsi_91x_ps.o
+rsi_91x-y			+= rsi_91x_coex.o
 rsi_91x-$(CONFIG_RSI_DEBUGFS)	+= rsi_91x_debugfs.o
 
 rsi_usb-y			+= rsi_91x_usb.o rsi_91x_usb_ops.o
diff --git a/drivers/net/wireless/rsi/rsi_91x_coex.c b/drivers/net/wireless/rsi/rsi_91x_coex.c
new file mode 100644
index 0000000..914a0c5
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_91x_coex.c
@@ -0,0 +1,182 @@
+/**
+ * Copyright (c) 2017 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "rsi_main.h"
+#include "rsi_coex.h"
+#include "rsi_mgmt.h"
+#include "rsi_hal.h"
+
+static enum rsi_coex_queues rsi_coex_determine_coex_q
+			(struct rsi_coex_ctrl_block *coex_cb)
+{
+	enum rsi_coex_queues q_num = RSI_COEX_Q_INVALID;
+
+	if (skb_queue_len(&coex_cb->coex_tx_qs[RSI_COEX_Q_COMMON]) > 0)
+		q_num = RSI_COEX_Q_COMMON;
+	if (skb_queue_len(&coex_cb->coex_tx_qs[RSI_COEX_Q_BT]) > 0)
+		q_num = RSI_COEX_Q_BT;
+	if (skb_queue_len(&coex_cb->coex_tx_qs[RSI_COEX_Q_WLAN]) > 0)
+		q_num = RSI_COEX_Q_WLAN;
+
+	return q_num;
+}
+
+static void rsi_coex_sched_tx_pkts(struct rsi_coex_ctrl_block *coex_cb)
+{
+	enum rsi_coex_queues coex_q;
+	struct sk_buff *skb;
+
+	while (1) {
+		coex_q = rsi_coex_determine_coex_q(coex_cb);
+		rsi_dbg(INFO_ZONE, "queue = %d\n", coex_q);
+
+		if (coex_q == RSI_COEX_Q_INVALID) {
+			rsi_dbg(DATA_TX_ZONE, "No more pkt\n");
+			break;
+		}
+
+		if (coex_q == RSI_COEX_Q_BT)
+			skb = skb_dequeue(&coex_cb->coex_tx_qs[RSI_COEX_Q_BT]);
+	}
+}
+
+static void rsi_coex_scheduler_thread(struct rsi_common *common)
+{
+	struct rsi_coex_ctrl_block *coex_cb =
+		(struct rsi_coex_ctrl_block *)common->coex_cb;
+	u32 timeout = EVENT_WAIT_FOREVER;
+
+	do {
+		rsi_wait_event(&coex_cb->coex_tx_thread.event, timeout);
+		rsi_reset_event(&coex_cb->coex_tx_thread.event);
+
+		rsi_coex_sched_tx_pkts(coex_cb);
+	} while (atomic_read(&coex_cb->coex_tx_thread.thread_done) == 0);
+
+	complete_and_exit(&coex_cb->coex_tx_thread.completion, 0);
+}
+
+int rsi_coex_recv_pkt(struct rsi_common *common, u8 *msg)
+{
+	u8 msg_type = msg[RSI_RX_DESC_MSG_TYPE_OFFSET];
+
+	switch (msg_type) {
+	case COMMON_CARD_READY_IND:
+		rsi_dbg(INFO_ZONE, "common card ready received\n");
+		rsi_handle_card_ready(common, msg);
+		break;
+	case SLEEP_NOTIFY_IND:
+		rsi_dbg(INFO_ZONE, "sleep notify received\n");
+		rsi_mgmt_pkt_recv(common, msg);
+		break;
+	}
+
+	return 0;
+}
+
+static inline int rsi_map_coex_q(u8 hal_queue)
+{
+	switch (hal_queue) {
+	case RSI_COEX_Q:
+		return RSI_COEX_Q_COMMON;
+	case RSI_WLAN_Q:
+		return RSI_COEX_Q_WLAN;
+	case RSI_BT_Q:
+		return RSI_COEX_Q_BT;
+	}
+	return RSI_COEX_Q_INVALID;
+}
+
+int rsi_coex_send_pkt(void *priv, struct sk_buff *skb, u8 hal_queue)
+{
+	struct rsi_common *common = (struct rsi_common *)priv;
+	struct rsi_coex_ctrl_block *coex_cb =
+		(struct rsi_coex_ctrl_block *)common->coex_cb;
+	struct skb_info *tx_params = NULL;
+	enum rsi_coex_queues coex_q;
+	int status;
+
+	coex_q = rsi_map_coex_q(hal_queue);
+	if (coex_q == RSI_COEX_Q_INVALID) {
+		rsi_dbg(ERR_ZONE, "Invalid coex queue\n");
+		return -EINVAL;
+	}
+	if (coex_q != RSI_COEX_Q_COMMON &&
+	    coex_q != RSI_COEX_Q_WLAN) {
+		skb_queue_tail(&coex_cb->coex_tx_qs[coex_q], skb);
+		rsi_set_event(&coex_cb->coex_tx_thread.event);
+		return 0;
+	}
+	if (common->iface_down) {
+		tx_params =
+			(struct skb_info *)&IEEE80211_SKB_CB(skb)->driver_data;
+
+		if (!(tx_params->flags & INTERNAL_MGMT_PKT)) {
+			rsi_indicate_tx_status(common->priv, skb, -EINVAL);
+			return 0;
+		}
+	}
+
+	/* Send packet to hal */
+	if (skb->priority == MGMT_SOFT_Q)
+		status = rsi_send_mgmt_pkt(common, skb);
+	else
+		status = rsi_send_data_pkt(common, skb);
+
+	return status;
+}
+
+int rsi_coex_attach(struct rsi_common *common)
+{
+	struct rsi_coex_ctrl_block *coex_cb;
+	int cnt;
+
+	coex_cb = kzalloc(sizeof(*coex_cb), GFP_KERNEL);
+	if (!coex_cb)
+		return -ENOMEM;
+
+	common->coex_cb = (void *)coex_cb;
+	coex_cb->priv = common;
+
+	/* Initialize co-ex queues */
+	for (cnt = 0; cnt < NUM_COEX_TX_QUEUES; cnt++)
+		skb_queue_head_init(&coex_cb->coex_tx_qs[cnt]);
+	rsi_init_event(&coex_cb->coex_tx_thread.event);
+
+	/* Initialize co-ex thread */
+	if (rsi_create_kthread(common,
+			       &coex_cb->coex_tx_thread,
+			       rsi_coex_scheduler_thread,
+			       "Coex-Tx-Thread")) {
+		rsi_dbg(ERR_ZONE, "%s: Unable to init tx thrd\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+void rsi_coex_detach(struct rsi_common *common)
+{
+	struct rsi_coex_ctrl_block *coex_cb =
+		(struct rsi_coex_ctrl_block *)common->coex_cb;
+	int cnt;
+
+	rsi_kill_thread(&coex_cb->coex_tx_thread);
+
+	for (cnt = 0; cnt < NUM_COEX_TX_QUEUES; cnt++)
+		skb_queue_purge(&coex_cb->coex_tx_qs[cnt]);
+
+	kfree(coex_cb);
+}
diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c
index 1176de6..8b30448 100644
--- a/drivers/net/wireless/rsi/rsi_91x_hal.c
+++ b/drivers/net/wireless/rsi/rsi_91x_hal.c
@@ -31,8 +31,15 @@ int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb)
 	struct rsi_hw *adapter = common->priv;
 	int status;
 
+	if (common->coex_mode > 1)
+		down(&common->tx_bus_lock);
+
 	status = adapter->host_intf_ops->write_pkt(common->priv,
 						   skb->data, skb->len);
+
+	if (common->coex_mode > 1)
+		up(&common->tx_bus_lock);
+
 	return status;
 }
 
@@ -296,8 +303,7 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb)
 	if (status)
 		goto err;
 
-	status = adapter->host_intf_ops->write_pkt(common->priv, skb->data,
-						   skb->len);
+	status = rsi_send_pkt_to_bus(common, skb);
 	if (status)
 		rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n", __func__);
 
@@ -342,8 +348,7 @@ int rsi_send_mgmt_pkt(struct rsi_common *common,
 		goto err;
 
 	rsi_prepare_mgmt_desc(common, skb);
-	status = adapter->host_intf_ops->write_pkt(common->priv,
-						   (u8 *)skb->data, skb->len);
+	status = rsi_send_pkt_to_bus(common, skb);
 	if (status)
 		rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__);
 
@@ -926,10 +931,6 @@ int rsi_hal_device_init(struct rsi_hw *adapter)
 {
 	struct rsi_common *common = adapter->priv;
 
-	common->coex_mode = RSI_DEV_COEX_MODE_WIFI_ALONE;
-	common->oper_mode = RSI_DEV_OPMODE_WIFI_ALONE;
-	adapter->device_model = RSI_DEV_9113;
-
 	switch (adapter->device_model) {
 	case RSI_DEV_9113:
 		if (rsi_load_firmware(adapter)) {
diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c
index 0413af8..7dce533 100644
--- a/drivers/net/wireless/rsi/rsi_91x_main.c
+++ b/drivers/net/wireless/rsi/rsi_91x_main.c
@@ -20,6 +20,7 @@
 #include <linux/firmware.h>
 #include "rsi_mgmt.h"
 #include "rsi_common.h"
+#include "rsi_coex.h"
 #include "rsi_hal.h"
 
 u32 rsi_zone_enabled = /* INFO_ZONE |
@@ -160,8 +161,13 @@ int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
 
 		switch (queueno) {
 		case RSI_COEX_Q:
-			rsi_mgmt_pkt_recv(common, (frame_desc + offset));
+			if (common->coex_mode > 1)
+				rsi_coex_recv_pkt(common, frame_desc + offset);
+			else
+				rsi_mgmt_pkt_recv(common,
+						  (frame_desc + offset));
 			break;
+
 		case RSI_WIFI_DATA_Q:
 			skb = rsi_prepare_skb(common,
 					      (frame_desc + offset),
@@ -217,6 +223,13 @@ static void rsi_tx_scheduler_thread(struct rsi_common *common)
 	complete_and_exit(&common->tx_thread.completion, 0);
 }
 
+enum rsi_host_intf rsi_get_host_intf(void *priv)
+{
+	struct rsi_common *common = (struct rsi_common *)priv;
+
+	return common->priv->rsi_host_intf;
+}
+
 /**
  * rsi_91x_init() - This function initializes os interface operations.
  * @void: Void.
@@ -251,6 +264,7 @@ struct rsi_hw *rsi_91x_init(void)
 	mutex_init(&common->mutex);
 	mutex_init(&common->tx_lock);
 	mutex_init(&common->rx_lock);
+	sema_init(&common->tx_bus_lock, 1);
 
 	if (rsi_create_kthread(common,
 			       &common->tx_thread,
@@ -265,6 +279,17 @@ struct rsi_hw *rsi_91x_init(void)
 	timer_setup(&common->roc_timer, rsi_roc_timeout, 0);
 	init_completion(&common->wlan_init_completion);
 	common->init_done = true;
+
+	common->coex_mode = RSI_DEV_COEX_MODE_WIFI_ALONE;
+	common->oper_mode = RSI_DEV_OPMODE_WIFI_ALONE;
+	adapter->device_model = RSI_DEV_9113;
+	if (common->coex_mode > 1) {
+		if (rsi_coex_attach(common)) {
+			rsi_dbg(ERR_ZONE, "Failed to init coex module\n");
+			goto err;
+		}
+	}
+
 	return adapter;
 
 err:
@@ -294,6 +319,9 @@ void rsi_91x_deinit(struct rsi_hw *adapter)
 
 	common->init_done = false;
 
+	if (common->coex_mode > 1)
+		rsi_coex_detach(common);
+
 	kfree(common);
 	kfree(adapter->rsi_dev);
 	kfree(adapter);
diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
index 46c9d54..c21fca7 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
@@ -1791,7 +1791,7 @@ static int rsi_handle_ta_confirm_type(struct rsi_common *common,
 	return -EINVAL;
 }
 
-static int rsi_handle_card_ready(struct rsi_common *common, u8 *msg)
+int rsi_handle_card_ready(struct rsi_common *common, u8 *msg)
 {
 	switch (common->fsm_state) {
 	case FSM_CARD_NOT_READY:
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
index b0cf411..ba38c6d 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -18,6 +18,7 @@
 #include <linux/module.h>
 #include "rsi_sdio.h"
 #include "rsi_common.h"
+#include "rsi_coex.h"
 #include "rsi_hal.h"
 
 /**
diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c
index b212a15..b09c7da 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb.c
@@ -16,8 +16,10 @@
  */
 
 #include <linux/module.h>
+#include <linux/rsi_header.h>
 #include "rsi_usb.h"
 #include "rsi_hal.h"
+#include "rsi_coex.h"
 
 /**
  * rsi_usb_card_write() - This function writes to the USB Card.
diff --git a/drivers/net/wireless/rsi/rsi_coex.h b/drivers/net/wireless/rsi/rsi_coex.h
new file mode 100644
index 0000000..22fe6ff
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_coex.h
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2017 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __RSI_COEX_H__
+#define __RSI_COEX_H__
+
+#include "rsi_common.h"
+
+#define RSI_COEX_TXQ_MAX_PKTS		64
+#define RSI_COEX_TXQ_WATER_MARK		50
+#define COMMON_CARD_READY_IND           0
+#define NUM_COEX_TX_QUEUES              5
+
+struct rsi_coex_ctrl_block {
+	struct rsi_common *priv;
+	struct sk_buff_head coex_tx_qs[NUM_COEX_TX_QUEUES];
+	struct rsi_thread coex_tx_thread;
+};
+
+int rsi_coex_attach(struct rsi_common *common);
+void rsi_coex_detach(struct rsi_common *common);
+int rsi_coex_send_pkt(void *priv, struct sk_buff *skb, u8 proto_type);
+int rsi_coex_recv_pkt(struct rsi_common *common, u8 *msg);
+
+#endif
diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
index ca02a4b..e1c1dc8 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -206,6 +206,7 @@ struct rsi_common {
 	struct rsi_hw *priv;
 	struct vif_priv vif_info[RSI_MAX_VIFS];
 
+	void *coex_cb;
 	bool mgmt_q_block;
 	struct version_info lmac_ver;
 
@@ -270,6 +271,7 @@ struct rsi_common {
 	u8 obm_ant_sel_val;
 	int tx_power;
 	u8 ant_in_use;
+	struct semaphore tx_bus_lock;
 	bool hibernate_resume;
 	bool reinit_hw;
 	u8 wow_flags;
@@ -359,4 +361,7 @@ struct rsi_host_intf_ops {
 				      u8 *fw);
 	int (*reinit_device)(struct rsi_hw *adapter);
 };
+
+enum rsi_host_intf rsi_get_host_intf(void *priv);
+
 #endif
diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h
index 389094a..cf6567a 100644
--- a/drivers/net/wireless/rsi/rsi_mgmt.h
+++ b/drivers/net/wireless/rsi/rsi_mgmt.h
@@ -57,12 +57,14 @@
 #define WOW_PATTERN_SIZE 256
 
 /* Receive Frame Types */
+#define RSI_RX_DESC_MSG_TYPE_OFFSET	2
 #define TA_CONFIRM_TYPE                 0x01
 #define RX_DOT11_MGMT                   0x02
 #define TX_STATUS_IND                   0x04
 #define BEACON_EVENT_IND		0x08
 #define PROBEREQ_CONFIRM                2
 #define CARD_READY_IND                  0x00
+#define SLEEP_NOTIFY_IND                0x06
 
 #define RSI_DELETE_PEER                 0x0
 #define RSI_ADD_PEER                    0x1
@@ -638,6 +640,7 @@ static inline void rsi_set_len_qno(__le16 *addr, u16 len, u8 qno)
 	*addr = cpu_to_le16(len | ((qno & 7) << 12));
 }
 
+int rsi_handle_card_ready(struct rsi_common *common, u8 *msg);
 int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg);
 int rsi_set_vap_capabilities(struct rsi_common *common, enum opmode mode,
 			     u8 *mac_addr, u8 vap_id, u8 vap_status);
diff --git a/include/linux/rsi_header.h b/include/linux/rsi_header.h
index 16a447b..277f748 100644
--- a/include/linux/rsi_header.h
+++ b/include/linux/rsi_header.h
@@ -17,6 +17,8 @@
 #ifndef __RSI_HEADER_H__
 #define __RSI_HEADER_H__
 
+#include <linux/skbuff.h>
+
 /* HAL queue information */
 #define RSI_COEX_Q			0x0
 #define RSI_BT_Q			0x2
@@ -26,9 +28,29 @@
 #define RSI_BT_MGMT_Q			0x6
 #define RSI_BT_DATA_Q			0x7
 
+enum rsi_coex_queues {
+	RSI_COEX_Q_INVALID = -1,
+	RSI_COEX_Q_COMMON = 0,
+	RSI_COEX_Q_BT,
+	RSI_COEX_Q_WLAN
+};
+
 enum rsi_host_intf {
 	RSI_HOST_INTF_SDIO = 0,
 	RSI_HOST_INTF_USB
 };
 
+struct rsi_proto_ops {
+	int (*coex_send_pkt)(void *priv, struct sk_buff *skb, u8 hal_queue);
+	enum rsi_host_intf (*get_host_intf)(void *priv);
+	void (*set_bt_context)(void *priv, void *context);
+	void *(*get_bt_context)(void *priv);
+	struct rsi_mod_ops *bt_ops;
+};
+
+struct rsi_mod_ops {
+	int (*attach)(void *priv, struct rsi_proto_ops *ops);
+	void (*detach)(void *priv);
+	int (*recv_pkt)(void *priv, u8 *msg);
+};
 #endif
-- 
2.7.4

^ permalink raw reply related

* [v2 3/8] rsi: add header file rsi_header
From: Amitkumar Karwar @ 2017-11-29 12:45 UTC (permalink / raw)
  To: Kalle Valo, marcel
  Cc: linux-wireless, Amitkumar Karwar, Prameela Rani Garnepudi,
	linux-bluetooth, Siva Rebbagondla
In-Reply-To: <1511959513-3902-1-git-send-email-amitkarwar@gmail.com>

From: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>

The common parameters used by wlan and bt modules are added
to a new header file "rsi_header.h" defined in '/include/linux'

Signed-off-by: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>
Signed-off-by: Siva Rebbagondla <siva.rebbagondla@redpinesignals.com>
Signed-off-by: Amitkumar Karwar <amit.karwar@redpinesignals.com>
---
 drivers/net/wireless/rsi/rsi_main.h | 12 ++----------
 include/linux/rsi_header.h          | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+), 10 deletions(-)
 create mode 100644 include/linux/rsi_header.h

diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
index ee469dc..ca02a4b 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -20,6 +20,7 @@
 #include <linux/string.h>
 #include <linux/skbuff.h>
 #include <net/mac80211.h>
+#include <linux/rsi_header.h>
 
 struct rsi_sta {
 	struct ieee80211_sta *sta;
@@ -85,10 +86,6 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...);
 #define MGMT_HW_Q			10
 #define BEACON_HW_Q			11
 
-/* Queue information */
-#define RSI_COEX_Q			0x0
-#define RSI_WIFI_MGMT_Q                 0x4
-#define RSI_WIFI_DATA_Q                 0x5
 #define IEEE80211_MGMT_FRAME            0x00
 #define IEEE80211_CTL_FRAME             0x04
 
@@ -293,11 +290,6 @@ struct rsi_common {
 	struct ieee80211_vif *roc_vif;
 };
 
-enum host_intf {
-	RSI_HOST_INTF_SDIO = 0,
-	RSI_HOST_INTF_USB
-};
-
 struct eepromrw_info {
 	u32 offset;
 	u32 length;
@@ -322,7 +314,7 @@ struct rsi_hw {
 	struct device *device;
 	u8 sc_nvifs;
 
-	enum host_intf rsi_host_intf;
+	enum rsi_host_intf rsi_host_intf;
 	u16 block_size;
 	enum ps_state ps_state;
 	struct rsi_ps_info ps_info;
diff --git a/include/linux/rsi_header.h b/include/linux/rsi_header.h
new file mode 100644
index 0000000..16a447b
--- /dev/null
+++ b/include/linux/rsi_header.h
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2017 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __RSI_HEADER_H__
+#define __RSI_HEADER_H__
+
+/* HAL queue information */
+#define RSI_COEX_Q			0x0
+#define RSI_BT_Q			0x2
+#define RSI_WLAN_Q                      0x3
+#define RSI_WIFI_MGMT_Q                 0x4
+#define RSI_WIFI_DATA_Q                 0x5
+#define RSI_BT_MGMT_Q			0x6
+#define RSI_BT_DATA_Q			0x7
+
+enum rsi_host_intf {
+	RSI_HOST_INTF_SDIO = 0,
+	RSI_HOST_INTF_USB
+};
+
+#endif
-- 
2.7.4

^ permalink raw reply related

* [v2 2/8] rsi: add bluetooth rx endpoint
From: Amitkumar Karwar @ 2017-11-29 12:45 UTC (permalink / raw)
  To: Kalle Valo, marcel
  Cc: linux-wireless, Amitkumar Karwar, Prameela Rani Garnepudi,
	linux-bluetooth, Siva Rebbagondla
In-Reply-To: <1511959513-3902-1-git-send-email-amitkarwar@gmail.com>

From: Siva Rebbagondla <siva.rebbagondla@redpinesignals.com>

USB endpoint 1 is used for WLAN which is presently in use.
USB endpoint 2 is introduced for BT Rx traffic. Enumeration
of Rx BT endpoint and submitting Rx BT URB are added.

>From /sys/kernel/debug/usb/devices,
Ad=81(I) is for WLAN EP IN and Ad=01(O) is for Wlan EP OUT.
Ad=82(I) is for BT EP IN and Ad=02(O) is for BT EP OUT.

T:  Bus=01 Lev=01 Prnt=01 Port=09 Cnt=03 Dev#=  4 Spd=480  MxCh= 0
D:  Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=1618 ProdID=9113 Rev= 0.02
S:  Manufacturer=Redpine Signals, Inc.
S:  Product=Wireless USB Network Module
S:  SerialNumber=000000000001
C:* #Ifs= 1 Cfg#= 1 Atr=c0 MxPwr=  2mA
I:* If#= 0 Alt= 0 #EPs= 6 Cls=00(>ifc ) Sub=00 Prot=00 Driver=(none)
E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms

Signed-off-by: Siva Rebbagondla <siva.rebbagondla@redpinesignals.com>
Signed-off-by: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>
Signed-off-by: Amitkumar Karwar <amit.karwar@redpinesignals.com>
---
v2: Included '/sys/kernel/debug/usb/devices' info in patch description(Marcel)
---
 drivers/net/wireless/rsi/rsi_91x_usb.c | 37 ++++++++++++++++++++--------------
 drivers/net/wireless/rsi/rsi_usb.h     |  6 +++---
 2 files changed, 25 insertions(+), 18 deletions(-)

diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c
index 147fcee2..b212a15 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb.c
@@ -103,41 +103,42 @@ static int rsi_find_bulk_in_and_out_endpoints(struct usb_interface *interface,
 	struct usb_host_interface *iface_desc;
 	struct usb_endpoint_descriptor *endpoint;
 	__le16 buffer_size;
-	int ii, bep_found = 0;
+	int ii, bin_found = 0, bout_found = 0;
 
 	iface_desc = &(interface->altsetting[0]);
 
 	for (ii = 0; ii < iface_desc->desc.bNumEndpoints; ++ii) {
 		endpoint = &(iface_desc->endpoint[ii].desc);
 
-		if ((!(dev->bulkin_endpoint_addr)) &&
+		if (!dev->bulkin_endpoint_addr[bin_found] &&
 		    (endpoint->bEndpointAddress & USB_DIR_IN) &&
-		    ((endpoint->bmAttributes &
-		    USB_ENDPOINT_XFERTYPE_MASK) ==
+		    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
 		    USB_ENDPOINT_XFER_BULK)) {
 			buffer_size = endpoint->wMaxPacketSize;
-			dev->bulkin_size = buffer_size;
-			dev->bulkin_endpoint_addr =
+			dev->bulkin_size[bin_found] = buffer_size;
+			dev->bulkin_endpoint_addr[bin_found] =
 				endpoint->bEndpointAddress;
+			bin_found++;
 		}
 
-		if (!dev->bulkout_endpoint_addr[bep_found] &&
+		if (!dev->bulkout_endpoint_addr[bout_found] &&
 		    !(endpoint->bEndpointAddress & USB_DIR_IN) &&
 		    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
-		      USB_ENDPOINT_XFER_BULK)) {
-			dev->bulkout_endpoint_addr[bep_found] =
+		    USB_ENDPOINT_XFER_BULK)) {
+			buffer_size = endpoint->wMaxPacketSize;
+			dev->bulkout_endpoint_addr[bout_found] =
 				endpoint->bEndpointAddress;
 			buffer_size = endpoint->wMaxPacketSize;
-			dev->bulkout_size[bep_found] = buffer_size;
-			bep_found++;
+			dev->bulkout_size[bout_found] = buffer_size;
+			bout_found++;
 		}
 
-		if (bep_found >= MAX_BULK_EP)
+		if (bin_found >= MAX_BULK_EP || bout_found >= MAX_BULK_EP)
 			break;
 	}
 
-	if (!(dev->bulkin_endpoint_addr) &&
-	    (dev->bulkout_endpoint_addr[0]))
+	if (!(dev->bulkin_endpoint_addr[0]) &&
+	    dev->bulkout_endpoint_addr[0])
 		return -EINVAL;
 
 	return 0;
@@ -273,7 +274,7 @@ static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num)
 	usb_fill_bulk_urb(urb,
 			  dev->usbdev,
 			  usb_rcvbulkpipe(dev->usbdev,
-				dev->bulkin_endpoint_addr),
+			  dev->bulkin_endpoint_addr[ep_num - 1]),
 			  urb->transfer_buffer,
 			  3000,
 			  rsi_rx_done_handler,
@@ -745,6 +746,12 @@ static int rsi_probe(struct usb_interface *pfunction,
 	if (status)
 		goto err1;
 
+	if (adapter->priv->coex_mode > 1) {
+		status = rsi_rx_urb_submit(adapter, BT_EP);
+		if (status)
+			goto err1;
+	}
+
 	return 0;
 err1:
 	rsi_deinit_usb_interface(adapter);
diff --git a/drivers/net/wireless/rsi/rsi_usb.h b/drivers/net/wireless/rsi/rsi_usb.h
index 7e781d5..0fda14c 100644
--- a/drivers/net/wireless/rsi/rsi_usb.h
+++ b/drivers/net/wireless/rsi/rsi_usb.h
@@ -31,7 +31,7 @@
 #define USB_VENDOR_REGISTER_WRITE    0x16
 #define RSI_USB_TX_HEAD_ROOM         128
 
-#define MAX_RX_URBS                  1
+#define MAX_RX_URBS                  2
 #define MAX_BULK_EP                  8
 #define WLAN_EP                      1
 #define BT_EP                        2
@@ -54,8 +54,8 @@ struct rsi_91x_usbdev {
 	struct usb_interface *pfunction;
 	struct rx_usb_ctrl_block rx_cb[MAX_RX_URBS];
 	u8 *tx_buffer;
-	__le16 bulkin_size;
-	u8 bulkin_endpoint_addr;
+	__le16 bulkin_size[MAX_BULK_EP];
+	u8 bulkin_endpoint_addr[MAX_BULK_EP];
 	__le16 bulkout_size[MAX_BULK_EP];
 	u8 bulkout_endpoint_addr[MAX_BULK_EP];
 	u32 tx_blk_size;
-- 
2.7.4

^ permalink raw reply related

* [v2 1/8] rsi: add rx control block to handle rx packets in USB
From: Amitkumar Karwar @ 2017-11-29 12:45 UTC (permalink / raw)
  To: Kalle Valo, marcel
  Cc: linux-wireless, Amitkumar Karwar, Prameela Rani Garnepudi,
	linux-bluetooth, Siva Rebbagondla
In-Reply-To: <1511959513-3902-1-git-send-email-amitkarwar@gmail.com>

From: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>

Rx bluetooth endpoint shall be added in further patches. Rx control
block is introduced here to handle Rx packets properly. Separate
function is written to initialize the RX control blocks.

Signed-off-by: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>
Signed-off-by: Siva Rebbagondla <siva.rebbagondla@redpinesignals.com>
Signed-off-by: Amitkumar Karwar <amit.karwar@redpinesignals.com>
---
 drivers/net/wireless/rsi/rsi_91x_main.c     |  4 +-
 drivers/net/wireless/rsi/rsi_91x_sdio_ops.c |  2 +-
 drivers/net/wireless/rsi/rsi_91x_usb.c      | 75 +++++++++++++++++++++++------
 drivers/net/wireless/rsi/rsi_91x_usb_ops.c  | 35 +++++++++-----
 drivers/net/wireless/rsi/rsi_common.h       |  2 +-
 drivers/net/wireless/rsi/rsi_main.h         |  2 +-
 drivers/net/wireless/rsi/rsi_usb.h          | 10 +++-
 7 files changed, 96 insertions(+), 34 deletions(-)

diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c
index 0cb8e68..0413af8 100644
--- a/drivers/net/wireless/rsi/rsi_91x_main.c
+++ b/drivers/net/wireless/rsi/rsi_91x_main.c
@@ -137,7 +137,7 @@ static struct sk_buff *rsi_prepare_skb(struct rsi_common *common,
  *
  * Return: 0 on success, -1 on failure.
  */
-int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len)
+int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
 {
 	u8 *frame_desc = NULL, extended_desc = 0;
 	u32 index, length = 0, queueno = 0;
@@ -146,7 +146,7 @@ int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len)
 
 	index = 0;
 	do {
-		frame_desc = &common->rx_data_pkt[index];
+		frame_desc = &rx_pkt[index];
 		actual_length = *(u16 *)&frame_desc[0];
 		offset = *(u16 *)&frame_desc[2];
 
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
index 8e2a95c..9fbc0ef 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
@@ -118,7 +118,7 @@ static int rsi_process_pkt(struct rsi_common *common)
 		goto fail;
 	}
 
-	status = rsi_read_pkt(common, rcv_pkt_len);
+	status = rsi_read_pkt(common, common->rx_data_pkt, rcv_pkt_len);
 
 fail:
 	kfree(common->rx_data_pkt);
diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c
index 0873022..147fcee2 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb.c
@@ -247,12 +247,13 @@ static int rsi_usb_reg_write(struct usb_device *usbdev,
  */
 static void rsi_rx_done_handler(struct urb *urb)
 {
-	struct rsi_hw *adapter = urb->context;
-	struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+	struct rx_usb_ctrl_block *rx_cb = urb->context;
+	struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)rx_cb->data;
 
 	if (urb->status)
 		return;
 
+	rx_cb->pend = 1;
 	rsi_set_event(&dev->rx_thread.event);
 }
 
@@ -262,10 +263,11 @@ static void rsi_rx_done_handler(struct urb *urb)
  *
  * Return: 0 on success, a negative error code on failure.
  */
-static int rsi_rx_urb_submit(struct rsi_hw *adapter)
+static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num)
 {
 	struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
-	struct urb *urb = dev->rx_usb_urb[0];
+	struct rx_usb_ctrl_block *rx_cb = &dev->rx_cb[ep_num - 1];
+	struct urb *urb = rx_cb->rx_urb;
 	int status;
 
 	usb_fill_bulk_urb(urb,
@@ -275,7 +277,7 @@ static int rsi_rx_urb_submit(struct rsi_hw *adapter)
 			  urb->transfer_buffer,
 			  3000,
 			  rsi_rx_done_handler,
-			  adapter);
+			  rx_cb);
 
 	status = usb_submit_urb(urb, GFP_KERNEL);
 	if (status)
@@ -484,14 +486,54 @@ static struct rsi_host_intf_ops usb_host_intf_ops = {
  */
 static void rsi_deinit_usb_interface(struct rsi_hw *adapter)
 {
+	u8 idx;
+
 	struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
 
 	rsi_kill_thread(&dev->rx_thread);
-	usb_free_urb(dev->rx_usb_urb[0]);
+
+	for (idx = 0; idx < MAX_RX_URBS; idx++) {
+		usb_free_urb(dev->rx_cb[idx].rx_urb);
+		kfree(dev->rx_cb[idx].rx_buffer);
+	}
+
 	kfree(adapter->priv->rx_data_pkt);
 	kfree(dev->tx_buffer);
 }
 
+static int rsi_usb_init_rx(struct rsi_hw *adapter)
+{
+	struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+	struct rx_usb_ctrl_block *rx_cb;
+	u8 idx;
+
+	for (idx = 0; idx < MAX_RX_URBS; idx++) {
+		rx_cb = &dev->rx_cb[idx];
+
+		rx_cb->rx_buffer = kzalloc(RSI_USB_BUF_SIZE * 2,
+					   GFP_KERNEL | GFP_DMA);
+		if (!rx_cb->rx_buffer)
+			goto err;
+
+		rx_cb->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!rx_cb->rx_urb) {
+			rsi_dbg(ERR_ZONE, "Failed alloc rx urb[%d]\n", idx);
+			goto err;
+		}
+		rx_cb->rx_urb->transfer_buffer = rx_cb->rx_buffer;
+		rx_cb->ep_num = idx + 1;
+		rx_cb->data = (void *)dev;
+	}
+	return 0;
+
+err:
+	for (idx = 0; idx < MAX_RX_URBS; idx++) {
+		kfree(dev->rx_cb[idx].rx_buffer);
+		kfree(dev->rx_cb[idx].rx_urb);
+	}
+	return -1;
+}
+
 /**
  * rsi_init_usb_interface() - This function initializes the usb interface.
  * @adapter: Pointer to the adapter structure.
@@ -504,7 +546,7 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter,
 {
 	struct rsi_91x_usbdev *rsi_dev;
 	struct rsi_common *common = adapter->priv;
-	int status;
+	int status, i;
 
 	rsi_dev = kzalloc(sizeof(*rsi_dev), GFP_KERNEL);
 	if (!rsi_dev)
@@ -531,12 +573,12 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter,
 		status = -ENOMEM;
 		goto fail_tx;
 	}
-	rsi_dev->rx_usb_urb[0] = usb_alloc_urb(0, GFP_KERNEL);
-	if (!rsi_dev->rx_usb_urb[0]) {
-		status = -ENOMEM;
-		goto fail_rx;
+
+	if (rsi_usb_init_rx(adapter)) {
+		rsi_dbg(ERR_ZONE, "Failed to init RX handle\n");
+		return -ENOMEM;
 	}
-	rsi_dev->rx_usb_urb[0]->transfer_buffer = adapter->priv->rx_data_pkt;
+
 	rsi_dev->tx_blk_size = 252;
 	adapter->block_size = rsi_dev->tx_blk_size;
 
@@ -564,9 +606,10 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter,
 	return 0;
 
 fail_thread:
-	usb_free_urb(rsi_dev->rx_usb_urb[0]);
-fail_rx:
-	kfree(rsi_dev->tx_buffer);
+	for (i = 0; i < MAX_RX_URBS; i++) {
+		kfree(rsi_dev->rx_cb[i].rx_buffer);
+		kfree(rsi_dev->rx_cb[i].rx_urb);
+	}
 fail_tx:
 	kfree(common->rx_data_pkt);
 	return status;
@@ -698,7 +741,7 @@ static int rsi_probe(struct usb_interface *pfunction,
 		rsi_dbg(INIT_ZONE, "%s: Device Init Done\n", __func__);
 	}
 
-	status = rsi_rx_urb_submit(adapter);
+	status = rsi_rx_urb_submit(adapter, WLAN_EP);
 	if (status)
 		goto err1;
 
diff --git a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c
index 465692b..d0650ea 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c
@@ -29,7 +29,8 @@ void rsi_usb_rx_thread(struct rsi_common *common)
 {
 	struct rsi_hw *adapter = common->priv;
 	struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
-	int status;
+	struct rx_usb_ctrl_block *rx_cb;
+	int status, idx;
 
 	do {
 		rsi_wait_event(&dev->rx_thread.event, EVENT_WAIT_FOREVER);
@@ -37,20 +38,30 @@ void rsi_usb_rx_thread(struct rsi_common *common)
 		if (atomic_read(&dev->rx_thread.thread_done))
 			goto out;
 
-		mutex_lock(&common->rx_lock);
-		status = rsi_read_pkt(common, 0);
-		if (status) {
-			rsi_dbg(ERR_ZONE, "%s: Failed To read data", __func__);
+		for (idx = 0; idx < MAX_RX_URBS; idx++) {
+			rx_cb = &dev->rx_cb[idx];
+			if (!rx_cb->pend)
+				continue;
+
+			mutex_lock(&common->rx_lock);
+			status = rsi_read_pkt(common, rx_cb->rx_buffer, 0);
+			if (status) {
+				rsi_dbg(ERR_ZONE, "%s: Failed To read data",
+					__func__);
+				mutex_unlock(&common->rx_lock);
+				break;
+			}
+			rx_cb->pend = 0;
 			mutex_unlock(&common->rx_lock);
-			return;
+
+			if (adapter->rx_urb_submit(adapter, rx_cb->ep_num)) {
+				rsi_dbg(ERR_ZONE,
+					"%s: Failed in urb submission",
+					__func__);
+				return;
+			}
 		}
-		mutex_unlock(&common->rx_lock);
 		rsi_reset_event(&dev->rx_thread.event);
-		if (adapter->rx_urb_submit(adapter)) {
-			rsi_dbg(ERR_ZONE,
-				"%s: Failed in urb submission", __func__);
-			return;
-		}
 	} while (1);
 
 out:
diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h
index d07dbba..1d8af41 100644
--- a/drivers/net/wireless/rsi/rsi_common.h
+++ b/drivers/net/wireless/rsi/rsi_common.h
@@ -82,7 +82,7 @@ void rsi_mac80211_detach(struct rsi_hw *hw);
 u16 rsi_get_connected_channel(struct ieee80211_vif *vif);
 struct rsi_hw *rsi_91x_init(void);
 void rsi_91x_deinit(struct rsi_hw *adapter);
-int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len);
+int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len);
 #ifdef CONFIG_PM
 int rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan);
 #endif
diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
index 8cab630..ee469dc 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -343,7 +343,7 @@ struct rsi_hw {
 	void *rsi_dev;
 	struct rsi_host_intf_ops *host_intf_ops;
 	int (*check_hw_queue_status)(struct rsi_hw *adapter, u8 q_num);
-	int (*rx_urb_submit)(struct rsi_hw *adapter);
+	int (*rx_urb_submit)(struct rsi_hw *adapter, u8 ep_num);
 	int (*determine_event_timeout)(struct rsi_hw *adapter);
 };
 
diff --git a/drivers/net/wireless/rsi/rsi_usb.h b/drivers/net/wireless/rsi/rsi_usb.h
index 891daea..7e781d5 100644
--- a/drivers/net/wireless/rsi/rsi_usb.h
+++ b/drivers/net/wireless/rsi/rsi_usb.h
@@ -39,12 +39,20 @@
 #define RSI_USB_BUF_SIZE	     4096
 #define RSI_USB_CTRL_BUF_SIZE	     0x04
 
+struct rx_usb_ctrl_block {
+	u8 *data;
+	struct urb *rx_urb;
+	u8 *rx_buffer;
+	u8 ep_num;
+	u8 pend;
+};
+
 struct rsi_91x_usbdev {
 	struct rsi_thread rx_thread;
 	u8 endpoint;
 	struct usb_device *usbdev;
 	struct usb_interface *pfunction;
-	struct urb *rx_usb_urb[MAX_RX_URBS];
+	struct rx_usb_ctrl_block rx_cb[MAX_RX_URBS];
 	u8 *tx_buffer;
 	__le16 bulkin_size;
 	u8 bulkin_endpoint_addr;
-- 
2.7.4

^ permalink raw reply related

* [v2 0/8] rsi: add bluetooth and coex support
From: Amitkumar Karwar @ 2017-11-29 12:45 UTC (permalink / raw)
  To: Kalle Valo, marcel
  Cc: linux-wireless, Amitkumar Karwar, Prameela Rani Garnepudi,
	linux-bluetooth

From: Amitkumar Karwar <amit.karwar@redpinesignals.com>

This patch series adds new bluetooth driver and coex enhancments
in existing wlan driver for RSI chipsets.
As per our architecture, both wlan and bluetooth drivers talk
over same SDIO interface to device. Separate endpoint will be
used in case of USB interface.

Changes since v1:
2/8, 5/8 and 6/8 patches are modified

Prameela Rani Garnepudi (6):
  rsi: add rx control block to handle rx packets in USB
  rsi: add header file rsi_header
  rsi: add coex support
  Bluetooth: btrsi: add new rsi bluetooth driver
  rsi: add module parameter operating mode
  rsi: sdio changes to support BT

Siva Rebbagondla (2):
  rsi: add bluetooth rx endpoint
  rsi: handle BT traffic in driver

 drivers/bluetooth/Kconfig                   |  11 ++
 drivers/bluetooth/Makefile                  |   2 +
 drivers/bluetooth/btrsi.c                   | 216 ++++++++++++++++++++++++++++
 drivers/bluetooth/rsi_hci.h                 |  40 ++++++
 drivers/net/wireless/rsi/Kconfig            |   2 +-
 drivers/net/wireless/rsi/Makefile           |   1 +
 drivers/net/wireless/rsi/rsi_91x_coex.c     | 184 ++++++++++++++++++++++++
 drivers/net/wireless/rsi/rsi_91x_core.c     |  16 ++-
 drivers/net/wireless/rsi/rsi_91x_hal.c      |  56 ++++++--
 drivers/net/wireless/rsi/rsi_91x_main.c     | 127 +++++++++++++++-
 drivers/net/wireless/rsi/rsi_91x_mgmt.c     |   2 +-
 drivers/net/wireless/rsi/rsi_91x_sdio.c     |  13 +-
 drivers/net/wireless/rsi/rsi_91x_sdio_ops.c |   5 +-
 drivers/net/wireless/rsi/rsi_91x_usb.c      | 124 +++++++++++-----
 drivers/net/wireless/rsi/rsi_91x_usb_ops.c  |  35 +++--
 drivers/net/wireless/rsi/rsi_coex.h         |  38 +++++
 drivers/net/wireless/rsi/rsi_common.h       |   5 +-
 drivers/net/wireless/rsi/rsi_hal.h          |  21 +++
 drivers/net/wireless/rsi/rsi_main.h         |  22 +--
 drivers/net/wireless/rsi/rsi_mgmt.h         |   3 +
 drivers/net/wireless/rsi/rsi_usb.h          |  16 ++-
 include/linux/rsi_header.h                  |  58 ++++++++
 22 files changed, 914 insertions(+), 83 deletions(-)
 create mode 100644 drivers/bluetooth/btrsi.c
 create mode 100644 drivers/bluetooth/rsi_hci.h
 create mode 100644 drivers/net/wireless/rsi/rsi_91x_coex.c
 create mode 100644 drivers/net/wireless/rsi/rsi_coex.h
 create mode 100644 include/linux/rsi_header.h

-- 
2.7.4

^ permalink raw reply

* Re: [PATCH 5/8] Bluetooth: btrsi: add new rsi bluetooth driver
From: Amitkumar Karwar @ 2017-11-29 12:49 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Kalle Valo, linux-wireless, Amitkumar Karwar,
	Prameela Rani Garnepudi, open list:BLUETOOTH DRIVERS,
	Siva Rebbagondla
In-Reply-To: <6E0D3434-F2E9-4B4D-B66E-78DE921BB2CF@holtmann.org>

On Wed, Nov 15, 2017 at 9:07 PM, Marcel Holtmann <marcel@holtmann.org> wrot=
e:
> Hi Amitkumar,
>
>> Redpine bluetooth driver is a thin driver which depends on
>> 'rsi_91x' driver for transmitting and receiving packets
>> to/from device. It creates hci interface when attach() is
>> called from 'rsi_91x' module.
>>
>> Signed-off-by: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>
>> Signed-off-by: Siva Rebbagondla <siva.rebbagondla@redpinesignals.com>
>> Signed-off-by: Amitkumar Karwar <amit.karwar@redpinesignals.com>
>> ---
>> drivers/bluetooth/Kconfig   |  12 ++
>> drivers/bluetooth/Makefile  |   2 +
>> drivers/bluetooth/btrsi.c   | 268 ++++++++++++++++++++++++++++++++++++++=
++++++
>> drivers/bluetooth/rsi_hci.h |  51 +++++++++
>> 4 files changed, 333 insertions(+)
>> create mode 100644 drivers/bluetooth/btrsi.c
>> create mode 100644 drivers/bluetooth/rsi_hci.h
>>
>> diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
>> index 60e1c7d..ca58d74 100644
>> --- a/drivers/bluetooth/Kconfig
>> +++ b/drivers/bluetooth/Kconfig
>> @@ -378,4 +378,16 @@ config BT_QCOMSMD
>>         Say Y here to compile support for HCI over Qualcomm SMD into the
>>         kernel or say M to compile as a module.
>>
>> +config BT_RSI
>> +     tristate "Redpine HCI support"
>> +     depends on BT && BT_RFCOMM
>
> the depends on BT_RFCOMM is wrong. And even the depends on BT is unneeded=
 since that is already covered with the above menu clause.
>
>
>> +     default m
>
> No. New drivers are by default off.

We made it by default on, as RSI core module depends on this.

>
>> +     help
>> +       Redpine BT driver.
>> +       This driver handles BT traffic from upper layers and pass
>> +       to the RSI_91x coex module for further scheduling to device
>> +
>> +       Say Y here to compile support for HCI over Qualcomm SMD into the
>> +       kernel or say M to compile as a module.
>> +
>
> What I am missing is the depends on the RSI core piece that is needed.

Actually RSI core module depends on RSI BT module as per our design.
As soon as firmware is downloaded by RSI core module, we get WLAN and
BT card ready frames from firmware. BT initialization has to happen at
this point. So btrsi module should be loaded first.

>
>> endmenu
>> diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
>> index 4e4e44d..712af83a 100644
>> --- a/drivers/bluetooth/Makefile
>> +++ b/drivers/bluetooth/Makefile
>> @@ -28,6 +28,8 @@ obj-$(CONFIG_BT_QCA)                +=3D btqca.o
>>
>> obj-$(CONFIG_BT_HCIUART_NOKIA)        +=3D hci_nokia.o
>>
>> +obj-$(CONFIG_BT_RSI)         +=3D btrsi.o
>> +
>> btmrvl-y                      :=3D btmrvl_main.o
>> btmrvl-$(CONFIG_DEBUG_FS)     +=3D btmrvl_debugfs.o
>>
>> diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c
>> new file mode 100644
>> index 0000000..c52f418
>> --- /dev/null
>> +++ b/drivers/bluetooth/btrsi.c
>> @@ -0,0 +1,268 @@
>> +/**
>> + * Copyright (c) 2017 Redpine Signals Inc.
>> + *
>> + * Permission to use, copy, modify, and/or distribute this software for=
 any
>> + * purpose with or without fee is hereby granted, provided that the abo=
ve
>> + * copyright notice and this permission notice appear in all copies.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRAN=
TIES
>> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
>> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE =
FOR
>> +e* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAG=
ES
>> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN A=
N
>> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT=
 OF
>> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +#include <linux/version.h>
>> +#include <linux/module.h>
>> +#include <linux/kernel.h>
>> +#include "rsi_hci.h"
>> +
>> +static struct rsi_mod_ops rsi_bt_ops =3D {
>> +     .attach =3D rsi_hci_attach,
>> +     .detach =3D rsi_hci_detach,
>> +     .recv_pkt =3D rsi_hci_recv_pkt,
>> +};
>> +
>> +static int rsi_hci_open(struct hci_dev *hdev)
>> +{
>> +     BT_INFO("%s open\n", hdev->name);
>
> No BT_INFO here. We are not spamming dmesg with pointless information. An=
d this applies to all of these.
>
>> +
>> +     return 0;
>> +}
>> +
>> +static int rsi_hci_close(struct hci_dev *hdev)
>> +{
>> +     BT_INFO("%s closed\n", hdev->name);
>> +
>> +     return 0;
>> +}
>> +
>> +static int rsi_hci_flush(struct hci_dev *hdev)
>> +{
>> +     BT_ERR("%s flush\n", hdev->name);
>> +
>> +     return 0;
>> +}
>> +
>> +static int rsi_hci_send_pkt(struct hci_dev *hdev, struct sk_buff *skb)
>> +{
>> +     struct rsi_hci_adapter *h_adapter;
>
>                                         =3D hci_get_drvdata(dev);
>
> There is no need to do that separate.
>
>> +     struct sk_buff *new_skb =3D NULL;
>> +
>> +     int status =3D 0;
>> +
>> +     h_adapter =3D hci_get_drvdata(hdev);
>> +     if (!h_adapter) {
>> +             status =3D -EFAULT;
>> +             goto fail;
>> +     }
>
> And this error check seems unneeded since the Bluetooth core will never c=
all ->send unless it is all correctly set up.
>
>> +
>> +     if (h_adapter->fsm_state !=3D RSI_BT_FSM_DEVICE_READY) {
>> +             BT_INFO("BT Device not ready\n");
>> +             status =3D -ENODEV;
>> +             goto fail;
>> +     }
>
> Why are we registering a HCI device that might not be ready. This will be=
 a massive bug in the whole system. Also one that is not recoverable. If so=
mething goes wrong, then lets unregister the HCI device.
>
>> +
>> +     if (!test_bit(HCI_RUNNING, &hdev->flags)) {
>> +             status =3D -EBUSY;
>> +             goto fail;
>> +     }
>
> This should no longer be needed. We moved this into the core and besides =
some old USB drivers, nobody is using this anymore.
>
>> +
>> +     switch (bt_cb(skb)->pkt_type) {
>> +     case HCI_COMMAND_PKT:
>> +             hdev->stat.cmd_tx++;
>> +             break;
>> +
>> +     case HCI_ACLDATA_PKT:
>> +             hdev->stat.acl_tx++;
>> +             break;
>> +
>> +     case HCI_SCODATA_PKT:
>> +             hdev->stat.sco_tx++;
>> +             break;
>> +
>> +     default:
>> +             dev_kfree_skb(skb);
>
> Don=E2=80=99t use dev_kfree_skb() here. I think the Bluetooth subsystem i=
s not ready for that.
>
>> +             status =3D -EILSEQ;
>> +             goto fail;
>> +     }
>> +
>> +     if (skb_headroom(skb) < RSI_HEADROOM_FOR_BT_HAL) {
>> +             /* Re-allocate one more skb with sufficent headroom */
>> +             /* Space for Descriptor (16 bytes) is required in head roo=
m */
>> +             u16 new_len =3D skb->len + RSI_HEADROOM_FOR_BT_HAL;
>> +
>> +             new_skb =3D dev_alloc_skb(new_len);
>> +             if (!new_skb) {
>> +                     dev_kfree_skb(skb);
>> +                     return -ENOMEM;
>> +             }
>> +             skb_reserve(new_skb, RSI_HEADROOM_FOR_BT_HAL);
>> +             skb_put(new_skb, skb->len);
>> +             memcpy(new_skb->data, skb->data, skb->len);
>> +             bt_cb(new_skb)->pkt_type =3D bt_cb(skb)->pkt_type;
>> +             dev_kfree_skb(skb);
>> +             skb =3D new_skb;
>
> Just allocate a new skb with proper headroom. The data part can be shared=
. Doing this fully manual is just a bad idea.
>
> I also get the feeling that long term we want to change the Bluetooth dri=
vers to specify the required SKB headroom so that they always get SKBs that=
 are large enough for their needs.
>
>> +     }
>> +     if (h_adapter->proto_ops->coex_send_pkt)
>> +             return h_adapter->proto_ops->coex_send_pkt(h_adapter->priv=
, skb,
>> +                                                       RSI_BT_Q);
>
> This is worrisome. You need to send. If this callback is not available, t=
hen better not register the HCI device at all.
>
>> +
>> +fail:
>> +     dev_kfree_skb(skb);
>> +     return status;
>> +}
>> +
>> +int rsi_hci_recv_pkt(void *priv, u8 *pkt)
>> +{
>> +     struct rsi_hci_adapter *h_adapter =3D (struct rsi_hci_adapter *)pr=
iv;
>> +     struct hci_dev *hdev =3D NULL;
>> +     struct sk_buff *skb;
>> +     int pkt_len =3D (le16_to_cpu(*(__le16 *)pkt)) & 0x0fff;
>> +     u8 queue_no =3D (le16_to_cpu(*(__le16 *)pkt) & 0x7000) >> 12;
>
> We have get_unaligned_le16 helpers for this.
>
>> +
>> +     if (h_adapter->fsm_state !=3D RSI_BT_FSM_DEVICE_READY) {
>> +             BT_INFO("BT Device not ready\n");
>> +             return 0;
>> +     }
>
> Why call this function if the device is not ready? Can that not be checke=
d and the HCI device not be registered.
>
>> +
>> +     if (queue_no =3D=3D RSI_BT_MGMT_Q) {
>> +             u8 msg_type =3D pkt[14] & 0xFF;
>> +
>> +             switch (msg_type) {
>> +             case RSI_RESULT_CONFIRM:
>> +                     BT_INFO("BT Result Confirm\n");
>> +                     return 0;
>> +             case RSI_BT_BER:
>> +                     BT_INFO("BT Ber\n");
>> +                     return 0;
>> +             case RSI_BT_CW:
>> +                     BT_INFO("BT CW\n");
>> +                     return 0;
>> +             default:
>> +                     break;
>> +             }
>> +     }
>
> How noisy is this? Also no \n required for the BT_INFO functions. And her=
e bt_dev_info is preferred anyway.
>
>> +
>> +     skb =3D dev_alloc_skb(pkt_len);
>> +     if (!skb)
>> +             return -ENOMEM;
>> +
>> +     hdev =3D h_adapter->hdev;
>> +     memcpy(skb->data, pkt + RSI_FRAME_DESC_SIZE, pkt_len);
>> +     skb_put(skb, pkt_len);
>> +     h_adapter->hdev->stat.byte_rx +=3D skb->len;
>> +
>> +     skb->dev =3D (void *)hdev;
>> +     bt_cb(skb)->pkt_type =3D pkt[14];
>> +
>> +     return hci_recv_frame(hdev, skb);
>> +}
>> +EXPORT_SYMBOL_GPL(rsi_hci_recv_pkt);
>> +
>> +int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops)
>> +{
>> +     struct rsi_hci_adapter *h_adapter =3D NULL;
>> +     struct hci_dev *hdev;
>> +     int status =3D 0;
>> +
>> +     h_adapter =3D kzalloc(sizeof(*h_adapter), GFP_KERNEL);
>> +     if (!h_adapter)
>> +             return -ENOMEM;
>> +
>> +     h_adapter->priv =3D priv;
>> +     ops->set_bt_context(priv, h_adapter);
>> +     h_adapter->proto_ops =3D ops;
>> +     ops->bt_ops =3D &rsi_bt_ops;
>> +     h_adapter->fsm_state =3D RSI_BT_FSM_DEVICE_READY;
>> +
>> +     hdev =3D hci_alloc_dev();
>> +     if (!hdev) {
>> +             BT_ERR("Failed to alloc HCI device\n");
>> +             goto err;
>> +     }
>> +     h_adapter->hdev =3D hdev;
>> +
>> +     if (ops->get_host_intf(priv) =3D=3D RSI_HOST_INTF_SDIO)
>> +             hdev->bus =3D HCI_SDIO;
>> +     else
>> +             hdev->bus =3D HCI_USB;
>> +
>> +     hci_set_drvdata(hdev, h_adapter);
>> +     hdev->dev_type =3D HCI_PRIMARY;
>> +     hdev->open =3D rsi_hci_open;
>> +     hdev->close =3D rsi_hci_close;
>> +     hdev->flush =3D rsi_hci_flush;
>> +     hdev->send =3D rsi_hci_send_pkt;
>> +
>> +     status =3D hci_register_dev(hdev);
>> +     if (status < 0) {
>> +             BT_ERR("%s: HCI registration failed with errcode %d\n",
>> +                    __func__, status);
>> +             goto err;
>> +     }
>> +
>> +     BT_INFO("%s interface created\n", hdev->name);
>> +
>> +     h_adapter->fsm_state =3D RSI_BT_FSM_DEVICE_READY;
>> +
>> +     return 0;
>> +
>> +err:
>> +     if (hdev) {
>> +             hci_unregister_dev(hdev);
>> +             hci_free_dev(hdev);
>> +             h_adapter->hdev =3D NULL;
>> +     }
>> +     kfree(h_adapter);
>> +
>> +     return -EINVAL;
>> +}
>> +
>> +void rsi_hci_detach(void *priv)
>> +{
>> +     struct rsi_hci_adapter *h_adapter =3D (struct rsi_hci_adapter *)pr=
iv;
>> +     struct hci_dev *hdev;
>> +
>> +     if (!h_adapter)
>> +             return;
>> +
>> +     hdev =3D h_adapter->hdev;
>> +
>> +     BT_INFO("Detaching %s\n", hdev->name);
>> +
>> +     if (hdev) {
>> +             hci_unregister_dev(hdev);
>> +             hci_free_dev(hdev);
>> +             h_adapter->hdev =3D NULL;
>> +     }
>> +
>> +     kfree(h_adapter);
>> +     h_adapter->fsm_state =3D RSI_BT_FSM_DEVICE_NOT_READY;
>> +}
>> +
>> +struct rsi_mod_ops *rsi_get_hci_ops(void)
>> +{
>> +     return &rsi_bt_ops;
>> +};
>> +EXPORT_SYMBOL_GPL(rsi_get_hci_ops);
>> +
>> +static int rsi_91x_bt_module_init(void)
>> +{
>> +     BT_INFO("%s: BT Module init called\n", __func__);
>> +
>> +     return 0;
>> +}
>> +
>> +static void rsi_91x_bt_module_exit(void)
>> +{
>> +     BT_INFO("%s: BT Module exit called\n", __func__);
>> +}
>> +
>> +module_init(rsi_91x_bt_module_init);
>> +module_exit(rsi_91x_bt_module_exit);
>> +MODULE_AUTHOR("Redpine Signals Inc");
>> +MODULE_DESCRIPTION("RSI BT driver");
>> +MODULE_SUPPORTED_DEVICE("RSI-BT");
>> +MODULE_LICENSE("Dual BSD/GPL");
>> diff --git a/drivers/bluetooth/rsi_hci.h b/drivers/bluetooth/rsi_hci.h
>> new file mode 100644
>> index 0000000..6f44231
>> --- /dev/null
>> +++ b/drivers/bluetooth/rsi_hci.h
>> @@ -0,0 +1,51 @@
>> +/**
>> + * Copyright (c) 2017 Redpine Signals Inc.
>> + *
>> + * Permission to use, copy, modify, and/or distribute this software for=
 any
>> + * purpose with or without fee is hereby granted, provided that the abo=
ve
>> + * copyright notice and this permission notice appear in all copies.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRAN=
TIES
>> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
>> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE =
FOR
>> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAG=
ES
>> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN A=
N
>> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT=
 OF
>> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#ifndef __RSI_HCI_H__
>> +#define __RSI_HCI_H__
>> +
>> +#include <net/bluetooth/bluetooth.h>
>> +#include <net/bluetooth/hci_core.h>
>> +#include <linux/rsi_header.h>
>> +#include <net/genetlink.h>
>> +
>> +/* RX frame types */
>> +#define RSI_RESULT_CONFIRM                   0x80
>> +#define RSI_BT_PER                           0x10
>> +#define RSI_BT_BER                           0x11
>> +#define RSI_BT_CW                            0x12
>> +
>> +#define RSI_HEADROOM_FOR_BT_HAL      16
>> +
>> +enum bt_fsm_state {
>> +     RSI_BT_FSM_DEVICE_NOT_READY =3D 0,
>> +     RSI_BT_FSM_DEVICE_READY,
>> +};
>> +
>> +struct rsi_hci_adapter {
>> +     void *priv;
>> +     struct rsi_proto_ops *proto_ops;
>> +     enum bt_fsm_state fsm_state;
>> +     struct hci_dev *hdev;
>> +};
>
> If they are btrsi.c specific, they should be in btrsi.c and not in a head=
er file.
>
>> +
>> +#define RSI_FRAME_DESC_SIZE          16
>> +
>> +int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops);
>> +void rsi_hci_detach(void *priv);
>> +int rsi_hci_recv_pkt(void *data, u8 *pkt);
>
> And this is the part I do not get. What is the deal with the rsi_bt_ops. =
Having both exported is pointless.

rsi core module initializes rsi_bt_ops by calling exported function
rsi_get_hci_ops().

Regards,
Amitkumar

^ permalink raw reply

* Re: [PATCH 6/6] iwlwifi: fix access to prph when transport is stopped
From: Luca Coelho @ 2017-11-29 10:29 UTC (permalink / raw)
  To: Kalle Valo; +Cc: linux-wireless, Sara Sharon
In-Reply-To: <87mv351iys.fsf@kamboji.qca.qualcomm.com>

On Wed, 2017-11-29 at 12:23 +0200, Kalle Valo wrote:
> Luca Coelho <luca@coelho.fi> writes:
> 
> > From: Sara Sharon <sara.sharon@intel.com>
> > 
> > When getting HW rfkill we get stop_device being called from
> > two paths.
> > One path is the IRQ calling stop device, and updating op
> > mode and stack.
> > As a result, cfg80211 is running rfkill sync work that shuts
> > down all devices (second path).
> > In the second path, we eventually get to iwl_mvm_stop_device
> > which calls iwl_fw_dump_conf_clear->iwl_fw_dbg_stop_recording,
> > that access periphery registers.
> > The device may be stopped at this point from the first path,
> > which will result with a failure to access those registers.
> > Simply checking for the trans status is insufficient, since
> > the race will still exist, only minimized.
> > Instead, move the stop from iwl_fw_dump_conf_clear (which is
> > getting called only from stop path) to the transport stop
> > device function, where the access is always safe.
> > This has the added value, of actually stopping dbgc before
> > stopping device even when the stop is initiated from the
> > transport.
> > 
> > Fixes: 1efc3843a4ee ("iwlwifi: stop dbgc recording before stopping
> > DMA")
> > Signed-off-by: Sara Sharon <sara.sharon@intel.com>
> > Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
> 
> But no wonder I called gnus-article-fill-cited-article, the commit
> log
> is just weirdly wrapped. Are you using outlook or how do you get it
> so
> ugly? :)

Heh! I don't think it's wrapped weirdly, it's just that the paragraphs
don't have spaces between them, right? ;)

I noticed this but was probably too tired to nitpick back when I merged
this in our internal tree.  I'll make sure people space the commit
messages better from now on.

Sorry for the trouble.

--
Cheers,
Luca.

^ permalink raw reply

* Re: [PATCH 6/6] iwlwifi: fix access to prph when transport is stopped
From: Kalle Valo @ 2017-11-29 10:23 UTC (permalink / raw)
  To: Luca Coelho; +Cc: linux-wireless, Sara Sharon, Luca Coelho
In-Reply-To: <20171125153510.25359-7-luca@coelho.fi>

Luca Coelho <luca@coelho.fi> writes:

> From: Sara Sharon <sara.sharon@intel.com>
>
> When getting HW rfkill we get stop_device being called from
> two paths.
> One path is the IRQ calling stop device, and updating op
> mode and stack.
> As a result, cfg80211 is running rfkill sync work that shuts
> down all devices (second path).
> In the second path, we eventually get to iwl_mvm_stop_device
> which calls iwl_fw_dump_conf_clear->iwl_fw_dbg_stop_recording,
> that access periphery registers.
> The device may be stopped at this point from the first path,
> which will result with a failure to access those registers.
> Simply checking for the trans status is insufficient, since
> the race will still exist, only minimized.
> Instead, move the stop from iwl_fw_dump_conf_clear (which is
> getting called only from stop path) to the transport stop
> device function, where the access is always safe.
> This has the added value, of actually stopping dbgc before
> stopping device even when the stop is initiated from the
> transport.
>
> Fixes: 1efc3843a4ee ("iwlwifi: stop dbgc recording before stopping DMA")
> Signed-off-by: Sara Sharon <sara.sharon@intel.com>
> Signed-off-by: Luca Coelho <luciano.coelho@intel.com>

But no wonder I called gnus-article-fill-cited-article, the commit log
is just weirdly wrapped. Are you using outlook or how do you get it so
ugly? :)

-- 
Kalle Valo

^ permalink raw reply

* Re: [PATCH 6/6] iwlwifi: fix access to prph when transport is stopped
From: Kalle Valo @ 2017-11-29 10:21 UTC (permalink / raw)
  To: Luca Coelho; +Cc: linux-wireless@vger.kernel.org, Sara Sharon, Luca Coelho
In-Reply-To: <87vaht1j63.fsf@kamboji.qca.qualcomm.com>

Kalle Valo <kvalo@codeaurora.org> writes:

> Luca Coelho <luca@coelho.fi> writes:
>
>> From: Sara Sharon <sara.sharon@intel.com>
>>
>> When getting HW rfkill we get stop_device being called from two paths.
>> One path is the IRQ calling stop device, and updating op mode and
>> stack. As a result, cfg80211 is running rfkill sync work that shuts
>> down all devices (second path). In the second path, we eventually get
>> to iwl_mvm_stop_device which calls
>> iwl_fw_dump_conf_clear->iwl_fw_dbg_stop_recording, that access
>> periphery registers. The device may be stopped at this point from the
>> first path, which will result with a failure to access those
>> registers. Simply checking for the trans status is insufficient, since
>> the race will still exist, only minimized. Instead, move the stop from
>> iwl_fw_dump_conf_clear (which is getting called only from stop path)
>> to the transport stop device function, where the access is always
>> safe. This has the added value, of actually stopping dbgc before
>> stopping device even when the stop is initiated from the transport.
>>
>> Fixes: 1efc3843a4ee ("iwlwifi: stop dbgc recording before stopping
>> DMA")
>
> No need to resend because of this, but Fixes should be in one line.

Please ignore, I was too clever and forgot that I had called
gnus-article-fill-cited-article which word wraps the mail :)

--=20
Kalle Valo=

^ permalink raw reply

* Re: [PATCH 6/6] iwlwifi: fix access to prph when transport is stopped
From: Kalle Valo @ 2017-11-29 10:19 UTC (permalink / raw)
  To: Luca Coelho; +Cc: linux-wireless, Sara Sharon, Luca Coelho
In-Reply-To: <20171125153510.25359-7-luca@coelho.fi>

Luca Coelho <luca@coelho.fi> writes:

> From: Sara Sharon <sara.sharon@intel.com>
>
> When getting HW rfkill we get stop_device being called from two paths.
> One path is the IRQ calling stop device, and updating op mode and
> stack. As a result, cfg80211 is running rfkill sync work that shuts
> down all devices (second path). In the second path, we eventually get
> to iwl_mvm_stop_device which calls
> iwl_fw_dump_conf_clear->iwl_fw_dbg_stop_recording, that access
> periphery registers. The device may be stopped at this point from the
> first path, which will result with a failure to access those
> registers. Simply checking for the trans status is insufficient, since
> the race will still exist, only minimized. Instead, move the stop from
> iwl_fw_dump_conf_clear (which is getting called only from stop path)
> to the transport stop device function, where the access is always
> safe. This has the added value, of actually stopping dbgc before
> stopping device even when the stop is initiated from the transport.
>
> Fixes: 1efc3843a4ee ("iwlwifi: stop dbgc recording before stopping
> DMA")

No need to resend because of this, but Fixes should be in one line.

-- 
Kalle Valo

^ permalink raw reply

* RE: [PATCH] ath10k: handling qos at STA side based on AP WMM enable/disable
From: Balaji Pothunoori @ 2017-11-29 10:12 UTC (permalink / raw)
  To: Sebastian Gottschall, ath10k@lists.infradead.org
  Cc: linux-wireless@vger.kernel.org
In-Reply-To: <e84f2a95-178b-dc07-bc6e-9dc779e0db0f@dd-wrt.com>

Pj4gSGkgU2ViYXN0aWFuLA0KPj4NCj4+IElmIEkgYW0gbm90IHdyb25nIHlvdSBhcmUgc2VlaW5n
IHRoZSBpc3N1ZSB3aXRoIFdSVDMyMDBBQ00gKE1hcnZlbGwgODhXODk2NCkgYXMgY2xpZW50ICsg
UUNBOTk4NCAoRlcgOiAxMC40LTMuNS4zLTAwMDM4KSBhcyBBUCB3aXRoIGJlbG93IGNoYW5nZSB5
b3UgYXJlIHNlZWluZyB0aGUgY3Jhc2ggd2hpbGUgcnVubmluZyB0cmFmZmljIGJldHdlZW4gdGhl
IFdSVDMyMDBBQ00gKyBRQ0E5OTg0ID8NCj4+IERvIHlvdSB1c2VkICBhbnkgb3RoZXIgY2xpZW50
IGluIHBsYWNlIG9mIFdSVDMyMDBBQ00gPw0KDQo+dGhlcmUgaXMgbm90IG11Y2ggIHRyYWZmaWMg
cmVxdWlyZWQuIGFzIGl0IHNlZW1zIHRoZSBmaXJtd2FyZSBjcmFzaGVzIGltbWVkaWF0bHkgYWZ0
ZXIgYXNzb2NpYXRpb24uIHRoZSBpc3N1ZSBpcyBhbHNvIG5vdCBwcmVzZW50IGluIDEwLjQtMy40
LTAwODJ3dw0KDQpTdGlsbCBteSBxdWVzdGlvbiBpcyBub3QgY2xlYXJlZCwgIGZpcm13YXJlIGNy
YXNoIGlzIGR1ZSB0byB0aGlzIHBhdGNoID8gQWxzbyBsZXQgbWUga25vdyBkbyB5b3Ugb2JzZXJ2
ZWQgc2FtZSBiZWhhdmlvciB3aXRoIGFueSBvdGhlciBjaGlwc2V0ID8NCg0KIA0KUmVnYXJkcywN
CkJhbGFqaS4NCg0KPlNlYmFzdGlhbg0KDQoNCj4+DQo+PiBSZWdhcmRzLA0KPj4gQmFsYWppLg0K
DQotLS0tLU9yaWdpbmFsIE1lc3NhZ2UtLS0tLQ0KRnJvbTogU2ViYXN0aWFuIEdvdHRzY2hhbGwg
W21haWx0bzpzLmdvdHRzY2hhbGxAZGQtd3J0LmNvbV0gDQpTZW50OiBXZWRuZXNkYXksIE5vdmVt
YmVyIDI5LCAyMDE3IDI6MDQgUE0NClRvOiBCYWxhamkgUG90aHVub29yaSA8YnBvdGh1bm9AcXRp
LnF1YWxjb21tLmNvbT47IGF0aDEwa0BsaXN0cy5pbmZyYWRlYWQub3JnDQpDYzogbGludXgtd2ly
ZWxlc3NAdmdlci5rZXJuZWwub3JnDQpTdWJqZWN0OiBSZTogW1BBVENIXSBhdGgxMGs6IGhhbmRs
aW5nIHFvcyBhdCBTVEEgc2lkZSBiYXNlZCBvbiBBUCBXTU0gZW5hYmxlL2Rpc2FibGUNCg0KQW0g
MjkuMTEuMjAxNyB1bSAwNzo1OCBzY2hyaWViIEJhbGFqaSBQb3RodW5vb3JpOg0KPiBIaSBTZWJh
c3RpYW4sDQo+DQo+IElmIEkgYW0gbm90IHdyb25nIHlvdSBhcmUgc2VlaW5nIHRoZSBpc3N1ZSB3
aXRoIFdSVDMyMDBBQ00gKE1hcnZlbGwgODhXODk2NCkgYXMgY2xpZW50ICsgUUNBOTk4NCAoRlcg
OiAxMC40LTMuNS4zLTAwMDM4KSBhcyBBUCB3aXRoIGJlbG93IGNoYW5nZSB5b3UgYXJlIHNlZWlu
ZyB0aGUgY3Jhc2ggd2hpbGUgcnVubmluZyB0cmFmZmljIGJldHdlZW4gdGhlIFdSVDMyMDBBQ00g
KyBRQ0E5OTg0ID8NCj4gRG8geW91IHVzZWQgIGFueSBvdGhlciBjbGllbnQgaW4gcGxhY2Ugb2Yg
V1JUMzIwMEFDTSA/DQoNCnRoZXJlIGlzIG5vdCBtdWNowqAgdHJhZmZpYyByZXF1aXJlZC4gYXMg
aXQgc2VlbXMgdGhlIGZpcm13YXJlIGNyYXNoZXMgaW1tZWRpYXRseSBhZnRlciBhc3NvY2lhdGlv
bi4gdGhlIGlzc3VlIGlzIGFsc28gbm90IHByZXNlbnQgaW4gMTAuNC0zLjQtMDA4Mnd3DQoNCj4g
Q2FuIHlvdSBzaGFyZSB0aGUgbW9yZSBkZXRhaWxzIG9uIGZpcm13YXJlIGNyYXNoID8NCg0Kc28g
YSBmaXJtd2FyZSBjcmFzaGR1bXAgZnJvbSBsb2c/IGknbGwgdHJ5IHRvIGdldCBpdCB3aXRoaW4g
dGhlIG5leHQgaG91cnMuIGp1c3QgbmVlZCB0byByZXNldHVwIHRoZSB0ZXN0IHNjZW5hcmlvDQoN
Cg0KU2ViYXN0aWFuDQoNCg0KPg0KPiBSZWdhcmRzLA0KPiBCYWxhamkuDQo+DQo+IC0tLS0tT3Jp
Z2luYWwgTWVzc2FnZS0tLS0tDQo+IEZyb206IFNlYmFzdGlhbiBHb3R0c2NoYWxsIFttYWlsdG86
cy5nb3R0c2NoYWxsQGRkLXdydC5jb21dDQo+IFNlbnQ6IFdlZG5lc2RheSwgTm92ZW1iZXIgMjks
IDIwMTcgODoyOCBBTQ0KPiBUbzogQmFsYWppIFBvdGh1bm9vcmkgPGJwb3RodW5vQHF0aS5xdWFs
Y29tbS5jb20+OyBhdGgxMGtAbGlzdHMuaW5mcmFkZWFkLm9yZw0KPiBDYzogbGludXgtd2lyZWxl
c3NAdmdlci5rZXJuZWwub3JnDQo+IFN1YmplY3Q6IFJlOiBbUEFUQ0hdIGF0aDEwazogaGFuZGxp
bmcgcW9zIGF0IFNUQSBzaWRlIGJhc2VkIG9uIEFQIFdNTSBlbmFibGUvZGlzYWJsZQ0KPg0KPiBk
aWQgeW91IG5vdGljZcKgIHRoYXQgTWFydmVsbCA4OFc4OTY0IGJhc2VkIGNsaWVudHMgd2lsbCBj
cmFzaCAxMC40LTMuNS4zIGZpcm13YXJlcz/CoCAodGVzdGVkIHdpdGggOTk4NCBhbmQgMTAuNC0z
LjUuMy0wMDAzOCkgY2xpZW50IGRldmljZSB3YXMgYSBsaW5rc3lzIHdydDMyMDBhY20gcnVubmlu
ZyBkZC13cnQgZm9yIHRlc3RpbmcNCj4NCj4gQW0gMjguMTEuMjAxNyB1bSAxMTowNyBzY2hyaWVi
IGJwb3RodW5vQHF0aS5xdWFsY29tbS5jb206DQo+PiBGcm9tOiBCYWxhamkgUG90aHVub29yaSA8
YnBvdGh1bm9AcXRpLnF1YWxjb21tLmNvbT4NCj4+DQo+PiBEYXRhIHBhY2tldHMgYXJlIG5vdCBz
ZW50IGJ5IFNUQSBpbiBjYXNlIG9mIFNUQSBqb2luZWQgdG8gbm9uIFFPUyBBUA0KPj4gKFdNTSBk
aXNhYmxlZCBBUCkuIFRoaXMgaXMgaGFwcGVuaW5nIGJlY2F1c2Ugb2YgU1RBIGlzIHNlbmRpbmcg
ZGF0YQ0KPj4gcGFja2V0cyB0byBmaXJtd2FyZSBmcm9tIGhvc3Qgd2l0aCBxb3MgZW5hYmxlZCBh
bG9uZyB3aXRoIG5vbiBxb3MNCj4+IHF1ZXVlIHZhbHVlKFRJRCA9IDE2KS4NCj4+IER1ZSB0byBx
b3MgZW5hYmxlZCwgZmlybXdhcmUgaXMgZGlzY2FyZGluZyB0aGUgcGFja2V0Lg0KPj4NCj4+IFRo
aXMgcGF0Y2ggZml4ZXMgdGhpcyBpc3N1ZSBieSB1cGRhdGluZyB0aGUgcW9zIGJhc2VkIG9uIHN0
YXRpb24gV01FDQo+PiBjYXBhYmlsaXR5IGZpZWxkIGlmIFdNTSBpcyBkaXNhYmxlZCBpbiBBUC4N
Cj4+DQo+PiBUaGlzIHBhdGNoIGlzIHJlcXVpcmVkIGJ5IDEwLjQgZmFtaWx5IGNoaXBzZXRzIGxp
a2UNCj4+IFFDQTQwMTkvUUNBOTg4OC9RQ0E5ODg0L1FDQTk5WDAuDQo+PiBGaXJtd2FyZSBWZXJz
b2luIDogMTAuNC0zLjUuMS0wMDAxOC4NCj4+DQo+PiBGb3IgMTAuMi40IGZhbWlseSBjaGlwc2V0
cyBRQ0E5ODhYL1FDQTk4ODcgYW5kIFFDQTYxNzQgdGhpcyBwYXRjaCBoYXMNCj4+IG5vIGVmZmVj
dC4NCj4+DQo+PiBTaWduZWQtb2ZmLWJ5OiBCYWxhamkgUG90aHVub29yaSA8YnBvdGh1bm9AcXRp
LnF1YWxjb21tLmNvbT4NCj4+IC0tLQ0KPj4gICAgZHJpdmVycy9uZXQvd2lyZWxlc3MvYXRoL2F0
aDEway9tYWMuYyB8ICAgIDIgKy0NCj4+ICAgIDEgZmlsZSBjaGFuZ2VkLCAxIGluc2VydGlvbigr
KSwgMSBkZWxldGlvbigtKQ0KPj4NCj4+IGRpZmYgLS1naXQgYS9kcml2ZXJzL25ldC93aXJlbGVz
cy9hdGgvYXRoMTBrL21hYy5jDQo+PiBiL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2F0aC9hdGgxMGsv
bWFjLmMNCj4+IGluZGV4IDBhOTQ3ZWUuLjI2MTZiOTkgMTAwNjQ0DQo+PiAtLS0gYS9kcml2ZXJz
L25ldC93aXJlbGVzcy9hdGgvYXRoMTBrL21hYy5jDQo+PiArKysgYi9kcml2ZXJzL25ldC93aXJl
bGVzcy9hdGgvYXRoMTBrL21hYy5jDQo+PiBAQCAtMjU2Myw3ICsyNTYzLDcgQEAgc3RhdGljIHZv
aWQgYXRoMTBrX3BlZXJfYXNzb2NfaF9xb3Moc3RydWN0IGF0aDEwayAqYXIsDQo+PiAgICAJCX0N
Cj4+ICAgIAkJYnJlYWs7DQo+PiAgICAJY2FzZSBXTUlfVkRFVl9UWVBFX1NUQToNCj4+IC0JCWlm
ICh2aWYtPmJzc19jb25mLnFvcykNCj4+ICsJCWlmIChzdGEtPndtZSkNCj4+ICAgIAkJCWFyZy0+
cGVlcl9mbGFncyB8PSBhcnZpZi0+YXItPndtaS5wZWVyX2ZsYWdzLT5xb3M7DQo+PiAgICAJCWJy
ZWFrOw0KPj4gICAgCWNhc2UgV01JX1ZERVZfVFlQRV9JQlNTOg0KPg0KPiAtLQ0KPiBNaXQgZnJl
dW5kbGljaGVuIEdyw7xzc2VuIC8gUmVnYXJkcw0KPg0KPiBTZWJhc3RpYW4gR290dHNjaGFsbCAv
IENUTw0KPg0KPiBOZXdNZWRpYS1ORVQgR21iSCAtIERELVdSVA0KPiBGaXJtZW5zaXR6OiAgU3R1
YmVud2FsZGFsbGVlIDIxYSwgNjQ2MjUgQmVuc2hlaW0NCj4gUmVnaXN0ZXJnZXJpY2h0OiBBbXRz
Z2VyaWNodCBEYXJtc3RhZHQsIEhSQiAyNTQ3Mw0KPiBHZXNjaMOkZnRzZsO8aHJlcjogUGV0ZXIg
U3RlaW5ow6R1c2VyLCBDaHJpc3RpYW4gU2NoZWVsZSBodHRwOi8vd3d3LmRkLXdydC5jb20NCj4g
ZW1haWw6IHMuZ290dHNjaGFsbEBkZC13cnQuY29tDQo+IFRlbC46ICs0OTYyNTEtNTgyNjUwIC8g
RmF4OiArNDk2MjUxLTU4MjY1NjUNCj4NCg0KLS0gDQpNaXQgZnJldW5kbGljaGVuIEdyw7xzc2Vu
IC8gUmVnYXJkcw0KDQpTZWJhc3RpYW4gR290dHNjaGFsbCAvIENUTw0KDQpOZXdNZWRpYS1ORVQg
R21iSCAtIERELVdSVA0KRmlybWVuc2l0ejogIFN0dWJlbndhbGRhbGxlZSAyMWEsIDY0NjI1IEJl
bnNoZWltDQpSZWdpc3RlcmdlcmljaHQ6IEFtdHNnZXJpY2h0IERhcm1zdGFkdCwgSFJCIDI1NDcz
DQpHZXNjaMOkZnRzZsO8aHJlcjogUGV0ZXIgU3RlaW5ow6R1c2VyLCBDaHJpc3RpYW4gU2NoZWVs
ZQ0KaHR0cDovL3d3dy5kZC13cnQuY29tDQplbWFpbDogcy5nb3R0c2NoYWxsQGRkLXdydC5jb20N
ClRlbC46ICs0OTYyNTEtNTgyNjUwIC8gRmF4OiArNDk2MjUxLTU4MjY1NjUNCg0K

^ permalink raw reply

* [PATCH 3/4] ath10k: WMI: get wmi init parameter values from hw params
From: Rakesh Pillai @ 2017-11-29  9:51 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Rakesh Pillai, Govind Singh
In-Reply-To: <1511949097-524-1-git-send-email-pillair@qti.qualcomm.com>

The parameter values for skid limit, number of peers and wds
entries values which are sent in wmi init cmd are hardware
specific.

Add support to obtain skid limit, number of peers and wds entries
values from hw params which will have the hw specific values
for these parameters.

Signed-off-by: Rakesh Pillai <pillair@qti.qualcomm.com>
Signed-off-by: Govind Singh <govinds@qti.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/core.c    | 36 +++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/hw.h      |  4 ++++
 drivers/net/wireless/ath/ath10k/wmi-tlv.c |  7 +++---
 3 files changed, 44 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 1e4e18e..be18913 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -75,6 +75,9 @@
 		.vht160_mcs_rx_highest = 0,
 		.vht160_mcs_tx_highest = 0,
 		.n_cipher_suites = 8,
+		.num_peers = TARGET_TLV_NUM_PEERS,
+		.ast_skid_limit = 0x10,
+		.num_wds_entries = 0x20,
 	},
 	{
 		.id = QCA9887_HW_1_0_VERSION,
@@ -99,6 +102,9 @@
 		.vht160_mcs_rx_highest = 0,
 		.vht160_mcs_tx_highest = 0,
 		.n_cipher_suites = 8,
+		.num_peers = TARGET_TLV_NUM_PEERS,
+		.ast_skid_limit = 0x10,
+		.num_wds_entries = 0x20,
 	},
 	{
 		.id = QCA6174_HW_2_1_VERSION,
@@ -122,6 +128,9 @@
 		.vht160_mcs_rx_highest = 0,
 		.vht160_mcs_tx_highest = 0,
 		.n_cipher_suites = 8,
+		.num_peers = TARGET_TLV_NUM_PEERS,
+		.ast_skid_limit = 0x10,
+		.num_wds_entries = 0x20,
 	},
 	{
 		.id = QCA6174_HW_2_1_VERSION,
@@ -145,6 +154,9 @@
 		.vht160_mcs_rx_highest = 0,
 		.vht160_mcs_tx_highest = 0,
 		.n_cipher_suites = 8,
+		.num_peers = TARGET_TLV_NUM_PEERS,
+		.ast_skid_limit = 0x10,
+		.num_wds_entries = 0x20,
 	},
 	{
 		.id = QCA6174_HW_3_0_VERSION,
@@ -168,6 +180,9 @@
 		.vht160_mcs_rx_highest = 0,
 		.vht160_mcs_tx_highest = 0,
 		.n_cipher_suites = 8,
+		.num_peers = TARGET_TLV_NUM_PEERS,
+		.ast_skid_limit = 0x10,
+		.num_wds_entries = 0x20,
 	},
 	{
 		.id = QCA6174_HW_3_2_VERSION,
@@ -194,6 +209,9 @@
 		.vht160_mcs_rx_highest = 0,
 		.vht160_mcs_tx_highest = 0,
 		.n_cipher_suites = 8,
+		.num_peers = TARGET_TLV_NUM_PEERS,
+		.ast_skid_limit = 0x10,
+		.num_wds_entries = 0x20,
 	},
 	{
 		.id = QCA99X0_HW_2_0_DEV_VERSION,
@@ -223,6 +241,9 @@
 		.vht160_mcs_rx_highest = 0,
 		.vht160_mcs_tx_highest = 0,
 		.n_cipher_suites = 11,
+		.num_peers = TARGET_TLV_NUM_PEERS,
+		.ast_skid_limit = 0x10,
+		.num_wds_entries = 0x20,
 	},
 	{
 		.id = QCA9984_HW_1_0_DEV_VERSION,
@@ -257,6 +278,9 @@
 		.vht160_mcs_rx_highest = 1560,
 		.vht160_mcs_tx_highest = 1560,
 		.n_cipher_suites = 11,
+		.num_peers = TARGET_TLV_NUM_PEERS,
+		.ast_skid_limit = 0x10,
+		.num_wds_entries = 0x20,
 	},
 	{
 		.id = QCA9888_HW_2_0_DEV_VERSION,
@@ -290,6 +314,9 @@
 		.vht160_mcs_rx_highest = 780,
 		.vht160_mcs_tx_highest = 780,
 		.n_cipher_suites = 11,
+		.num_peers = TARGET_TLV_NUM_PEERS,
+		.ast_skid_limit = 0x10,
+		.num_wds_entries = 0x20,
 	},
 	{
 		.id = QCA9377_HW_1_0_DEV_VERSION,
@@ -313,6 +340,9 @@
 		.vht160_mcs_rx_highest = 0,
 		.vht160_mcs_tx_highest = 0,
 		.n_cipher_suites = 8,
+		.num_peers = TARGET_TLV_NUM_PEERS,
+		.ast_skid_limit = 0x10,
+		.num_wds_entries = 0x20,
 	},
 	{
 		.id = QCA9377_HW_1_1_DEV_VERSION,
@@ -338,6 +368,9 @@
 		.vht160_mcs_rx_highest = 0,
 		.vht160_mcs_tx_highest = 0,
 		.n_cipher_suites = 8,
+		.num_peers = TARGET_TLV_NUM_PEERS,
+		.ast_skid_limit = 0x10,
+		.num_wds_entries = 0x20,
 	},
 	{
 		.id = QCA4019_HW_1_0_DEV_VERSION,
@@ -368,6 +401,9 @@
 		.vht160_mcs_rx_highest = 0,
 		.vht160_mcs_tx_highest = 0,
 		.n_cipher_suites = 11,
+		.num_peers = TARGET_TLV_NUM_PEERS,
+		.ast_skid_limit = 0x10,
+		.num_wds_entries = 0x20,
 	},
 };
 
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 05f26e5..fedb6c7 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -553,6 +553,10 @@ struct ath10k_hw_params {
 
 	/* Number of ciphers supported (i.e First N) in cipher_suites array */
 	int n_cipher_suites;
+
+	u32 num_peers;
+	u32 ast_skid_limit;
+	u32 num_wds_entries;
 };
 
 struct htt_rx_desc;
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 452846c..0183d01 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -1440,7 +1440,10 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
 	cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
 
 	cfg->num_vdevs = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);
-	cfg->num_peers = __cpu_to_le32(TARGET_TLV_NUM_PEERS);
+
+	cfg->num_peers = ar->hw_params.num_peers;
+	cfg->ast_skid_limit = ar->hw_params.ast_skid_limit;
+	cfg->num_wds_entries = ar->hw_params.num_wds_entries;
 
 	if (test_bit(WMI_SERVICE_RX_FULL_REORDER, ar->wmi.svc_map)) {
 		cfg->num_offload_peers = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);
@@ -1452,7 +1455,6 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
 
 	cfg->num_peer_keys = __cpu_to_le32(2);
 	cfg->num_tids = __cpu_to_le32(TARGET_TLV_NUM_TIDS);
-	cfg->ast_skid_limit = __cpu_to_le32(0x10);
 	cfg->tx_chain_mask = __cpu_to_le32(0x7);
 	cfg->rx_chain_mask = __cpu_to_le32(0x7);
 	cfg->rx_timeout_pri[0] = __cpu_to_le32(0x64);
@@ -1468,7 +1470,6 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
 	cfg->num_mcast_table_elems = __cpu_to_le32(0);
 	cfg->mcast2ucast_mode = __cpu_to_le32(0);
 	cfg->tx_dbg_log_size = __cpu_to_le32(0x400);
-	cfg->num_wds_entries = __cpu_to_le32(0x20);
 	cfg->dma_burst_size = __cpu_to_le32(0);
 	cfg->mac_aggr_delim = __cpu_to_le32(0);
 	cfg->rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(0);
-- 
1.9.1

^ permalink raw reply related

* [PATCH 4/4] ath10k: WMI: add hw params entry for wcn3990
From: Rakesh Pillai @ 2017-11-29  9:51 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Rakesh Pillai, Govind Singh
In-Reply-To: <1511949097-524-1-git-send-email-pillair@qti.qualcomm.com>

Add hw params entry for wcn3990 and populate various
target specific values for wcn3990.

Signed-off-by: Rakesh Pillai <pillair@qti.qualcomm.com>
Signed-off-by: Govind Singh <govinds@qti.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/core.c | 18 ++++++++++++++++++
 drivers/net/wireless/ath/ath10k/hw.c   |  2 ++
 drivers/net/wireless/ath/ath10k/hw.h   | 10 ++++++++++
 3 files changed, 30 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index be18913..6abffb5 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -405,6 +405,24 @@
 		.ast_skid_limit = 0x10,
 		.num_wds_entries = 0x20,
 	},
+	{
+		.id = WCN3990_HW_1_0_DEV_VERSION,
+		.dev_id = 0,
+		.name = "wcn3990 hw1.0",
+		.continuous_frag_desc = true,
+		.tx_chain_mask = 0x7,
+		.rx_chain_mask = 0x7,
+		.max_spatial_stream = 4,
+		.fw = {
+			.dir = WCN3990_HW_1_0_FW_DIR,
+		},
+		.sw_decrypt_mcast_mgmt = true,
+		.hw_ops = &wcn3990_ops,
+		.decap_align_bytes = 1,
+		.num_peers = TARGET_HL_10_TLV_NUM_PEERS,
+		.ast_skid_limit = TARGET_HL_10_TLV_AST_SKID_LIMIT,
+		.num_wds_entries = TARGET_HL_10_TLV_NUM_WDS_ENTRIES,
+	},
 };
 
 static const char *const ath10k_core_fw_feature_str[] = {
diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c
index 88955bb..76b9b41 100644
--- a/drivers/net/wireless/ath/ath10k/hw.c
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -931,3 +931,5 @@ static int ath10k_qca99x0_rx_desc_get_l3_pad_bytes(struct htt_rx_desc *rxd)
 	.set_coverage_class = ath10k_hw_qca988x_set_coverage_class,
 	.enable_pll_clk = ath10k_hw_qca6174_enable_pll_clock,
 };
+
+const struct ath10k_hw_ops wcn3990_ops = {0};
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index fedb6c7..90ad39b 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -128,6 +128,10 @@ enum qca9377_chip_id_rev {
 #define QCA4019_HW_1_0_BOARD_DATA_FILE "board.bin"
 #define QCA4019_HW_1_0_PATCH_LOAD_ADDR  0x1234
 
+/* WCN3990 1.0 definitions */
+#define WCN3990_HW_1_0_DEV_VERSION	ATH10K_HW_WCN3990
+#define WCN3990_HW_1_0_FW_DIR		ATH10K_FW_DIR "/WCN3990/hw3.0"
+
 #define ATH10K_FW_FILE_BASE		"firmware"
 #define ATH10K_FW_API_MAX		6
 #define ATH10K_FW_API_MIN		2
@@ -571,6 +575,7 @@ struct ath10k_hw_ops {
 extern const struct ath10k_hw_ops qca988x_ops;
 extern const struct ath10k_hw_ops qca99x0_ops;
 extern const struct ath10k_hw_ops qca6174_ops;
+extern const struct ath10k_hw_ops wcn3990_ops;
 
 extern const struct ath10k_hw_clk_params qca6174_clk[];
 
@@ -667,6 +672,11 @@ struct ath10k_hw_ops {
 #define TARGET_TLV_NUM_MSDU_DESC		(1024 + 32)
 #define TARGET_TLV_NUM_WOW_PATTERNS		22
 
+/* Target specific defines for WMI-HL-1.0 firmware */
+#define TARGET_HL_10_TLV_NUM_PEERS		14
+#define TARGET_HL_10_TLV_AST_SKID_LIMIT		6
+#define TARGET_HL_10_TLV_NUM_WDS_ENTRIES	2
+
 /* Diagnostic Window */
 #define CE_DIAG_PIPE	7
 
-- 
1.9.1

^ permalink raw reply related

* [PATCH 2/4] ath10k: WMI: Add management tx by reference support over wmi
From: Rakesh Pillai @ 2017-11-29  9:51 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Rakesh Pillai, Govind Singh
In-Reply-To: <1511949097-524-1-git-send-email-pillair@qti.qualcomm.com>

HL1.0 firmware branch, used in wcn3990, transmits management
frames by reference over WMI.

Add support for management tx by reference over WMI.

Signed-off-by: Rakesh Pillai <pillair@qti.qualcomm.com>
Signed-off-by: Govind Singh <govinds@qti.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/core.c    |  1 +
 drivers/net/wireless/ath/ath10k/core.h    |  3 ++
 drivers/net/wireless/ath/ath10k/wmi-ops.h |  9 +++-
 drivers/net/wireless/ath/ath10k/wmi-tlv.c | 78 +++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/wmi-tlv.h | 67 ++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/wmi.h     |  1 +
 6 files changed, 158 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index b29fdbd..1e4e18e 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -390,6 +390,7 @@
 	[ATH10K_FW_FEATURE_SKIP_NULL_FUNC_WAR] = "skip-null-func-war",
 	[ATH10K_FW_FEATURE_ALLOWS_MESH_BCAST] = "allows-mesh-bcast",
 	[ATH10K_FW_FEATURE_NO_PS] = "no-ps",
+	[ATH10K_FW_FEATURE_MGMT_TX_BY_REF] = "mgmt-tx-by-reference",
 };
 
 static unsigned int ath10k_core_get_fw_feature_str(char *buf,
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 643041e..30c4c07 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -615,6 +615,9 @@ enum ath10k_fw_features {
 	/* Firmware does not support power save in station mode. */
 	ATH10K_FW_FEATURE_NO_PS = 17,
 
+	/* Firmware allows management tx by reference instead of by value. */
+	ATH10K_FW_FEATURE_MGMT_TX_BY_REF = 18,
+
 	/* keep last */
 	ATH10K_FW_FEATURE_COUNT,
 };
diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
index 2fc3f24..41eef94 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -377,6 +377,7 @@ struct wmi_ops {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu);
 	struct sk_buff *skb;
 	int ret;
+	u32 mgmt_tx_cmdid;
 
 	if (!ar->wmi.ops->gen_mgmt_tx)
 		return -EOPNOTSUPP;
@@ -385,7 +386,13 @@ struct wmi_ops {
 	if (IS_ERR(skb))
 		return PTR_ERR(skb);
 
-	ret = ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->mgmt_tx_cmdid);
+	if (test_bit(ATH10K_FW_FEATURE_MGMT_TX_BY_REF,
+		     ar->running_fw->fw_file.fw_features))
+		mgmt_tx_cmdid = ar->wmi.cmd->mgmt_tx_send_cmdid;
+	else
+		mgmt_tx_cmdid = ar->wmi.cmd->mgmt_tx_cmdid;
+
+	ret = ath10k_wmi_cmd_send(ar, skb, mgmt_tx_cmdid);
 	if (ret)
 		return ret;
 
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 35bcae4..452846c 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -2484,6 +2484,82 @@ static void *ath10k_wmi_tlv_put_wmm(void *ptr,
 }
 
 static struct sk_buff *
+ath10k_wmi_tlv_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
+{
+	struct ath10k_skb_cb *cb = ATH10K_SKB_CB(msdu);
+	struct wmi_tlv_mgmt_tx_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct ieee80211_hdr *hdr;
+	struct sk_buff *skb;
+	void *ptr;
+	int len;
+	u32 buf_len = msdu->len;
+	u16 fc;
+	struct ath10k_vif *arvif;
+	dma_addr_t mgmt_frame_dma;
+	u32 vdev_id;
+
+	if (!cb->vif)
+		return ERR_PTR(-EINVAL);
+
+	hdr = (struct ieee80211_hdr *)msdu->data;
+	fc = le16_to_cpu(hdr->frame_control);
+	arvif = (void *)cb->vif->drv_priv;
+	vdev_id = arvif->vdev_id;
+
+	if (WARN_ON_ONCE(!ieee80211_is_mgmt(hdr->frame_control)))
+		return ERR_PTR(-EINVAL);
+
+	len = sizeof(*cmd) + 2 * sizeof(*tlv);
+
+	if ((ieee80211_is_action(hdr->frame_control) ||
+	     ieee80211_is_deauth(hdr->frame_control) ||
+	     ieee80211_is_disassoc(hdr->frame_control)) &&
+	     ieee80211_has_protected(hdr->frame_control)) {
+		len += IEEE80211_CCMP_MIC_LEN;
+		buf_len += IEEE80211_CCMP_MIC_LEN;
+	}
+
+	buf_len = min_t(u32, buf_len, WMI_TLV_MGMT_TX_FRAME_MAX_LEN);
+	buf_len = round_up(buf_len, 4);
+
+	len += buf_len;
+	len = round_up(len, 4);
+	skb = ath10k_wmi_alloc_skb(ar, len);
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	ptr = (void *)skb->data;
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_MGMT_TX_CMD);
+	tlv->len = __cpu_to_le16(sizeof(*cmd));
+	cmd = (void *)tlv->value;
+	cmd->vdev_id = vdev_id;
+	cmd->desc_id = 0;
+	cmd->chanfreq = 0;
+	cmd->buf_len = __cpu_to_le32(buf_len);
+	cmd->frame_len = __cpu_to_le32(msdu->len);
+	mgmt_frame_dma = dma_map_single(arvif->ar->dev, msdu->data,
+					msdu->len, DMA_TO_DEVICE);
+	if (!mgmt_frame_dma)
+		return ERR_PTR(-ENOMEM);
+
+	cmd->paddr = __cpu_to_le64(mgmt_frame_dma);
+
+	ptr += sizeof(*tlv);
+	ptr += sizeof(*cmd);
+
+	tlv = ptr;
+	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
+	tlv->len = __cpu_to_le16(buf_len);
+
+	ptr += sizeof(*tlv);
+	memcpy(ptr, msdu->data, buf_len);
+
+	return skb;
+}
+
+static struct sk_buff *
 ath10k_wmi_tlv_op_gen_force_fw_hang(struct ath10k *ar,
 				    enum wmi_force_fw_hang_type type,
 				    u32 delay_ms)
@@ -3292,6 +3368,7 @@ static u32 ath10k_wmi_tlv_prepare_peer_qos(u8 uapsd_queues, u8 sp)
 	.bcn_filter_rx_cmdid = WMI_TLV_BCN_FILTER_RX_CMDID,
 	.prb_req_filter_rx_cmdid = WMI_TLV_PRB_REQ_FILTER_RX_CMDID,
 	.mgmt_tx_cmdid = WMI_TLV_MGMT_TX_CMDID,
+	.mgmt_tx_send_cmdid = WMI_TLV_MGMT_TX_SEND_CMD,
 	.prb_tmpl_cmdid = WMI_TLV_PRB_TMPL_CMDID,
 	.addba_clear_resp_cmdid = WMI_TLV_ADDBA_CLEAR_RESP_CMDID,
 	.addba_send_cmdid = WMI_TLV_ADDBA_SEND_CMDID,
@@ -3626,6 +3703,7 @@ static u32 ath10k_wmi_tlv_prepare_peer_qos(u8 uapsd_queues, u8 sp)
 	.gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats,
 	.gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang,
 	/* .gen_mgmt_tx = not implemented; HTT is used */
+	.gen_mgmt_tx =  ath10k_wmi_tlv_op_gen_mgmt_tx,
 	.gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg,
 	.gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable,
 	.gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable,
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
index 77327a2..4faaa64 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -22,6 +22,7 @@
 #define WMI_TLV_CMD_UNSUPPORTED 0
 #define WMI_TLV_PDEV_PARAM_UNSUPPORTED 0
 #define WMI_TLV_VDEV_PARAM_UNSUPPORTED 0
+#define WMI_TLV_MGMT_TX_FRAME_MAX_LEN	64
 
 enum wmi_tlv_grp_id {
 	WMI_TLV_GRP_START = 0x3,
@@ -132,6 +133,7 @@ enum wmi_tlv_cmd_id {
 	WMI_TLV_PRB_REQ_FILTER_RX_CMDID,
 	WMI_TLV_MGMT_TX_CMDID,
 	WMI_TLV_PRB_TMPL_CMDID,
+	WMI_TLV_MGMT_TX_SEND_CMD,
 	WMI_TLV_ADDBA_CLEAR_RESP_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_BA_NEG),
 	WMI_TLV_ADDBA_SEND_CMDID,
 	WMI_TLV_ADDBA_STATUS_CMDID,
@@ -890,6 +892,63 @@ enum wmi_tlv_tag {
 	WMI_TLV_TAG_STRUCT_SAP_OFL_DEL_STA_EVENT,
 	WMI_TLV_TAG_STRUCT_APFIND_CMD_PARAM,
 	WMI_TLV_TAG_STRUCT_APFIND_EVENT_HDR,
+	WMI_TLV_TAG_STRUCT_OCB_SET_SCHED_CMD,
+	WMI_TLV_TAG_STRUCT_OCB_SET_SCHED_EVENT,
+	WMI_TLV_TAG_STRUCT_OCB_SET_CONFIG_CMD,
+	WMI_TLV_TAG_STRUCT_OCB_SET_CONFIG_RESP_EVENT,
+	WMI_TLV_TAG_STRUCT_OCB_SET_UTC_TIME_CMD,
+	WMI_TLV_TAG_STRUCT_OCB_START_TIMING_ADVERT_CMD,
+	WMI_TLV_TAG_STRUCT_OCB_STOP_TIMING_ADVERT_CMD,
+	WMI_TLV_TAG_STRUCT_OCB_GET_TSF_TIMER_CMD,
+	WMI_TLV_TAG_STRUCT_OCB_GET_TSF_TIMER_RESP_EVENT,
+	WMI_TLV_TAG_STRUCT_DCC_GET_STATS_CMD,
+	WMI_TLV_TAG_STRUCT_DCC_CHANNEL_STATS_REQUEST,
+	WMI_TLV_TAG_STRUCT_DCC_GET_STATS_RESP_EVENT,
+	WMI_TLV_TAG_STRUCT_DCC_CLEAR_STATS_CMD,
+	WMI_TLV_TAG_STRUCT_DCC_UPDATE_NDL_CMD,
+	WMI_TLV_TAG_STRUCT_DCC_UPDATE_NDL_RESP_EVENT,
+	WMI_TLV_TAG_STRUCT_DCC_STATS_EVENT,
+	WMI_TLV_TAG_STRUCT_OCB_CHANNEL,
+	WMI_TLV_TAG_STRUCT_OCB_SCHEDULE_ELEMENT,
+	WMI_TLV_TAG_STRUCT_DCC_NDL_STATS_PER_CHANNEL,
+	WMI_TLV_TAG_STRUCT_DCC_NDL_CHAN,
+	WMI_TLV_TAG_STRUCT_QOS_PARAMETER,
+	WMI_TLV_TAG_STRUCT_DCC_NDL_ACTIVE_STATE_CONFIG,
+	WMI_TLV_TAG_STRUCT_ROAM_SCAN_EXTENDED_THRESHOLD_PARAM,
+	WMI_TLV_TAG_STRUCT_ROAM_FILTER_FIXED_PARAM,
+	WMI_TLV_TAG_STRUCT_PASSPOINT_CONFIG_CMD,
+	WMI_TLV_TAG_STRUCT_PASSPOINT_EVENT_HDR,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMD,
+	WMI_TLV_TAG_STRUCT_EXTSCAN_HOTLIST_SSID_MATCH_EVENT,
+	WMI_TLV_TAG_STRUCT_VDEV_TSF_TSTAMP_ACTION_CMD,
+	WMI_TLV_TAG_STRUCT_VDEV_TSF_REPORT_EVENT,
+	WMI_TLV_TAG_STRUCT_GET_FW_MEM_DUMP,
+	WMI_TLV_TAG_STRUCT_UPDATE_FW_MEM_DUMP,
+	WMI_TLV_TAG_STRUCT_FW_MEM_DUMP_PARAMS,
+	WMI_TLV_TAG_STRUCT_DEBUG_MESG_FLUSH,
+	WMI_TLV_TAG_STRUCT_DEBUG_MESG_FLUSH_COMPLETE,
+	WMI_TLV_TAG_STRUCT_PEER_SET_RATE_REPORT_CONDITION,
+	WMI_TLV_TAG_STRUCT_ROAM_SUBNET_CHANGE_CONFIG,
+	WMI_TLV_TAG_STRUCT_VDEV_SET_IE_CMD,
+	WMI_TLV_TAG_STRUCT_RSSI_BREACH_MONITOR_CONFIG,
+	WMI_TLV_TAG_STRUCT_RSSI_BREACH_EVENT,
+	WMI_TLV_TAG_STRUCT_EVENT_INITIAL_WAKEUP,
+	WMI_TLV_TAG_STRUCT_SOC_SET_PCL_CMD,
+	WMI_TLV_TAG_STRUCT_SOC_SET_HW_MODE_CMD,
+	WMI_TLV_TAG_STRUCT_SOC_SET_HW_MODE_RESPONSE_EVENT,
+	WMI_TLV_TAG_STRUCT_SOC_HW_MODE_TRANSITION_EVENT,
+	WMI_TLV_TAG_STRUCT_VDEV_TXRX_STREAMS,
+	WMI_TLV_TAG_STRUCT_SOC_SET_HW_MODE_RESPONSE_VDEV_MAC_ENTRY,
+	WMI_TLV_TAG_STRUCT_SOC_SET_DUAL_MAC_CONFIG_CMD,
+	WMI_TLV_TAG_STRUCT_SOC_SET_DUAL_MAC_CONFIG_RESPONSE_EVENT,
+	WMI_TLV_TAG_STRUCT_IOAC_SOCK_PATTERN_T,
+	WMI_TLV_TAG_STRUCT_WOW_ENABLE_ICMPV6_NA_FLT_CMD,
+	WMI_TLV_TAG_STRUCT_DIAG_EVENT_LOG_CONFIG,
+	WMI_TLV_TAG_STRUCT_DIAG_EVENT_LOG_SUPPORTED_EVENT,
+	WMI_TLV_TAG_STRUCT_PACKET_FILTER_CONFIG,
+	WMI_TLV_TAG_STRUCT_PACKET_FILTER_ENABLE,
+	WMI_TLV_TAG_STRUCT_SAP_SET_BLACKLIST_PARAM_CMD,
+	WMI_TLV_TAG_STRUCT_MGMT_TX_CMD,
 
 	WMI_TLV_TAG_MAX
 };
@@ -1689,4 +1748,12 @@ struct wmi_tlv_tx_pause_ev {
 
 void ath10k_wmi_tlv_attach(struct ath10k *ar);
 
+struct wmi_tlv_mgmt_tx_cmd {
+	__le32 vdev_id;
+	__le32 desc_id;
+	__le32 chanfreq;
+	__le64 paddr;
+	__le32 frame_len;
+	__le32 buf_len;
+} __packed;
 #endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 6c11b36..6259bd6 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -798,6 +798,7 @@ struct wmi_cmd_map {
 	u32 bcn_filter_rx_cmdid;
 	u32 prb_req_filter_rx_cmdid;
 	u32 mgmt_tx_cmdid;
+	u32 mgmt_tx_send_cmdid;
 	u32 prb_tmpl_cmdid;
 	u32 addba_clear_resp_cmdid;
 	u32 addba_send_cmdid;
-- 
1.9.1

^ permalink raw reply related

* [PATCH 1/4] ath10k: WMI: modify svc bitmap parsing for wcn3990
From: Rakesh Pillai @ 2017-11-29  9:51 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Rakesh Pillai, Govind Singh

Due to the limitation of wmi tlv parsing logic, if there are
two parameters in a wmi event with same tlv tag, we can get only
the last value, as it overwrites the prev value of the same tlv tag.

The service ready event in wcn3990 contains two parameters of the
same tag UINT32, due to which the svc bitmap is overwritten with the
DBS support parameter.

Refactor the service ready event parsing to allow parsing two tlv
of the same tag UINT32 for wcn3990.

Signed-off-by: Rakesh Pillai <pillair@qti.qualcomm.com>
Signed-off-by: Govind Singh <govinds@qti.qualcomm.com>
---
 drivers/net/wireless/ath/ath10k/mac.c     |  4 ++-
 drivers/net/wireless/ath/ath10k/wmi-tlv.c | 58 ++++++++++++++++++++++++-------
 drivers/net/wireless/ath/ath10k/wmi-tlv.h | 46 ++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/wmi.h     |  1 +
 4 files changed, 96 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 0a947ee..b86b9c8 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3574,7 +3574,9 @@ static int ath10k_mac_tx_wmi_mgmt(struct ath10k *ar, struct sk_buff *skb)
 		return ATH10K_MAC_TX_HTT;
 	case ATH10K_HW_TXRX_MGMT:
 		if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
-			     ar->running_fw->fw_file.fw_features))
+			     ar->running_fw->fw_file.fw_features) ||
+			     test_bit(WMI_SERVICE_MGMT_TX_WMI,
+				      ar->wmi.svc_map))
 			return ATH10K_MAC_TX_WMI_MGMT;
 		else if (ar->htt.target_version_major >= 3)
 			return ATH10K_MAC_TX_HTT;
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 7616c1c..35bcae4 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -917,31 +917,68 @@ static int ath10k_wmi_tlv_op_pull_phyerr_ev_hdr(struct ath10k *ar,
 	return -ENOMEM;
 }
 
+struct wmi_tlv_svc_rdy_parse {
+	const struct hal_reg_capabilities *reg;
+	const struct wmi_tlv_svc_rdy_ev *ev;
+	const __le32 *svc_bmap;
+	const struct wlan_host_mem_req *mem_reqs;
+	bool svc_bmap_done;
+	bool dbs_hw_mode_done;
+};
+
+static int ath10k_wmi_tlv_svc_rdy_parse(struct ath10k *ar, u16 tag, u16 len,
+					const void *ptr, void *data)
+{
+	struct wmi_tlv_svc_rdy_parse *svc_rdy = data;
+
+	switch (tag) {
+	case WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT:
+		svc_rdy->ev = ptr;
+		break;
+	case WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES:
+		svc_rdy->reg = ptr;
+		break;
+	case WMI_TLV_TAG_ARRAY_STRUCT:
+		svc_rdy->mem_reqs = ptr;
+		break;
+	case WMI_TLV_TAG_ARRAY_UINT32:
+		if (!svc_rdy->svc_bmap_done) {
+			svc_rdy->svc_bmap_done = true;
+			svc_rdy->svc_bmap = ptr;
+		} else if (!svc_rdy->dbs_hw_mode_done) {
+			svc_rdy->dbs_hw_mode_done = true;
+		}
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
 static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar,
 					     struct sk_buff *skb,
 					     struct wmi_svc_rdy_ev_arg *arg)
 {
-	const void **tb;
 	const struct hal_reg_capabilities *reg;
 	const struct wmi_tlv_svc_rdy_ev *ev;
 	const __le32 *svc_bmap;
 	const struct wlan_host_mem_req *mem_reqs;
+	struct wmi_tlv_svc_rdy_parse svc_rdy = { };
 	int ret;
 
-	tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
-	if (IS_ERR(tb)) {
-		ret = PTR_ERR(tb);
+	ret = ath10k_wmi_tlv_iter(ar, skb->data, skb->len,
+				  ath10k_wmi_tlv_svc_rdy_parse, &svc_rdy);
+	if (ret) {
 		ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
 		return ret;
 	}
 
-	ev = tb[WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT];
-	reg = tb[WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES];
-	svc_bmap = tb[WMI_TLV_TAG_ARRAY_UINT32];
-	mem_reqs = tb[WMI_TLV_TAG_ARRAY_STRUCT];
+	ev = svc_rdy.ev;
+	reg = svc_rdy.reg;
+	svc_bmap = svc_rdy.svc_bmap;
+	mem_reqs = svc_rdy.mem_reqs;
 
 	if (!ev || !reg || !svc_bmap || !mem_reqs) {
-		kfree(tb);
 		return -EPROTO;
 	}
 
@@ -961,7 +998,6 @@ static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar,
 	    __le32_to_cpu(ev->abi.abi_ver_ns1) != WMI_TLV_ABI_VER_NS1 ||
 	    __le32_to_cpu(ev->abi.abi_ver_ns2) != WMI_TLV_ABI_VER_NS2 ||
 	    __le32_to_cpu(ev->abi.abi_ver_ns3) != WMI_TLV_ABI_VER_NS3) {
-		kfree(tb);
 		return -ENOTSUPP;
 	}
 
@@ -982,12 +1018,10 @@ static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar,
 	ret = ath10k_wmi_tlv_iter(ar, mem_reqs, ath10k_wmi_tlv_len(mem_reqs),
 				  ath10k_wmi_tlv_parse_mem_reqs, arg);
 	if (ret) {
-		kfree(tb);
 		ath10k_warn(ar, "failed to parse mem_reqs tlv: %d\n", ret);
 		return ret;
 	}
 
-	kfree(tb);
 	return 0;
 }
 
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
index 22cf011..77327a2 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -965,6 +965,50 @@ enum wmi_tlv_service {
 	WMI_TLV_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT,
 	WMI_TLV_SERVICE_MDNS_OFFLOAD,
 	WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD,
+	WMI_TLV_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT,
+	WMI_TLV_SERVICE_OCB,
+	WMI_TLV_SERVICE_AP_ARPNS_OFFLOAD,
+	WMI_TLV_SERVICE_PER_BAND_CHAINMASK_SUPPORT,
+	WMI_TLV_SERVICE_PACKET_FILTER_OFFLOAD,
+	WMI_TLV_SERVICE_MGMT_TX_HTT,
+	WMI_TLV_SERVICE_MGMT_TX_WMI,
+	WMI_TLV_SERVICE_EXT_MSG,
+	WMI_TLV_SERVICE_MAWC,
+	WMI_TLV_SERVICE_PEER_ASSOC_CONF,
+	WMI_TLV_SERVICE_EGAP,
+	WMI_TLV_SERVICE_STA_PMF_OFFLOAD,
+	WMI_TLV_SERVICE_UNIFIED_WOW_CAPABILITY,
+	WMI_TLV_SERVICE_ENHANCED_PROXY_STA,
+	WMI_TLV_SERVICE_ATF,
+	WMI_TLV_SERVICE_COEX_GPIO,
+	WMI_TLV_SERVICE_AUX_SPECTRAL_INTF,
+	WMI_TLV_SERVICE_AUX_CHAN_LOAD_INTF,
+	WMI_TLV_SERVICE_BSS_CHANNEL_INFO_64,
+	WMI_TLV_SERVICE_ENTERPRISE_MESH,
+	WMI_TLV_SERVICE_RESTRT_CHNL_SUPPORT,
+	WMI_TLV_SERVICE_BPF_OFFLOAD,
+	WMI_TLV_SERVICE_SYNC_DELETE_CMDS,
+	WMI_TLV_SERVICE_SMART_ANTENNA_SW_SUPPORT,
+	WMI_TLV_SERVICE_SMART_ANTENNA_HW_SUPPORT,
+	WMI_TLV_SERVICE_RATECTRL_LIMIT_MAX_MIN_RATES,
+	WMI_TLV_SERVICE_NAN_DATA,
+	WMI_TLV_SERVICE_NAN_RTT,
+	WMI_TLV_SERVICE_11AX,
+	WMI_TLV_SERVICE_DEPRECATED_REPLACE,
+	WMI_TLV_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE,
+	WMI_TLV_SERVICE_ENHANCED_MCAST_FILTER,
+	WMI_TLV_SERVICE_PERIODIC_CHAN_STAT_SUPPORT,
+	WMI_TLV_SERVICE_MESH_11S,
+	WMI_TLV_SERVICE_HALF_RATE_QUARTER_RATE_SUPPORT,
+	WMI_TLV_SERVICE_VDEV_RX_FILTER,
+	WMI_TLV_SERVICE_P2P_LISTEN_OFFLOAD_SUPPORT,
+	WMI_TLV_SERVICE_MARK_FIRST_WAKEUP_PACKET,
+	WMI_TLV_SERVICE_MULTIPLE_MCAST_FILTER_SET,
+	WMI_TLV_SERVICE_HOST_MANAGED_RX_REORDER,
+	WMI_TLV_SERVICE_FLASH_RDWR_SUPPORT,
+	WMI_TLV_SERVICE_WLAN_STATS_REPORT,
+	WMI_TLV_SERVICE_TX_MSDU_ID_NEW_PARTITION_SUPPORT,
+	WMI_TLV_SERVICE_DFS_PHYERR_OFFLOAD,
 };
 
 #define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \
@@ -1121,6 +1165,8 @@ enum wmi_tlv_service {
 	       WMI_SERVICE_MDNS_OFFLOAD, len);
 	SVCMAP(WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD,
 	       WMI_SERVICE_SAP_AUTH_OFFLOAD, len);
+	SVCMAP(WMI_TLV_SERVICE_MGMT_TX_WMI,
+	       WMI_SERVICE_MGMT_TX_WMI, len);
 }
 
 #undef SVCMAP
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index c02b21c..6c11b36 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -195,6 +195,7 @@ enum wmi_service {
 	WMI_SERVICE_SMART_LOGGING_SUPPORT,
 	WMI_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE,
 	WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY,
+	WMI_SERVICE_MGMT_TX_WMI,
 
 	/* keep last */
 	WMI_SERVICE_MAX,
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH] ath10k: handling qos at STA side based on AP WMM enable/disable
From: Sebastian Gottschall @ 2017-11-29  8:33 UTC (permalink / raw)
  To: Balaji Pothunoori, ath10k@lists.infradead.org
  Cc: linux-wireless@vger.kernel.org
In-Reply-To: <e93273148ad44a54bfb39bc7018bfcc0@aptaiexm02b.ap.qualcomm.com>

Am 29.11.2017 um 07:58 schrieb Balaji Pothunoori:
> Hi Sebastian,
>
> If I am not wrong you are seeing the issue with WRT3200ACM (Marvell 88W8964) as client + QCA9984 (FW : 10.4-3.5.3-00038) as AP with below change you are seeing the crash while running traffic between the WRT3200ACM + QCA9984 ?
> Do you used  any other client in place of WRT3200ACM ?

there is not much  traffic required. as it seems the firmware crashes 
immediatly after association. the issue is also not present in 
10.4-3.4-0082ww

> Can you share the more details on firmware crash ?

so a firmware crashdump from log? i'll try to get it within the next 
hours. just need to resetup the test scenario


Sebastian


>
> Regards,
> Balaji.
>
> -----Original Message-----
> From: Sebastian Gottschall [mailto:s.gottschall@dd-wrt.com]
> Sent: Wednesday, November 29, 2017 8:28 AM
> To: Balaji Pothunoori <bpothuno@qti.qualcomm.com>; ath10k@lists.infradead.org
> Cc: linux-wireless@vger.kernel.org
> Subject: Re: [PATCH] ath10k: handling qos at STA side based on AP WMM enable/disable
>
> did you notice  that Marvell 88W8964 based clients will crash 10.4-3.5.3 firmwares?  (tested with 9984 and 10.4-3.5.3-00038) client device was a linksys wrt3200acm running dd-wrt for testing
>
> Am 28.11.2017 um 11:07 schrieb bpothuno@qti.qualcomm.com:
>> From: Balaji Pothunoori <bpothuno@qti.qualcomm.com>
>>
>> Data packets are not sent by STA in case of STA joined to non QOS AP
>> (WMM disabled AP). This is happening because of STA is sending data
>> packets to firmware from host with qos enabled along with non qos
>> queue value(TID = 16).
>> Due to qos enabled, firmware is discarding the packet.
>>
>> This patch fixes this issue by updating the qos based on station WME
>> capability field if WMM is disabled in AP.
>>
>> This patch is required by 10.4 family chipsets like
>> QCA4019/QCA9888/QCA9884/QCA99X0.
>> Firmware Versoin : 10.4-3.5.1-00018.
>>
>> For 10.2.4 family chipsets QCA988X/QCA9887 and QCA6174 this patch has
>> no effect.
>>
>> Signed-off-by: Balaji Pothunoori <bpothuno@qti.qualcomm.com>
>> ---
>>    drivers/net/wireless/ath/ath10k/mac.c |    2 +-
>>    1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/net/wireless/ath/ath10k/mac.c
>> b/drivers/net/wireless/ath/ath10k/mac.c
>> index 0a947ee..2616b99 100644
>> --- a/drivers/net/wireless/ath/ath10k/mac.c
>> +++ b/drivers/net/wireless/ath/ath10k/mac.c
>> @@ -2563,7 +2563,7 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
>>    		}
>>    		break;
>>    	case WMI_VDEV_TYPE_STA:
>> -		if (vif->bss_conf.qos)
>> +		if (sta->wme)
>>    			arg->peer_flags |= arvif->ar->wmi.peer_flags->qos;
>>    		break;
>>    	case WMI_VDEV_TYPE_IBSS:
>
> --
> Mit freundlichen Grüssen / Regards
>
> Sebastian Gottschall / CTO
>
> NewMedia-NET GmbH - DD-WRT
> Firmensitz:  Stubenwaldallee 21a, 64625 Bensheim
> Registergericht: Amtsgericht Darmstadt, HRB 25473
> Geschäftsführer: Peter Steinhäuser, Christian Scheele http://www.dd-wrt.com
> email: s.gottschall@dd-wrt.com
> Tel.: +496251-582650 / Fax: +496251-5826565
>

-- 
Mit freundlichen Grüssen / Regards

Sebastian Gottschall / CTO

NewMedia-NET GmbH - DD-WRT
Firmensitz:  Stubenwaldallee 21a, 64625 Bensheim
Registergericht: Amtsgericht Darmstadt, HRB 25473
Geschäftsführer: Peter Steinhäuser, Christian Scheele
http://www.dd-wrt.com
email: s.gottschall@dd-wrt.com
Tel.: +496251-582650 / Fax: +496251-5826565

^ permalink raw reply


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