xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/nxp/mlan/mlan_sdio.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /** @file mlan_sdio.c
2*4882a593Smuzhiyun  *
3*4882a593Smuzhiyun  *  @brief This file contains SDIO specific code
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  *  Copyright 2008-2021 NXP
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *  This software file (the File) is distributed by NXP
9*4882a593Smuzhiyun  *  under the terms of the GNU General Public License Version 2, June 1991
10*4882a593Smuzhiyun  *  (the License).  You may use, redistribute and/or modify the File in
11*4882a593Smuzhiyun  *  accordance with the terms and conditions of the License, a copy of which
12*4882a593Smuzhiyun  *  is available by writing to the Free Software Foundation, Inc.,
13*4882a593Smuzhiyun  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
14*4882a593Smuzhiyun  *  worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
17*4882a593Smuzhiyun  *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
18*4882a593Smuzhiyun  *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
19*4882a593Smuzhiyun  *  this warranty disclaimer.
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  */
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun /********************************************************
24*4882a593Smuzhiyun Change log:
25*4882a593Smuzhiyun     10/27/2008: initial version
26*4882a593Smuzhiyun ********************************************************/
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #include "mlan.h"
29*4882a593Smuzhiyun #ifdef STA_SUPPORT
30*4882a593Smuzhiyun #include "mlan_join.h"
31*4882a593Smuzhiyun #endif
32*4882a593Smuzhiyun #include "mlan_util.h"
33*4882a593Smuzhiyun #include "mlan_fw.h"
34*4882a593Smuzhiyun #include "mlan_main.h"
35*4882a593Smuzhiyun #include "mlan_init.h"
36*4882a593Smuzhiyun #include "mlan_wmm.h"
37*4882a593Smuzhiyun #include "mlan_11n.h"
38*4882a593Smuzhiyun #include "mlan_sdio.h"
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun /********************************************************
41*4882a593Smuzhiyun 		Local Variables
42*4882a593Smuzhiyun ********************************************************/
43*4882a593Smuzhiyun #ifdef SD8887
44*4882a593Smuzhiyun static const struct _mlan_sdio_card_reg mlan_reg_sd8887 = {
45*4882a593Smuzhiyun 	.start_rd_port = 0,
46*4882a593Smuzhiyun 	.start_wr_port = 0,
47*4882a593Smuzhiyun 	.base_0_reg = 0x6C,
48*4882a593Smuzhiyun 	.base_1_reg = 0x6D,
49*4882a593Smuzhiyun 	.poll_reg = 0x5C,
50*4882a593Smuzhiyun 	.host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK |
51*4882a593Smuzhiyun 			   CMD_PORT_UPLD_INT_MASK | CMD_PORT_DNLD_INT_MASK,
52*4882a593Smuzhiyun 	.host_int_status = DN_LD_HOST_INT_STATUS | UP_LD_HOST_INT_STATUS |
53*4882a593Smuzhiyun 			   DN_LD_CMD_PORT_HOST_INT_STATUS |
54*4882a593Smuzhiyun 			   UP_LD_CMD_PORT_HOST_INT_STATUS,
55*4882a593Smuzhiyun 	.status_reg_0 = 0x90,
56*4882a593Smuzhiyun 	.status_reg_1 = 0x91,
57*4882a593Smuzhiyun 	.sdio_int_mask = 0xff,
58*4882a593Smuzhiyun 	.data_port_mask = 0xffffffff,
59*4882a593Smuzhiyun 	.max_mp_regs = 196,
60*4882a593Smuzhiyun 	.rd_bitmap_l = 0x10,
61*4882a593Smuzhiyun 	.rd_bitmap_u = 0x11,
62*4882a593Smuzhiyun 	.rd_bitmap_1l = 0x12,
63*4882a593Smuzhiyun 	.rd_bitmap_1u = 0x13,
64*4882a593Smuzhiyun 	.wr_bitmap_l = 0x14,
65*4882a593Smuzhiyun 	.wr_bitmap_u = 0x15,
66*4882a593Smuzhiyun 	.wr_bitmap_1l = 0x16,
67*4882a593Smuzhiyun 	.wr_bitmap_1u = 0x17,
68*4882a593Smuzhiyun 	.rd_len_p0_l = 0x18,
69*4882a593Smuzhiyun 	.rd_len_p0_u = 0x19,
70*4882a593Smuzhiyun 	.card_config_2_1_reg = 0xD9,
71*4882a593Smuzhiyun 	.cmd_config_0 = 0xC4,
72*4882a593Smuzhiyun 	.cmd_config_1 = 0xC5,
73*4882a593Smuzhiyun 	.cmd_config_2 = 0xC6,
74*4882a593Smuzhiyun 	.cmd_config_3 = 0xC7,
75*4882a593Smuzhiyun 	.cmd_rd_len_0 = 0xC0,
76*4882a593Smuzhiyun 	.cmd_rd_len_1 = 0xC1,
77*4882a593Smuzhiyun 	.cmd_rd_len_2 = 0xC2,
78*4882a593Smuzhiyun 	.cmd_rd_len_3 = 0xC3,
79*4882a593Smuzhiyun 	.io_port_0_reg = 0xE4,
80*4882a593Smuzhiyun 	.io_port_1_reg = 0xE5,
81*4882a593Smuzhiyun 	.io_port_2_reg = 0xE6,
82*4882a593Smuzhiyun 	.host_int_rsr_reg = 0x04,
83*4882a593Smuzhiyun 	.host_int_mask_reg = 0x08,
84*4882a593Smuzhiyun 	.host_int_status_reg = 0x0C,
85*4882a593Smuzhiyun 	.host_restart_reg = 0x58,
86*4882a593Smuzhiyun 	.card_to_host_event_reg = 0x5C,
87*4882a593Smuzhiyun 	.host_interrupt_mask_reg = 0x60,
88*4882a593Smuzhiyun 	.card_interrupt_status_reg = 0x64,
89*4882a593Smuzhiyun 	.card_interrupt_rsr_reg = 0x68,
90*4882a593Smuzhiyun 	.card_revision_reg = 0xC8,
91*4882a593Smuzhiyun 	.card_ocr_0_reg = 0xD4,
92*4882a593Smuzhiyun 	.card_ocr_1_reg = 0xD5,
93*4882a593Smuzhiyun 	.card_ocr_3_reg = 0xD6,
94*4882a593Smuzhiyun 	.card_config_reg = 0xD7,
95*4882a593Smuzhiyun 	.card_misc_cfg_reg = 0xD8,
96*4882a593Smuzhiyun 	.debug_0_reg = 0xDC,
97*4882a593Smuzhiyun 	.debug_1_reg = 0xDD,
98*4882a593Smuzhiyun 	.debug_2_reg = 0xDE,
99*4882a593Smuzhiyun 	.debug_3_reg = 0xDF,
100*4882a593Smuzhiyun 	.fw_reset_reg = 0x0B6,
101*4882a593Smuzhiyun 	.fw_reset_val = 1,
102*4882a593Smuzhiyun 	.winner_check_reg = 0x90,
103*4882a593Smuzhiyun };
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun static const struct _mlan_card_info mlan_card_info_sd8887 = {
106*4882a593Smuzhiyun 	.max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_2K,
107*4882a593Smuzhiyun 	.v16_fw_api = 0,
108*4882a593Smuzhiyun 	.supp_ps_handshake = 0,
109*4882a593Smuzhiyun 	.default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_1X1,
110*4882a593Smuzhiyun };
111*4882a593Smuzhiyun #endif
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun #ifdef SD8801
114*4882a593Smuzhiyun static const struct _mlan_sdio_card_reg mlan_reg_sd8801 = {
115*4882a593Smuzhiyun 	.start_rd_port = 1,
116*4882a593Smuzhiyun 	.start_wr_port = 1,
117*4882a593Smuzhiyun 	.base_0_reg = 0x40,
118*4882a593Smuzhiyun 	.base_1_reg = 0x41,
119*4882a593Smuzhiyun 	.poll_reg = 0x30,
120*4882a593Smuzhiyun 	.host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK,
121*4882a593Smuzhiyun 	.host_int_status = DN_LD_HOST_INT_STATUS | UP_LD_HOST_INT_STATUS,
122*4882a593Smuzhiyun 	.status_reg_0 = 0x60,
123*4882a593Smuzhiyun 	.status_reg_1 = 0x61,
124*4882a593Smuzhiyun 	.sdio_int_mask = 0x3f,
125*4882a593Smuzhiyun 	.data_port_mask = 0x0000fffe,
126*4882a593Smuzhiyun 	.max_mp_regs = 64,
127*4882a593Smuzhiyun 	.rd_bitmap_l = 0x4,
128*4882a593Smuzhiyun 	.rd_bitmap_u = 0x5,
129*4882a593Smuzhiyun 	.wr_bitmap_l = 0x6,
130*4882a593Smuzhiyun 	.wr_bitmap_u = 0x7,
131*4882a593Smuzhiyun 	.rd_len_p0_l = 0x8,
132*4882a593Smuzhiyun 	.rd_len_p0_u = 0x9,
133*4882a593Smuzhiyun 	.io_port_0_reg = 0x78,
134*4882a593Smuzhiyun 	.io_port_1_reg = 0x79,
135*4882a593Smuzhiyun 	.io_port_2_reg = 0x7A,
136*4882a593Smuzhiyun 	.host_int_rsr_reg = 0x01,
137*4882a593Smuzhiyun 	.host_int_mask_reg = 0x02,
138*4882a593Smuzhiyun 	.host_int_status_reg = 0x03,
139*4882a593Smuzhiyun 	.card_misc_cfg_reg = 0x6c,
140*4882a593Smuzhiyun 	.fw_reset_reg = 0x64,
141*4882a593Smuzhiyun 	.fw_reset_val = 0,
142*4882a593Smuzhiyun };
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun static const struct _mlan_card_info mlan_card_info_sd8801 = {
145*4882a593Smuzhiyun 	.max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_2K,
146*4882a593Smuzhiyun 	.v14_fw_api = 1,
147*4882a593Smuzhiyun 	.v16_fw_api = 0,
148*4882a593Smuzhiyun 	.supp_ps_handshake = 0,
149*4882a593Smuzhiyun 	.default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_1X1,
150*4882a593Smuzhiyun };
151*4882a593Smuzhiyun #endif
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun #ifdef SD8897
154*4882a593Smuzhiyun static const struct _mlan_sdio_card_reg mlan_reg_sd8897 = {
155*4882a593Smuzhiyun 	.start_rd_port = 0,
156*4882a593Smuzhiyun 	.start_wr_port = 0,
157*4882a593Smuzhiyun 	.base_0_reg = 0x60,
158*4882a593Smuzhiyun 	.base_1_reg = 0x61,
159*4882a593Smuzhiyun 	.poll_reg = 0x50,
160*4882a593Smuzhiyun 	.host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK |
161*4882a593Smuzhiyun 			   CMD_PORT_UPLD_INT_MASK | CMD_PORT_DNLD_INT_MASK,
162*4882a593Smuzhiyun 	.host_int_status = DN_LD_HOST_INT_STATUS | UP_LD_HOST_INT_STATUS |
163*4882a593Smuzhiyun 			   DN_LD_CMD_PORT_HOST_INT_STATUS |
164*4882a593Smuzhiyun 			   UP_LD_CMD_PORT_HOST_INT_STATUS,
165*4882a593Smuzhiyun 	.status_reg_0 = 0xC0,
166*4882a593Smuzhiyun 	.status_reg_1 = 0xC1,
167*4882a593Smuzhiyun 	.sdio_int_mask = 0xff,
168*4882a593Smuzhiyun 	.data_port_mask = 0xffffffff,
169*4882a593Smuzhiyun 	.max_mp_regs = 184,
170*4882a593Smuzhiyun 	.rd_bitmap_l = 0x04,
171*4882a593Smuzhiyun 	.rd_bitmap_u = 0x05,
172*4882a593Smuzhiyun 	.rd_bitmap_1l = 0x06,
173*4882a593Smuzhiyun 	.rd_bitmap_1u = 0x07,
174*4882a593Smuzhiyun 	.wr_bitmap_l = 0x08,
175*4882a593Smuzhiyun 	.wr_bitmap_u = 0x09,
176*4882a593Smuzhiyun 	.wr_bitmap_1l = 0x0A,
177*4882a593Smuzhiyun 	.wr_bitmap_1u = 0x0B,
178*4882a593Smuzhiyun 	.rd_len_p0_l = 0x0C,
179*4882a593Smuzhiyun 	.rd_len_p0_u = 0x0D,
180*4882a593Smuzhiyun 	.card_config_2_1_reg = 0xCD,
181*4882a593Smuzhiyun 	.cmd_config_0 = 0xB8,
182*4882a593Smuzhiyun 	.cmd_config_1 = 0xB9,
183*4882a593Smuzhiyun 	.cmd_config_2 = 0xBA,
184*4882a593Smuzhiyun 	.cmd_config_3 = 0xBB,
185*4882a593Smuzhiyun 	.cmd_rd_len_0 = 0xB4,
186*4882a593Smuzhiyun 	.cmd_rd_len_1 = 0xB5,
187*4882a593Smuzhiyun 	.cmd_rd_len_2 = 0xB6,
188*4882a593Smuzhiyun 	.cmd_rd_len_3 = 0xB7,
189*4882a593Smuzhiyun 	.io_port_0_reg = 0xD8,
190*4882a593Smuzhiyun 	.io_port_1_reg = 0xD9,
191*4882a593Smuzhiyun 	.io_port_2_reg = 0xDA,
192*4882a593Smuzhiyun 	.host_int_rsr_reg = 0x01,
193*4882a593Smuzhiyun 	.host_int_mask_reg = 0x02,
194*4882a593Smuzhiyun 	.host_int_status_reg = 0x03,
195*4882a593Smuzhiyun 	.host_restart_reg = 0x4C,
196*4882a593Smuzhiyun 	.card_to_host_event_reg = 0x50,
197*4882a593Smuzhiyun 	.host_interrupt_mask_reg = 0x54,
198*4882a593Smuzhiyun 	.card_interrupt_status_reg = 0x58,
199*4882a593Smuzhiyun 	.card_interrupt_rsr_reg = 0x5C,
200*4882a593Smuzhiyun 	.card_revision_reg = 0xBC,
201*4882a593Smuzhiyun 	.card_ocr_0_reg = 0xC8,
202*4882a593Smuzhiyun 	.card_ocr_1_reg = 0xC9,
203*4882a593Smuzhiyun 	.card_ocr_3_reg = 0xCA,
204*4882a593Smuzhiyun 	.card_config_reg = 0xCB,
205*4882a593Smuzhiyun 	.card_misc_cfg_reg = 0xCC,
206*4882a593Smuzhiyun 	.debug_0_reg = 0xD0,
207*4882a593Smuzhiyun 	.debug_1_reg = 0xD1,
208*4882a593Smuzhiyun 	.debug_2_reg = 0xD2,
209*4882a593Smuzhiyun 	.debug_3_reg = 0xD3,
210*4882a593Smuzhiyun 	.fw_reset_reg = 0x0E8,
211*4882a593Smuzhiyun 	.fw_reset_val = 1,
212*4882a593Smuzhiyun 	.winner_check_reg = 0xC0,
213*4882a593Smuzhiyun };
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun static const struct _mlan_card_info mlan_card_info_sd8897 = {
216*4882a593Smuzhiyun 	.max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
217*4882a593Smuzhiyun 	.v16_fw_api = 0,
218*4882a593Smuzhiyun 	.supp_ps_handshake = 0,
219*4882a593Smuzhiyun 	.default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
220*4882a593Smuzhiyun };
221*4882a593Smuzhiyun #endif
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun #if defined(SD8977) || defined(SD8997) || defined(SD8987) ||                   \
224*4882a593Smuzhiyun 	defined(SD9098) || defined(SD9097) || defined(SDNW62X) ||              \
225*4882a593Smuzhiyun 	defined(SD8978) || defined(SD9177)
226*4882a593Smuzhiyun static const struct _mlan_sdio_card_reg mlan_reg_sd8977_sd8997 = {
227*4882a593Smuzhiyun 	.start_rd_port = 0,
228*4882a593Smuzhiyun 	.start_wr_port = 0,
229*4882a593Smuzhiyun 	.base_0_reg = 0xf8,
230*4882a593Smuzhiyun 	.base_1_reg = 0xf9,
231*4882a593Smuzhiyun 	.poll_reg = 0x5C,
232*4882a593Smuzhiyun 	.host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK |
233*4882a593Smuzhiyun 			   CMD_PORT_UPLD_INT_MASK | CMD_PORT_DNLD_INT_MASK,
234*4882a593Smuzhiyun 	.host_int_status = DN_LD_HOST_INT_STATUS | UP_LD_HOST_INT_STATUS |
235*4882a593Smuzhiyun 			   DN_LD_CMD_PORT_HOST_INT_STATUS |
236*4882a593Smuzhiyun 			   UP_LD_CMD_PORT_HOST_INT_STATUS,
237*4882a593Smuzhiyun 	.status_reg_0 = 0xe8,
238*4882a593Smuzhiyun 	.status_reg_1 = 0xe9,
239*4882a593Smuzhiyun 	.sdio_int_mask = 0xff,
240*4882a593Smuzhiyun 	.data_port_mask = 0xffffffff,
241*4882a593Smuzhiyun 	.max_mp_regs = 196,
242*4882a593Smuzhiyun 	.rd_bitmap_l = 0x10,
243*4882a593Smuzhiyun 	.rd_bitmap_u = 0x11,
244*4882a593Smuzhiyun 	.rd_bitmap_1l = 0x12,
245*4882a593Smuzhiyun 	.rd_bitmap_1u = 0x13,
246*4882a593Smuzhiyun 	.wr_bitmap_l = 0x14,
247*4882a593Smuzhiyun 	.wr_bitmap_u = 0x15,
248*4882a593Smuzhiyun 	.wr_bitmap_1l = 0x16,
249*4882a593Smuzhiyun 	.wr_bitmap_1u = 0x17,
250*4882a593Smuzhiyun 	.rd_len_p0_l = 0x18,
251*4882a593Smuzhiyun 	.rd_len_p0_u = 0x19,
252*4882a593Smuzhiyun 	.card_config_2_1_reg = 0xD9,
253*4882a593Smuzhiyun 	.cmd_config_0 = 0xC4,
254*4882a593Smuzhiyun 	.cmd_config_1 = 0xC5,
255*4882a593Smuzhiyun 	.cmd_config_2 = 0xC6,
256*4882a593Smuzhiyun 	.cmd_config_3 = 0xC7,
257*4882a593Smuzhiyun 	.cmd_rd_len_0 = 0xC0,
258*4882a593Smuzhiyun 	.cmd_rd_len_1 = 0xC1,
259*4882a593Smuzhiyun 	.cmd_rd_len_2 = 0xC2,
260*4882a593Smuzhiyun 	.cmd_rd_len_3 = 0xC3,
261*4882a593Smuzhiyun 	.io_port_0_reg = 0xE4,
262*4882a593Smuzhiyun 	.io_port_1_reg = 0xE5,
263*4882a593Smuzhiyun 	.io_port_2_reg = 0xE6,
264*4882a593Smuzhiyun 	.host_int_rsr_reg = 0x04,
265*4882a593Smuzhiyun 	.host_int_mask_reg = 0x08,
266*4882a593Smuzhiyun 	.host_int_status_reg = 0x0C,
267*4882a593Smuzhiyun 	.host_restart_reg = 0x58,
268*4882a593Smuzhiyun 	.card_to_host_event_reg = 0x5C,
269*4882a593Smuzhiyun 	.host_interrupt_mask_reg = 0x60,
270*4882a593Smuzhiyun 	.card_interrupt_status_reg = 0x64,
271*4882a593Smuzhiyun 	.card_interrupt_rsr_reg = 0x68,
272*4882a593Smuzhiyun 	.card_revision_reg = 0xC8,
273*4882a593Smuzhiyun 	.card_ocr_0_reg = 0xD4,
274*4882a593Smuzhiyun 	.card_ocr_1_reg = 0xD5,
275*4882a593Smuzhiyun 	.card_ocr_3_reg = 0xD6,
276*4882a593Smuzhiyun 	.card_config_reg = 0xD7,
277*4882a593Smuzhiyun 	.card_misc_cfg_reg = 0xD8,
278*4882a593Smuzhiyun 	.debug_0_reg = 0xDC,
279*4882a593Smuzhiyun 	.debug_1_reg = 0xDD,
280*4882a593Smuzhiyun 	.debug_2_reg = 0xDE,
281*4882a593Smuzhiyun 	.debug_3_reg = 0xDF,
282*4882a593Smuzhiyun 	.fw_reset_reg = 0x0EE,
283*4882a593Smuzhiyun 	.fw_reset_val = 0x99,
284*4882a593Smuzhiyun 	.fw_dnld_offset_0_reg = 0xEC,
285*4882a593Smuzhiyun 	.fw_dnld_offset_1_reg = 0xED,
286*4882a593Smuzhiyun 	.fw_dnld_offset_2_reg = 0xEE,
287*4882a593Smuzhiyun 	.fw_dnld_offset_3_reg = 0xEF,
288*4882a593Smuzhiyun 	.fw_dnld_status_0_reg = 0xE8,
289*4882a593Smuzhiyun 	.fw_dnld_status_1_reg = 0xE9,
290*4882a593Smuzhiyun 	.winner_check_reg = 0xFC,
291*4882a593Smuzhiyun };
292*4882a593Smuzhiyun #endif
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun #ifdef SD8997
295*4882a593Smuzhiyun static const struct _mlan_card_info mlan_card_info_sd8997 = {
296*4882a593Smuzhiyun 	.max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
297*4882a593Smuzhiyun 	.v16_fw_api = 1,
298*4882a593Smuzhiyun 	.supp_ps_handshake = 0,
299*4882a593Smuzhiyun 	.default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
300*4882a593Smuzhiyun };
301*4882a593Smuzhiyun #endif
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun #ifdef SD9097
304*4882a593Smuzhiyun static const struct _mlan_card_info mlan_card_info_sd9097 = {
305*4882a593Smuzhiyun 	.max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
306*4882a593Smuzhiyun 	.v16_fw_api = 1,
307*4882a593Smuzhiyun 	.v17_fw_api = 1,
308*4882a593Smuzhiyun 	.supp_ps_handshake = 0,
309*4882a593Smuzhiyun 	.default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
310*4882a593Smuzhiyun };
311*4882a593Smuzhiyun #endif
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun #ifdef SDNW62X
314*4882a593Smuzhiyun static const struct _mlan_card_info mlan_card_info_sdnw62x = {
315*4882a593Smuzhiyun 	.max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
316*4882a593Smuzhiyun 	.v16_fw_api = 1,
317*4882a593Smuzhiyun 	.v17_fw_api = 1,
318*4882a593Smuzhiyun 	.supp_ps_handshake = 0,
319*4882a593Smuzhiyun 	.default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
320*4882a593Smuzhiyun };
321*4882a593Smuzhiyun #endif
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun #ifdef SD9098
324*4882a593Smuzhiyun static const struct _mlan_card_info mlan_card_info_sd9098 = {
325*4882a593Smuzhiyun 	.max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
326*4882a593Smuzhiyun 	.v16_fw_api = 1,
327*4882a593Smuzhiyun 	.v17_fw_api = 1,
328*4882a593Smuzhiyun 	.supp_ps_handshake = 0,
329*4882a593Smuzhiyun 	.default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
330*4882a593Smuzhiyun };
331*4882a593Smuzhiyun #endif
332*4882a593Smuzhiyun #ifdef SD9177
333*4882a593Smuzhiyun static const struct _mlan_card_info mlan_card_info_sd9177 = {
334*4882a593Smuzhiyun 	.max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
335*4882a593Smuzhiyun 	.v16_fw_api = 1,
336*4882a593Smuzhiyun 	.v17_fw_api = 1,
337*4882a593Smuzhiyun 	.supp_ps_handshake = 0,
338*4882a593Smuzhiyun 	.default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_1X1,
339*4882a593Smuzhiyun };
340*4882a593Smuzhiyun #endif
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun #if defined(SD8977) || defined(SD8978)
343*4882a593Smuzhiyun static const struct _mlan_card_info mlan_card_info_sd8977 = {
344*4882a593Smuzhiyun 	.max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_2K,
345*4882a593Smuzhiyun 	.v16_fw_api = 1,
346*4882a593Smuzhiyun 	.supp_ps_handshake = 0,
347*4882a593Smuzhiyun 	.default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_1X1,
348*4882a593Smuzhiyun };
349*4882a593Smuzhiyun #endif
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun #ifdef SD8987
352*4882a593Smuzhiyun static const struct _mlan_card_info mlan_card_info_sd8987 = {
353*4882a593Smuzhiyun 	.max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_2K,
354*4882a593Smuzhiyun 	.v16_fw_api = 1,
355*4882a593Smuzhiyun 	.supp_ps_handshake = 0,
356*4882a593Smuzhiyun 	.default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_1X1,
357*4882a593Smuzhiyun };
358*4882a593Smuzhiyun #endif
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun /********************************************************
361*4882a593Smuzhiyun 		Global Variables
362*4882a593Smuzhiyun ********************************************************/
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun /********************************************************
365*4882a593Smuzhiyun 		Local Functions
366*4882a593Smuzhiyun ********************************************************/
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun /**
369*4882a593Smuzhiyun  *  @brief This function initialize the SDIO port
370*4882a593Smuzhiyun  *
371*4882a593Smuzhiyun  *  @param pmadapter    A pointer to mlan_adapter structure
372*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
373*4882a593Smuzhiyun  */
wlan_sdio_init_ioport(mlan_adapter * pmadapter)374*4882a593Smuzhiyun static mlan_status wlan_sdio_init_ioport(mlan_adapter *pmadapter)
375*4882a593Smuzhiyun {
376*4882a593Smuzhiyun 	t_u32 reg;
377*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
378*4882a593Smuzhiyun 	t_u8 host_int_rsr_reg = pmadapter->pcard_sd->reg->host_int_rsr_reg;
379*4882a593Smuzhiyun 	t_u8 host_int_rsr_mask = pmadapter->pcard_sd->reg->sdio_int_mask;
380*4882a593Smuzhiyun 	t_u8 card_misc_cfg_reg = pmadapter->pcard_sd->reg->card_misc_cfg_reg;
381*4882a593Smuzhiyun 	t_u8 card_config_2_1_reg =
382*4882a593Smuzhiyun 		pmadapter->pcard_sd->reg->card_config_2_1_reg;
383*4882a593Smuzhiyun 	t_u8 cmd_config_0 = pmadapter->pcard_sd->reg->cmd_config_0;
384*4882a593Smuzhiyun 	t_u8 cmd_config_1 = pmadapter->pcard_sd->reg->cmd_config_1;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	ENTER();
387*4882a593Smuzhiyun 	if (pmadapter->pcard_sd->supports_sdio_new_mode) {
388*4882a593Smuzhiyun 		pmadapter->pcard_sd->ioport = MEM_PORT;
389*4882a593Smuzhiyun 	} else {
390*4882a593Smuzhiyun 		if (MLAN_STATUS_SUCCESS ==
391*4882a593Smuzhiyun 		    pcb->moal_read_reg(pmadapter->pmoal_handle,
392*4882a593Smuzhiyun 				       pmadapter->pcard_sd->reg->io_port_0_reg,
393*4882a593Smuzhiyun 				       &reg))
394*4882a593Smuzhiyun 			pmadapter->pcard_sd->ioport |= (reg & 0xff);
395*4882a593Smuzhiyun 		else {
396*4882a593Smuzhiyun 			LEAVE();
397*4882a593Smuzhiyun 			return MLAN_STATUS_FAILURE;
398*4882a593Smuzhiyun 		}
399*4882a593Smuzhiyun 		if (MLAN_STATUS_SUCCESS ==
400*4882a593Smuzhiyun 		    pcb->moal_read_reg(pmadapter->pmoal_handle,
401*4882a593Smuzhiyun 				       pmadapter->pcard_sd->reg->io_port_1_reg,
402*4882a593Smuzhiyun 				       &reg))
403*4882a593Smuzhiyun 			pmadapter->pcard_sd->ioport |= ((reg & 0xff) << 8);
404*4882a593Smuzhiyun 		else {
405*4882a593Smuzhiyun 			LEAVE();
406*4882a593Smuzhiyun 			return MLAN_STATUS_FAILURE;
407*4882a593Smuzhiyun 		}
408*4882a593Smuzhiyun 		if (MLAN_STATUS_SUCCESS ==
409*4882a593Smuzhiyun 		    pcb->moal_read_reg(pmadapter->pmoal_handle,
410*4882a593Smuzhiyun 				       pmadapter->pcard_sd->reg->io_port_2_reg,
411*4882a593Smuzhiyun 				       &reg))
412*4882a593Smuzhiyun 			pmadapter->pcard_sd->ioport |= ((reg & 0xff) << 16);
413*4882a593Smuzhiyun 		else {
414*4882a593Smuzhiyun 			LEAVE();
415*4882a593Smuzhiyun 			return MLAN_STATUS_FAILURE;
416*4882a593Smuzhiyun 		}
417*4882a593Smuzhiyun 	}
418*4882a593Smuzhiyun 	PRINTM(MINFO, "SDIO FUNC1 IO port: 0x%x\n",
419*4882a593Smuzhiyun 	       pmadapter->pcard_sd->ioport);
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	if (pmadapter->pcard_sd->supports_sdio_new_mode) {
422*4882a593Smuzhiyun 		/* enable sdio cmd53 new mode */
423*4882a593Smuzhiyun 		if (MLAN_STATUS_SUCCESS ==
424*4882a593Smuzhiyun 		    pcb->moal_read_reg(pmadapter->pmoal_handle,
425*4882a593Smuzhiyun 				       card_config_2_1_reg, &reg)) {
426*4882a593Smuzhiyun 			pcb->moal_write_reg(pmadapter->pmoal_handle,
427*4882a593Smuzhiyun 					    card_config_2_1_reg,
428*4882a593Smuzhiyun 					    reg | CMD53_NEW_MODE);
429*4882a593Smuzhiyun 		} else {
430*4882a593Smuzhiyun 			LEAVE();
431*4882a593Smuzhiyun 			return MLAN_STATUS_FAILURE;
432*4882a593Smuzhiyun 		}
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 		/* configure cmd port  */
435*4882a593Smuzhiyun 		/* enable reading rx length from the register  */
436*4882a593Smuzhiyun 		if (MLAN_STATUS_SUCCESS ==
437*4882a593Smuzhiyun 		    pcb->moal_read_reg(pmadapter->pmoal_handle, cmd_config_0,
438*4882a593Smuzhiyun 				       &reg)) {
439*4882a593Smuzhiyun 			pcb->moal_write_reg(pmadapter->pmoal_handle,
440*4882a593Smuzhiyun 					    cmd_config_0,
441*4882a593Smuzhiyun 					    reg | CMD_PORT_RD_LEN_EN);
442*4882a593Smuzhiyun 		} else {
443*4882a593Smuzhiyun 			LEAVE();
444*4882a593Smuzhiyun 			return MLAN_STATUS_FAILURE;
445*4882a593Smuzhiyun 		}
446*4882a593Smuzhiyun 		/* enable Dnld/Upld ready auto reset for cmd port
447*4882a593Smuzhiyun 		 * after cmd53 is completed */
448*4882a593Smuzhiyun 		if (MLAN_STATUS_SUCCESS ==
449*4882a593Smuzhiyun 		    pcb->moal_read_reg(pmadapter->pmoal_handle, cmd_config_1,
450*4882a593Smuzhiyun 				       &reg)) {
451*4882a593Smuzhiyun 			pcb->moal_write_reg(pmadapter->pmoal_handle,
452*4882a593Smuzhiyun 					    cmd_config_1,
453*4882a593Smuzhiyun 					    reg | CMD_PORT_AUTO_EN);
454*4882a593Smuzhiyun 		} else {
455*4882a593Smuzhiyun 			LEAVE();
456*4882a593Smuzhiyun 			return MLAN_STATUS_FAILURE;
457*4882a593Smuzhiyun 		}
458*4882a593Smuzhiyun 	}
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun #if defined(SD8977) || defined(SD8978)
461*4882a593Smuzhiyun 	if (IS_SD8977(pmadapter->card_type) ||
462*4882a593Smuzhiyun 	    IS_SD8978(pmadapter->card_type)) {
463*4882a593Smuzhiyun 		if ((pmadapter->init_para.int_mode == INT_MODE_GPIO) &&
464*4882a593Smuzhiyun 		    (pmadapter->init_para.gpio_pin == GPIO_INT_NEW_MODE)) {
465*4882a593Smuzhiyun 			PRINTM(MMSG, "Enable GPIO-1 int mode\n");
466*4882a593Smuzhiyun 			pcb->moal_write_reg(pmadapter->pmoal_handle,
467*4882a593Smuzhiyun 					    SCRATCH_REG_32,
468*4882a593Smuzhiyun 					    ENABLE_GPIO_1_INT_MODE);
469*4882a593Smuzhiyun 		}
470*4882a593Smuzhiyun 	}
471*4882a593Smuzhiyun #endif
472*4882a593Smuzhiyun 	/* Set Host interrupt reset to read to clear */
473*4882a593Smuzhiyun 	if (MLAN_STATUS_SUCCESS == pcb->moal_read_reg(pmadapter->pmoal_handle,
474*4882a593Smuzhiyun 						      host_int_rsr_reg, &reg)) {
475*4882a593Smuzhiyun 		pcb->moal_write_reg(pmadapter->pmoal_handle, host_int_rsr_reg,
476*4882a593Smuzhiyun 				    reg | host_int_rsr_mask);
477*4882a593Smuzhiyun 	} else {
478*4882a593Smuzhiyun 		LEAVE();
479*4882a593Smuzhiyun 		return MLAN_STATUS_FAILURE;
480*4882a593Smuzhiyun 	}
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	/* Dnld/Upld ready set to auto reset */
483*4882a593Smuzhiyun 	if (MLAN_STATUS_SUCCESS == pcb->moal_read_reg(pmadapter->pmoal_handle,
484*4882a593Smuzhiyun 						      card_misc_cfg_reg,
485*4882a593Smuzhiyun 						      &reg)) {
486*4882a593Smuzhiyun 		pcb->moal_write_reg(pmadapter->pmoal_handle, card_misc_cfg_reg,
487*4882a593Smuzhiyun 				    reg | AUTO_RE_ENABLE_INT);
488*4882a593Smuzhiyun 	} else {
489*4882a593Smuzhiyun 		LEAVE();
490*4882a593Smuzhiyun 		return MLAN_STATUS_FAILURE;
491*4882a593Smuzhiyun 	}
492*4882a593Smuzhiyun 	LEAVE();
493*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun /**
497*4882a593Smuzhiyun  *  @brief This function sends data to the card.
498*4882a593Smuzhiyun  *
499*4882a593Smuzhiyun  *  @param pmadapter A pointer to mlan_adapter structure
500*4882a593Smuzhiyun  *  @param pmbuf     A pointer to mlan_buffer (pmbuf->data_len should include
501*4882a593Smuzhiyun  * SDIO header)
502*4882a593Smuzhiyun  *  @param port      Port
503*4882a593Smuzhiyun  *  @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
504*4882a593Smuzhiyun  */
wlan_write_data_sync(mlan_adapter * pmadapter,mlan_buffer * pmbuf,t_u32 port)505*4882a593Smuzhiyun static mlan_status wlan_write_data_sync(mlan_adapter *pmadapter,
506*4882a593Smuzhiyun 					mlan_buffer *pmbuf, t_u32 port)
507*4882a593Smuzhiyun {
508*4882a593Smuzhiyun 	t_u32 i = 0;
509*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
510*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	ENTER();
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	do {
515*4882a593Smuzhiyun 		ret = pcb->moal_write_data_sync(pmadapter->pmoal_handle, pmbuf,
516*4882a593Smuzhiyun 						port, 0);
517*4882a593Smuzhiyun 		if (ret != MLAN_STATUS_SUCCESS) {
518*4882a593Smuzhiyun 			i++;
519*4882a593Smuzhiyun 			PRINTM(MERROR,
520*4882a593Smuzhiyun 			       "host_to_card, write iomem (%d) failed: %d\n", i,
521*4882a593Smuzhiyun 			       ret);
522*4882a593Smuzhiyun 			if (MLAN_STATUS_SUCCESS !=
523*4882a593Smuzhiyun 			    pcb->moal_write_reg(pmadapter->pmoal_handle,
524*4882a593Smuzhiyun 						HOST_TO_CARD_EVENT_REG,
525*4882a593Smuzhiyun 						HOST_TERM_CMD53)) {
526*4882a593Smuzhiyun 				PRINTM(MERROR, "write CFG reg failed\n");
527*4882a593Smuzhiyun 			}
528*4882a593Smuzhiyun 			ret = MLAN_STATUS_FAILURE;
529*4882a593Smuzhiyun 			if (i > MAX_WRITE_IOMEM_RETRY) {
530*4882a593Smuzhiyun 				pmbuf->status_code = MLAN_ERROR_DATA_TX_FAIL;
531*4882a593Smuzhiyun 				goto exit;
532*4882a593Smuzhiyun 			}
533*4882a593Smuzhiyun 		}
534*4882a593Smuzhiyun 	} while (ret == MLAN_STATUS_FAILURE);
535*4882a593Smuzhiyun exit:
536*4882a593Smuzhiyun 	LEAVE();
537*4882a593Smuzhiyun 	return ret;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun /**
541*4882a593Smuzhiyun  *  @brief This function gets available SDIO port for reading cmd/data
542*4882a593Smuzhiyun  *
543*4882a593Smuzhiyun  *  @param pmadapter  A pointer to mlan_adapter structure
544*4882a593Smuzhiyun  *  @param pport      A pointer to port number
545*4882a593Smuzhiyun  *  @return           MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
546*4882a593Smuzhiyun  */
wlan_get_rd_port(mlan_adapter * pmadapter,t_u8 * pport)547*4882a593Smuzhiyun static mlan_status wlan_get_rd_port(mlan_adapter *pmadapter, t_u8 *pport)
548*4882a593Smuzhiyun {
549*4882a593Smuzhiyun 	t_u32 rd_bitmap = pmadapter->pcard_sd->mp_rd_bitmap;
550*4882a593Smuzhiyun 	const mlan_sdio_card_reg *reg = pmadapter->pcard_sd->reg;
551*4882a593Smuzhiyun 	t_u8 max_ports = pmadapter->pcard_sd->max_ports;
552*4882a593Smuzhiyun 	t_bool new_mode = pmadapter->pcard_sd->supports_sdio_new_mode;
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	ENTER();
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	PRINTM(MIF_D, "wlan_get_rd_port: mp_rd_bitmap=0x%08x\n", rd_bitmap);
557*4882a593Smuzhiyun 	if (new_mode) {
558*4882a593Smuzhiyun 		if (!(rd_bitmap & reg->data_port_mask)) {
559*4882a593Smuzhiyun 			LEAVE();
560*4882a593Smuzhiyun 			return MLAN_STATUS_FAILURE;
561*4882a593Smuzhiyun 		}
562*4882a593Smuzhiyun 	} else {
563*4882a593Smuzhiyun 		if (!(rd_bitmap & (CTRL_PORT_MASK | reg->data_port_mask))) {
564*4882a593Smuzhiyun 			LEAVE();
565*4882a593Smuzhiyun 			return MLAN_STATUS_FAILURE;
566*4882a593Smuzhiyun 		}
567*4882a593Smuzhiyun 	}
568*4882a593Smuzhiyun 	if (!new_mode && (pmadapter->pcard_sd->mp_rd_bitmap & CTRL_PORT_MASK)) {
569*4882a593Smuzhiyun 		pmadapter->pcard_sd->mp_rd_bitmap &= (t_u32)(~CTRL_PORT_MASK);
570*4882a593Smuzhiyun 		*pport = CTRL_PORT;
571*4882a593Smuzhiyun 		PRINTM(MIF_D, "wlan_get_rd_port: port=%d mp_rd_bitmap=0x%08x\n",
572*4882a593Smuzhiyun 		       *pport, pmadapter->pcard_sd->mp_rd_bitmap);
573*4882a593Smuzhiyun 	} else {
574*4882a593Smuzhiyun 		if (pmadapter->pcard_sd->mp_rd_bitmap &
575*4882a593Smuzhiyun 		    (1 << pmadapter->pcard_sd->curr_rd_port)) {
576*4882a593Smuzhiyun 			pmadapter->pcard_sd->mp_rd_bitmap &= (t_u32)(
577*4882a593Smuzhiyun 				~(1 << pmadapter->pcard_sd->curr_rd_port));
578*4882a593Smuzhiyun 			*pport = pmadapter->pcard_sd->curr_rd_port;
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 			/* hw rx wraps round only after port (MAX_PORT-1) */
581*4882a593Smuzhiyun 			if (++pmadapter->pcard_sd->curr_rd_port == max_ports)
582*4882a593Smuzhiyun 				pmadapter->pcard_sd->curr_rd_port =
583*4882a593Smuzhiyun 					reg->start_rd_port;
584*4882a593Smuzhiyun 		} else {
585*4882a593Smuzhiyun 			LEAVE();
586*4882a593Smuzhiyun 			return MLAN_STATUS_FAILURE;
587*4882a593Smuzhiyun 		}
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 		PRINTM(MIF_D, "port=%d mp_rd_bitmap=0x%08x -> 0x%08x\n", *pport,
590*4882a593Smuzhiyun 		       rd_bitmap, pmadapter->pcard_sd->mp_rd_bitmap);
591*4882a593Smuzhiyun 	}
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	LEAVE();
594*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun /**
598*4882a593Smuzhiyun  *  @brief This function gets available SDIO port for writing data
599*4882a593Smuzhiyun  *
600*4882a593Smuzhiyun  *  @param pmadapter  A pointer to mlan_adapter structure
601*4882a593Smuzhiyun  *  @param pport      A pointer to port number
602*4882a593Smuzhiyun  *  @return           MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
603*4882a593Smuzhiyun  */
wlan_get_wr_port_data(mlan_adapter * pmadapter,t_u8 * pport)604*4882a593Smuzhiyun static mlan_status wlan_get_wr_port_data(mlan_adapter *pmadapter, t_u8 *pport)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun 	t_u32 wr_bitmap = pmadapter->pcard_sd->mp_wr_bitmap;
607*4882a593Smuzhiyun 	const mlan_sdio_card_reg *reg = pmadapter->pcard_sd->reg;
608*4882a593Smuzhiyun 	t_bool new_mode = pmadapter->pcard_sd->supports_sdio_new_mode;
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	ENTER();
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 	PRINTM(MIF_D, "wlan_get_wr_port_data: mp_wr_bitmap=0x%08x\n",
613*4882a593Smuzhiyun 	       wr_bitmap);
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	if (!(wr_bitmap & pmadapter->pcard_sd->mp_data_port_mask)) {
616*4882a593Smuzhiyun 		pmadapter->data_sent = MTRUE;
617*4882a593Smuzhiyun 		LEAVE();
618*4882a593Smuzhiyun 		return MLAN_STATUS_RESOURCE;
619*4882a593Smuzhiyun 	}
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	if (pmadapter->pcard_sd->mp_wr_bitmap &
622*4882a593Smuzhiyun 	    (1 << pmadapter->pcard_sd->curr_wr_port)) {
623*4882a593Smuzhiyun 		pmadapter->pcard_sd->mp_wr_bitmap &=
624*4882a593Smuzhiyun 			(t_u32)(~(1 << pmadapter->pcard_sd->curr_wr_port));
625*4882a593Smuzhiyun 		*pport = pmadapter->pcard_sd->curr_wr_port;
626*4882a593Smuzhiyun 		if (++pmadapter->pcard_sd->curr_wr_port ==
627*4882a593Smuzhiyun 		    pmadapter->pcard_sd->mp_end_port)
628*4882a593Smuzhiyun 			pmadapter->pcard_sd->curr_wr_port = reg->start_wr_port;
629*4882a593Smuzhiyun 	} else {
630*4882a593Smuzhiyun 		pmadapter->data_sent = MTRUE;
631*4882a593Smuzhiyun 		LEAVE();
632*4882a593Smuzhiyun 		return MLAN_STATUS_RESOURCE;
633*4882a593Smuzhiyun 	}
634*4882a593Smuzhiyun 	if ((!new_mode) && (*pport == CTRL_PORT)) {
635*4882a593Smuzhiyun 		PRINTM(MERROR,
636*4882a593Smuzhiyun 		       "Invalid data port=%d cur port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n",
637*4882a593Smuzhiyun 		       *pport, pmadapter->pcard_sd->curr_wr_port, wr_bitmap,
638*4882a593Smuzhiyun 		       pmadapter->pcard_sd->mp_wr_bitmap);
639*4882a593Smuzhiyun 		LEAVE();
640*4882a593Smuzhiyun 		return MLAN_STATUS_FAILURE;
641*4882a593Smuzhiyun 	}
642*4882a593Smuzhiyun 	PRINTM(MIF_D, "port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n", *pport,
643*4882a593Smuzhiyun 	       wr_bitmap, pmadapter->pcard_sd->mp_wr_bitmap);
644*4882a593Smuzhiyun 	LEAVE();
645*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun /**
649*4882a593Smuzhiyun  *  @brief This function polls the card status register.
650*4882a593Smuzhiyun  *
651*4882a593Smuzhiyun  *  @param pmadapter  A pointer to mlan_adapter structure
652*4882a593Smuzhiyun  *  @param bits       the bit mask
653*4882a593Smuzhiyun  *  @return           MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
654*4882a593Smuzhiyun  */
wlan_sdio_poll_card_status(mlan_adapter * pmadapter,t_u8 bits)655*4882a593Smuzhiyun static mlan_status wlan_sdio_poll_card_status(mlan_adapter *pmadapter,
656*4882a593Smuzhiyun 					      t_u8 bits)
657*4882a593Smuzhiyun {
658*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
659*4882a593Smuzhiyun 	t_u32 tries;
660*4882a593Smuzhiyun 	t_u32 cs = 0;
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	ENTER();
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	for (tries = 0; tries < 10000; tries++) {
665*4882a593Smuzhiyun 		if (pcb->moal_read_reg(pmadapter->pmoal_handle,
666*4882a593Smuzhiyun 				       pmadapter->pcard_sd->reg->poll_reg,
667*4882a593Smuzhiyun 				       &cs) != MLAN_STATUS_SUCCESS)
668*4882a593Smuzhiyun 			break;
669*4882a593Smuzhiyun 		else if ((cs & bits) == bits) {
670*4882a593Smuzhiyun 			LEAVE();
671*4882a593Smuzhiyun 			return MLAN_STATUS_SUCCESS;
672*4882a593Smuzhiyun 		}
673*4882a593Smuzhiyun 		wlan_udelay(pmadapter, 10);
674*4882a593Smuzhiyun 	}
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	PRINTM(MERROR,
677*4882a593Smuzhiyun 	       "wlan_sdio_poll_card_status failed, tries = %d, cs = 0x%x\n",
678*4882a593Smuzhiyun 	       tries, cs);
679*4882a593Smuzhiyun 	LEAVE();
680*4882a593Smuzhiyun 	return MLAN_STATUS_FAILURE;
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun /**
684*4882a593Smuzhiyun  *  @brief This function reads firmware status registers
685*4882a593Smuzhiyun  *
686*4882a593Smuzhiyun  *  @param pmadapter    A pointer to mlan_adapter structure
687*4882a593Smuzhiyun  *  @param dat          A pointer to keep returned data
688*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
689*4882a593Smuzhiyun  */
wlan_sdio_read_fw_status(mlan_adapter * pmadapter,t_u16 * dat)690*4882a593Smuzhiyun static mlan_status wlan_sdio_read_fw_status(mlan_adapter *pmadapter, t_u16 *dat)
691*4882a593Smuzhiyun {
692*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
693*4882a593Smuzhiyun 	t_u32 fws0 = 0, fws1 = 0;
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	ENTER();
696*4882a593Smuzhiyun 	if (MLAN_STATUS_SUCCESS !=
697*4882a593Smuzhiyun 	    pcb->moal_read_reg(pmadapter->pmoal_handle,
698*4882a593Smuzhiyun 			       pmadapter->pcard_sd->reg->status_reg_0, &fws0)) {
699*4882a593Smuzhiyun 		LEAVE();
700*4882a593Smuzhiyun 		return MLAN_STATUS_FAILURE;
701*4882a593Smuzhiyun 	}
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	if (MLAN_STATUS_SUCCESS !=
704*4882a593Smuzhiyun 	    pcb->moal_read_reg(pmadapter->pmoal_handle,
705*4882a593Smuzhiyun 			       pmadapter->pcard_sd->reg->status_reg_1, &fws1)) {
706*4882a593Smuzhiyun 		LEAVE();
707*4882a593Smuzhiyun 		return MLAN_STATUS_FAILURE;
708*4882a593Smuzhiyun 	}
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	*dat = (t_u16)((fws1 << 8) | fws0);
711*4882a593Smuzhiyun 	LEAVE();
712*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun /**
716*4882a593Smuzhiyun  *  @brief This function reads firmware dnld offset registers
717*4882a593Smuzhiyun  *
718*4882a593Smuzhiyun  *  @param pmadapter    A pointer to mlan_adapter structure
719*4882a593Smuzhiyun  *  @param dat          A pointer to keep returned data
720*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
721*4882a593Smuzhiyun  */
wlan_sdio_read_fw_dnld_offset(mlan_adapter * pmadapter,t_u32 * dat)722*4882a593Smuzhiyun static mlan_status wlan_sdio_read_fw_dnld_offset(mlan_adapter *pmadapter,
723*4882a593Smuzhiyun 						 t_u32 *dat)
724*4882a593Smuzhiyun {
725*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
726*4882a593Smuzhiyun 	const mlan_sdio_card_reg *reg = pmadapter->pcard_sd->reg;
727*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
728*4882a593Smuzhiyun 	t_u32 fw_dnld_offset_0 = 0;
729*4882a593Smuzhiyun 	t_u32 fw_dnld_offset_1 = 0;
730*4882a593Smuzhiyun 	t_u32 fw_dnld_offset_2 = 0;
731*4882a593Smuzhiyun 	t_u32 fw_dnld_offset_3 = 0;
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 	ENTER();
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun 	ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
736*4882a593Smuzhiyun 				 reg->fw_dnld_offset_0_reg, &fw_dnld_offset_0);
737*4882a593Smuzhiyun 	if (ret != MLAN_STATUS_SUCCESS) {
738*4882a593Smuzhiyun 		PRINTM(MERROR,
739*4882a593Smuzhiyun 		       "Dev fw_dnld_offset_0 reg read failed: reg(0x%04X)=0x%x. Terminating download\n",
740*4882a593Smuzhiyun 		       reg->fw_dnld_offset_0_reg, fw_dnld_offset_0);
741*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
742*4882a593Smuzhiyun 		goto done;
743*4882a593Smuzhiyun 	}
744*4882a593Smuzhiyun 	ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
745*4882a593Smuzhiyun 				 reg->fw_dnld_offset_1_reg, &fw_dnld_offset_1);
746*4882a593Smuzhiyun 	if (ret != MLAN_STATUS_SUCCESS) {
747*4882a593Smuzhiyun 		PRINTM(MERROR,
748*4882a593Smuzhiyun 		       "Dev fw_dnld_offset_1 reg read failed: reg(0x%04X)=0x%x. Terminating download\n",
749*4882a593Smuzhiyun 		       reg->fw_dnld_offset_1_reg, fw_dnld_offset_1);
750*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
751*4882a593Smuzhiyun 		goto done;
752*4882a593Smuzhiyun 	}
753*4882a593Smuzhiyun 	ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
754*4882a593Smuzhiyun 				 reg->fw_dnld_offset_2_reg, &fw_dnld_offset_2);
755*4882a593Smuzhiyun 	if (ret != MLAN_STATUS_SUCCESS) {
756*4882a593Smuzhiyun 		PRINTM(MERROR,
757*4882a593Smuzhiyun 		       "Dev fw_dnld_offset_2 reg read failed: reg(0x%04X)=0x%x. Terminating download\n",
758*4882a593Smuzhiyun 		       reg->fw_dnld_offset_2_reg, fw_dnld_offset_2);
759*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
760*4882a593Smuzhiyun 		goto done;
761*4882a593Smuzhiyun 	}
762*4882a593Smuzhiyun 	ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
763*4882a593Smuzhiyun 				 reg->fw_dnld_offset_3_reg, &fw_dnld_offset_3);
764*4882a593Smuzhiyun 	if (ret != MLAN_STATUS_SUCCESS) {
765*4882a593Smuzhiyun 		PRINTM(MERROR,
766*4882a593Smuzhiyun 		       "Dev fw_dnld_offset_3 reg read failed: reg(0x%04X)=0x%x. Terminating download\n",
767*4882a593Smuzhiyun 		       reg->fw_dnld_offset_3_reg, fw_dnld_offset_3);
768*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
769*4882a593Smuzhiyun 		goto done;
770*4882a593Smuzhiyun 	}
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 	*dat = (t_u32)(((fw_dnld_offset_3 & 0xff) << 24) |
773*4882a593Smuzhiyun 		       ((fw_dnld_offset_2 & 0xff) << 16) |
774*4882a593Smuzhiyun 		       ((fw_dnld_offset_1 & 0xff) << 8) |
775*4882a593Smuzhiyun 		       (fw_dnld_offset_0 & 0xff));
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun done:
778*4882a593Smuzhiyun 	LEAVE();
779*4882a593Smuzhiyun 	return ret;
780*4882a593Smuzhiyun }
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun /**
783*4882a593Smuzhiyun  *  @brief This function reads firmware dnld status registers
784*4882a593Smuzhiyun  *
785*4882a593Smuzhiyun  *  @param pmadapter    A pointer to mlan_adapter structure
786*4882a593Smuzhiyun  *  @param dat          A pointer to keep returned data
787*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
788*4882a593Smuzhiyun  */
wlan_sdio_read_fw_dnld_status(mlan_adapter * pmadapter,t_u16 * dat)789*4882a593Smuzhiyun static mlan_status wlan_sdio_read_fw_dnld_status(mlan_adapter *pmadapter,
790*4882a593Smuzhiyun 						 t_u16 *dat)
791*4882a593Smuzhiyun {
792*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
793*4882a593Smuzhiyun 	const mlan_sdio_card_reg *reg = pmadapter->pcard_sd->reg;
794*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
795*4882a593Smuzhiyun 	t_u32 fw_dnld_status_0 = 0;
796*4882a593Smuzhiyun 	t_u32 fw_dnld_status_1 = 0;
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 	ENTER();
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 	ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
801*4882a593Smuzhiyun 				 reg->fw_dnld_status_0_reg, &fw_dnld_status_0);
802*4882a593Smuzhiyun 	if (ret != MLAN_STATUS_SUCCESS) {
803*4882a593Smuzhiyun 		PRINTM(MERROR,
804*4882a593Smuzhiyun 		       "Dev fw_dnld_status_0 reg read failed: reg(0x%04X)=0x%x. Terminating download\n",
805*4882a593Smuzhiyun 		       reg->fw_dnld_status_0_reg, fw_dnld_status_0);
806*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
807*4882a593Smuzhiyun 		goto done;
808*4882a593Smuzhiyun 	}
809*4882a593Smuzhiyun 	ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
810*4882a593Smuzhiyun 				 reg->fw_dnld_status_1_reg, &fw_dnld_status_1);
811*4882a593Smuzhiyun 	if (ret != MLAN_STATUS_SUCCESS) {
812*4882a593Smuzhiyun 		PRINTM(MERROR,
813*4882a593Smuzhiyun 		       "Dev fw_dnld_status_1 reg read failed: reg(0x%04X)=0x%x. Terminating download\n",
814*4882a593Smuzhiyun 		       reg->fw_dnld_status_1_reg, fw_dnld_status_1);
815*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
816*4882a593Smuzhiyun 		goto done;
817*4882a593Smuzhiyun 	}
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 	*dat = (t_u16)(((fw_dnld_status_1 & 0xff) << 8) |
820*4882a593Smuzhiyun 		       (fw_dnld_status_0 & 0xff));
821*4882a593Smuzhiyun 
822*4882a593Smuzhiyun done:
823*4882a593Smuzhiyun 	LEAVE();
824*4882a593Smuzhiyun 	return ret;
825*4882a593Smuzhiyun }
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun /**  @brief This function disables the host interrupts mask.
828*4882a593Smuzhiyun  *
829*4882a593Smuzhiyun  *  @param pmadapter    A pointer to mlan_adapter structure
830*4882a593Smuzhiyun  *  @param mask         the interrupt mask
831*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
832*4882a593Smuzhiyun  */
wlan_sdio_disable_host_int_mask(pmlan_adapter pmadapter,t_u8 mask)833*4882a593Smuzhiyun static mlan_status wlan_sdio_disable_host_int_mask(pmlan_adapter pmadapter,
834*4882a593Smuzhiyun 						   t_u8 mask)
835*4882a593Smuzhiyun {
836*4882a593Smuzhiyun 	t_u32 host_int_mask = 0;
837*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun 	ENTER();
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun 	/* Read back the host_int_mask register */
842*4882a593Smuzhiyun 	if (MLAN_STATUS_SUCCESS !=
843*4882a593Smuzhiyun 	    pcb->moal_read_reg(pmadapter->pmoal_handle,
844*4882a593Smuzhiyun 			       pmadapter->pcard_sd->reg->host_int_mask_reg,
845*4882a593Smuzhiyun 			       &host_int_mask)) {
846*4882a593Smuzhiyun 		LEAVE();
847*4882a593Smuzhiyun 		return MLAN_STATUS_FAILURE;
848*4882a593Smuzhiyun 	}
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun 	/* Update with the mask and write back to the register */
851*4882a593Smuzhiyun 	host_int_mask &= ~mask;
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun 	if (MLAN_STATUS_SUCCESS !=
854*4882a593Smuzhiyun 	    pcb->moal_write_reg(pmadapter->pmoal_handle,
855*4882a593Smuzhiyun 				pmadapter->pcard_sd->reg->host_int_mask_reg,
856*4882a593Smuzhiyun 				host_int_mask)) {
857*4882a593Smuzhiyun 		PRINTM(MWARN, "Disable host interrupt failed\n");
858*4882a593Smuzhiyun 		LEAVE();
859*4882a593Smuzhiyun 		return MLAN_STATUS_FAILURE;
860*4882a593Smuzhiyun 	}
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun 	LEAVE();
863*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
864*4882a593Smuzhiyun }
865*4882a593Smuzhiyun 
866*4882a593Smuzhiyun /**
867*4882a593Smuzhiyun  *  @brief This function enables the host interrupts mask
868*4882a593Smuzhiyun  *
869*4882a593Smuzhiyun  *  @param pmadapter A pointer to mlan_adapter structure
870*4882a593Smuzhiyun  *  @param mask    the interrupt mask
871*4882a593Smuzhiyun  *  @return        MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
872*4882a593Smuzhiyun  */
wlan_sdio_enable_host_int_mask(pmlan_adapter pmadapter,t_u8 mask)873*4882a593Smuzhiyun static mlan_status wlan_sdio_enable_host_int_mask(pmlan_adapter pmadapter,
874*4882a593Smuzhiyun 						  t_u8 mask)
875*4882a593Smuzhiyun {
876*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
877*4882a593Smuzhiyun 
878*4882a593Smuzhiyun 	ENTER();
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun 	/* Simply write the mask to the register */
881*4882a593Smuzhiyun 	if (MLAN_STATUS_SUCCESS !=
882*4882a593Smuzhiyun 	    pcb->moal_write_reg(pmadapter->pmoal_handle,
883*4882a593Smuzhiyun 				pmadapter->pcard_sd->reg->host_int_mask_reg,
884*4882a593Smuzhiyun 				mask)) {
885*4882a593Smuzhiyun 		PRINTM(MWARN, "Enable host interrupt failed\n");
886*4882a593Smuzhiyun 		LEAVE();
887*4882a593Smuzhiyun 		return MLAN_STATUS_FAILURE;
888*4882a593Smuzhiyun 	}
889*4882a593Smuzhiyun 
890*4882a593Smuzhiyun 	LEAVE();
891*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
892*4882a593Smuzhiyun }
893*4882a593Smuzhiyun 
894*4882a593Smuzhiyun /**
895*4882a593Smuzhiyun  *  @brief This function reads data from the card.
896*4882a593Smuzhiyun  *
897*4882a593Smuzhiyun  *  @param pmadapter A pointer to mlan_adapter structure
898*4882a593Smuzhiyun  *  @param type     A pointer to keep type as data or command
899*4882a593Smuzhiyun  *  @param nb       A pointer to keep the data/cmd length returned in buffer
900*4882a593Smuzhiyun  *  @param pmbuf    A pointer to the SDIO data/cmd buffer
901*4882a593Smuzhiyun  *  @param npayload the length of data/cmd buffer
902*4882a593Smuzhiyun  *  @param ioport   the SDIO ioport
903*4882a593Smuzhiyun  *  @return         MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
904*4882a593Smuzhiyun  */
wlan_sdio_card_to_host(mlan_adapter * pmadapter,t_u32 * type,t_u32 * nb,pmlan_buffer pmbuf,t_u32 npayload,t_u32 ioport)905*4882a593Smuzhiyun static mlan_status wlan_sdio_card_to_host(mlan_adapter *pmadapter, t_u32 *type,
906*4882a593Smuzhiyun 					  t_u32 *nb, pmlan_buffer pmbuf,
907*4882a593Smuzhiyun 					  t_u32 npayload, t_u32 ioport)
908*4882a593Smuzhiyun {
909*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
910*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
911*4882a593Smuzhiyun 	t_u32 i = 0;
912*4882a593Smuzhiyun 
913*4882a593Smuzhiyun 	ENTER();
914*4882a593Smuzhiyun 
915*4882a593Smuzhiyun 	if (!pmbuf) {
916*4882a593Smuzhiyun 		PRINTM(MWARN, "pmbuf is NULL!\n");
917*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
918*4882a593Smuzhiyun 		goto exit;
919*4882a593Smuzhiyun 	}
920*4882a593Smuzhiyun 	do {
921*4882a593Smuzhiyun 		ret = pcb->moal_read_data_sync(pmadapter->pmoal_handle, pmbuf,
922*4882a593Smuzhiyun 					       ioport, 0);
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun 		if (ret != MLAN_STATUS_SUCCESS) {
925*4882a593Smuzhiyun 			PRINTM(MERROR,
926*4882a593Smuzhiyun 			       "wlan: cmd53 read failed: %d ioport=0x%x retry=%d\n",
927*4882a593Smuzhiyun 			       ret, ioport, i);
928*4882a593Smuzhiyun 			i++;
929*4882a593Smuzhiyun 			if (MLAN_STATUS_SUCCESS !=
930*4882a593Smuzhiyun 			    pcb->moal_write_reg(pmadapter->pmoal_handle,
931*4882a593Smuzhiyun 						HOST_TO_CARD_EVENT_REG,
932*4882a593Smuzhiyun 						HOST_TERM_CMD53)) {
933*4882a593Smuzhiyun 				PRINTM(MERROR, "Set Term cmd53 failed\n");
934*4882a593Smuzhiyun 			}
935*4882a593Smuzhiyun 			if (i > MAX_WRITE_IOMEM_RETRY) {
936*4882a593Smuzhiyun 				pmbuf->status_code = MLAN_ERROR_DATA_RX_FAIL;
937*4882a593Smuzhiyun 				ret = MLAN_STATUS_FAILURE;
938*4882a593Smuzhiyun 				goto exit;
939*4882a593Smuzhiyun 			}
940*4882a593Smuzhiyun 		}
941*4882a593Smuzhiyun 	} while (ret == MLAN_STATUS_FAILURE);
942*4882a593Smuzhiyun 	*nb = wlan_le16_to_cpu(*(t_u16 *)(pmbuf->pbuf + pmbuf->data_offset));
943*4882a593Smuzhiyun 	if (*nb > npayload) {
944*4882a593Smuzhiyun 		PRINTM(MERROR, "invalid packet, *nb=%d, npayload=%d\n", *nb,
945*4882a593Smuzhiyun 		       npayload);
946*4882a593Smuzhiyun 		pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
947*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
948*4882a593Smuzhiyun 		goto exit;
949*4882a593Smuzhiyun 	}
950*4882a593Smuzhiyun 
951*4882a593Smuzhiyun 	DBG_HEXDUMP(MIF_D, "SDIO Blk Rd", pmbuf->pbuf + pmbuf->data_offset,
952*4882a593Smuzhiyun 		    MIN(*nb, MAX_DATA_DUMP_LEN));
953*4882a593Smuzhiyun 
954*4882a593Smuzhiyun 	*type = wlan_le16_to_cpu(
955*4882a593Smuzhiyun 		*(t_u16 *)(pmbuf->pbuf + pmbuf->data_offset + 2));
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun exit:
958*4882a593Smuzhiyun 	LEAVE();
959*4882a593Smuzhiyun 	return ret;
960*4882a593Smuzhiyun }
961*4882a593Smuzhiyun 
962*4882a593Smuzhiyun /**
963*4882a593Smuzhiyun  *  @brief  This function downloads FW blocks to device
964*4882a593Smuzhiyun  *
965*4882a593Smuzhiyun  *  @param pmadapter	A pointer to mlan_adapter
966*4882a593Smuzhiyun  *  @param firmware     A pointer to firmware image
967*4882a593Smuzhiyun  *  @param firmwarelen  firmware len
968*4882a593Smuzhiyun  *
969*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
970*4882a593Smuzhiyun  */
wlan_sdio_prog_fw_w_helper(pmlan_adapter pmadapter,t_u8 * fw,t_u32 fw_len)971*4882a593Smuzhiyun static mlan_status wlan_sdio_prog_fw_w_helper(pmlan_adapter pmadapter, t_u8 *fw,
972*4882a593Smuzhiyun 					      t_u32 fw_len)
973*4882a593Smuzhiyun {
974*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
975*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
976*4882a593Smuzhiyun 	t_u8 *firmware = fw;
977*4882a593Smuzhiyun 	t_u32 firmwarelen = fw_len;
978*4882a593Smuzhiyun 	t_u32 offset = 0;
979*4882a593Smuzhiyun 	t_u32 base0, base1;
980*4882a593Smuzhiyun 	t_void *tmpfwbuf = MNULL;
981*4882a593Smuzhiyun 	t_u32 tmpfwbufsz;
982*4882a593Smuzhiyun 	t_u8 *fwbuf;
983*4882a593Smuzhiyun 	mlan_buffer mbuf;
984*4882a593Smuzhiyun 	t_u16 len = 0;
985*4882a593Smuzhiyun 	t_u32 txlen = 0, tx_blocks = 0, tries = 0;
986*4882a593Smuzhiyun 	t_u32 i = 0;
987*4882a593Smuzhiyun 	const mlan_sdio_card_reg *reg = pmadapter->pcard_sd->reg;
988*4882a593Smuzhiyun 	t_u32 read_base_0_reg = reg->base_0_reg;
989*4882a593Smuzhiyun 	t_u32 read_base_1_reg = reg->base_1_reg;
990*4882a593Smuzhiyun #if defined(SD9098)
991*4882a593Smuzhiyun 	t_u32 rev_id_reg = 0;
992*4882a593Smuzhiyun 	t_u32 revision_id = 0;
993*4882a593Smuzhiyun #endif
994*4882a593Smuzhiyun 	t_u8 check_fw_status = MFALSE;
995*4882a593Smuzhiyun 	t_u16 fw_dnld_status = 0;
996*4882a593Smuzhiyun 	t_u32 fw_dnld_offset = 0;
997*4882a593Smuzhiyun 	t_u8 mic_retry = 0;
998*4882a593Smuzhiyun 
999*4882a593Smuzhiyun 	ENTER();
1000*4882a593Smuzhiyun 
1001*4882a593Smuzhiyun 	if (!firmware && !pcb->moal_get_fw_data) {
1002*4882a593Smuzhiyun 		PRINTM(MMSG, "No firmware image found! Terminating download\n");
1003*4882a593Smuzhiyun 		LEAVE();
1004*4882a593Smuzhiyun 		return MLAN_STATUS_FAILURE;
1005*4882a593Smuzhiyun 	}
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 	PRINTM(MINFO, "WLAN: Downloading FW image (%d bytes)\n", firmwarelen);
1008*4882a593Smuzhiyun 
1009*4882a593Smuzhiyun 	tmpfwbufsz = ALIGN_SZ(WLAN_UPLD_SIZE, DMA_ALIGNMENT);
1010*4882a593Smuzhiyun 	ret = pcb->moal_malloc(pmadapter->pmoal_handle, tmpfwbufsz,
1011*4882a593Smuzhiyun 			       MLAN_MEM_DEF | MLAN_MEM_DMA, (t_u8 **)&tmpfwbuf);
1012*4882a593Smuzhiyun 	if ((ret != MLAN_STATUS_SUCCESS) || !tmpfwbuf) {
1013*4882a593Smuzhiyun 		PRINTM(MERROR,
1014*4882a593Smuzhiyun 		       "Unable to allocate buffer for firmware. Terminating download\n");
1015*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
1016*4882a593Smuzhiyun 		goto done;
1017*4882a593Smuzhiyun 	}
1018*4882a593Smuzhiyun 	memset(pmadapter, tmpfwbuf, 0, tmpfwbufsz);
1019*4882a593Smuzhiyun 	/* Ensure 8-byte aligned firmware buffer */
1020*4882a593Smuzhiyun 	fwbuf = (t_u8 *)ALIGN_ADDR(tmpfwbuf, DMA_ALIGNMENT);
1021*4882a593Smuzhiyun #if defined(SD9098)
1022*4882a593Smuzhiyun 	if (IS_SD9098(pmadapter->card_type)) {
1023*4882a593Smuzhiyun 		rev_id_reg = pmadapter->pcard_sd->reg->card_revision_reg;
1024*4882a593Smuzhiyun 		ret = pcb->moal_read_reg(pmadapter->pmoal_handle, rev_id_reg,
1025*4882a593Smuzhiyun 					 &revision_id);
1026*4882a593Smuzhiyun 		if (ret != MLAN_STATUS_SUCCESS) {
1027*4882a593Smuzhiyun 			PRINTM(MERROR,
1028*4882a593Smuzhiyun 			       "Card Revision register read failed:"
1029*4882a593Smuzhiyun 			       "card_revision_reg=0x%x\n",
1030*4882a593Smuzhiyun 			       rev_id_reg);
1031*4882a593Smuzhiyun 			goto done;
1032*4882a593Smuzhiyun 		}
1033*4882a593Smuzhiyun 		/* Skyhawk A0, need to check both CRC and MIC error */
1034*4882a593Smuzhiyun 		if (revision_id >= CHIP_9098_REV_A0)
1035*4882a593Smuzhiyun 			check_fw_status = MTRUE;
1036*4882a593Smuzhiyun 	}
1037*4882a593Smuzhiyun #endif
1038*4882a593Smuzhiyun #if defined(SD9097) || defined(SD9177) || defined(SDNW62X)
1039*4882a593Smuzhiyun 	if (IS_SD9097(pmadapter->card_type) ||
1040*4882a593Smuzhiyun 	    IS_SDNW62X(pmadapter->card_type) || IS_SD9177(pmadapter->card_type))
1041*4882a593Smuzhiyun 		check_fw_status = MTRUE;
1042*4882a593Smuzhiyun #endif
1043*4882a593Smuzhiyun 
1044*4882a593Smuzhiyun 	/* Perform firmware data transfer */
1045*4882a593Smuzhiyun 	do {
1046*4882a593Smuzhiyun 		/* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits
1047*4882a593Smuzhiyun 		 */
1048*4882a593Smuzhiyun 		ret = wlan_sdio_poll_card_status(
1049*4882a593Smuzhiyun 			pmadapter, CARD_IO_READY | DN_LD_CARD_RDY);
1050*4882a593Smuzhiyun 		if (ret != MLAN_STATUS_SUCCESS) {
1051*4882a593Smuzhiyun 			PRINTM(MFATAL,
1052*4882a593Smuzhiyun 			       "WLAN: FW download with helper poll status timeout @ %d\n",
1053*4882a593Smuzhiyun 			       offset);
1054*4882a593Smuzhiyun 			goto done;
1055*4882a593Smuzhiyun 		}
1056*4882a593Smuzhiyun 
1057*4882a593Smuzhiyun 		/* More data */
1058*4882a593Smuzhiyun 		if (firmwarelen && offset >= firmwarelen)
1059*4882a593Smuzhiyun 			break;
1060*4882a593Smuzhiyun 
1061*4882a593Smuzhiyun 		for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
1062*4882a593Smuzhiyun 			ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
1063*4882a593Smuzhiyun 						 read_base_0_reg, &base0);
1064*4882a593Smuzhiyun 			if (ret != MLAN_STATUS_SUCCESS) {
1065*4882a593Smuzhiyun 				PRINTM(MERROR,
1066*4882a593Smuzhiyun 				       "Dev BASE0 register read failed:"
1067*4882a593Smuzhiyun 				       " base0=0x%04X(%d). Terminating download\n",
1068*4882a593Smuzhiyun 				       base0, base0);
1069*4882a593Smuzhiyun 				goto done;
1070*4882a593Smuzhiyun 			}
1071*4882a593Smuzhiyun 			ret = pcb->moal_read_reg(pmadapter->pmoal_handle,
1072*4882a593Smuzhiyun 						 read_base_1_reg, &base1);
1073*4882a593Smuzhiyun 			if (ret != MLAN_STATUS_SUCCESS) {
1074*4882a593Smuzhiyun 				PRINTM(MERROR,
1075*4882a593Smuzhiyun 				       "Dev BASE1 register read failed:"
1076*4882a593Smuzhiyun 				       " base1=0x%04X(%d). Terminating download\n",
1077*4882a593Smuzhiyun 				       base1, base1);
1078*4882a593Smuzhiyun 				goto done;
1079*4882a593Smuzhiyun 			}
1080*4882a593Smuzhiyun 			len = (t_u16)(((base1 & 0xff) << 8) | (base0 & 0xff));
1081*4882a593Smuzhiyun 
1082*4882a593Smuzhiyun 			if (len)
1083*4882a593Smuzhiyun 				break;
1084*4882a593Smuzhiyun 			wlan_udelay(pmadapter, 10);
1085*4882a593Smuzhiyun 		}
1086*4882a593Smuzhiyun 
1087*4882a593Smuzhiyun 		if (!len)
1088*4882a593Smuzhiyun 			break;
1089*4882a593Smuzhiyun 		else if (len > WLAN_UPLD_SIZE) {
1090*4882a593Smuzhiyun 			PRINTM(MFATAL,
1091*4882a593Smuzhiyun 			       "WLAN: FW download failure @ %d, invalid length %d\n",
1092*4882a593Smuzhiyun 			       offset, len);
1093*4882a593Smuzhiyun 			ret = MLAN_STATUS_FAILURE;
1094*4882a593Smuzhiyun 			goto done;
1095*4882a593Smuzhiyun 		}
1096*4882a593Smuzhiyun 
1097*4882a593Smuzhiyun 		/* Ignore CRC check before download the 1st packet */
1098*4882a593Smuzhiyun 		if (offset == 0 && (len & MBIT(0)))
1099*4882a593Smuzhiyun 			len &= ~MBIT(0);
1100*4882a593Smuzhiyun 
1101*4882a593Smuzhiyun 		txlen = len;
1102*4882a593Smuzhiyun 
1103*4882a593Smuzhiyun 		if (len & MBIT(0)) {
1104*4882a593Smuzhiyun 			/* New fw download process, check CRC and MIC error */
1105*4882a593Smuzhiyun 			if (check_fw_status) {
1106*4882a593Smuzhiyun 				/* Get offset from fw dnld offset Register */
1107*4882a593Smuzhiyun 				ret = wlan_sdio_read_fw_dnld_offset(
1108*4882a593Smuzhiyun 					pmadapter, &fw_dnld_offset);
1109*4882a593Smuzhiyun 				if (ret != MLAN_STATUS_SUCCESS) {
1110*4882a593Smuzhiyun 					PRINTM(MFATAL,
1111*4882a593Smuzhiyun 					       "WLAN: FW download with helper read fw dnld offset failed @ %d\n",
1112*4882a593Smuzhiyun 					       offset);
1113*4882a593Smuzhiyun 					goto done;
1114*4882a593Smuzhiyun 				}
1115*4882a593Smuzhiyun 				/* Get CRC MIC error from fw dnld status
1116*4882a593Smuzhiyun 				 * Register */
1117*4882a593Smuzhiyun 				ret = wlan_sdio_read_fw_dnld_status(
1118*4882a593Smuzhiyun 					pmadapter, &fw_dnld_status);
1119*4882a593Smuzhiyun 				if (ret != MLAN_STATUS_SUCCESS) {
1120*4882a593Smuzhiyun 					PRINTM(MFATAL,
1121*4882a593Smuzhiyun 					       "WLAN: FW download with helper read fw dnld status failed @ %d\n",
1122*4882a593Smuzhiyun 					       offset);
1123*4882a593Smuzhiyun 					goto done;
1124*4882a593Smuzhiyun 				}
1125*4882a593Smuzhiyun 				PRINTM(MERROR,
1126*4882a593Smuzhiyun 				       "WLAN: FW download error: status=0x%x offset = 0x%x fw offset = 0x%x\n",
1127*4882a593Smuzhiyun 				       fw_dnld_status, offset, fw_dnld_offset);
1128*4882a593Smuzhiyun 			}
1129*4882a593Smuzhiyun 			i++;
1130*4882a593Smuzhiyun 			if (i > MAX_WRITE_IOMEM_RETRY) {
1131*4882a593Smuzhiyun 				PRINTM(MFATAL,
1132*4882a593Smuzhiyun 				       "WLAN: FW download failure @ %d, over max retry count\n",
1133*4882a593Smuzhiyun 				       offset);
1134*4882a593Smuzhiyun 				ret = MLAN_STATUS_FAILURE;
1135*4882a593Smuzhiyun 				goto done;
1136*4882a593Smuzhiyun 			}
1137*4882a593Smuzhiyun 
1138*4882a593Smuzhiyun 			PRINTM(MERROR,
1139*4882a593Smuzhiyun 			       "WLAN: FW CRC error indicated by the helper:"
1140*4882a593Smuzhiyun 			       " len = 0x%04X, txlen = %d\n",
1141*4882a593Smuzhiyun 			       len, txlen);
1142*4882a593Smuzhiyun 			len &= ~MBIT(0);
1143*4882a593Smuzhiyun 			if (fw_dnld_status & (MBIT(6) | MBIT(7))) {
1144*4882a593Smuzhiyun 				offset = 0;
1145*4882a593Smuzhiyun 				mic_retry++;
1146*4882a593Smuzhiyun 				if (mic_retry > MAX_FW_RETRY) {
1147*4882a593Smuzhiyun 					PRINTM(MFATAL,
1148*4882a593Smuzhiyun 					       "WLAN: FW download failure @ %d, over max mic retry count\n",
1149*4882a593Smuzhiyun 					       offset);
1150*4882a593Smuzhiyun 					ret = MLAN_STATUS_FAILURE;
1151*4882a593Smuzhiyun 					goto done;
1152*4882a593Smuzhiyun 				}
1153*4882a593Smuzhiyun 			}
1154*4882a593Smuzhiyun 			PRINTM(MERROR, "WLAN: retry: %d, offset %d\n", i,
1155*4882a593Smuzhiyun 			       offset);
1156*4882a593Smuzhiyun 			DBG_HEXDUMP(MERROR, "WLAN: FW block:", fwbuf, len);
1157*4882a593Smuzhiyun 			/* Setting this to 0 to resend from same offset */
1158*4882a593Smuzhiyun 			txlen = 0;
1159*4882a593Smuzhiyun 		} else {
1160*4882a593Smuzhiyun 			i = 0;
1161*4882a593Smuzhiyun 
1162*4882a593Smuzhiyun 			/* Set blocksize to transfer - checking
1163*4882a593Smuzhiyun 			 * for last block */
1164*4882a593Smuzhiyun 			if (firmwarelen && firmwarelen - offset < txlen)
1165*4882a593Smuzhiyun 				txlen = firmwarelen - offset;
1166*4882a593Smuzhiyun 			PRINTM(MINFO, ".");
1167*4882a593Smuzhiyun 
1168*4882a593Smuzhiyun 			tx_blocks = (txlen + MLAN_SDIO_BLOCK_SIZE_FW_DNLD - 1) /
1169*4882a593Smuzhiyun 				    MLAN_SDIO_BLOCK_SIZE_FW_DNLD;
1170*4882a593Smuzhiyun 
1171*4882a593Smuzhiyun 			/* Copy payload to buffer */
1172*4882a593Smuzhiyun 			if (firmware)
1173*4882a593Smuzhiyun 				memmove(pmadapter, fwbuf, &firmware[offset],
1174*4882a593Smuzhiyun 					txlen);
1175*4882a593Smuzhiyun 			else
1176*4882a593Smuzhiyun 				pcb->moal_get_fw_data(pmadapter->pmoal_handle,
1177*4882a593Smuzhiyun 						      offset, txlen, fwbuf);
1178*4882a593Smuzhiyun 		}
1179*4882a593Smuzhiyun 
1180*4882a593Smuzhiyun 		/* Send data */
1181*4882a593Smuzhiyun 		memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
1182*4882a593Smuzhiyun 		mbuf.pbuf = (t_u8 *)fwbuf;
1183*4882a593Smuzhiyun 		mbuf.data_len = tx_blocks * MLAN_SDIO_BLOCK_SIZE_FW_DNLD;
1184*4882a593Smuzhiyun 
1185*4882a593Smuzhiyun 		ret = pcb->moal_write_data_sync(pmadapter->pmoal_handle, &mbuf,
1186*4882a593Smuzhiyun 						pmadapter->pcard_sd->ioport, 0);
1187*4882a593Smuzhiyun 		if (ret != MLAN_STATUS_SUCCESS) {
1188*4882a593Smuzhiyun 			PRINTM(MERROR,
1189*4882a593Smuzhiyun 			       "WLAN: FW download, write iomem (%d) failed @ %d\n",
1190*4882a593Smuzhiyun 			       i, offset);
1191*4882a593Smuzhiyun 			if (pcb->moal_write_reg(pmadapter->pmoal_handle,
1192*4882a593Smuzhiyun 						HOST_TO_CARD_EVENT_REG,
1193*4882a593Smuzhiyun 						HOST_TERM_CMD53) !=
1194*4882a593Smuzhiyun 			    MLAN_STATUS_SUCCESS) {
1195*4882a593Smuzhiyun 				PRINTM(MERROR, "write CFG reg failed\n");
1196*4882a593Smuzhiyun 			}
1197*4882a593Smuzhiyun 			ret = MLAN_STATUS_FAILURE;
1198*4882a593Smuzhiyun 			goto done;
1199*4882a593Smuzhiyun 		}
1200*4882a593Smuzhiyun 
1201*4882a593Smuzhiyun 		offset += txlen;
1202*4882a593Smuzhiyun 	} while (MTRUE);
1203*4882a593Smuzhiyun 
1204*4882a593Smuzhiyun 	PRINTM(MMSG, "Wlan: FW download over, firmwarelen=%d downloaded %d\n",
1205*4882a593Smuzhiyun 	       firmwarelen, offset);
1206*4882a593Smuzhiyun 
1207*4882a593Smuzhiyun 	ret = MLAN_STATUS_SUCCESS;
1208*4882a593Smuzhiyun done:
1209*4882a593Smuzhiyun 	if (tmpfwbuf)
1210*4882a593Smuzhiyun 		pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)tmpfwbuf);
1211*4882a593Smuzhiyun 
1212*4882a593Smuzhiyun 	LEAVE();
1213*4882a593Smuzhiyun 	return ret;
1214*4882a593Smuzhiyun }
1215*4882a593Smuzhiyun 
1216*4882a593Smuzhiyun /**
1217*4882a593Smuzhiyun  *  @brief This function disables the host interrupts.
1218*4882a593Smuzhiyun  *
1219*4882a593Smuzhiyun  *  @param pmadapter A pointer to mlan_adapter structure
1220*4882a593Smuzhiyun  *  @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1221*4882a593Smuzhiyun  */
wlan_disable_sdio_host_int(pmlan_adapter pmadapter)1222*4882a593Smuzhiyun static mlan_status wlan_disable_sdio_host_int(pmlan_adapter pmadapter)
1223*4882a593Smuzhiyun {
1224*4882a593Smuzhiyun 	mlan_status ret;
1225*4882a593Smuzhiyun 
1226*4882a593Smuzhiyun 	ENTER();
1227*4882a593Smuzhiyun 	ret = wlan_sdio_disable_host_int_mask(pmadapter, HIM_DISABLE);
1228*4882a593Smuzhiyun 	LEAVE();
1229*4882a593Smuzhiyun 	return ret;
1230*4882a593Smuzhiyun }
1231*4882a593Smuzhiyun 
1232*4882a593Smuzhiyun /**
1233*4882a593Smuzhiyun  *  @brief This function decodes the rx packet &
1234*4882a593Smuzhiyun  *  calls corresponding handlers according to the packet type
1235*4882a593Smuzhiyun  *
1236*4882a593Smuzhiyun  *  @param pmadapter A pointer to mlan_adapter structure
1237*4882a593Smuzhiyun  *  @param pmbuf      A pointer to the SDIO data/cmd buffer
1238*4882a593Smuzhiyun  *  @param upld_typ  Type of rx packet
1239*4882a593Smuzhiyun  *  @param lock_flag  flag for spin_lock.
1240*4882a593Smuzhiyun  *  @return          MLAN_STATUS_SUCCESS
1241*4882a593Smuzhiyun  */
wlan_decode_rx_packet(mlan_adapter * pmadapter,mlan_buffer * pmbuf,t_u32 upld_typ,t_u8 lock_flag)1242*4882a593Smuzhiyun static mlan_status wlan_decode_rx_packet(mlan_adapter *pmadapter,
1243*4882a593Smuzhiyun 					 mlan_buffer *pmbuf, t_u32 upld_typ,
1244*4882a593Smuzhiyun 					 t_u8 lock_flag)
1245*4882a593Smuzhiyun {
1246*4882a593Smuzhiyun 	t_u8 *cmd_buf;
1247*4882a593Smuzhiyun 	t_u32 event;
1248*4882a593Smuzhiyun 	t_u32 in_ts_sec, in_ts_usec;
1249*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
1250*4882a593Smuzhiyun 
1251*4882a593Smuzhiyun 	ENTER();
1252*4882a593Smuzhiyun 
1253*4882a593Smuzhiyun 	switch (upld_typ) {
1254*4882a593Smuzhiyun 	case MLAN_TYPE_SPA_DATA:
1255*4882a593Smuzhiyun 		PRINTM(MINFO, "--- Rx: SPA Data packet ---\n");
1256*4882a593Smuzhiyun 		pmbuf->data_len = pmadapter->upld_len;
1257*4882a593Smuzhiyun 		if (pmadapter->rx_work_flag) {
1258*4882a593Smuzhiyun 			pmbuf->buf_type = MLAN_BUF_TYPE_SPA_DATA;
1259*4882a593Smuzhiyun 			if (lock_flag)
1260*4882a593Smuzhiyun 				pmadapter->callbacks.moal_spin_lock(
1261*4882a593Smuzhiyun 					pmadapter->pmoal_handle,
1262*4882a593Smuzhiyun 					pmadapter->rx_data_queue.plock);
1263*4882a593Smuzhiyun 			util_enqueue_list_tail(pmadapter->pmoal_handle,
1264*4882a593Smuzhiyun 					       &pmadapter->rx_data_queue,
1265*4882a593Smuzhiyun 					       (pmlan_linked_list)pmbuf, MNULL,
1266*4882a593Smuzhiyun 					       MNULL);
1267*4882a593Smuzhiyun 			pmadapter->rx_pkts_queued++;
1268*4882a593Smuzhiyun 			if (lock_flag)
1269*4882a593Smuzhiyun 				pmadapter->callbacks.moal_spin_unlock(
1270*4882a593Smuzhiyun 					pmadapter->pmoal_handle,
1271*4882a593Smuzhiyun 					pmadapter->rx_data_queue.plock);
1272*4882a593Smuzhiyun 		} else {
1273*4882a593Smuzhiyun 			wlan_decode_spa_buffer(pmadapter,
1274*4882a593Smuzhiyun 					       pmbuf->pbuf + pmbuf->data_offset,
1275*4882a593Smuzhiyun 					       pmbuf->data_len);
1276*4882a593Smuzhiyun 			wlan_free_mlan_buffer(pmadapter, pmbuf);
1277*4882a593Smuzhiyun 		}
1278*4882a593Smuzhiyun 		pmadapter->data_received = MTRUE;
1279*4882a593Smuzhiyun 		break;
1280*4882a593Smuzhiyun 	case MLAN_TYPE_DATA:
1281*4882a593Smuzhiyun 		PRINTM(MINFO, "--- Rx: Data packet ---\n");
1282*4882a593Smuzhiyun 		if (pmadapter->upld_len > pmbuf->data_len) {
1283*4882a593Smuzhiyun 			PRINTM(MERROR,
1284*4882a593Smuzhiyun 			       "SDIO: Drop packet upld_len=%d data_len=%d \n",
1285*4882a593Smuzhiyun 			       pmadapter->upld_len, pmbuf->data_len);
1286*4882a593Smuzhiyun 			wlan_free_mlan_buffer(pmadapter, pmbuf);
1287*4882a593Smuzhiyun 			break;
1288*4882a593Smuzhiyun 		}
1289*4882a593Smuzhiyun 		pmbuf->data_len = (pmadapter->upld_len - SDIO_INTF_HEADER_LEN);
1290*4882a593Smuzhiyun 		pmbuf->data_offset += SDIO_INTF_HEADER_LEN;
1291*4882a593Smuzhiyun 		if (pmadapter->rx_work_flag) {
1292*4882a593Smuzhiyun 			// rx_trace 5
1293*4882a593Smuzhiyun 			if (pmadapter->tp_state_on) {
1294*4882a593Smuzhiyun 				pmadapter->callbacks.moal_tp_accounting(
1295*4882a593Smuzhiyun 					pmadapter->pmoal_handle, pmbuf,
1296*4882a593Smuzhiyun 					5 /*RX_DROP_P1*/);
1297*4882a593Smuzhiyun 				pcb->moal_get_system_time(
1298*4882a593Smuzhiyun 					pmadapter->pmoal_handle, &in_ts_sec,
1299*4882a593Smuzhiyun 					&in_ts_usec);
1300*4882a593Smuzhiyun 				pmbuf->in_ts_sec = in_ts_sec;
1301*4882a593Smuzhiyun 				pmbuf->in_ts_usec = in_ts_usec;
1302*4882a593Smuzhiyun 			}
1303*4882a593Smuzhiyun 			if (pmadapter->tp_state_drop_point ==
1304*4882a593Smuzhiyun 			    5 /*RX_DROP_P1*/) {
1305*4882a593Smuzhiyun 				pmadapter->ops.data_complete(
1306*4882a593Smuzhiyun 					pmadapter, pmbuf, MLAN_STATUS_SUCCESS);
1307*4882a593Smuzhiyun 			} else {
1308*4882a593Smuzhiyun 				if (lock_flag)
1309*4882a593Smuzhiyun 					pmadapter->callbacks.moal_spin_lock(
1310*4882a593Smuzhiyun 						pmadapter->pmoal_handle,
1311*4882a593Smuzhiyun 						pmadapter->rx_data_queue.plock);
1312*4882a593Smuzhiyun 				util_enqueue_list_tail(
1313*4882a593Smuzhiyun 					pmadapter->pmoal_handle,
1314*4882a593Smuzhiyun 					&pmadapter->rx_data_queue,
1315*4882a593Smuzhiyun 					(pmlan_linked_list)pmbuf, MNULL, MNULL);
1316*4882a593Smuzhiyun 				pmadapter->rx_pkts_queued++;
1317*4882a593Smuzhiyun 				if (pmadapter->tp_state_on)
1318*4882a593Smuzhiyun 					pmadapter->callbacks
1319*4882a593Smuzhiyun 						.moal_tp_accounting_rx_param(
1320*4882a593Smuzhiyun 							pmadapter->pmoal_handle,
1321*4882a593Smuzhiyun 							1,
1322*4882a593Smuzhiyun 							pmadapter
1323*4882a593Smuzhiyun 								->rx_pkts_queued);
1324*4882a593Smuzhiyun 				if (lock_flag)
1325*4882a593Smuzhiyun 					pmadapter->callbacks.moal_spin_unlock(
1326*4882a593Smuzhiyun 						pmadapter->pmoal_handle,
1327*4882a593Smuzhiyun 						pmadapter->rx_data_queue.plock);
1328*4882a593Smuzhiyun 			}
1329*4882a593Smuzhiyun 		} else {
1330*4882a593Smuzhiyun 			wlan_handle_rx_packet(pmadapter, pmbuf);
1331*4882a593Smuzhiyun 		}
1332*4882a593Smuzhiyun 		pmadapter->data_received = MTRUE;
1333*4882a593Smuzhiyun 		break;
1334*4882a593Smuzhiyun 
1335*4882a593Smuzhiyun 	case MLAN_TYPE_CMD:
1336*4882a593Smuzhiyun 		PRINTM(MINFO, "--- Rx: Cmd Response ---\n");
1337*4882a593Smuzhiyun 		if (pmadapter->cmd_sent)
1338*4882a593Smuzhiyun 			pmadapter->cmd_sent = MFALSE;
1339*4882a593Smuzhiyun 		/* take care of curr_cmd = NULL case */
1340*4882a593Smuzhiyun 		if (!pmadapter->curr_cmd) {
1341*4882a593Smuzhiyun 			cmd_buf = pmadapter->upld_buf;
1342*4882a593Smuzhiyun 			if (pmadapter->ps_state == PS_STATE_SLEEP_CFM) {
1343*4882a593Smuzhiyun 				wlan_process_sleep_confirm_resp(
1344*4882a593Smuzhiyun 					pmadapter,
1345*4882a593Smuzhiyun 					pmbuf->pbuf + pmbuf->data_offset +
1346*4882a593Smuzhiyun 						SDIO_INTF_HEADER_LEN,
1347*4882a593Smuzhiyun 					pmadapter->upld_len -
1348*4882a593Smuzhiyun 						SDIO_INTF_HEADER_LEN);
1349*4882a593Smuzhiyun 			}
1350*4882a593Smuzhiyun 			pmadapter->upld_len -= SDIO_INTF_HEADER_LEN;
1351*4882a593Smuzhiyun 			memcpy_ext(pmadapter, cmd_buf,
1352*4882a593Smuzhiyun 				   pmbuf->pbuf + pmbuf->data_offset +
1353*4882a593Smuzhiyun 					   SDIO_INTF_HEADER_LEN,
1354*4882a593Smuzhiyun 				   pmadapter->upld_len - SDIO_INTF_HEADER_LEN,
1355*4882a593Smuzhiyun 				   MRVDRV_SIZE_OF_CMD_BUFFER);
1356*4882a593Smuzhiyun 			wlan_free_mlan_buffer(pmadapter, pmbuf);
1357*4882a593Smuzhiyun 		} else {
1358*4882a593Smuzhiyun 			pmadapter->cmd_resp_received = MTRUE;
1359*4882a593Smuzhiyun 			pmadapter->upld_len -= SDIO_INTF_HEADER_LEN;
1360*4882a593Smuzhiyun 			pmbuf->data_len = pmadapter->upld_len;
1361*4882a593Smuzhiyun 			pmbuf->data_offset += SDIO_INTF_HEADER_LEN;
1362*4882a593Smuzhiyun 			pmadapter->curr_cmd->respbuf = pmbuf;
1363*4882a593Smuzhiyun 			if (pmadapter->upld_len >= MRVDRV_SIZE_OF_CMD_BUFFER) {
1364*4882a593Smuzhiyun 				PRINTM(MMSG, "Invalid CmdResp len=%d\n",
1365*4882a593Smuzhiyun 				       pmadapter->upld_len);
1366*4882a593Smuzhiyun 				DBG_HEXDUMP(MERROR, "Invalid CmdResp",
1367*4882a593Smuzhiyun 					    pmbuf->pbuf + pmbuf->data_offset,
1368*4882a593Smuzhiyun 					    MAX_DATA_DUMP_LEN);
1369*4882a593Smuzhiyun 			}
1370*4882a593Smuzhiyun 		}
1371*4882a593Smuzhiyun 		break;
1372*4882a593Smuzhiyun 
1373*4882a593Smuzhiyun 	case MLAN_TYPE_EVENT:
1374*4882a593Smuzhiyun 		PRINTM(MINFO, "--- Rx: Event ---\n");
1375*4882a593Smuzhiyun 		event = *(t_u32 *)&pmbuf->pbuf[pmbuf->data_offset +
1376*4882a593Smuzhiyun 					       SDIO_INTF_HEADER_LEN];
1377*4882a593Smuzhiyun 		pmadapter->event_cause = wlan_le32_to_cpu(event);
1378*4882a593Smuzhiyun 		if ((pmadapter->upld_len > MLAN_EVENT_HEADER_LEN) &&
1379*4882a593Smuzhiyun 		    ((pmadapter->upld_len - MLAN_EVENT_HEADER_LEN) <
1380*4882a593Smuzhiyun 		     MAX_EVENT_SIZE)) {
1381*4882a593Smuzhiyun 			memcpy_ext(pmadapter, pmadapter->event_body,
1382*4882a593Smuzhiyun 				   pmbuf->pbuf + pmbuf->data_offset +
1383*4882a593Smuzhiyun 					   MLAN_EVENT_HEADER_LEN,
1384*4882a593Smuzhiyun 				   pmadapter->upld_len - MLAN_EVENT_HEADER_LEN,
1385*4882a593Smuzhiyun 				   MAX_EVENT_SIZE);
1386*4882a593Smuzhiyun 		}
1387*4882a593Smuzhiyun 
1388*4882a593Smuzhiyun 		/* event cause has been saved to adapter->event_cause */
1389*4882a593Smuzhiyun 		pmadapter->event_received = MTRUE;
1390*4882a593Smuzhiyun 		pmbuf->data_len = pmadapter->upld_len;
1391*4882a593Smuzhiyun 		pmadapter->pmlan_buffer_event = pmbuf;
1392*4882a593Smuzhiyun 
1393*4882a593Smuzhiyun 		/* remove SDIO header */
1394*4882a593Smuzhiyun 		pmbuf->data_offset += SDIO_INTF_HEADER_LEN;
1395*4882a593Smuzhiyun 		pmbuf->data_len -= SDIO_INTF_HEADER_LEN;
1396*4882a593Smuzhiyun 		break;
1397*4882a593Smuzhiyun 
1398*4882a593Smuzhiyun 	default:
1399*4882a593Smuzhiyun 		PRINTM(MERROR, "SDIO unknown upload type = 0x%x\n", upld_typ);
1400*4882a593Smuzhiyun 		wlan_free_mlan_buffer(pmadapter, pmbuf);
1401*4882a593Smuzhiyun 		break;
1402*4882a593Smuzhiyun 	}
1403*4882a593Smuzhiyun 
1404*4882a593Smuzhiyun 	LEAVE();
1405*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
1406*4882a593Smuzhiyun }
1407*4882a593Smuzhiyun 
1408*4882a593Smuzhiyun /**
1409*4882a593Smuzhiyun  *  @brief This function receives single packet
1410*4882a593Smuzhiyun  *
1411*4882a593Smuzhiyun  *  @param pmadapter A pointer to mlan_adapter structure
1412*4882a593Smuzhiyun  *  @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1413*4882a593Smuzhiyun  */
wlan_receive_single_packet(mlan_adapter * pmadapter)1414*4882a593Smuzhiyun static mlan_status wlan_receive_single_packet(mlan_adapter *pmadapter)
1415*4882a593Smuzhiyun {
1416*4882a593Smuzhiyun 	mlan_buffer *pmbuf;
1417*4882a593Smuzhiyun 	t_u8 port;
1418*4882a593Smuzhiyun 	t_u16 rx_len;
1419*4882a593Smuzhiyun 	t_u32 pkt_type = 0;
1420*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
1421*4882a593Smuzhiyun 
1422*4882a593Smuzhiyun 	ENTER();
1423*4882a593Smuzhiyun 	pmbuf = pmadapter->pcard_sd->mpa_rx.mbuf_arr[0];
1424*4882a593Smuzhiyun 	port = pmadapter->pcard_sd->mpa_rx.start_port;
1425*4882a593Smuzhiyun 	rx_len = pmadapter->pcard_sd->mpa_rx.len_arr[0];
1426*4882a593Smuzhiyun 	if (MLAN_STATUS_SUCCESS !=
1427*4882a593Smuzhiyun 	    wlan_sdio_card_to_host(pmadapter, &pkt_type,
1428*4882a593Smuzhiyun 				   (t_u32 *)&pmadapter->upld_len, pmbuf, rx_len,
1429*4882a593Smuzhiyun 				   pmadapter->pcard_sd->ioport + port)) {
1430*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
1431*4882a593Smuzhiyun 		goto done;
1432*4882a593Smuzhiyun 	}
1433*4882a593Smuzhiyun 	if (pkt_type != MLAN_TYPE_DATA && pkt_type != MLAN_TYPE_SPA_DATA) {
1434*4882a593Smuzhiyun 		PRINTM(MERROR,
1435*4882a593Smuzhiyun 		       "receive a wrong pkt from DATA PORT: type=%d, len=%dd\n",
1436*4882a593Smuzhiyun 		       pkt_type, pmbuf->data_len);
1437*4882a593Smuzhiyun 		pmbuf->status_code = MLAN_ERROR_DATA_RX_FAIL;
1438*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
1439*4882a593Smuzhiyun 		goto done;
1440*4882a593Smuzhiyun 	}
1441*4882a593Smuzhiyun 	pmadapter->pcard_sd->mpa_rx_count[0]++;
1442*4882a593Smuzhiyun 	wlan_decode_rx_packet(pmadapter, pmbuf, pkt_type, MTRUE);
1443*4882a593Smuzhiyun done:
1444*4882a593Smuzhiyun 	if (ret != MLAN_STATUS_SUCCESS)
1445*4882a593Smuzhiyun 		wlan_free_mlan_buffer(pmadapter, pmbuf);
1446*4882a593Smuzhiyun 	MP_RX_AGGR_BUF_RESET(pmadapter);
1447*4882a593Smuzhiyun 	LEAVE();
1448*4882a593Smuzhiyun 	return ret;
1449*4882a593Smuzhiyun }
1450*4882a593Smuzhiyun 
1451*4882a593Smuzhiyun /**
1452*4882a593Smuzhiyun  *  @brief This function receives data from the card in aggregate mode.
1453*4882a593Smuzhiyun  *
1454*4882a593Smuzhiyun  *  @param pmadapter A pointer to mlan_adapter structure
1455*4882a593Smuzhiyun  *  @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1456*4882a593Smuzhiyun  */
wlan_receive_mp_aggr_buf(mlan_adapter * pmadapter)1457*4882a593Smuzhiyun static mlan_status wlan_receive_mp_aggr_buf(mlan_adapter *pmadapter)
1458*4882a593Smuzhiyun {
1459*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
1460*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
1461*4882a593Smuzhiyun 	mlan_buffer mbuf_aggr;
1462*4882a593Smuzhiyun 	mlan_buffer *mbuf_deaggr;
1463*4882a593Smuzhiyun 	t_u32 pind = 0;
1464*4882a593Smuzhiyun 	t_u32 pkt_len, pkt_type = 0;
1465*4882a593Smuzhiyun 	t_u8 *curr_ptr;
1466*4882a593Smuzhiyun 	t_u32 cmd53_port = 0;
1467*4882a593Smuzhiyun 	t_u32 i = 0;
1468*4882a593Smuzhiyun 	t_u32 port_count = 0;
1469*4882a593Smuzhiyun 	t_bool new_mode = pmadapter->pcard_sd->supports_sdio_new_mode;
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun 	/* do aggr RX now */
1472*4882a593Smuzhiyun 	PRINTM(MINFO, "do_rx_aggr: num of packets: %d\n",
1473*4882a593Smuzhiyun 	       pmadapter->pcard_sd->mpa_rx.pkt_cnt);
1474*4882a593Smuzhiyun 
1475*4882a593Smuzhiyun 	memset(pmadapter, &mbuf_aggr, 0, sizeof(mlan_buffer));
1476*4882a593Smuzhiyun 
1477*4882a593Smuzhiyun 	if (pmadapter->pcard_sd->mpa_rx.pkt_cnt == 1)
1478*4882a593Smuzhiyun 		return wlan_receive_single_packet(pmadapter);
1479*4882a593Smuzhiyun 	if (!pmadapter->pcard_sd->mpa_rx.buf) {
1480*4882a593Smuzhiyun 		mbuf_aggr.data_len = pmadapter->pcard_sd->mpa_rx.buf_len;
1481*4882a593Smuzhiyun 		mbuf_aggr.pnext = mbuf_aggr.pprev = &mbuf_aggr;
1482*4882a593Smuzhiyun 		mbuf_aggr.use_count = 0;
1483*4882a593Smuzhiyun 		for (pind = 0; pind < pmadapter->pcard_sd->mpa_rx.pkt_cnt;
1484*4882a593Smuzhiyun 		     pind++) {
1485*4882a593Smuzhiyun 			pmadapter->pcard_sd->mpa_rx.mbuf_arr[pind]->data_len =
1486*4882a593Smuzhiyun 				pmadapter->pcard_sd->mpa_rx.len_arr[pind];
1487*4882a593Smuzhiyun 			wlan_link_buf_to_aggr(
1488*4882a593Smuzhiyun 				&mbuf_aggr,
1489*4882a593Smuzhiyun 				pmadapter->pcard_sd->mpa_rx.mbuf_arr[pind]);
1490*4882a593Smuzhiyun 		}
1491*4882a593Smuzhiyun 	} else {
1492*4882a593Smuzhiyun 		mbuf_aggr.pbuf = (t_u8 *)pmadapter->pcard_sd->mpa_rx.buf;
1493*4882a593Smuzhiyun 		mbuf_aggr.data_len = pmadapter->pcard_sd->mpa_rx.buf_len;
1494*4882a593Smuzhiyun 	}
1495*4882a593Smuzhiyun 
1496*4882a593Smuzhiyun 	if (new_mode) {
1497*4882a593Smuzhiyun 		port_count = bitcount(pmadapter->pcard_sd->mpa_rx.ports) - 1;
1498*4882a593Smuzhiyun 		/* port_count = pmadapter->mpa_rx.pkt_cnt - 1; */
1499*4882a593Smuzhiyun 		cmd53_port = (pmadapter->pcard_sd->ioport | SDIO_MPA_ADDR_BASE |
1500*4882a593Smuzhiyun 			      (port_count << 8)) +
1501*4882a593Smuzhiyun 			     pmadapter->pcard_sd->mpa_rx.start_port;
1502*4882a593Smuzhiyun 	} else {
1503*4882a593Smuzhiyun 		cmd53_port = (pmadapter->pcard_sd->ioport | SDIO_MPA_ADDR_BASE |
1504*4882a593Smuzhiyun 			      (pmadapter->pcard_sd->mpa_rx.ports << 4)) +
1505*4882a593Smuzhiyun 			     pmadapter->pcard_sd->mpa_rx.start_port;
1506*4882a593Smuzhiyun 	}
1507*4882a593Smuzhiyun 	do {
1508*4882a593Smuzhiyun 		ret = pcb->moal_read_data_sync(pmadapter->pmoal_handle,
1509*4882a593Smuzhiyun 					       &mbuf_aggr, cmd53_port, 0);
1510*4882a593Smuzhiyun 		if (ret != MLAN_STATUS_SUCCESS) {
1511*4882a593Smuzhiyun 			PRINTM(MERROR,
1512*4882a593Smuzhiyun 			       "wlan: sdio mp cmd53 read failed: %d ioport=0x%x retry=%d\n",
1513*4882a593Smuzhiyun 			       ret, cmd53_port, i);
1514*4882a593Smuzhiyun 			i++;
1515*4882a593Smuzhiyun 			if (MLAN_STATUS_SUCCESS !=
1516*4882a593Smuzhiyun 			    pcb->moal_write_reg(pmadapter->pmoal_handle,
1517*4882a593Smuzhiyun 						HOST_TO_CARD_EVENT_REG,
1518*4882a593Smuzhiyun 						HOST_TERM_CMD53)) {
1519*4882a593Smuzhiyun 				PRINTM(MERROR, "Set Term cmd53 failed\n");
1520*4882a593Smuzhiyun 			}
1521*4882a593Smuzhiyun 			if (i > MAX_WRITE_IOMEM_RETRY) {
1522*4882a593Smuzhiyun 				ret = MLAN_STATUS_FAILURE;
1523*4882a593Smuzhiyun 				goto done;
1524*4882a593Smuzhiyun 			}
1525*4882a593Smuzhiyun 		}
1526*4882a593Smuzhiyun 	} while (ret == MLAN_STATUS_FAILURE);
1527*4882a593Smuzhiyun 	if (pmadapter->rx_work_flag)
1528*4882a593Smuzhiyun 		pmadapter->callbacks.moal_spin_lock(
1529*4882a593Smuzhiyun 			pmadapter->pmoal_handle,
1530*4882a593Smuzhiyun 			pmadapter->rx_data_queue.plock);
1531*4882a593Smuzhiyun 	if (!pmadapter->pcard_sd->mpa_rx.buf &&
1532*4882a593Smuzhiyun 	    pmadapter->pcard_sd->mpa_rx.pkt_cnt > 1) {
1533*4882a593Smuzhiyun 		for (pind = 0; pind < pmadapter->pcard_sd->mpa_rx.pkt_cnt;
1534*4882a593Smuzhiyun 		     pind++) {
1535*4882a593Smuzhiyun 			mbuf_deaggr =
1536*4882a593Smuzhiyun 				pmadapter->pcard_sd->mpa_rx.mbuf_arr[pind];
1537*4882a593Smuzhiyun 			pkt_len = wlan_le16_to_cpu(
1538*4882a593Smuzhiyun 				*(t_u16 *)(mbuf_deaggr->pbuf +
1539*4882a593Smuzhiyun 					   mbuf_deaggr->data_offset));
1540*4882a593Smuzhiyun 			pkt_type = wlan_le16_to_cpu(
1541*4882a593Smuzhiyun 				*(t_u16 *)(mbuf_deaggr->pbuf +
1542*4882a593Smuzhiyun 					   mbuf_deaggr->data_offset + 2));
1543*4882a593Smuzhiyun 			pmadapter->upld_len = pkt_len;
1544*4882a593Smuzhiyun 			wlan_decode_rx_packet(pmadapter, mbuf_deaggr, pkt_type,
1545*4882a593Smuzhiyun 					      MFALSE);
1546*4882a593Smuzhiyun 		}
1547*4882a593Smuzhiyun 	} else {
1548*4882a593Smuzhiyun 		DBG_HEXDUMP(MIF_D, "SDIO MP-A Blk Rd",
1549*4882a593Smuzhiyun 			    pmadapter->pcard_sd->mpa_rx.buf,
1550*4882a593Smuzhiyun 			    MIN(pmadapter->pcard_sd->mpa_rx.buf_len,
1551*4882a593Smuzhiyun 				MAX_DATA_DUMP_LEN));
1552*4882a593Smuzhiyun 
1553*4882a593Smuzhiyun 		curr_ptr = pmadapter->pcard_sd->mpa_rx.buf;
1554*4882a593Smuzhiyun 
1555*4882a593Smuzhiyun 		for (pind = 0; pind < pmadapter->pcard_sd->mpa_rx.pkt_cnt;
1556*4882a593Smuzhiyun 		     pind++) {
1557*4882a593Smuzhiyun 			/* get curr PKT len & type */
1558*4882a593Smuzhiyun 			pkt_len = wlan_le16_to_cpu(*(t_u16 *)&curr_ptr[0]);
1559*4882a593Smuzhiyun 			pkt_type = wlan_le16_to_cpu(*(t_u16 *)&curr_ptr[2]);
1560*4882a593Smuzhiyun 
1561*4882a593Smuzhiyun 			PRINTM(MINFO, "RX: [%d] pktlen: %d pkt_type: 0x%x\n",
1562*4882a593Smuzhiyun 			       pind, pkt_len, pkt_type);
1563*4882a593Smuzhiyun 
1564*4882a593Smuzhiyun 			/* copy pkt to deaggr buf */
1565*4882a593Smuzhiyun 			mbuf_deaggr =
1566*4882a593Smuzhiyun 				pmadapter->pcard_sd->mpa_rx.mbuf_arr[pind];
1567*4882a593Smuzhiyun 			if ((pkt_type == MLAN_TYPE_DATA ||
1568*4882a593Smuzhiyun 			     pkt_type == MLAN_TYPE_SPA_DATA) &&
1569*4882a593Smuzhiyun 			    (pkt_len <=
1570*4882a593Smuzhiyun 			     pmadapter->pcard_sd->mpa_rx.len_arr[pind])) {
1571*4882a593Smuzhiyun 				memcpy_ext(pmadapter,
1572*4882a593Smuzhiyun 					   mbuf_deaggr->pbuf +
1573*4882a593Smuzhiyun 						   mbuf_deaggr->data_offset,
1574*4882a593Smuzhiyun 					   curr_ptr, pkt_len, pkt_len);
1575*4882a593Smuzhiyun 				pmadapter->upld_len = pkt_len;
1576*4882a593Smuzhiyun 				/* Process de-aggr packet */
1577*4882a593Smuzhiyun 				wlan_decode_rx_packet(pmadapter, mbuf_deaggr,
1578*4882a593Smuzhiyun 						      pkt_type, MFALSE);
1579*4882a593Smuzhiyun 			} else {
1580*4882a593Smuzhiyun 				PRINTM(MERROR,
1581*4882a593Smuzhiyun 				       "Wrong aggr packet: type=%d, len=%d, max_len=%d\n",
1582*4882a593Smuzhiyun 				       pkt_type, pkt_len,
1583*4882a593Smuzhiyun 				       pmadapter->pcard_sd->mpa_rx
1584*4882a593Smuzhiyun 					       .len_arr[pind]);
1585*4882a593Smuzhiyun 				wlan_free_mlan_buffer(pmadapter, mbuf_deaggr);
1586*4882a593Smuzhiyun 			}
1587*4882a593Smuzhiyun 			curr_ptr += pmadapter->pcard_sd->mpa_rx.len_arr[pind];
1588*4882a593Smuzhiyun 		}
1589*4882a593Smuzhiyun 	}
1590*4882a593Smuzhiyun 	if (pmadapter->rx_work_flag)
1591*4882a593Smuzhiyun 		pmadapter->callbacks.moal_spin_unlock(
1592*4882a593Smuzhiyun 			pmadapter->pmoal_handle,
1593*4882a593Smuzhiyun 			pmadapter->rx_data_queue.plock);
1594*4882a593Smuzhiyun 	pmadapter->pcard_sd
1595*4882a593Smuzhiyun 		->mpa_rx_count[pmadapter->pcard_sd->mpa_rx.pkt_cnt - 1]++;
1596*4882a593Smuzhiyun 	MP_RX_AGGR_BUF_RESET(pmadapter);
1597*4882a593Smuzhiyun done:
1598*4882a593Smuzhiyun 	return ret;
1599*4882a593Smuzhiyun }
1600*4882a593Smuzhiyun 
1601*4882a593Smuzhiyun /**
1602*4882a593Smuzhiyun  *  @brief This function receives data from the card in aggregate mode.
1603*4882a593Smuzhiyun  *
1604*4882a593Smuzhiyun  *  @param pmadapter A pointer to mlan_adapter structure
1605*4882a593Smuzhiyun  *  @param pmbuf      A pointer to the SDIO data/cmd buffer
1606*4882a593Smuzhiyun  *  @param port      Current port on which packet needs to be rxed
1607*4882a593Smuzhiyun  *  @param rx_len    Length of received packet
1608*4882a593Smuzhiyun  *  @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1609*4882a593Smuzhiyun  */
wlan_sdio_card_to_host_mp_aggr(mlan_adapter * pmadapter,mlan_buffer * pmbuf,t_u8 port,t_u16 rx_len)1610*4882a593Smuzhiyun static mlan_status wlan_sdio_card_to_host_mp_aggr(mlan_adapter *pmadapter,
1611*4882a593Smuzhiyun 						  mlan_buffer *pmbuf, t_u8 port,
1612*4882a593Smuzhiyun 						  t_u16 rx_len)
1613*4882a593Smuzhiyun {
1614*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
1615*4882a593Smuzhiyun 	t_s32 f_do_rx_aggr = 0;
1616*4882a593Smuzhiyun 	t_s32 f_do_rx_cur = 0;
1617*4882a593Smuzhiyun 	t_s32 f_aggr_cur = 0;
1618*4882a593Smuzhiyun 	t_s32 f_post_aggr_cur = 0;
1619*4882a593Smuzhiyun 	t_u32 pind = 0;
1620*4882a593Smuzhiyun 	t_u32 pkt_type = 0;
1621*4882a593Smuzhiyun 	const mlan_sdio_card_reg *reg = pmadapter->pcard_sd->reg;
1622*4882a593Smuzhiyun 	t_bool new_mode = pmadapter->pcard_sd->supports_sdio_new_mode;
1623*4882a593Smuzhiyun 
1624*4882a593Smuzhiyun 	ENTER();
1625*4882a593Smuzhiyun 	if (!new_mode && (port == CTRL_PORT)) {
1626*4882a593Smuzhiyun 		/* Read the command response or event without aggr */
1627*4882a593Smuzhiyun 		PRINTM(MINFO,
1628*4882a593Smuzhiyun 		       "card_2_host_mp_aggr: No aggr for control port\n");
1629*4882a593Smuzhiyun 
1630*4882a593Smuzhiyun 		f_do_rx_cur = 1;
1631*4882a593Smuzhiyun 		goto rx_curr_single;
1632*4882a593Smuzhiyun 	}
1633*4882a593Smuzhiyun 
1634*4882a593Smuzhiyun 	if (!pmadapter->pcard_sd->mpa_rx.enabled) {
1635*4882a593Smuzhiyun 		PRINTM(MINFO,
1636*4882a593Smuzhiyun 		       "card_2_host_mp_aggr: rx aggregation disabled !\n");
1637*4882a593Smuzhiyun 
1638*4882a593Smuzhiyun 		f_do_rx_cur = 1;
1639*4882a593Smuzhiyun 		goto rx_curr_single;
1640*4882a593Smuzhiyun 	}
1641*4882a593Smuzhiyun 	if ((new_mode &&
1642*4882a593Smuzhiyun 	     (pmadapter->pcard_sd->mp_rd_bitmap & reg->data_port_mask)) ||
1643*4882a593Smuzhiyun 	    (!new_mode && (pmadapter->pcard_sd->mp_rd_bitmap &
1644*4882a593Smuzhiyun 			   (~((t_u32)CTRL_PORT_MASK))))) {
1645*4882a593Smuzhiyun 		/* Some more data RX pending */
1646*4882a593Smuzhiyun 		PRINTM(MINFO, "card_2_host_mp_aggr: Not last packet\n");
1647*4882a593Smuzhiyun 
1648*4882a593Smuzhiyun 		if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) {
1649*4882a593Smuzhiyun 			if (MP_RX_AGGR_BUF_HAS_ROOM(pmadapter, rx_len)) {
1650*4882a593Smuzhiyun 				f_aggr_cur = 1;
1651*4882a593Smuzhiyun 			} else {
1652*4882a593Smuzhiyun 				/* No room in Aggr buf, do rx aggr now */
1653*4882a593Smuzhiyun 				f_do_rx_aggr = 1;
1654*4882a593Smuzhiyun 				f_post_aggr_cur = 1;
1655*4882a593Smuzhiyun 			}
1656*4882a593Smuzhiyun 		} else {
1657*4882a593Smuzhiyun 			/* Rx aggr not in progress */
1658*4882a593Smuzhiyun 			f_aggr_cur = 1;
1659*4882a593Smuzhiyun 		}
1660*4882a593Smuzhiyun 
1661*4882a593Smuzhiyun 	} else {
1662*4882a593Smuzhiyun 		/* No more data RX pending */
1663*4882a593Smuzhiyun 		PRINTM(MINFO, "card_2_host_mp_aggr: Last packet\n");
1664*4882a593Smuzhiyun 
1665*4882a593Smuzhiyun 		if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) {
1666*4882a593Smuzhiyun 			f_do_rx_aggr = 1;
1667*4882a593Smuzhiyun 			if (MP_RX_AGGR_BUF_HAS_ROOM(pmadapter, rx_len)) {
1668*4882a593Smuzhiyun 				f_aggr_cur = 1;
1669*4882a593Smuzhiyun 			} else {
1670*4882a593Smuzhiyun 				/* No room in Aggr buf, do rx aggr now */
1671*4882a593Smuzhiyun 				f_do_rx_cur = 1;
1672*4882a593Smuzhiyun 			}
1673*4882a593Smuzhiyun 		} else {
1674*4882a593Smuzhiyun 			f_do_rx_cur = 1;
1675*4882a593Smuzhiyun 		}
1676*4882a593Smuzhiyun 	}
1677*4882a593Smuzhiyun 
1678*4882a593Smuzhiyun 	if (f_aggr_cur) {
1679*4882a593Smuzhiyun 		PRINTM(MINFO, "Current packet aggregation.\n");
1680*4882a593Smuzhiyun 		/* Curr pkt can be aggregated */
1681*4882a593Smuzhiyun 		if (new_mode)
1682*4882a593Smuzhiyun 			MP_RX_AGGR_SETUP(pmadapter, pmbuf, port, rx_len);
1683*4882a593Smuzhiyun 		else
1684*4882a593Smuzhiyun 			MP_RX_AGGR_SETUP_NONEWMODE(pmadapter, pmbuf, port,
1685*4882a593Smuzhiyun 						   rx_len);
1686*4882a593Smuzhiyun 		if (MP_RX_AGGR_PKT_LIMIT_REACHED(pmadapter) ||
1687*4882a593Smuzhiyun 		    ((new_mode && MP_RX_AGGR_PORT_LIMIT_REACHED(pmadapter)) ||
1688*4882a593Smuzhiyun 		     (!new_mode &&
1689*4882a593Smuzhiyun 		      MP_RX_AGGR_PORT_LIMIT_REACHED_NONEWMODE(pmadapter)))) {
1690*4882a593Smuzhiyun 			PRINTM(MINFO,
1691*4882a593Smuzhiyun 			       "card_2_host_mp_aggr: Aggregation Packet limit reached\n");
1692*4882a593Smuzhiyun 			/* No more pkts allowed in Aggr buf, rx it */
1693*4882a593Smuzhiyun 			f_do_rx_aggr = 1;
1694*4882a593Smuzhiyun 		}
1695*4882a593Smuzhiyun 	}
1696*4882a593Smuzhiyun 
1697*4882a593Smuzhiyun 	if (f_do_rx_aggr) {
1698*4882a593Smuzhiyun 		/* do aggr RX now */
1699*4882a593Smuzhiyun 		if (MLAN_STATUS_SUCCESS !=
1700*4882a593Smuzhiyun 		    wlan_receive_mp_aggr_buf(pmadapter)) {
1701*4882a593Smuzhiyun 			ret = MLAN_STATUS_FAILURE;
1702*4882a593Smuzhiyun 			goto done;
1703*4882a593Smuzhiyun 		}
1704*4882a593Smuzhiyun 	}
1705*4882a593Smuzhiyun rx_curr_single:
1706*4882a593Smuzhiyun 	if (f_do_rx_cur) {
1707*4882a593Smuzhiyun 		PRINTM(MINFO, "RX: f_do_rx_cur: port: %d rx_len: %d\n", port,
1708*4882a593Smuzhiyun 		       rx_len);
1709*4882a593Smuzhiyun 
1710*4882a593Smuzhiyun 		if (MLAN_STATUS_SUCCESS !=
1711*4882a593Smuzhiyun 		    wlan_sdio_card_to_host(
1712*4882a593Smuzhiyun 			    pmadapter, &pkt_type, (t_u32 *)&pmadapter->upld_len,
1713*4882a593Smuzhiyun 			    pmbuf, rx_len,
1714*4882a593Smuzhiyun 			    pmadapter->pcard_sd->ioport + port)) {
1715*4882a593Smuzhiyun 			ret = MLAN_STATUS_FAILURE;
1716*4882a593Smuzhiyun 			goto done;
1717*4882a593Smuzhiyun 		}
1718*4882a593Smuzhiyun 		if (!new_mode &&
1719*4882a593Smuzhiyun 		    ((port == CTRL_PORT) && ((pkt_type != MLAN_TYPE_EVENT) &&
1720*4882a593Smuzhiyun 					     (pkt_type != MLAN_TYPE_CMD)))) {
1721*4882a593Smuzhiyun 			PRINTM(MERROR,
1722*4882a593Smuzhiyun 			       "Wrong pkt from CTRL PORT: type=%d, len=%dd\n",
1723*4882a593Smuzhiyun 			       pkt_type, pmbuf->data_len);
1724*4882a593Smuzhiyun 			pmbuf->status_code = MLAN_ERROR_DATA_RX_FAIL;
1725*4882a593Smuzhiyun 			ret = MLAN_STATUS_FAILURE;
1726*4882a593Smuzhiyun 			goto done;
1727*4882a593Smuzhiyun 		}
1728*4882a593Smuzhiyun 		if (new_mode || (port != CTRL_PORT)) {
1729*4882a593Smuzhiyun 			if (pkt_type != MLAN_TYPE_DATA &&
1730*4882a593Smuzhiyun 			    pkt_type != MLAN_TYPE_SPA_DATA) {
1731*4882a593Smuzhiyun 				PRINTM(MERROR,
1732*4882a593Smuzhiyun 				       "receive a wrong pkt from DATA PORT: type=%d, len=%dd\n",
1733*4882a593Smuzhiyun 				       pkt_type, pmbuf->data_len);
1734*4882a593Smuzhiyun 				pmbuf->status_code = MLAN_ERROR_DATA_RX_FAIL;
1735*4882a593Smuzhiyun 				ret = MLAN_STATUS_FAILURE;
1736*4882a593Smuzhiyun 				goto done;
1737*4882a593Smuzhiyun 			}
1738*4882a593Smuzhiyun 		}
1739*4882a593Smuzhiyun 
1740*4882a593Smuzhiyun 		if (new_mode || (port != CTRL_PORT))
1741*4882a593Smuzhiyun 			pmadapter->pcard_sd->mpa_rx_count[0]++;
1742*4882a593Smuzhiyun 
1743*4882a593Smuzhiyun 		wlan_decode_rx_packet(pmadapter, pmbuf, pkt_type, MTRUE);
1744*4882a593Smuzhiyun 	}
1745*4882a593Smuzhiyun 	if (f_post_aggr_cur) {
1746*4882a593Smuzhiyun 		PRINTM(MINFO, "Current packet aggregation.\n");
1747*4882a593Smuzhiyun 		/* Curr pkt can be aggregated */
1748*4882a593Smuzhiyun 		if (new_mode)
1749*4882a593Smuzhiyun 			MP_RX_AGGR_SETUP(pmadapter, pmbuf, port, rx_len);
1750*4882a593Smuzhiyun 		else
1751*4882a593Smuzhiyun 			MP_RX_AGGR_SETUP_NONEWMODE(pmadapter, pmbuf, port,
1752*4882a593Smuzhiyun 						   rx_len);
1753*4882a593Smuzhiyun 	}
1754*4882a593Smuzhiyun done:
1755*4882a593Smuzhiyun 	if (ret == MLAN_STATUS_FAILURE) {
1756*4882a593Smuzhiyun 		if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) {
1757*4882a593Smuzhiyun 			/* MP-A transfer failed - cleanup */
1758*4882a593Smuzhiyun 			for (pind = 0;
1759*4882a593Smuzhiyun 			     pind < pmadapter->pcard_sd->mpa_rx.pkt_cnt;
1760*4882a593Smuzhiyun 			     pind++) {
1761*4882a593Smuzhiyun 				wlan_free_mlan_buffer(
1762*4882a593Smuzhiyun 					pmadapter, pmadapter->pcard_sd->mpa_rx
1763*4882a593Smuzhiyun 							   .mbuf_arr[pind]);
1764*4882a593Smuzhiyun 			}
1765*4882a593Smuzhiyun 			MP_RX_AGGR_BUF_RESET(pmadapter);
1766*4882a593Smuzhiyun 		}
1767*4882a593Smuzhiyun 
1768*4882a593Smuzhiyun 		if (f_do_rx_cur) {
1769*4882a593Smuzhiyun 			/* Single Transfer pending */
1770*4882a593Smuzhiyun 			/* Free curr buff also */
1771*4882a593Smuzhiyun 			wlan_free_mlan_buffer(pmadapter, pmbuf);
1772*4882a593Smuzhiyun 		}
1773*4882a593Smuzhiyun 	}
1774*4882a593Smuzhiyun 
1775*4882a593Smuzhiyun 	LEAVE();
1776*4882a593Smuzhiyun 	return ret;
1777*4882a593Smuzhiyun }
1778*4882a593Smuzhiyun 
1779*4882a593Smuzhiyun /**
1780*4882a593Smuzhiyun  *  @brief This function sends aggr buf
1781*4882a593Smuzhiyun  *
1782*4882a593Smuzhiyun  *  @param pmadapter A pointer to mlan_adapter structure
1783*4882a593Smuzhiyun  *  @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1784*4882a593Smuzhiyun  */
wlan_send_mp_aggr_buf(mlan_adapter * pmadapter)1785*4882a593Smuzhiyun mlan_status wlan_send_mp_aggr_buf(mlan_adapter *pmadapter)
1786*4882a593Smuzhiyun {
1787*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
1788*4882a593Smuzhiyun 	t_u32 cmd53_port = 0;
1789*4882a593Smuzhiyun 	t_u32 port_count = 0;
1790*4882a593Smuzhiyun 	mlan_buffer mbuf_aggr;
1791*4882a593Smuzhiyun 	t_u8 i = 0;
1792*4882a593Smuzhiyun 	t_u8 mp_aggr_pkt_limit = pmadapter->pcard_sd->mp_aggr_pkt_limit;
1793*4882a593Smuzhiyun 	t_bool new_mode = pmadapter->pcard_sd->supports_sdio_new_mode;
1794*4882a593Smuzhiyun 
1795*4882a593Smuzhiyun 	ENTER();
1796*4882a593Smuzhiyun 
1797*4882a593Smuzhiyun 	if (!pmadapter->pcard_sd->mpa_tx.pkt_cnt) {
1798*4882a593Smuzhiyun 		LEAVE();
1799*4882a593Smuzhiyun 		return ret;
1800*4882a593Smuzhiyun 	}
1801*4882a593Smuzhiyun 	PRINTM(MINFO,
1802*4882a593Smuzhiyun 	       "host_2_card_mp_aggr: Send aggregation buffer."
1803*4882a593Smuzhiyun 	       "%d %d\n",
1804*4882a593Smuzhiyun 	       pmadapter->pcard_sd->mpa_tx.start_port,
1805*4882a593Smuzhiyun 	       pmadapter->pcard_sd->mpa_tx.ports);
1806*4882a593Smuzhiyun 
1807*4882a593Smuzhiyun 	memset(pmadapter, &mbuf_aggr, 0, sizeof(mlan_buffer));
1808*4882a593Smuzhiyun 
1809*4882a593Smuzhiyun 	if (!pmadapter->pcard_sd->mpa_tx.buf &&
1810*4882a593Smuzhiyun 	    pmadapter->pcard_sd->mpa_tx.pkt_cnt > 1) {
1811*4882a593Smuzhiyun 		mbuf_aggr.data_len = pmadapter->pcard_sd->mpa_tx.buf_len;
1812*4882a593Smuzhiyun 		mbuf_aggr.pnext = mbuf_aggr.pprev = &mbuf_aggr;
1813*4882a593Smuzhiyun 		mbuf_aggr.use_count = 0;
1814*4882a593Smuzhiyun 		for (i = 0; i < pmadapter->pcard_sd->mpa_tx.pkt_cnt; i++)
1815*4882a593Smuzhiyun 			wlan_link_buf_to_aggr(
1816*4882a593Smuzhiyun 				&mbuf_aggr,
1817*4882a593Smuzhiyun 				pmadapter->pcard_sd->mpa_tx.mbuf_arr[i]);
1818*4882a593Smuzhiyun 	} else {
1819*4882a593Smuzhiyun 		mbuf_aggr.pbuf = (t_u8 *)pmadapter->pcard_sd->mpa_tx.buf;
1820*4882a593Smuzhiyun 		mbuf_aggr.data_len = pmadapter->pcard_sd->mpa_tx.buf_len;
1821*4882a593Smuzhiyun 	}
1822*4882a593Smuzhiyun 
1823*4882a593Smuzhiyun 	if (new_mode) {
1824*4882a593Smuzhiyun 		port_count = bitcount(pmadapter->pcard_sd->mpa_tx.ports) - 1;
1825*4882a593Smuzhiyun 		cmd53_port = (pmadapter->pcard_sd->ioport | SDIO_MPA_ADDR_BASE |
1826*4882a593Smuzhiyun 			      (port_count << 8)) +
1827*4882a593Smuzhiyun 			     pmadapter->pcard_sd->mpa_tx.start_port;
1828*4882a593Smuzhiyun 	} else {
1829*4882a593Smuzhiyun 		cmd53_port = (pmadapter->pcard_sd->ioport | SDIO_MPA_ADDR_BASE |
1830*4882a593Smuzhiyun 			      (pmadapter->pcard_sd->mpa_tx.ports << 4)) +
1831*4882a593Smuzhiyun 			     pmadapter->pcard_sd->mpa_tx.start_port;
1832*4882a593Smuzhiyun 	}
1833*4882a593Smuzhiyun 	if (pmadapter->pcard_sd->mpa_tx.pkt_cnt == 1)
1834*4882a593Smuzhiyun 		cmd53_port = pmadapter->pcard_sd->ioport +
1835*4882a593Smuzhiyun 			     pmadapter->pcard_sd->mpa_tx.start_port;
1836*4882a593Smuzhiyun 	/** only one packet */
1837*4882a593Smuzhiyun 	if (!pmadapter->pcard_sd->mpa_tx.buf &&
1838*4882a593Smuzhiyun 	    pmadapter->pcard_sd->mpa_tx.pkt_cnt == 1)
1839*4882a593Smuzhiyun 		ret = wlan_write_data_sync(
1840*4882a593Smuzhiyun 			pmadapter, pmadapter->pcard_sd->mpa_tx.mbuf_arr[0],
1841*4882a593Smuzhiyun 			cmd53_port);
1842*4882a593Smuzhiyun 	else
1843*4882a593Smuzhiyun 		ret = wlan_write_data_sync(pmadapter, &mbuf_aggr, cmd53_port);
1844*4882a593Smuzhiyun 	if (!pmadapter->pcard_sd->mpa_tx.buf) {
1845*4882a593Smuzhiyun 		/** free mlan buffer */
1846*4882a593Smuzhiyun 		for (i = 0; i < pmadapter->pcard_sd->mpa_tx.pkt_cnt; i++) {
1847*4882a593Smuzhiyun 			wlan_write_data_complete(
1848*4882a593Smuzhiyun 				pmadapter,
1849*4882a593Smuzhiyun 				pmadapter->pcard_sd->mpa_tx.mbuf_arr[i],
1850*4882a593Smuzhiyun 				MLAN_STATUS_SUCCESS);
1851*4882a593Smuzhiyun 		}
1852*4882a593Smuzhiyun 	}
1853*4882a593Smuzhiyun 	if (!(pmadapter->pcard_sd->mp_wr_bitmap &
1854*4882a593Smuzhiyun 	      (1 << pmadapter->pcard_sd->curr_wr_port)) &&
1855*4882a593Smuzhiyun 	    (pmadapter->pcard_sd->mpa_tx.pkt_cnt < mp_aggr_pkt_limit))
1856*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_sent_no_ports++;
1857*4882a593Smuzhiyun 	pmadapter->pcard_sd
1858*4882a593Smuzhiyun 		->mpa_tx_count[pmadapter->pcard_sd->mpa_tx.pkt_cnt - 1]++;
1859*4882a593Smuzhiyun 	pmadapter->pcard_sd
1860*4882a593Smuzhiyun 		->last_mp_wr_bitmap[pmadapter->pcard_sd->last_mp_index] =
1861*4882a593Smuzhiyun 		pmadapter->pcard_sd->mp_wr_bitmap;
1862*4882a593Smuzhiyun 	pmadapter->pcard_sd
1863*4882a593Smuzhiyun 		->last_mp_wr_ports[pmadapter->pcard_sd->last_mp_index] =
1864*4882a593Smuzhiyun 		cmd53_port;
1865*4882a593Smuzhiyun 	pmadapter->pcard_sd->last_mp_wr_len[pmadapter->pcard_sd->last_mp_index] =
1866*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_tx.buf_len;
1867*4882a593Smuzhiyun 	pmadapter->pcard_sd
1868*4882a593Smuzhiyun 		->last_curr_wr_port[pmadapter->pcard_sd->last_mp_index] =
1869*4882a593Smuzhiyun 		pmadapter->pcard_sd->curr_wr_port;
1870*4882a593Smuzhiyun 	memcpy_ext(
1871*4882a593Smuzhiyun 		pmadapter,
1872*4882a593Smuzhiyun 		(t_u8 *)&pmadapter->pcard_sd
1873*4882a593Smuzhiyun 			->last_mp_wr_info[pmadapter->pcard_sd->last_mp_index *
1874*4882a593Smuzhiyun 					  mp_aggr_pkt_limit],
1875*4882a593Smuzhiyun 		(t_u8 *)pmadapter->pcard_sd->mpa_tx.mp_wr_info,
1876*4882a593Smuzhiyun 		mp_aggr_pkt_limit * sizeof(t_u16),
1877*4882a593Smuzhiyun 		mp_aggr_pkt_limit * sizeof(t_u16));
1878*4882a593Smuzhiyun 	pmadapter->pcard_sd->last_mp_index++;
1879*4882a593Smuzhiyun 	if (pmadapter->pcard_sd->last_mp_index >= SDIO_MP_DBG_NUM)
1880*4882a593Smuzhiyun 		pmadapter->pcard_sd->last_mp_index = 0;
1881*4882a593Smuzhiyun 	MP_TX_AGGR_BUF_RESET(pmadapter);
1882*4882a593Smuzhiyun 	LEAVE();
1883*4882a593Smuzhiyun 	return ret;
1884*4882a593Smuzhiyun }
1885*4882a593Smuzhiyun 
1886*4882a593Smuzhiyun /**
1887*4882a593Smuzhiyun  *  @brief This function sends data to the card in SDIO aggregated mode.
1888*4882a593Smuzhiyun  *
1889*4882a593Smuzhiyun  *  @param pmadapter A pointer to mlan_adapter structure
1890*4882a593Smuzhiyun  *  @param mbuf      A pointer to the SDIO data/cmd buffer
1891*4882a593Smuzhiyun  *  @param port	     current port for aggregation
1892*4882a593Smuzhiyun  *  @param next_pkt_len Length of next packet used for multiport aggregation
1893*4882a593Smuzhiyun  *  @return         MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1894*4882a593Smuzhiyun  */
wlan_host_to_card_mp_aggr(mlan_adapter * pmadapter,mlan_buffer * mbuf,t_u8 port,t_u32 next_pkt_len)1895*4882a593Smuzhiyun static mlan_status wlan_host_to_card_mp_aggr(mlan_adapter *pmadapter,
1896*4882a593Smuzhiyun 					     mlan_buffer *mbuf, t_u8 port,
1897*4882a593Smuzhiyun 					     t_u32 next_pkt_len)
1898*4882a593Smuzhiyun {
1899*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
1900*4882a593Smuzhiyun 	t_s32 f_send_aggr_buf = 0;
1901*4882a593Smuzhiyun 	t_s32 f_send_cur_buf = 0;
1902*4882a593Smuzhiyun 	t_s32 f_precopy_cur_buf = 0;
1903*4882a593Smuzhiyun 	t_s32 f_postcopy_cur_buf = 0;
1904*4882a593Smuzhiyun 	t_u8 aggr_sg = 0;
1905*4882a593Smuzhiyun 	t_u8 mp_aggr_pkt_limit = pmadapter->pcard_sd->mp_aggr_pkt_limit;
1906*4882a593Smuzhiyun 	t_bool new_mode = pmadapter->pcard_sd->supports_sdio_new_mode;
1907*4882a593Smuzhiyun 
1908*4882a593Smuzhiyun 	ENTER();
1909*4882a593Smuzhiyun 
1910*4882a593Smuzhiyun 	PRINTM(MIF_D, "host_2_card_mp_aggr: next_pkt_len: %d curr_port:%d\n",
1911*4882a593Smuzhiyun 	       next_pkt_len, port);
1912*4882a593Smuzhiyun 
1913*4882a593Smuzhiyun 	if (!pmadapter->pcard_sd->mpa_tx.enabled) {
1914*4882a593Smuzhiyun 		PRINTM(MINFO,
1915*4882a593Smuzhiyun 		       "host_2_card_mp_aggr: tx aggregation disabled !\n");
1916*4882a593Smuzhiyun 		f_send_cur_buf = 1;
1917*4882a593Smuzhiyun 		goto tx_curr_single;
1918*4882a593Smuzhiyun 	}
1919*4882a593Smuzhiyun 
1920*4882a593Smuzhiyun 	if (next_pkt_len) {
1921*4882a593Smuzhiyun 		/* More pkt in TX queue */
1922*4882a593Smuzhiyun 		PRINTM(MINFO, "host_2_card_mp_aggr: More packets in Queue.\n");
1923*4882a593Smuzhiyun 
1924*4882a593Smuzhiyun 		if (MP_TX_AGGR_IN_PROGRESS(pmadapter)) {
1925*4882a593Smuzhiyun 			if (MP_TX_AGGR_BUF_HAS_ROOM(pmadapter, mbuf,
1926*4882a593Smuzhiyun 						    mbuf->data_len)) {
1927*4882a593Smuzhiyun 				f_precopy_cur_buf = 1;
1928*4882a593Smuzhiyun 
1929*4882a593Smuzhiyun 				if (!(pmadapter->pcard_sd->mp_wr_bitmap &
1930*4882a593Smuzhiyun 				      (1
1931*4882a593Smuzhiyun 				       << pmadapter->pcard_sd->curr_wr_port)) ||
1932*4882a593Smuzhiyun 				    !MP_TX_AGGR_BUF_HAS_ROOM(
1933*4882a593Smuzhiyun 					    pmadapter, mbuf,
1934*4882a593Smuzhiyun 					    mbuf->data_len + next_pkt_len)) {
1935*4882a593Smuzhiyun 					f_send_aggr_buf = 1;
1936*4882a593Smuzhiyun 				}
1937*4882a593Smuzhiyun 			} else {
1938*4882a593Smuzhiyun 				/* No room in Aggr buf, send it */
1939*4882a593Smuzhiyun 				f_send_aggr_buf = 1;
1940*4882a593Smuzhiyun 
1941*4882a593Smuzhiyun 				if (!(pmadapter->pcard_sd->mp_wr_bitmap &
1942*4882a593Smuzhiyun 				      (1
1943*4882a593Smuzhiyun 				       << pmadapter->pcard_sd->curr_wr_port))) {
1944*4882a593Smuzhiyun 					f_send_cur_buf = 1;
1945*4882a593Smuzhiyun 				} else {
1946*4882a593Smuzhiyun 					f_postcopy_cur_buf = 1;
1947*4882a593Smuzhiyun 				}
1948*4882a593Smuzhiyun 			}
1949*4882a593Smuzhiyun 		} else {
1950*4882a593Smuzhiyun 			if (MP_TX_AGGR_BUF_HAS_ROOM(pmadapter, mbuf,
1951*4882a593Smuzhiyun 						    mbuf->data_len) &&
1952*4882a593Smuzhiyun 			    (pmadapter->pcard_sd->mp_wr_bitmap &
1953*4882a593Smuzhiyun 			     (1 << pmadapter->pcard_sd->curr_wr_port)))
1954*4882a593Smuzhiyun 				f_precopy_cur_buf = 1;
1955*4882a593Smuzhiyun 			else
1956*4882a593Smuzhiyun 				f_send_cur_buf = 1;
1957*4882a593Smuzhiyun 		}
1958*4882a593Smuzhiyun 	} else {
1959*4882a593Smuzhiyun 		/* Last pkt in TX queue */
1960*4882a593Smuzhiyun 		PRINTM(MINFO,
1961*4882a593Smuzhiyun 		       "host_2_card_mp_aggr: Last packet in Tx Queue.\n");
1962*4882a593Smuzhiyun 
1963*4882a593Smuzhiyun 		if (MP_TX_AGGR_IN_PROGRESS(pmadapter)) {
1964*4882a593Smuzhiyun 			/* some packs in Aggr buf already */
1965*4882a593Smuzhiyun 			f_send_aggr_buf = 1;
1966*4882a593Smuzhiyun 
1967*4882a593Smuzhiyun 			if (MP_TX_AGGR_BUF_HAS_ROOM(pmadapter, mbuf,
1968*4882a593Smuzhiyun 						    mbuf->data_len)) {
1969*4882a593Smuzhiyun 				f_precopy_cur_buf = 1;
1970*4882a593Smuzhiyun 			} else {
1971*4882a593Smuzhiyun 				/* No room in Aggr buf, send it */
1972*4882a593Smuzhiyun 				f_send_cur_buf = 1;
1973*4882a593Smuzhiyun 			}
1974*4882a593Smuzhiyun 		} else {
1975*4882a593Smuzhiyun 			f_send_cur_buf = 1;
1976*4882a593Smuzhiyun 		}
1977*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_sent_last_pkt++;
1978*4882a593Smuzhiyun 	}
1979*4882a593Smuzhiyun 
1980*4882a593Smuzhiyun 	if (f_precopy_cur_buf) {
1981*4882a593Smuzhiyun 		PRINTM(MINFO, "host_2_card_mp_aggr: Precopy current buffer\n");
1982*4882a593Smuzhiyun 		if (pmadapter->pcard_sd->mpa_buf)
1983*4882a593Smuzhiyun 			memcpy_ext(
1984*4882a593Smuzhiyun 				pmadapter,
1985*4882a593Smuzhiyun 				pmadapter->pcard_sd->mpa_buf +
1986*4882a593Smuzhiyun 					(pmadapter->pcard_sd->last_mp_index *
1987*4882a593Smuzhiyun 						 mp_aggr_pkt_limit +
1988*4882a593Smuzhiyun 					 pmadapter->pcard_sd->mpa_tx.pkt_cnt) *
1989*4882a593Smuzhiyun 						MLAN_SDIO_BLOCK_SIZE,
1990*4882a593Smuzhiyun 				mbuf->pbuf + mbuf->data_offset,
1991*4882a593Smuzhiyun 				MLAN_SDIO_BLOCK_SIZE, MLAN_SDIO_BLOCK_SIZE);
1992*4882a593Smuzhiyun 		if (!pmadapter->pcard_sd->mpa_tx.buf) {
1993*4882a593Smuzhiyun 			if (new_mode)
1994*4882a593Smuzhiyun 				MP_TX_AGGR_BUF_PUT_SG(pmadapter, mbuf, port);
1995*4882a593Smuzhiyun 			else
1996*4882a593Smuzhiyun 				MP_TX_AGGR_BUF_PUT_SG_NONEWMODE(pmadapter, mbuf,
1997*4882a593Smuzhiyun 								port);
1998*4882a593Smuzhiyun 			aggr_sg = MTRUE;
1999*4882a593Smuzhiyun 		} else {
2000*4882a593Smuzhiyun 			if (new_mode)
2001*4882a593Smuzhiyun 				MP_TX_AGGR_BUF_PUT(pmadapter, mbuf, port);
2002*4882a593Smuzhiyun 			else
2003*4882a593Smuzhiyun 				MP_TX_AGGR_BUF_PUT_NONEWMODE(pmadapter, mbuf,
2004*4882a593Smuzhiyun 							     port);
2005*4882a593Smuzhiyun 		}
2006*4882a593Smuzhiyun 		if (MP_TX_AGGR_PKT_LIMIT_REACHED(pmadapter) ||
2007*4882a593Smuzhiyun 		    (!new_mode && MP_TX_AGGR_PORT_LIMIT_REACHED(pmadapter))) {
2008*4882a593Smuzhiyun 			PRINTM(MIF_D,
2009*4882a593Smuzhiyun 			       "host_2_card_mp_aggr: Aggregation Pkt limit reached\n");
2010*4882a593Smuzhiyun 			/* No more pkts allowed in Aggr buf, send it */
2011*4882a593Smuzhiyun 			f_send_aggr_buf = 1;
2012*4882a593Smuzhiyun 		}
2013*4882a593Smuzhiyun 	}
2014*4882a593Smuzhiyun 
2015*4882a593Smuzhiyun 	if (f_send_aggr_buf)
2016*4882a593Smuzhiyun 		ret = wlan_send_mp_aggr_buf(pmadapter);
2017*4882a593Smuzhiyun 
2018*4882a593Smuzhiyun tx_curr_single:
2019*4882a593Smuzhiyun 	if (f_send_cur_buf) {
2020*4882a593Smuzhiyun 		PRINTM(MINFO, "host_2_card_mp_aggr: writing to port #%d\n",
2021*4882a593Smuzhiyun 		       port);
2022*4882a593Smuzhiyun 		ret = wlan_write_data_sync(pmadapter, mbuf,
2023*4882a593Smuzhiyun 					   pmadapter->pcard_sd->ioport + port);
2024*4882a593Smuzhiyun 		if (!(pmadapter->pcard_sd->mp_wr_bitmap &
2025*4882a593Smuzhiyun 		      (1 << pmadapter->pcard_sd->curr_wr_port)))
2026*4882a593Smuzhiyun 			pmadapter->pcard_sd->mpa_sent_no_ports++;
2027*4882a593Smuzhiyun 		pmadapter->pcard_sd
2028*4882a593Smuzhiyun 			->last_mp_wr_bitmap[pmadapter->pcard_sd->last_mp_index] =
2029*4882a593Smuzhiyun 			pmadapter->pcard_sd->mp_wr_bitmap;
2030*4882a593Smuzhiyun 		pmadapter->pcard_sd
2031*4882a593Smuzhiyun 			->last_mp_wr_ports[pmadapter->pcard_sd->last_mp_index] =
2032*4882a593Smuzhiyun 			pmadapter->pcard_sd->ioport + port;
2033*4882a593Smuzhiyun 		pmadapter->pcard_sd
2034*4882a593Smuzhiyun 			->last_mp_wr_len[pmadapter->pcard_sd->last_mp_index] =
2035*4882a593Smuzhiyun 			mbuf->data_len;
2036*4882a593Smuzhiyun 		memset(pmadapter,
2037*4882a593Smuzhiyun 		       (t_u8 *)&pmadapter->pcard_sd->last_mp_wr_info
2038*4882a593Smuzhiyun 			       [pmadapter->pcard_sd->last_mp_index *
2039*4882a593Smuzhiyun 				mp_aggr_pkt_limit],
2040*4882a593Smuzhiyun 		       0, sizeof(t_u16) * mp_aggr_pkt_limit);
2041*4882a593Smuzhiyun 		pmadapter->pcard_sd
2042*4882a593Smuzhiyun 			->last_mp_wr_info[pmadapter->pcard_sd->last_mp_index *
2043*4882a593Smuzhiyun 					  mp_aggr_pkt_limit] =
2044*4882a593Smuzhiyun 			*(t_u16 *)(mbuf->pbuf + mbuf->data_offset);
2045*4882a593Smuzhiyun 		pmadapter->pcard_sd
2046*4882a593Smuzhiyun 			->last_curr_wr_port[pmadapter->pcard_sd->last_mp_index] =
2047*4882a593Smuzhiyun 			pmadapter->pcard_sd->curr_wr_port;
2048*4882a593Smuzhiyun 		if (pmadapter->pcard_sd->mpa_buf)
2049*4882a593Smuzhiyun 			memcpy_ext(pmadapter,
2050*4882a593Smuzhiyun 				   pmadapter->pcard_sd->mpa_buf +
2051*4882a593Smuzhiyun 					   (pmadapter->pcard_sd->last_mp_index *
2052*4882a593Smuzhiyun 					    mp_aggr_pkt_limit *
2053*4882a593Smuzhiyun 					    MLAN_SDIO_BLOCK_SIZE),
2054*4882a593Smuzhiyun 				   mbuf->pbuf + mbuf->data_offset,
2055*4882a593Smuzhiyun 				   MLAN_SDIO_BLOCK_SIZE, MLAN_SDIO_BLOCK_SIZE);
2056*4882a593Smuzhiyun 		pmadapter->pcard_sd->last_mp_index++;
2057*4882a593Smuzhiyun 		if (pmadapter->pcard_sd->last_mp_index >= SDIO_MP_DBG_NUM)
2058*4882a593Smuzhiyun 			pmadapter->pcard_sd->last_mp_index = 0;
2059*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_tx_count[0]++;
2060*4882a593Smuzhiyun 	}
2061*4882a593Smuzhiyun 	if (f_postcopy_cur_buf) {
2062*4882a593Smuzhiyun 		PRINTM(MINFO, "host_2_card_mp_aggr: Postcopy current buffer\n");
2063*4882a593Smuzhiyun 		if (pmadapter->pcard_sd->mpa_buf)
2064*4882a593Smuzhiyun 			memcpy_ext(
2065*4882a593Smuzhiyun 				pmadapter,
2066*4882a593Smuzhiyun 				pmadapter->pcard_sd->mpa_buf +
2067*4882a593Smuzhiyun 					(pmadapter->pcard_sd->last_mp_index *
2068*4882a593Smuzhiyun 						 mp_aggr_pkt_limit +
2069*4882a593Smuzhiyun 					 pmadapter->pcard_sd->mpa_tx.pkt_cnt) *
2070*4882a593Smuzhiyun 						MLAN_SDIO_BLOCK_SIZE,
2071*4882a593Smuzhiyun 				mbuf->pbuf + mbuf->data_offset,
2072*4882a593Smuzhiyun 				MLAN_SDIO_BLOCK_SIZE, MLAN_SDIO_BLOCK_SIZE);
2073*4882a593Smuzhiyun 		if (!pmadapter->pcard_sd->mpa_tx.buf) {
2074*4882a593Smuzhiyun 			if (new_mode)
2075*4882a593Smuzhiyun 				MP_TX_AGGR_BUF_PUT_SG(pmadapter, mbuf, port);
2076*4882a593Smuzhiyun 			else
2077*4882a593Smuzhiyun 				MP_TX_AGGR_BUF_PUT_SG_NONEWMODE(pmadapter, mbuf,
2078*4882a593Smuzhiyun 								port);
2079*4882a593Smuzhiyun 			aggr_sg = MTRUE;
2080*4882a593Smuzhiyun 		} else {
2081*4882a593Smuzhiyun 			if (new_mode)
2082*4882a593Smuzhiyun 				MP_TX_AGGR_BUF_PUT(pmadapter, mbuf, port);
2083*4882a593Smuzhiyun 			else
2084*4882a593Smuzhiyun 				MP_TX_AGGR_BUF_PUT_NONEWMODE(pmadapter, mbuf,
2085*4882a593Smuzhiyun 							     port);
2086*4882a593Smuzhiyun 		}
2087*4882a593Smuzhiyun 	}
2088*4882a593Smuzhiyun 	/* Always return PENDING in SG mode */
2089*4882a593Smuzhiyun 	if (aggr_sg)
2090*4882a593Smuzhiyun 		ret = MLAN_STATUS_PENDING;
2091*4882a593Smuzhiyun 
2092*4882a593Smuzhiyun 	LEAVE();
2093*4882a593Smuzhiyun 	return ret;
2094*4882a593Smuzhiyun }
2095*4882a593Smuzhiyun 
2096*4882a593Smuzhiyun /********************************************************
2097*4882a593Smuzhiyun 		Global functions
2098*4882a593Smuzhiyun ********************************************************/
2099*4882a593Smuzhiyun 
2100*4882a593Smuzhiyun /**
2101*4882a593Smuzhiyun  *  @brief This function checks if the interface is ready to download
2102*4882a593Smuzhiyun  *  or not while other download interface is present
2103*4882a593Smuzhiyun  *
2104*4882a593Smuzhiyun  *  @param pmadapter  A pointer to mlan_adapter structure
2105*4882a593Smuzhiyun  *  @param val        Winner status (0: winner)
2106*4882a593Smuzhiyun  *  @return           MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2107*4882a593Smuzhiyun  *
2108*4882a593Smuzhiyun  */
wlan_sdio_check_winner_status(mlan_adapter * pmadapter,t_u32 * val)2109*4882a593Smuzhiyun static mlan_status wlan_sdio_check_winner_status(mlan_adapter *pmadapter,
2110*4882a593Smuzhiyun 						 t_u32 *val)
2111*4882a593Smuzhiyun {
2112*4882a593Smuzhiyun 	t_u32 winner = 0;
2113*4882a593Smuzhiyun 	pmlan_callbacks pcb;
2114*4882a593Smuzhiyun 	t_u8 card_winner_check_reg = pmadapter->pcard_sd->reg->winner_check_reg;
2115*4882a593Smuzhiyun 
2116*4882a593Smuzhiyun 	ENTER();
2117*4882a593Smuzhiyun 
2118*4882a593Smuzhiyun #ifdef SD8801
2119*4882a593Smuzhiyun 	if (IS_SD8801(pmadapter->card_type)) {
2120*4882a593Smuzhiyun 		*val = 0;
2121*4882a593Smuzhiyun 		return MLAN_STATUS_SUCCESS;
2122*4882a593Smuzhiyun 	}
2123*4882a593Smuzhiyun #endif
2124*4882a593Smuzhiyun 	pcb = &pmadapter->callbacks;
2125*4882a593Smuzhiyun 
2126*4882a593Smuzhiyun 	if (MLAN_STATUS_SUCCESS != pcb->moal_read_reg(pmadapter->pmoal_handle,
2127*4882a593Smuzhiyun 						      card_winner_check_reg,
2128*4882a593Smuzhiyun 						      &winner)) {
2129*4882a593Smuzhiyun 		LEAVE();
2130*4882a593Smuzhiyun 		return MLAN_STATUS_FAILURE;
2131*4882a593Smuzhiyun 	}
2132*4882a593Smuzhiyun 	*val = winner;
2133*4882a593Smuzhiyun 
2134*4882a593Smuzhiyun 	LEAVE();
2135*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
2136*4882a593Smuzhiyun }
2137*4882a593Smuzhiyun 
2138*4882a593Smuzhiyun /**
2139*4882a593Smuzhiyun  *  @brief This function checks if the firmware is ready to accept
2140*4882a593Smuzhiyun  *  command or not.
2141*4882a593Smuzhiyun  *
2142*4882a593Smuzhiyun  *  @param pmadapter  A pointer to mlan_adapter structure
2143*4882a593Smuzhiyun  *  @param pollnum    Maximum polling number
2144*4882a593Smuzhiyun  *  @return           MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2145*4882a593Smuzhiyun  */
wlan_sdio_check_fw_status(mlan_adapter * pmadapter,t_u32 pollnum)2146*4882a593Smuzhiyun static mlan_status wlan_sdio_check_fw_status(mlan_adapter *pmadapter,
2147*4882a593Smuzhiyun 					     t_u32 pollnum)
2148*4882a593Smuzhiyun {
2149*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
2150*4882a593Smuzhiyun 	t_u16 firmwarestat = 0;
2151*4882a593Smuzhiyun 	t_u32 tries;
2152*4882a593Smuzhiyun 
2153*4882a593Smuzhiyun 	ENTER();
2154*4882a593Smuzhiyun 
2155*4882a593Smuzhiyun 	/* Wait for firmware initialization event */
2156*4882a593Smuzhiyun 	for (tries = 0; tries < pollnum; tries++) {
2157*4882a593Smuzhiyun 		ret = wlan_sdio_read_fw_status(pmadapter, &firmwarestat);
2158*4882a593Smuzhiyun 		if (MLAN_STATUS_SUCCESS != ret)
2159*4882a593Smuzhiyun 			continue;
2160*4882a593Smuzhiyun 		if (firmwarestat == SDIO_FIRMWARE_READY) {
2161*4882a593Smuzhiyun 			ret = MLAN_STATUS_SUCCESS;
2162*4882a593Smuzhiyun 			break;
2163*4882a593Smuzhiyun 		} else {
2164*4882a593Smuzhiyun 			wlan_mdelay(pmadapter, 10);
2165*4882a593Smuzhiyun 			ret = MLAN_STATUS_FAILURE;
2166*4882a593Smuzhiyun 		}
2167*4882a593Smuzhiyun 	}
2168*4882a593Smuzhiyun 
2169*4882a593Smuzhiyun 	if (ret != MLAN_STATUS_SUCCESS) {
2170*4882a593Smuzhiyun 		if (pollnum > 1)
2171*4882a593Smuzhiyun 			PRINTM(MERROR,
2172*4882a593Smuzhiyun 			       "Fail to poll firmware status: firmwarestat=0x%x\n",
2173*4882a593Smuzhiyun 			       firmwarestat);
2174*4882a593Smuzhiyun 		goto done;
2175*4882a593Smuzhiyun 	}
2176*4882a593Smuzhiyun 
2177*4882a593Smuzhiyun done:
2178*4882a593Smuzhiyun 	LEAVE();
2179*4882a593Smuzhiyun 	return ret;
2180*4882a593Smuzhiyun }
2181*4882a593Smuzhiyun 
2182*4882a593Smuzhiyun /**
2183*4882a593Smuzhiyun  *  @brief This function enables the host interrupts.
2184*4882a593Smuzhiyun  *
2185*4882a593Smuzhiyun  *  @param pmadapter A pointer to mlan_adapter structure
2186*4882a593Smuzhiyun  *  @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2187*4882a593Smuzhiyun  */
wlan_enable_sdio_host_int(pmlan_adapter pmadapter)2188*4882a593Smuzhiyun static mlan_status wlan_enable_sdio_host_int(pmlan_adapter pmadapter)
2189*4882a593Smuzhiyun {
2190*4882a593Smuzhiyun 	mlan_status ret;
2191*4882a593Smuzhiyun 	t_u8 mask = pmadapter->pcard_sd->reg->host_int_enable;
2192*4882a593Smuzhiyun 
2193*4882a593Smuzhiyun 	ENTER();
2194*4882a593Smuzhiyun 	ret = wlan_sdio_enable_host_int_mask(pmadapter, mask);
2195*4882a593Smuzhiyun 	LEAVE();
2196*4882a593Smuzhiyun 	return ret;
2197*4882a593Smuzhiyun }
2198*4882a593Smuzhiyun 
2199*4882a593Smuzhiyun /**
2200*4882a593Smuzhiyun  *  @brief  This function downloads firmware to card
2201*4882a593Smuzhiyun  *
2202*4882a593Smuzhiyun  *  @param pmadapter	A pointer to mlan_adapter
2203*4882a593Smuzhiyun  *  @param pmfw			A pointer to firmware image
2204*4882a593Smuzhiyun  *
2205*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2206*4882a593Smuzhiyun  */
wlan_sdio_dnld_fw(pmlan_adapter pmadapter,pmlan_fw_image pmfw)2207*4882a593Smuzhiyun static mlan_status wlan_sdio_dnld_fw(pmlan_adapter pmadapter,
2208*4882a593Smuzhiyun 				     pmlan_fw_image pmfw)
2209*4882a593Smuzhiyun {
2210*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
2211*4882a593Smuzhiyun 	t_u32 poll_num = 1;
2212*4882a593Smuzhiyun 	t_u32 winner = 0;
2213*4882a593Smuzhiyun 
2214*4882a593Smuzhiyun 	ENTER();
2215*4882a593Smuzhiyun 
2216*4882a593Smuzhiyun 	/*when using GPIO wakeup, don't run the below code.
2217*4882a593Smuzhiyun 	 *if using GPIO wakeup, host will do handshake with FW
2218*4882a593Smuzhiyun 	 *to check if FW wake up and pull up SDIO line, then reload driver.
2219*4882a593Smuzhiyun 	 *So when using GPIO wakeup, don't need driver to do check wakeup status
2220*4882a593Smuzhiyun 	 *again. when using SDIO interface wakeup, run the below code; if using
2221*4882a593Smuzhiyun 	 *SDIO interface wakeup, driver need to do check wakeup status with FW.
2222*4882a593Smuzhiyun 	 */
2223*4882a593Smuzhiyun 
2224*4882a593Smuzhiyun 	/* Card specific probing */
2225*4882a593Smuzhiyun 	ret = wlan_sdio_probe(pmadapter);
2226*4882a593Smuzhiyun 	if (ret == MLAN_STATUS_FAILURE) {
2227*4882a593Smuzhiyun 		PRINTM(MERROR, "WLAN SDIO probe failed\n", ret);
2228*4882a593Smuzhiyun 		LEAVE();
2229*4882a593Smuzhiyun 		return ret;
2230*4882a593Smuzhiyun 	}
2231*4882a593Smuzhiyun 
2232*4882a593Smuzhiyun 	/* Check if firmware is already running */
2233*4882a593Smuzhiyun 	ret = wlan_sdio_check_fw_status(pmadapter, poll_num);
2234*4882a593Smuzhiyun 	if (ret == MLAN_STATUS_SUCCESS) {
2235*4882a593Smuzhiyun #if defined(SDIO)
2236*4882a593Smuzhiyun 		if (pmfw->fw_reload == FW_RELOAD_SDIO_INBAND_RESET) {
2237*4882a593Smuzhiyun 			PRINTM(MMSG, "Try reset fw in mlan\n");
2238*4882a593Smuzhiyun 			ret = wlan_reset_fw(pmadapter);
2239*4882a593Smuzhiyun 			if (ret == MLAN_STATUS_FAILURE) {
2240*4882a593Smuzhiyun 				PRINTM(MERROR, "FW reset failure!");
2241*4882a593Smuzhiyun 				LEAVE();
2242*4882a593Smuzhiyun 				return ret;
2243*4882a593Smuzhiyun 			}
2244*4882a593Smuzhiyun 		} else {
2245*4882a593Smuzhiyun #endif
2246*4882a593Smuzhiyun 			PRINTM(MMSG,
2247*4882a593Smuzhiyun 			       "WLAN FW already running! Skip FW download\n");
2248*4882a593Smuzhiyun #if defined(SDIO)
2249*4882a593Smuzhiyun 			pmadapter->ops.wakeup_card(pmadapter, MFALSE);
2250*4882a593Smuzhiyun #endif
2251*4882a593Smuzhiyun 			goto done;
2252*4882a593Smuzhiyun #if defined(SDIO)
2253*4882a593Smuzhiyun 		}
2254*4882a593Smuzhiyun #endif
2255*4882a593Smuzhiyun 	}
2256*4882a593Smuzhiyun 	poll_num = MAX_FIRMWARE_POLL_TRIES;
2257*4882a593Smuzhiyun 	/* Check if other interface is downloading */
2258*4882a593Smuzhiyun 	ret = wlan_sdio_check_winner_status(pmadapter, &winner);
2259*4882a593Smuzhiyun 	if (ret == MLAN_STATUS_FAILURE) {
2260*4882a593Smuzhiyun 		PRINTM(MFATAL, "WLAN read winner status failed!\n");
2261*4882a593Smuzhiyun 		goto done;
2262*4882a593Smuzhiyun 	}
2263*4882a593Smuzhiyun 	if (winner) {
2264*4882a593Smuzhiyun 		PRINTM(MMSG,
2265*4882a593Smuzhiyun 		       "WLAN is not the winner (0x%x). Skip FW download\n",
2266*4882a593Smuzhiyun 		       winner);
2267*4882a593Smuzhiyun 		poll_num = MAX_MULTI_INTERFACE_POLL_TRIES;
2268*4882a593Smuzhiyun 		goto poll_fw;
2269*4882a593Smuzhiyun 	}
2270*4882a593Smuzhiyun 
2271*4882a593Smuzhiyun 	/* Download the firmware image via helper */
2272*4882a593Smuzhiyun 	ret = wlan_sdio_prog_fw_w_helper(pmadapter, pmfw->pfw_buf,
2273*4882a593Smuzhiyun 					 pmfw->fw_len);
2274*4882a593Smuzhiyun 	if (ret != MLAN_STATUS_SUCCESS) {
2275*4882a593Smuzhiyun 		PRINTM(MERROR, "wlan_dnld_fw fail ret=0x%x\n", ret);
2276*4882a593Smuzhiyun 		LEAVE();
2277*4882a593Smuzhiyun 		return ret;
2278*4882a593Smuzhiyun 	}
2279*4882a593Smuzhiyun 
2280*4882a593Smuzhiyun poll_fw:
2281*4882a593Smuzhiyun 	/* Check if the firmware is downloaded successfully or not */
2282*4882a593Smuzhiyun 	ret = wlan_sdio_check_fw_status(pmadapter, poll_num);
2283*4882a593Smuzhiyun 	if (ret != MLAN_STATUS_SUCCESS) {
2284*4882a593Smuzhiyun 		PRINTM(MFATAL, "FW failed to be active in time!\n");
2285*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
2286*4882a593Smuzhiyun 		LEAVE();
2287*4882a593Smuzhiyun 		return ret;
2288*4882a593Smuzhiyun 	}
2289*4882a593Smuzhiyun #ifdef SD9177
2290*4882a593Smuzhiyun 	if (IS_SD9177(pmadapter->card_type))
2291*4882a593Smuzhiyun 		wlan_mdelay(pmadapter, 1000);
2292*4882a593Smuzhiyun #endif
2293*4882a593Smuzhiyun done:
2294*4882a593Smuzhiyun 
2295*4882a593Smuzhiyun 	/* re-enable host interrupt for mlan after fw dnld is successful */
2296*4882a593Smuzhiyun 	wlan_enable_sdio_host_int(pmadapter);
2297*4882a593Smuzhiyun 
2298*4882a593Smuzhiyun 	LEAVE();
2299*4882a593Smuzhiyun 	return ret;
2300*4882a593Smuzhiyun }
2301*4882a593Smuzhiyun 
2302*4882a593Smuzhiyun /**
2303*4882a593Smuzhiyun  *  @brief This function probes the driver
2304*4882a593Smuzhiyun  *
2305*4882a593Smuzhiyun  *  @param pmadapter  A pointer to mlan_adapter structure
2306*4882a593Smuzhiyun  *  @return           MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2307*4882a593Smuzhiyun  */
wlan_sdio_probe(pmlan_adapter pmadapter)2308*4882a593Smuzhiyun mlan_status wlan_sdio_probe(pmlan_adapter pmadapter)
2309*4882a593Smuzhiyun {
2310*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
2311*4882a593Smuzhiyun 	t_u32 sdio_ireg = 0;
2312*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
2313*4882a593Smuzhiyun 
2314*4882a593Smuzhiyun 	ENTER();
2315*4882a593Smuzhiyun 	/*
2316*4882a593Smuzhiyun 	 * Read the HOST_INT_STATUS_REG for ACK the first interrupt got
2317*4882a593Smuzhiyun 	 * from the bootloader. If we don't do this we get a interrupt
2318*4882a593Smuzhiyun 	 * as soon as we register the irq.
2319*4882a593Smuzhiyun 	 */
2320*4882a593Smuzhiyun 	pcb->moal_read_reg(pmadapter->pmoal_handle,
2321*4882a593Smuzhiyun 			   pmadapter->pcard_sd->reg->host_int_status_reg,
2322*4882a593Smuzhiyun 			   &sdio_ireg);
2323*4882a593Smuzhiyun 
2324*4882a593Smuzhiyun 	/* Disable host interrupt mask register for SDIO */
2325*4882a593Smuzhiyun 	ret = wlan_disable_sdio_host_int(pmadapter);
2326*4882a593Smuzhiyun 	if (ret != MLAN_STATUS_SUCCESS) {
2327*4882a593Smuzhiyun 		LEAVE();
2328*4882a593Smuzhiyun 		return MLAN_STATUS_FAILURE;
2329*4882a593Smuzhiyun 	}
2330*4882a593Smuzhiyun 	/* Get SDIO ioport */
2331*4882a593Smuzhiyun 	ret = wlan_sdio_init_ioport(pmadapter);
2332*4882a593Smuzhiyun 	LEAVE();
2333*4882a593Smuzhiyun 	return ret;
2334*4882a593Smuzhiyun }
2335*4882a593Smuzhiyun 
2336*4882a593Smuzhiyun /**
2337*4882a593Smuzhiyun  *  @brief This function get sdio device from card type
2338*4882a593Smuzhiyun  *
2339*4882a593Smuzhiyun  *  @param pmadapter  A pointer to mlan_adapter structure
2340*4882a593Smuzhiyun  *  @return           MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2341*4882a593Smuzhiyun  */
wlan_get_sdio_device(pmlan_adapter pmadapter)2342*4882a593Smuzhiyun mlan_status wlan_get_sdio_device(pmlan_adapter pmadapter)
2343*4882a593Smuzhiyun {
2344*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
2345*4882a593Smuzhiyun 	t_u16 card_type = pmadapter->card_type;
2346*4882a593Smuzhiyun 
2347*4882a593Smuzhiyun 	ENTER();
2348*4882a593Smuzhiyun 
2349*4882a593Smuzhiyun 	ret = pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
2350*4882a593Smuzhiyun 					       sizeof(mlan_sdio_card),
2351*4882a593Smuzhiyun 					       MLAN_MEM_DEF,
2352*4882a593Smuzhiyun 					       (t_u8 **)&pmadapter->pcard_sd);
2353*4882a593Smuzhiyun 	if (ret != MLAN_STATUS_SUCCESS || !pmadapter->pcard_sd) {
2354*4882a593Smuzhiyun 		PRINTM(MERROR, "Failed to allocate pcard_sd\n");
2355*4882a593Smuzhiyun 		LEAVE();
2356*4882a593Smuzhiyun 		return MLAN_STATUS_FAILURE;
2357*4882a593Smuzhiyun 	}
2358*4882a593Smuzhiyun 	pmadapter->pcard_sd->max_ports = MAX_PORT;
2359*4882a593Smuzhiyun 	pmadapter->pcard_sd->mp_aggr_pkt_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
2360*4882a593Smuzhiyun 	pmadapter->pcard_sd->supports_sdio_new_mode = MTRUE;
2361*4882a593Smuzhiyun 	pmadapter->pcard_sd->mp_tx_aggr_buf_size = SDIO_MP_AGGR_BUF_SIZE_MAX;
2362*4882a593Smuzhiyun 	pmadapter->pcard_sd->mp_rx_aggr_buf_size = SDIO_MP_AGGR_BUF_SIZE_MAX;
2363*4882a593Smuzhiyun 
2364*4882a593Smuzhiyun 	switch (card_type) {
2365*4882a593Smuzhiyun #ifdef SD8801
2366*4882a593Smuzhiyun 	case CARD_TYPE_SD8801:
2367*4882a593Smuzhiyun 		pmadapter->pcard_sd->reg = &mlan_reg_sd8801;
2368*4882a593Smuzhiyun 		pmadapter->pcard_info = &mlan_card_info_sd8801;
2369*4882a593Smuzhiyun 		pmadapter->pcard_sd->max_ports = MAX_PORT_16;
2370*4882a593Smuzhiyun 		pmadapter->pcard_sd->mp_aggr_pkt_limit =
2371*4882a593Smuzhiyun 			SDIO_MP_AGGR_DEF_PKT_LIMIT_8;
2372*4882a593Smuzhiyun 		pmadapter->pcard_sd->supports_sdio_new_mode = MFALSE;
2373*4882a593Smuzhiyun 		pmadapter->pcard_sd->mp_tx_aggr_buf_size =
2374*4882a593Smuzhiyun 			SDIO_MP_AGGR_BUF_SIZE_32K;
2375*4882a593Smuzhiyun 		pmadapter->pcard_sd->mp_rx_aggr_buf_size =
2376*4882a593Smuzhiyun 			SDIO_MP_AGGR_BUF_SIZE_32K;
2377*4882a593Smuzhiyun 		break;
2378*4882a593Smuzhiyun #endif
2379*4882a593Smuzhiyun #ifdef SD8887
2380*4882a593Smuzhiyun 	case CARD_TYPE_SD8887:
2381*4882a593Smuzhiyun 		pmadapter->pcard_sd->reg = &mlan_reg_sd8887;
2382*4882a593Smuzhiyun 		pmadapter->pcard_info = &mlan_card_info_sd8887;
2383*4882a593Smuzhiyun 		break;
2384*4882a593Smuzhiyun #endif
2385*4882a593Smuzhiyun #ifdef SD8897
2386*4882a593Smuzhiyun 	case CARD_TYPE_SD8897:
2387*4882a593Smuzhiyun 		pmadapter->pcard_sd->reg = &mlan_reg_sd8897;
2388*4882a593Smuzhiyun 		pmadapter->pcard_info = &mlan_card_info_sd8897;
2389*4882a593Smuzhiyun 		break;
2390*4882a593Smuzhiyun #endif
2391*4882a593Smuzhiyun #if defined(SD8977) || defined(SD8978)
2392*4882a593Smuzhiyun 	case CARD_TYPE_SD8977:
2393*4882a593Smuzhiyun 	case CARD_TYPE_SD8978:
2394*4882a593Smuzhiyun 		pmadapter->pcard_sd->reg = &mlan_reg_sd8977_sd8997;
2395*4882a593Smuzhiyun 		pmadapter->pcard_info = &mlan_card_info_sd8977;
2396*4882a593Smuzhiyun 		break;
2397*4882a593Smuzhiyun #endif
2398*4882a593Smuzhiyun #ifdef SD8997
2399*4882a593Smuzhiyun 	case CARD_TYPE_SD8997:
2400*4882a593Smuzhiyun 		pmadapter->pcard_sd->reg = &mlan_reg_sd8977_sd8997;
2401*4882a593Smuzhiyun 		pmadapter->pcard_info = &mlan_card_info_sd8997;
2402*4882a593Smuzhiyun 		break;
2403*4882a593Smuzhiyun #endif
2404*4882a593Smuzhiyun #ifdef SD8987
2405*4882a593Smuzhiyun 	case CARD_TYPE_SD8987:
2406*4882a593Smuzhiyun 		pmadapter->pcard_sd->reg = &mlan_reg_sd8977_sd8997;
2407*4882a593Smuzhiyun 		pmadapter->pcard_info = &mlan_card_info_sd8987;
2408*4882a593Smuzhiyun 		break;
2409*4882a593Smuzhiyun #endif
2410*4882a593Smuzhiyun #ifdef SD9098
2411*4882a593Smuzhiyun 	case CARD_TYPE_SD9098:
2412*4882a593Smuzhiyun 		pmadapter->pcard_sd->reg = &mlan_reg_sd8977_sd8997;
2413*4882a593Smuzhiyun 		pmadapter->pcard_info = &mlan_card_info_sd9098;
2414*4882a593Smuzhiyun 		break;
2415*4882a593Smuzhiyun #endif
2416*4882a593Smuzhiyun #ifdef SD9097
2417*4882a593Smuzhiyun 	case CARD_TYPE_SD9097:
2418*4882a593Smuzhiyun 		pmadapter->pcard_sd->reg = &mlan_reg_sd8977_sd8997;
2419*4882a593Smuzhiyun 		pmadapter->pcard_info = &mlan_card_info_sd9097;
2420*4882a593Smuzhiyun 		break;
2421*4882a593Smuzhiyun #endif
2422*4882a593Smuzhiyun #ifdef SDNW62X
2423*4882a593Smuzhiyun 	case CARD_TYPE_SDNW62X:
2424*4882a593Smuzhiyun 		pmadapter->pcard_sd->reg = &mlan_reg_sd8977_sd8997;
2425*4882a593Smuzhiyun 		pmadapter->pcard_info = &mlan_card_info_sdnw62x;
2426*4882a593Smuzhiyun 		break;
2427*4882a593Smuzhiyun #endif
2428*4882a593Smuzhiyun #ifdef SD9177
2429*4882a593Smuzhiyun 	case CARD_TYPE_SD9177:
2430*4882a593Smuzhiyun 		pmadapter->pcard_sd->reg = &mlan_reg_sd8977_sd8997;
2431*4882a593Smuzhiyun 		pmadapter->pcard_info = &mlan_card_info_sd9177;
2432*4882a593Smuzhiyun 		break;
2433*4882a593Smuzhiyun #endif
2434*4882a593Smuzhiyun 	default:
2435*4882a593Smuzhiyun 		PRINTM(MERROR, "can't get right card type \n");
2436*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
2437*4882a593Smuzhiyun 		break;
2438*4882a593Smuzhiyun 	}
2439*4882a593Smuzhiyun 
2440*4882a593Smuzhiyun 	LEAVE();
2441*4882a593Smuzhiyun 	return ret;
2442*4882a593Smuzhiyun }
2443*4882a593Smuzhiyun 
2444*4882a593Smuzhiyun /**
2445*4882a593Smuzhiyun  *  @brief This function dump the mp registers when issue happened
2446*4882a593Smuzhiyun  *
2447*4882a593Smuzhiyun  *  @param pmadapter    A pointer to mlan_adapter structure
2448*4882a593Smuzhiyun  *  @return             N/A
2449*4882a593Smuzhiyun  */
wlan_dump_mp_registers(pmlan_adapter pmadapter)2450*4882a593Smuzhiyun void wlan_dump_mp_registers(pmlan_adapter pmadapter)
2451*4882a593Smuzhiyun {
2452*4882a593Smuzhiyun 	t_u32 mp_wr_bitmap;
2453*4882a593Smuzhiyun 	t_bool new_mode = pmadapter->pcard_sd->supports_sdio_new_mode;
2454*4882a593Smuzhiyun 	t_u32 mp_rd_bitmap;
2455*4882a593Smuzhiyun 	t_u16 rx_len = 0;
2456*4882a593Smuzhiyun 	const mlan_sdio_card_reg *reg = pmadapter->pcard_sd->reg;
2457*4882a593Smuzhiyun 	t_u8 cmd_rd_len_0 = reg->cmd_rd_len_0;
2458*4882a593Smuzhiyun 	t_u8 cmd_rd_len_1 = reg->cmd_rd_len_1;
2459*4882a593Smuzhiyun 	t_u8 host_int_status_reg = reg->host_int_status_reg;
2460*4882a593Smuzhiyun 	t_u32 sdio_ireg = 0;
2461*4882a593Smuzhiyun 
2462*4882a593Smuzhiyun 	mp_wr_bitmap = (t_u32)pmadapter->pcard_sd->mp_regs[reg->wr_bitmap_l];
2463*4882a593Smuzhiyun 	mp_wr_bitmap |= ((t_u32)pmadapter->pcard_sd->mp_regs[reg->wr_bitmap_u])
2464*4882a593Smuzhiyun 			<< 8;
2465*4882a593Smuzhiyun 	if (new_mode) {
2466*4882a593Smuzhiyun 		mp_wr_bitmap |=
2467*4882a593Smuzhiyun 			((t_u32)pmadapter->pcard_sd->mp_regs[reg->wr_bitmap_1l])
2468*4882a593Smuzhiyun 			<< 16;
2469*4882a593Smuzhiyun 		mp_wr_bitmap |=
2470*4882a593Smuzhiyun 			((t_u32)pmadapter->pcard_sd->mp_regs[reg->wr_bitmap_1u])
2471*4882a593Smuzhiyun 			<< 24;
2472*4882a593Smuzhiyun 	}
2473*4882a593Smuzhiyun 	PRINTM(MMSG, "wlan: mp_data_port_mask = 0x%x\n",
2474*4882a593Smuzhiyun 	       pmadapter->pcard_sd->mp_data_port_mask);
2475*4882a593Smuzhiyun 	PRINTM(MMSG, "wlan: HW wr_bitmap=0x%08x Host: wr_bitmap=0x%08x\n",
2476*4882a593Smuzhiyun 	       mp_wr_bitmap, pmadapter->pcard_sd->mp_wr_bitmap);
2477*4882a593Smuzhiyun 	mp_rd_bitmap = (t_u32)pmadapter->pcard_sd->mp_regs[reg->rd_bitmap_l];
2478*4882a593Smuzhiyun 	mp_rd_bitmap |= ((t_u32)pmadapter->pcard_sd->mp_regs[reg->rd_bitmap_u])
2479*4882a593Smuzhiyun 			<< 8;
2480*4882a593Smuzhiyun 	if (new_mode) {
2481*4882a593Smuzhiyun 		mp_rd_bitmap |=
2482*4882a593Smuzhiyun 			((t_u32)pmadapter->pcard_sd->mp_regs[reg->rd_bitmap_1l])
2483*4882a593Smuzhiyun 			<< 16;
2484*4882a593Smuzhiyun 		mp_rd_bitmap |=
2485*4882a593Smuzhiyun 			((t_u32)pmadapter->pcard_sd->mp_regs[reg->rd_bitmap_1u])
2486*4882a593Smuzhiyun 			<< 24;
2487*4882a593Smuzhiyun 	}
2488*4882a593Smuzhiyun 	PRINTM(MMSG, "wlan: HW rd_bitmap=0x%08x Host: rd_bitmap=0x%08x\n",
2489*4882a593Smuzhiyun 	       mp_rd_bitmap, pmadapter->pcard_sd->mp_rd_bitmap);
2490*4882a593Smuzhiyun 
2491*4882a593Smuzhiyun 	if (new_mode) {
2492*4882a593Smuzhiyun 		rx_len = ((t_u16)pmadapter->pcard_sd->mp_regs[cmd_rd_len_1])
2493*4882a593Smuzhiyun 			 << 8;
2494*4882a593Smuzhiyun 		rx_len |= (t_u16)pmadapter->pcard_sd->mp_regs[cmd_rd_len_0];
2495*4882a593Smuzhiyun 		PRINTM(MMSG, "wlan: cmd rx buffer rx_len = %d\n", rx_len);
2496*4882a593Smuzhiyun 	}
2497*4882a593Smuzhiyun 	PRINTM(MMSG, "wlan: HW sdio_ireg = 0x%x\n",
2498*4882a593Smuzhiyun 	       pmadapter->pcard_sd->mp_regs[host_int_status_reg]);
2499*4882a593Smuzhiyun 	sdio_ireg = pmadapter->pcard_sd->mp_regs[host_int_status_reg];
2500*4882a593Smuzhiyun 
2501*4882a593Smuzhiyun 	if (new_mode && rx_len)
2502*4882a593Smuzhiyun 		sdio_ireg |= UP_LD_CMD_PORT_HOST_INT_STATUS;
2503*4882a593Smuzhiyun 
2504*4882a593Smuzhiyun 	if (!(pmadapter->pcard_sd->mp_wr_bitmap &
2505*4882a593Smuzhiyun 	      pmadapter->pcard_sd->mp_data_port_mask)) {
2506*4882a593Smuzhiyun 		if (mp_wr_bitmap & pmadapter->pcard_sd->mp_data_port_mask)
2507*4882a593Smuzhiyun 			sdio_ireg |= DN_LD_HOST_INT_STATUS;
2508*4882a593Smuzhiyun 	}
2509*4882a593Smuzhiyun 
2510*4882a593Smuzhiyun 	if ((!pmadapter->pcard_sd->mp_rd_bitmap) && mp_rd_bitmap)
2511*4882a593Smuzhiyun 		sdio_ireg |= UP_LD_HOST_INT_STATUS;
2512*4882a593Smuzhiyun 
2513*4882a593Smuzhiyun 	pmadapter->pcard_sd->mp_regs[host_int_status_reg] = sdio_ireg;
2514*4882a593Smuzhiyun 	PRINTM(MMSG, "wlan: recovered sdio_ireg=0x%x\n", sdio_ireg);
2515*4882a593Smuzhiyun 	return;
2516*4882a593Smuzhiyun }
2517*4882a593Smuzhiyun 
2518*4882a593Smuzhiyun /**
2519*4882a593Smuzhiyun  *  @brief This function gets interrupt status.
2520*4882a593Smuzhiyun  *
2521*4882a593Smuzhiyun  *  @param pmadapter    A pointer to mlan_adapter structure
2522*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS
2523*4882a593Smuzhiyun  */
wlan_sdio_interrupt(t_u16 msg_id,pmlan_adapter pmadapter)2524*4882a593Smuzhiyun static mlan_status wlan_sdio_interrupt(t_u16 msg_id, pmlan_adapter pmadapter)
2525*4882a593Smuzhiyun {
2526*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
2527*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
2528*4882a593Smuzhiyun 	mlan_buffer mbuf;
2529*4882a593Smuzhiyun 	t_u32 sdio_ireg = 0;
2530*4882a593Smuzhiyun 	t_u8 offset = 0;
2531*4882a593Smuzhiyun 	t_u8 i = 0;
2532*4882a593Smuzhiyun 	int max_mp_regs = pmadapter->pcard_sd->reg->max_mp_regs;
2533*4882a593Smuzhiyun 	t_u8 host_int_status_reg =
2534*4882a593Smuzhiyun 		pmadapter->pcard_sd->reg->host_int_status_reg;
2535*4882a593Smuzhiyun 
2536*4882a593Smuzhiyun 	ENTER();
2537*4882a593Smuzhiyun 
2538*4882a593Smuzhiyun 	while (max_mp_regs) {
2539*4882a593Smuzhiyun 		memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
2540*4882a593Smuzhiyun 		mbuf.pbuf = pmadapter->pcard_sd->mp_regs + offset;
2541*4882a593Smuzhiyun 		mbuf.data_len = MIN(max_mp_regs, MLAN_SDIO_BLOCK_SIZE);
2542*4882a593Smuzhiyun 		do {
2543*4882a593Smuzhiyun 			ret = pcb->moal_read_data_sync(
2544*4882a593Smuzhiyun 				pmadapter->pmoal_handle, &mbuf,
2545*4882a593Smuzhiyun 				(REG_PORT + offset) | MLAN_SDIO_BYTE_MODE_MASK,
2546*4882a593Smuzhiyun 				0);
2547*4882a593Smuzhiyun 			if (ret != MLAN_STATUS_SUCCESS) {
2548*4882a593Smuzhiyun 				PRINTM(MERROR,
2549*4882a593Smuzhiyun 				       "wlan: cmd53 read regs failed: %d port=%x retry=%d\n",
2550*4882a593Smuzhiyun 				       ret, REG_PORT + offset, i);
2551*4882a593Smuzhiyun 				i++;
2552*4882a593Smuzhiyun 				pcb->moal_write_reg(pmadapter->pmoal_handle,
2553*4882a593Smuzhiyun 						    HOST_TO_CARD_EVENT_REG,
2554*4882a593Smuzhiyun 						    HOST_TERM_CMD53);
2555*4882a593Smuzhiyun 				if (i > MAX_WRITE_IOMEM_RETRY) {
2556*4882a593Smuzhiyun 					PRINTM(MERROR,
2557*4882a593Smuzhiyun 					       "wlan: Fail to read mp_regs\n");
2558*4882a593Smuzhiyun 					pmadapter->dbg.num_int_read_failure++;
2559*4882a593Smuzhiyun 					goto done;
2560*4882a593Smuzhiyun 				}
2561*4882a593Smuzhiyun 			}
2562*4882a593Smuzhiyun 		} while (ret == MLAN_STATUS_FAILURE);
2563*4882a593Smuzhiyun 		offset += mbuf.data_len;
2564*4882a593Smuzhiyun 		max_mp_regs -= mbuf.data_len;
2565*4882a593Smuzhiyun 	}
2566*4882a593Smuzhiyun 	if (i > 0)
2567*4882a593Smuzhiyun 		wlan_dump_mp_registers(pmadapter);
2568*4882a593Smuzhiyun 
2569*4882a593Smuzhiyun 	DBG_HEXDUMP(MIF_D, "SDIO MP Registers", pmadapter->pcard_sd->mp_regs,
2570*4882a593Smuzhiyun 		    max_mp_regs);
2571*4882a593Smuzhiyun 	sdio_ireg = pmadapter->pcard_sd->mp_regs[host_int_status_reg];
2572*4882a593Smuzhiyun 	pmadapter->dbg.last_int_status = pmadapter->ireg | sdio_ireg;
2573*4882a593Smuzhiyun 	if (sdio_ireg) {
2574*4882a593Smuzhiyun 		/*
2575*4882a593Smuzhiyun 		 * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
2576*4882a593Smuzhiyun 		 * DN_LD_CMD_PORT_HOST_INT_STATUS and/or
2577*4882a593Smuzhiyun 		 * UP_LD_CMD_PORT_HOST_INT_STATUS
2578*4882a593Smuzhiyun 		 * Clear the interrupt status register
2579*4882a593Smuzhiyun 		 */
2580*4882a593Smuzhiyun 		PRINTM(MINTR, "wlan_interrupt: sdio_ireg = 0x%x\n", sdio_ireg);
2581*4882a593Smuzhiyun 		pmadapter->pcard_sd->num_of_irq++;
2582*4882a593Smuzhiyun 		pcb->moal_spin_lock(pmadapter->pmoal_handle,
2583*4882a593Smuzhiyun 				    pmadapter->pint_lock);
2584*4882a593Smuzhiyun 		pmadapter->ireg |= sdio_ireg;
2585*4882a593Smuzhiyun 		pcb->moal_spin_unlock(pmadapter->pmoal_handle,
2586*4882a593Smuzhiyun 				      pmadapter->pint_lock);
2587*4882a593Smuzhiyun 		if (!pmadapter->pps_uapsd_mode &&
2588*4882a593Smuzhiyun 		    pmadapter->ps_state == PS_STATE_SLEEP) {
2589*4882a593Smuzhiyun 			pmadapter->pm_wakeup_fw_try = MFALSE;
2590*4882a593Smuzhiyun 			pmadapter->ps_state = PS_STATE_AWAKE;
2591*4882a593Smuzhiyun 			pmadapter->pm_wakeup_card_req = MFALSE;
2592*4882a593Smuzhiyun 		}
2593*4882a593Smuzhiyun 	} else {
2594*4882a593Smuzhiyun 		PRINTM(MMSG, "wlan_interrupt: sdio_ireg = 0x%x\n", sdio_ireg);
2595*4882a593Smuzhiyun 	}
2596*4882a593Smuzhiyun done:
2597*4882a593Smuzhiyun 	LEAVE();
2598*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
2599*4882a593Smuzhiyun }
2600*4882a593Smuzhiyun 
2601*4882a593Smuzhiyun /**
2602*4882a593Smuzhiyun  *  @brief This function try to read the packet when fail to alloc rx buffer
2603*4882a593Smuzhiyun  *
2604*4882a593Smuzhiyun  *  @param pmadapter A pointer to mlan_adapter structure
2605*4882a593Smuzhiyun  *  @param port      Current port on which packet needs to be rxed
2606*4882a593Smuzhiyun  *  @param rx_len    Length of received packet
2607*4882a593Smuzhiyun  *  @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2608*4882a593Smuzhiyun  */
wlan_sdio_card_to_host_recovery(mlan_adapter * pmadapter,t_u8 port,t_u16 rx_len)2609*4882a593Smuzhiyun static mlan_status wlan_sdio_card_to_host_recovery(mlan_adapter *pmadapter,
2610*4882a593Smuzhiyun 						   t_u8 port, t_u16 rx_len)
2611*4882a593Smuzhiyun {
2612*4882a593Smuzhiyun 	mlan_buffer mbuf;
2613*4882a593Smuzhiyun 	t_u32 pkt_type = 0;
2614*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_FAILURE;
2615*4882a593Smuzhiyun 	ENTER();
2616*4882a593Smuzhiyun 	if (!pmadapter->pcard_sd->supports_sdio_new_mode)
2617*4882a593Smuzhiyun 		goto done;
2618*4882a593Smuzhiyun 	if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) {
2619*4882a593Smuzhiyun 		PRINTM(MDATA, "Recovery:do Rx Aggr\n");
2620*4882a593Smuzhiyun 		/* do aggr RX now */
2621*4882a593Smuzhiyun 		wlan_receive_mp_aggr_buf(pmadapter);
2622*4882a593Smuzhiyun 	}
2623*4882a593Smuzhiyun 	memset(pmadapter, &mbuf, 0, sizeof(mlan_buffer));
2624*4882a593Smuzhiyun 	mbuf.pbuf = pmadapter->pcard_sd->rx_buf;
2625*4882a593Smuzhiyun 	mbuf.data_len = rx_len;
2626*4882a593Smuzhiyun 
2627*4882a593Smuzhiyun 	PRINTM(MDATA, "Recovery: Try read port=%d rx_len=%d\n", port, rx_len);
2628*4882a593Smuzhiyun 	if (MLAN_STATUS_SUCCESS !=
2629*4882a593Smuzhiyun 	    wlan_sdio_card_to_host(pmadapter, &pkt_type,
2630*4882a593Smuzhiyun 				   (t_u32 *)&pmadapter->upld_len, &mbuf, rx_len,
2631*4882a593Smuzhiyun 				   pmadapter->pcard_sd->ioport + port)) {
2632*4882a593Smuzhiyun 		PRINTM(MERROR, "Recovery: Fail to do cmd53\n");
2633*4882a593Smuzhiyun 	}
2634*4882a593Smuzhiyun 	if (pkt_type != MLAN_TYPE_DATA && pkt_type != MLAN_TYPE_SPA_DATA) {
2635*4882a593Smuzhiyun 		PRINTM(MERROR,
2636*4882a593Smuzhiyun 		       "Recovery: Receive a wrong pkt: type=%d, len=%d\n",
2637*4882a593Smuzhiyun 		       pkt_type, pmadapter->upld_len);
2638*4882a593Smuzhiyun 		goto done;
2639*4882a593Smuzhiyun 	}
2640*4882a593Smuzhiyun 	if (pkt_type == MLAN_TYPE_DATA) {
2641*4882a593Smuzhiyun 		// TODO fill the hole in Rx reorder table
2642*4882a593Smuzhiyun 		PRINTM(MDATA, "Recovery: Drop Data packet\n");
2643*4882a593Smuzhiyun 		pmadapter->dbg.num_pkt_dropped++;
2644*4882a593Smuzhiyun 	} else if (pkt_type == MLAN_TYPE_SPA_DATA) {
2645*4882a593Smuzhiyun 		PRINTM(MDATA, "Recovery: SPA Data packet len=%d\n",
2646*4882a593Smuzhiyun 		       pmadapter->upld_len);
2647*4882a593Smuzhiyun 		wlan_decode_spa_buffer(pmadapter, pmadapter->pcard_sd->rx_buf,
2648*4882a593Smuzhiyun 				       pmadapter->upld_len);
2649*4882a593Smuzhiyun 		pmadapter->data_received = MTRUE;
2650*4882a593Smuzhiyun 	}
2651*4882a593Smuzhiyun 	PRINTM(MMSG, "wlan: Success handle rx port=%d, rx_len=%d \n", port,
2652*4882a593Smuzhiyun 	       rx_len);
2653*4882a593Smuzhiyun 	ret = MLAN_STATUS_SUCCESS;
2654*4882a593Smuzhiyun done:
2655*4882a593Smuzhiyun 	LEAVE();
2656*4882a593Smuzhiyun 	return ret;
2657*4882a593Smuzhiyun }
2658*4882a593Smuzhiyun 
2659*4882a593Smuzhiyun /**
2660*4882a593Smuzhiyun  *  @brief This function checks the interrupt status and handle it accordingly.
2661*4882a593Smuzhiyun  *
2662*4882a593Smuzhiyun  *  @param pmadapter A pointer to mlan_adapter structure
2663*4882a593Smuzhiyun  *  @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2664*4882a593Smuzhiyun  */
wlan_process_sdio_int_status(mlan_adapter * pmadapter)2665*4882a593Smuzhiyun static mlan_status wlan_process_sdio_int_status(mlan_adapter *pmadapter)
2666*4882a593Smuzhiyun {
2667*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
2668*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
2669*4882a593Smuzhiyun 	t_u8 sdio_ireg;
2670*4882a593Smuzhiyun 	mlan_buffer *pmbuf = MNULL;
2671*4882a593Smuzhiyun 
2672*4882a593Smuzhiyun 	t_u8 port = 0;
2673*4882a593Smuzhiyun 	t_u32 len_reg_l, len_reg_u;
2674*4882a593Smuzhiyun 	t_u32 rx_blocks;
2675*4882a593Smuzhiyun 	t_u8 bit_count = 0;
2676*4882a593Smuzhiyun 	t_u32 ps_state = pmadapter->ps_state;
2677*4882a593Smuzhiyun 	t_u16 rx_len;
2678*4882a593Smuzhiyun 	t_u32 upld_typ = 0;
2679*4882a593Smuzhiyun 	t_u32 cr = 0;
2680*4882a593Smuzhiyun 	const mlan_sdio_card_reg *reg = pmadapter->pcard_sd->reg;
2681*4882a593Smuzhiyun 	t_u8 rd_len_p0_l = reg->rd_len_p0_l;
2682*4882a593Smuzhiyun 	t_u8 rd_len_p0_u = reg->rd_len_p0_u;
2683*4882a593Smuzhiyun 	t_u8 cmd_rd_len_0 = reg->cmd_rd_len_0;
2684*4882a593Smuzhiyun 	t_u8 cmd_rd_len_1 = reg->cmd_rd_len_1;
2685*4882a593Smuzhiyun 	t_bool new_mode = pmadapter->pcard_sd->supports_sdio_new_mode;
2686*4882a593Smuzhiyun 
2687*4882a593Smuzhiyun 	ENTER();
2688*4882a593Smuzhiyun 
2689*4882a593Smuzhiyun 	pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pint_lock);
2690*4882a593Smuzhiyun 	sdio_ireg = (t_u8)pmadapter->ireg;
2691*4882a593Smuzhiyun 	pmadapter->ireg = 0;
2692*4882a593Smuzhiyun 	pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pint_lock);
2693*4882a593Smuzhiyun 
2694*4882a593Smuzhiyun 	if (!sdio_ireg)
2695*4882a593Smuzhiyun 		goto done;
2696*4882a593Smuzhiyun 
2697*4882a593Smuzhiyun 	if (new_mode) {
2698*4882a593Smuzhiyun 		/* check the command port */
2699*4882a593Smuzhiyun 		if (sdio_ireg & DN_LD_CMD_PORT_HOST_INT_STATUS) {
2700*4882a593Smuzhiyun 			if (pmadapter->cmd_sent)
2701*4882a593Smuzhiyun 				pmadapter->cmd_sent = MFALSE;
2702*4882a593Smuzhiyun 
2703*4882a593Smuzhiyun 			PRINTM(MINFO, "cmd_sent=%d\n", pmadapter->cmd_sent);
2704*4882a593Smuzhiyun 		}
2705*4882a593Smuzhiyun 
2706*4882a593Smuzhiyun 		if (sdio_ireg & UP_LD_CMD_PORT_HOST_INT_STATUS) {
2707*4882a593Smuzhiyun 			/* read the len of control packet */
2708*4882a593Smuzhiyun 			rx_len = ((t_u16)pmadapter->pcard_sd
2709*4882a593Smuzhiyun 					  ->mp_regs[cmd_rd_len_1])
2710*4882a593Smuzhiyun 				 << 8;
2711*4882a593Smuzhiyun 			rx_len |= (t_u16)pmadapter->pcard_sd
2712*4882a593Smuzhiyun 					  ->mp_regs[cmd_rd_len_0];
2713*4882a593Smuzhiyun 			PRINTM(MINFO, "RX: cmd port rx_len=%u\n", rx_len);
2714*4882a593Smuzhiyun 			rx_blocks = (rx_len + MLAN_SDIO_BLOCK_SIZE - 1) /
2715*4882a593Smuzhiyun 				    MLAN_SDIO_BLOCK_SIZE;
2716*4882a593Smuzhiyun 			if (rx_len <= SDIO_INTF_HEADER_LEN ||
2717*4882a593Smuzhiyun 			    (rx_blocks * MLAN_SDIO_BLOCK_SIZE) >
2718*4882a593Smuzhiyun 				    ALLOC_BUF_SIZE) {
2719*4882a593Smuzhiyun 				PRINTM(MERROR, "invalid rx_len=%d\n", rx_len);
2720*4882a593Smuzhiyun 				ret = MLAN_STATUS_FAILURE;
2721*4882a593Smuzhiyun 				goto done;
2722*4882a593Smuzhiyun 			}
2723*4882a593Smuzhiyun 			rx_len = (t_u16)(rx_blocks * MLAN_SDIO_BLOCK_SIZE);
2724*4882a593Smuzhiyun 			pmbuf = wlan_alloc_mlan_buffer(pmadapter, rx_len, 0,
2725*4882a593Smuzhiyun 						       MOAL_MALLOC_BUFFER);
2726*4882a593Smuzhiyun 			if (pmbuf == MNULL) {
2727*4882a593Smuzhiyun 				PRINTM(MERROR,
2728*4882a593Smuzhiyun 				       "Failed to allocate 'mlan_buffer'\n");
2729*4882a593Smuzhiyun 				ret = MLAN_STATUS_FAILURE;
2730*4882a593Smuzhiyun 				goto done;
2731*4882a593Smuzhiyun 			}
2732*4882a593Smuzhiyun 			PRINTM(MINFO, "cmd rx buffer rx_len = %d\n", rx_len);
2733*4882a593Smuzhiyun 
2734*4882a593Smuzhiyun 			/* Transfer data from card */
2735*4882a593Smuzhiyun 			if (MLAN_STATUS_SUCCESS !=
2736*4882a593Smuzhiyun 			    wlan_sdio_card_to_host(pmadapter, &upld_typ,
2737*4882a593Smuzhiyun 						   (t_u32 *)&pmadapter->upld_len,
2738*4882a593Smuzhiyun 						   pmbuf, rx_len,
2739*4882a593Smuzhiyun 						   pmadapter->pcard_sd->ioport |
2740*4882a593Smuzhiyun 							   CMD_PORT_SLCT)) {
2741*4882a593Smuzhiyun 				pmadapter->dbg.num_cmdevt_card_to_host_failure++;
2742*4882a593Smuzhiyun 				PRINTM(MERROR,
2743*4882a593Smuzhiyun 				       "Card-to-host cmd failed: int status=0x%x\n",
2744*4882a593Smuzhiyun 				       sdio_ireg);
2745*4882a593Smuzhiyun 				wlan_free_mlan_buffer(pmadapter, pmbuf);
2746*4882a593Smuzhiyun 				ret = MLAN_STATUS_FAILURE;
2747*4882a593Smuzhiyun 				goto term_cmd53;
2748*4882a593Smuzhiyun 			}
2749*4882a593Smuzhiyun 
2750*4882a593Smuzhiyun 			if ((upld_typ != MLAN_TYPE_CMD) &&
2751*4882a593Smuzhiyun 			    (upld_typ != MLAN_TYPE_EVENT))
2752*4882a593Smuzhiyun 				PRINTM(MERROR,
2753*4882a593Smuzhiyun 				       "receive a wrong packet from CMD PORT. type =0x%x\n",
2754*4882a593Smuzhiyun 				       upld_typ);
2755*4882a593Smuzhiyun 
2756*4882a593Smuzhiyun 			wlan_decode_rx_packet(pmadapter, pmbuf, upld_typ,
2757*4882a593Smuzhiyun 					      MFALSE);
2758*4882a593Smuzhiyun 
2759*4882a593Smuzhiyun 			/* We might receive data/sleep_cfm at the same time */
2760*4882a593Smuzhiyun 			/* reset data_receive flag to avoid ps_state change */
2761*4882a593Smuzhiyun 			if ((ps_state == PS_STATE_SLEEP_CFM) &&
2762*4882a593Smuzhiyun 			    (pmadapter->ps_state == PS_STATE_SLEEP))
2763*4882a593Smuzhiyun 				pmadapter->data_received = MFALSE;
2764*4882a593Smuzhiyun 		}
2765*4882a593Smuzhiyun 	}
2766*4882a593Smuzhiyun 
2767*4882a593Smuzhiyun 	if (sdio_ireg & DN_LD_HOST_INT_STATUS) {
2768*4882a593Smuzhiyun 		if (pmadapter->pcard_sd->mp_wr_bitmap &
2769*4882a593Smuzhiyun 		    pmadapter->pcard_sd->mp_data_port_mask)
2770*4882a593Smuzhiyun 			pmadapter->pcard_sd->mp_invalid_update++;
2771*4882a593Smuzhiyun 		pmadapter->pcard_sd->mp_wr_bitmap =
2772*4882a593Smuzhiyun 			(t_u32)pmadapter->pcard_sd->mp_regs[reg->wr_bitmap_l];
2773*4882a593Smuzhiyun 		pmadapter->pcard_sd->mp_wr_bitmap |=
2774*4882a593Smuzhiyun 			((t_u32)pmadapter->pcard_sd->mp_regs[reg->wr_bitmap_u])
2775*4882a593Smuzhiyun 			<< 8;
2776*4882a593Smuzhiyun 		if (new_mode) {
2777*4882a593Smuzhiyun 			pmadapter->pcard_sd->mp_wr_bitmap |=
2778*4882a593Smuzhiyun 				((t_u32)pmadapter->pcard_sd
2779*4882a593Smuzhiyun 					 ->mp_regs[reg->wr_bitmap_1l])
2780*4882a593Smuzhiyun 				<< 16;
2781*4882a593Smuzhiyun 			pmadapter->pcard_sd->mp_wr_bitmap |=
2782*4882a593Smuzhiyun 				((t_u32)pmadapter->pcard_sd
2783*4882a593Smuzhiyun 					 ->mp_regs[reg->wr_bitmap_1u])
2784*4882a593Smuzhiyun 				<< 24;
2785*4882a593Smuzhiyun 		}
2786*4882a593Smuzhiyun 		bit_count = bitcount(pmadapter->pcard_sd->mp_wr_bitmap &
2787*4882a593Smuzhiyun 				     pmadapter->pcard_sd->mp_data_port_mask);
2788*4882a593Smuzhiyun 		if (bit_count) {
2789*4882a593Smuzhiyun 			pmadapter->pcard_sd->mp_update[bit_count - 1]++;
2790*4882a593Smuzhiyun 			if (pmadapter->pcard_sd->mp_update[bit_count - 1] ==
2791*4882a593Smuzhiyun 			    0xffffffff)
2792*4882a593Smuzhiyun 				memset(pmadapter,
2793*4882a593Smuzhiyun 				       pmadapter->pcard_sd->mp_update, 0,
2794*4882a593Smuzhiyun 				       sizeof(pmadapter->pcard_sd->mp_update));
2795*4882a593Smuzhiyun 		}
2796*4882a593Smuzhiyun 
2797*4882a593Smuzhiyun 		pmadapter->pcard_sd->last_recv_wr_bitmap =
2798*4882a593Smuzhiyun 			pmadapter->pcard_sd->mp_wr_bitmap;
2799*4882a593Smuzhiyun 		PRINTM(MINTR, "DNLD: wr_bitmap=0x%08x\n",
2800*4882a593Smuzhiyun 		       pmadapter->pcard_sd->mp_wr_bitmap);
2801*4882a593Smuzhiyun 		if (pmadapter->data_sent &&
2802*4882a593Smuzhiyun 		    (pmadapter->pcard_sd->mp_wr_bitmap &
2803*4882a593Smuzhiyun 		     (1 << pmadapter->pcard_sd->curr_wr_port))) {
2804*4882a593Smuzhiyun 			pmadapter->callbacks.moal_tp_accounting_rx_param(
2805*4882a593Smuzhiyun 				pmadapter->pmoal_handle, 3, 0);
2806*4882a593Smuzhiyun 			PRINTM(MINFO, " <--- Tx DONE Interrupt --->\n");
2807*4882a593Smuzhiyun 			pmadapter->data_sent = MFALSE;
2808*4882a593Smuzhiyun 		}
2809*4882a593Smuzhiyun 	}
2810*4882a593Smuzhiyun 	if ((!new_mode) && (pmadapter->cmd_sent == MTRUE)) {
2811*4882a593Smuzhiyun 		/* Check if firmware has attach buffer at command port and
2812*4882a593Smuzhiyun 		 * update just that in wr_bit_map. */
2813*4882a593Smuzhiyun 		pmadapter->pcard_sd->mp_wr_bitmap |=
2814*4882a593Smuzhiyun 			(t_u32)pmadapter->pcard_sd->mp_regs[reg->wr_bitmap_l] &
2815*4882a593Smuzhiyun 			CTRL_PORT_MASK;
2816*4882a593Smuzhiyun 		if (pmadapter->pcard_sd->mp_wr_bitmap & CTRL_PORT_MASK)
2817*4882a593Smuzhiyun 			pmadapter->cmd_sent = MFALSE;
2818*4882a593Smuzhiyun 	}
2819*4882a593Smuzhiyun 
2820*4882a593Smuzhiyun 	if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
2821*4882a593Smuzhiyun 		pmadapter->pcard_sd->mp_rd_bitmap =
2822*4882a593Smuzhiyun 			(t_u32)pmadapter->pcard_sd->mp_regs[reg->rd_bitmap_l];
2823*4882a593Smuzhiyun 		pmadapter->pcard_sd->mp_rd_bitmap |=
2824*4882a593Smuzhiyun 			((t_u32)pmadapter->pcard_sd->mp_regs[reg->rd_bitmap_u])
2825*4882a593Smuzhiyun 			<< 8;
2826*4882a593Smuzhiyun 		if (new_mode) {
2827*4882a593Smuzhiyun 			pmadapter->pcard_sd->mp_rd_bitmap |=
2828*4882a593Smuzhiyun 				((t_u32)pmadapter->pcard_sd
2829*4882a593Smuzhiyun 					 ->mp_regs[reg->rd_bitmap_1l])
2830*4882a593Smuzhiyun 				<< 16;
2831*4882a593Smuzhiyun 			pmadapter->pcard_sd->mp_rd_bitmap |=
2832*4882a593Smuzhiyun 				((t_u32)pmadapter->pcard_sd
2833*4882a593Smuzhiyun 					 ->mp_regs[reg->rd_bitmap_1u])
2834*4882a593Smuzhiyun 				<< 24;
2835*4882a593Smuzhiyun 		}
2836*4882a593Smuzhiyun 		pmadapter->pcard_sd->last_recv_rd_bitmap =
2837*4882a593Smuzhiyun 			pmadapter->pcard_sd->mp_rd_bitmap;
2838*4882a593Smuzhiyun 
2839*4882a593Smuzhiyun 		PRINTM(MINTR, "UPLD: rd_bitmap=0x%08x\n",
2840*4882a593Smuzhiyun 		       pmadapter->pcard_sd->mp_rd_bitmap);
2841*4882a593Smuzhiyun 		pmadapter->callbacks.moal_tp_accounting_rx_param(
2842*4882a593Smuzhiyun 			pmadapter->pmoal_handle, 0, 0);
2843*4882a593Smuzhiyun 
2844*4882a593Smuzhiyun 		while (MTRUE) {
2845*4882a593Smuzhiyun 			ret = wlan_get_rd_port(pmadapter, &port);
2846*4882a593Smuzhiyun 			if (ret != MLAN_STATUS_SUCCESS) {
2847*4882a593Smuzhiyun 				PRINTM(MINFO,
2848*4882a593Smuzhiyun 				       "no more rd_port to be handled\n");
2849*4882a593Smuzhiyun 				break;
2850*4882a593Smuzhiyun 			}
2851*4882a593Smuzhiyun 			len_reg_l = rd_len_p0_l + (port << 1);
2852*4882a593Smuzhiyun 			len_reg_u = rd_len_p0_u + (port << 1);
2853*4882a593Smuzhiyun 			rx_len =
2854*4882a593Smuzhiyun 				((t_u16)pmadapter->pcard_sd->mp_regs[len_reg_u])
2855*4882a593Smuzhiyun 				<< 8;
2856*4882a593Smuzhiyun 			rx_len |=
2857*4882a593Smuzhiyun 				(t_u16)pmadapter->pcard_sd->mp_regs[len_reg_l];
2858*4882a593Smuzhiyun 			PRINTM(MINFO, "RX: port=%d rx_len=%u\n", port, rx_len);
2859*4882a593Smuzhiyun 			rx_blocks = (rx_len + MLAN_SDIO_BLOCK_SIZE - 1) /
2860*4882a593Smuzhiyun 				    MLAN_SDIO_BLOCK_SIZE;
2861*4882a593Smuzhiyun 			if (rx_len <= SDIO_INTF_HEADER_LEN ||
2862*4882a593Smuzhiyun 			    (rx_blocks * MLAN_SDIO_BLOCK_SIZE) >
2863*4882a593Smuzhiyun 				    pmadapter->pcard_sd->mpa_rx.buf_size) {
2864*4882a593Smuzhiyun 				PRINTM(MERROR, "invalid rx_len=%d\n", rx_len);
2865*4882a593Smuzhiyun 				ret = MLAN_STATUS_FAILURE;
2866*4882a593Smuzhiyun 				goto done;
2867*4882a593Smuzhiyun 			}
2868*4882a593Smuzhiyun 			rx_len = (t_u16)(rx_blocks * MLAN_SDIO_BLOCK_SIZE);
2869*4882a593Smuzhiyun 
2870*4882a593Smuzhiyun 			if (!new_mode && (port == CTRL_PORT))
2871*4882a593Smuzhiyun 				pmbuf = wlan_alloc_mlan_buffer(
2872*4882a593Smuzhiyun 					pmadapter, rx_len, 0,
2873*4882a593Smuzhiyun 					MOAL_MALLOC_BUFFER);
2874*4882a593Smuzhiyun 			else
2875*4882a593Smuzhiyun 				pmbuf = wlan_alloc_mlan_buffer(
2876*4882a593Smuzhiyun 					pmadapter, rx_len, MLAN_RX_HEADER_LEN,
2877*4882a593Smuzhiyun 					MOAL_ALLOC_MLAN_BUFFER);
2878*4882a593Smuzhiyun 			if (pmbuf == MNULL) {
2879*4882a593Smuzhiyun 				PRINTM(MERROR,
2880*4882a593Smuzhiyun 				       "Failed to allocate 'mlan_buffer'\n");
2881*4882a593Smuzhiyun 				pmadapter->dbg.num_alloc_buffer_failure++;
2882*4882a593Smuzhiyun 				if (MLAN_STATUS_SUCCESS ==
2883*4882a593Smuzhiyun 				    wlan_sdio_card_to_host_recovery(
2884*4882a593Smuzhiyun 					    pmadapter, port, rx_len))
2885*4882a593Smuzhiyun 					continue;
2886*4882a593Smuzhiyun 				ret = MLAN_STATUS_FAILURE;
2887*4882a593Smuzhiyun 				goto done;
2888*4882a593Smuzhiyun 			}
2889*4882a593Smuzhiyun 			PRINTM(MINFO, "rx_len = %d\n", rx_len);
2890*4882a593Smuzhiyun 			if (MLAN_STATUS_SUCCESS !=
2891*4882a593Smuzhiyun 			    wlan_sdio_card_to_host_mp_aggr(pmadapter, pmbuf,
2892*4882a593Smuzhiyun 							   port, rx_len)) {
2893*4882a593Smuzhiyun 				if ((!new_mode) && (port == CTRL_PORT))
2894*4882a593Smuzhiyun 					pmadapter->dbg
2895*4882a593Smuzhiyun 						.num_cmdevt_card_to_host_failure++;
2896*4882a593Smuzhiyun 				else
2897*4882a593Smuzhiyun 					pmadapter->dbg
2898*4882a593Smuzhiyun 						.num_rx_card_to_host_failure++;
2899*4882a593Smuzhiyun 
2900*4882a593Smuzhiyun 				PRINTM(MERROR,
2901*4882a593Smuzhiyun 				       "Card to host failed: int status=0x%x\n",
2902*4882a593Smuzhiyun 				       sdio_ireg);
2903*4882a593Smuzhiyun 				ret = MLAN_STATUS_FAILURE;
2904*4882a593Smuzhiyun 				goto term_cmd53;
2905*4882a593Smuzhiyun 			}
2906*4882a593Smuzhiyun 		}
2907*4882a593Smuzhiyun 		/* We might receive data/sleep_cfm at the same time */
2908*4882a593Smuzhiyun 		/* reset data_receive flag to avoid ps_state change */
2909*4882a593Smuzhiyun 		if ((ps_state == PS_STATE_SLEEP_CFM) &&
2910*4882a593Smuzhiyun 		    (pmadapter->ps_state == PS_STATE_SLEEP))
2911*4882a593Smuzhiyun 			pmadapter->data_received = MFALSE;
2912*4882a593Smuzhiyun 	}
2913*4882a593Smuzhiyun 
2914*4882a593Smuzhiyun 	ret = MLAN_STATUS_SUCCESS;
2915*4882a593Smuzhiyun 	goto done;
2916*4882a593Smuzhiyun 
2917*4882a593Smuzhiyun term_cmd53:
2918*4882a593Smuzhiyun 	/* terminate cmd53 */
2919*4882a593Smuzhiyun 	if (MLAN_STATUS_SUCCESS != pcb->moal_read_reg(pmadapter->pmoal_handle,
2920*4882a593Smuzhiyun 						      HOST_TO_CARD_EVENT_REG,
2921*4882a593Smuzhiyun 						      &cr))
2922*4882a593Smuzhiyun 		PRINTM(MERROR, "read CFG reg failed\n");
2923*4882a593Smuzhiyun 	PRINTM(MINFO, "Config Reg val = %d\n", cr);
2924*4882a593Smuzhiyun 	if (MLAN_STATUS_SUCCESS != pcb->moal_write_reg(pmadapter->pmoal_handle,
2925*4882a593Smuzhiyun 						       HOST_TO_CARD_EVENT_REG,
2926*4882a593Smuzhiyun 						       (cr | HOST_TERM_CMD53)))
2927*4882a593Smuzhiyun 		PRINTM(MERROR, "write CFG reg failed\n");
2928*4882a593Smuzhiyun 	PRINTM(MINFO, "write success\n");
2929*4882a593Smuzhiyun 	if (MLAN_STATUS_SUCCESS != pcb->moal_read_reg(pmadapter->pmoal_handle,
2930*4882a593Smuzhiyun 						      HOST_TO_CARD_EVENT_REG,
2931*4882a593Smuzhiyun 						      &cr))
2932*4882a593Smuzhiyun 		PRINTM(MERROR, "read CFG reg failed\n");
2933*4882a593Smuzhiyun 	PRINTM(MINFO, "Config reg val =%x\n", cr);
2934*4882a593Smuzhiyun 
2935*4882a593Smuzhiyun done:
2936*4882a593Smuzhiyun 	LEAVE();
2937*4882a593Smuzhiyun 	return ret;
2938*4882a593Smuzhiyun }
2939*4882a593Smuzhiyun 
2940*4882a593Smuzhiyun /**
2941*4882a593Smuzhiyun  *  @brief This function sends data to the card.
2942*4882a593Smuzhiyun  *
2943*4882a593Smuzhiyun  *  @param pmadapter A pointer to mlan_adapter structure
2944*4882a593Smuzhiyun  *  @param type      data or command
2945*4882a593Smuzhiyun  *  @param pmbuf     A pointer to mlan_buffer (pmbuf->data_len should include
2946*4882a593Smuzhiyun  * SDIO header)
2947*4882a593Smuzhiyun  *  @param tx_param  A pointer to mlan_tx_param
2948*4882a593Smuzhiyun  *  @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2949*4882a593Smuzhiyun  */
wlan_sdio_host_to_card(mlan_adapter * pmadapter,t_u8 type,mlan_buffer * pmbuf,mlan_tx_param * tx_param)2950*4882a593Smuzhiyun mlan_status wlan_sdio_host_to_card(mlan_adapter *pmadapter, t_u8 type,
2951*4882a593Smuzhiyun 				   mlan_buffer *pmbuf, mlan_tx_param *tx_param)
2952*4882a593Smuzhiyun {
2953*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
2954*4882a593Smuzhiyun 	t_u32 buf_block_len;
2955*4882a593Smuzhiyun 	t_u32 blksz;
2956*4882a593Smuzhiyun 	t_u8 port = 0;
2957*4882a593Smuzhiyun 	t_u32 cmd53_port = 0;
2958*4882a593Smuzhiyun 	t_u8 *payload = pmbuf->pbuf + pmbuf->data_offset;
2959*4882a593Smuzhiyun 	t_bool new_mode = pmadapter->pcard_sd->supports_sdio_new_mode;
2960*4882a593Smuzhiyun 
2961*4882a593Smuzhiyun 	ENTER();
2962*4882a593Smuzhiyun 
2963*4882a593Smuzhiyun 	/* Allocate buffer and copy payload */
2964*4882a593Smuzhiyun 	blksz = MLAN_SDIO_BLOCK_SIZE;
2965*4882a593Smuzhiyun 	buf_block_len = (pmbuf->data_len + blksz - 1) / blksz;
2966*4882a593Smuzhiyun 	*(t_u16 *)&payload[0] = wlan_cpu_to_le16((t_u16)pmbuf->data_len);
2967*4882a593Smuzhiyun 	*(t_u16 *)&payload[2] = wlan_cpu_to_le16(type);
2968*4882a593Smuzhiyun 
2969*4882a593Smuzhiyun 	/*
2970*4882a593Smuzhiyun 	 * This is SDIO specific header
2971*4882a593Smuzhiyun 	 *  t_u16 length,
2972*4882a593Smuzhiyun 	 *  t_u16 type (MLAN_TYPE_DATA = 0,
2973*4882a593Smuzhiyun 	 *    MLAN_TYPE_CMD = 1, MLAN_TYPE_EVENT = 3)
2974*4882a593Smuzhiyun 	 */
2975*4882a593Smuzhiyun 	if (type == MLAN_TYPE_DATA) {
2976*4882a593Smuzhiyun 		ret = wlan_get_wr_port_data(pmadapter, &port);
2977*4882a593Smuzhiyun 		if (ret != MLAN_STATUS_SUCCESS) {
2978*4882a593Smuzhiyun 			PRINTM(MERROR,
2979*4882a593Smuzhiyun 			       "no wr_port available: wr_bitmap=0x%08x curr_wr_port=%d\n",
2980*4882a593Smuzhiyun 			       pmadapter->pcard_sd->mp_wr_bitmap,
2981*4882a593Smuzhiyun 			       pmadapter->pcard_sd->curr_wr_port);
2982*4882a593Smuzhiyun 			goto exit;
2983*4882a593Smuzhiyun 		}
2984*4882a593Smuzhiyun 		/* Transfer data to card */
2985*4882a593Smuzhiyun 		pmbuf->data_len = buf_block_len * blksz;
2986*4882a593Smuzhiyun 
2987*4882a593Smuzhiyun 		if (tx_param)
2988*4882a593Smuzhiyun 			ret = wlan_host_to_card_mp_aggr(pmadapter, pmbuf, port,
2989*4882a593Smuzhiyun 							tx_param->next_pkt_len);
2990*4882a593Smuzhiyun 		else
2991*4882a593Smuzhiyun 			ret = wlan_host_to_card_mp_aggr(pmadapter, pmbuf, port,
2992*4882a593Smuzhiyun 							0);
2993*4882a593Smuzhiyun 	} else {
2994*4882a593Smuzhiyun 		/*Type must be MLAN_TYPE_CMD*/
2995*4882a593Smuzhiyun 		pmadapter->cmd_sent = MTRUE;
2996*4882a593Smuzhiyun 		if (!new_mode)
2997*4882a593Smuzhiyun 			pmadapter->pcard_sd->mp_wr_bitmap &=
2998*4882a593Smuzhiyun 				(t_u32)(~(1 << CTRL_PORT));
2999*4882a593Smuzhiyun 		if (pmbuf->data_len <= SDIO_INTF_HEADER_LEN ||
3000*4882a593Smuzhiyun 		    pmbuf->data_len > WLAN_UPLD_SIZE)
3001*4882a593Smuzhiyun 			PRINTM(MWARN,
3002*4882a593Smuzhiyun 			       "wlan_sdio_host_to_card(): Error: payload=%p, nb=%d\n",
3003*4882a593Smuzhiyun 			       payload, pmbuf->data_len);
3004*4882a593Smuzhiyun 		/* Transfer data to card */
3005*4882a593Smuzhiyun 		pmbuf->data_len = buf_block_len * blksz;
3006*4882a593Smuzhiyun 		if (new_mode)
3007*4882a593Smuzhiyun 			cmd53_port =
3008*4882a593Smuzhiyun 				(pmadapter->pcard_sd->ioport) | CMD_PORT_SLCT;
3009*4882a593Smuzhiyun 		else
3010*4882a593Smuzhiyun 			cmd53_port = pmadapter->pcard_sd->ioport + CTRL_PORT;
3011*4882a593Smuzhiyun 		ret = wlan_write_data_sync(pmadapter, pmbuf, cmd53_port);
3012*4882a593Smuzhiyun 	}
3013*4882a593Smuzhiyun 
3014*4882a593Smuzhiyun 	if (ret == MLAN_STATUS_FAILURE) {
3015*4882a593Smuzhiyun 		PRINTM(MERROR, "Error: host_to_card failed: 0x%X\n", ret);
3016*4882a593Smuzhiyun 		if (type == MLAN_TYPE_CMD)
3017*4882a593Smuzhiyun 			pmadapter->cmd_sent = MFALSE;
3018*4882a593Smuzhiyun 		if (type == MLAN_TYPE_DATA)
3019*4882a593Smuzhiyun 			pmadapter->data_sent = MFALSE;
3020*4882a593Smuzhiyun 	} else {
3021*4882a593Smuzhiyun 		if (type == MLAN_TYPE_DATA) {
3022*4882a593Smuzhiyun 			if (!(pmadapter->pcard_sd->mp_wr_bitmap &
3023*4882a593Smuzhiyun 			      (1 << pmadapter->pcard_sd->curr_wr_port)))
3024*4882a593Smuzhiyun 				pmadapter->data_sent = MTRUE;
3025*4882a593Smuzhiyun 			else
3026*4882a593Smuzhiyun 				pmadapter->data_sent = MFALSE;
3027*4882a593Smuzhiyun 		}
3028*4882a593Smuzhiyun 		DBG_HEXDUMP(MIF_D, "SDIO Blk Wr",
3029*4882a593Smuzhiyun 			    pmbuf->pbuf + pmbuf->data_offset,
3030*4882a593Smuzhiyun 			    MIN(pmbuf->data_len, MAX_DATA_DUMP_LEN));
3031*4882a593Smuzhiyun 	}
3032*4882a593Smuzhiyun exit:
3033*4882a593Smuzhiyun 	LEAVE();
3034*4882a593Smuzhiyun 	return ret;
3035*4882a593Smuzhiyun }
3036*4882a593Smuzhiyun 
3037*4882a593Smuzhiyun #if (defined(SD9098) || defined(SD9097) || defined(SDNW62X) || defined(SD9177))
3038*4882a593Smuzhiyun /**
3039*4882a593Smuzhiyun  *  @brief This function sends vdll data to the card.
3040*4882a593Smuzhiyun  *
3041*4882a593Smuzhiyun  *  @param pmadapter   A pointer to mlan_adapter structure
3042*4882a593Smuzhiyun  *  @param pmbuf     A pointer to mlan_buffer (pmbuf->data_len should include
3043*4882a593Smuzhiyun  * SDIO header)
3044*4882a593Smuzhiyun  *  @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
3045*4882a593Smuzhiyun  */
wlan_sdio_send_vdll(mlan_adapter * pmadapter,mlan_buffer * pmbuf)3046*4882a593Smuzhiyun static mlan_status wlan_sdio_send_vdll(mlan_adapter *pmadapter,
3047*4882a593Smuzhiyun 				       mlan_buffer *pmbuf)
3048*4882a593Smuzhiyun {
3049*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
3050*4882a593Smuzhiyun 	t_u32 buf_block_len;
3051*4882a593Smuzhiyun 	t_u32 blksz;
3052*4882a593Smuzhiyun 	t_u8 *payload = pmbuf->pbuf + pmbuf->data_offset;
3053*4882a593Smuzhiyun 	t_u32 cmd53_port = 0;
3054*4882a593Smuzhiyun 	ENTER();
3055*4882a593Smuzhiyun 	blksz = MLAN_SDIO_BLOCK_SIZE;
3056*4882a593Smuzhiyun 	buf_block_len = (pmbuf->data_len + blksz - 1) / blksz;
3057*4882a593Smuzhiyun 
3058*4882a593Smuzhiyun 	*(t_u16 *)&payload[0] = wlan_cpu_to_le16((t_u16)pmbuf->data_len);
3059*4882a593Smuzhiyun 	*(t_u16 *)&payload[2] = wlan_cpu_to_le16(MLAN_TYPE_VDLL);
3060*4882a593Smuzhiyun 
3061*4882a593Smuzhiyun 	pmbuf->data_len = buf_block_len * blksz;
3062*4882a593Smuzhiyun 
3063*4882a593Smuzhiyun 	if (pmbuf->data_len > MRVDRV_SIZE_OF_CMD_BUFFER) {
3064*4882a593Smuzhiyun 		PRINTM(MERROR, "VDLL block is too big: %d\n", pmbuf->data_len);
3065*4882a593Smuzhiyun 		return MLAN_STATUS_FAILURE;
3066*4882a593Smuzhiyun 	}
3067*4882a593Smuzhiyun 	cmd53_port = (pmadapter->pcard_sd->ioport) | CMD_PORT_SLCT;
3068*4882a593Smuzhiyun 	pmadapter->cmd_sent = MTRUE;
3069*4882a593Smuzhiyun 	ret = wlan_write_data_sync(pmadapter, pmbuf, cmd53_port);
3070*4882a593Smuzhiyun 	if (ret == MLAN_STATUS_FAILURE)
3071*4882a593Smuzhiyun 		PRINTM(MERROR, "Send Vdll: host_to_card failed: 0x%X\n", ret);
3072*4882a593Smuzhiyun 	else
3073*4882a593Smuzhiyun 		DBG_HEXDUMP(MIF_D, "SDIO Blk Wr",
3074*4882a593Smuzhiyun 			    pmbuf->pbuf + pmbuf->data_offset,
3075*4882a593Smuzhiyun 			    MIN(pmbuf->data_len, MAX_DATA_DUMP_LEN));
3076*4882a593Smuzhiyun 	LEAVE();
3077*4882a593Smuzhiyun 	return ret;
3078*4882a593Smuzhiyun }
3079*4882a593Smuzhiyun #endif
3080*4882a593Smuzhiyun 
3081*4882a593Smuzhiyun /**
3082*4882a593Smuzhiyun  *  @brief This function sends data to the card.
3083*4882a593Smuzhiyun  *
3084*4882a593Smuzhiyun  *  @param pmpriv    A pointer to mlan_private structure
3085*4882a593Smuzhiyun  *  @param type      data or command
3086*4882a593Smuzhiyun  *  @param pmbuf     A pointer to mlan_buffer (pmbuf->data_len should include
3087*4882a593Smuzhiyun  * SDIO header)
3088*4882a593Smuzhiyun  *  @param tx_param  A pointer to mlan_tx_param
3089*4882a593Smuzhiyun  *  @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
3090*4882a593Smuzhiyun  */
wlan_sdio_host_to_card_ext(pmlan_private pmpriv,t_u8 type,mlan_buffer * pmbuf,mlan_tx_param * tx_param)3091*4882a593Smuzhiyun static mlan_status wlan_sdio_host_to_card_ext(pmlan_private pmpriv, t_u8 type,
3092*4882a593Smuzhiyun 					      mlan_buffer *pmbuf,
3093*4882a593Smuzhiyun 					      mlan_tx_param *tx_param)
3094*4882a593Smuzhiyun {
3095*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
3096*4882a593Smuzhiyun 	mlan_adapter *pmadapter = pmpriv->adapter;
3097*4882a593Smuzhiyun 
3098*4882a593Smuzhiyun #if (defined(SD9098) || defined(SD9097) || defined(SDNW62X) || defined(SD9177))
3099*4882a593Smuzhiyun 	if (type == MLAN_TYPE_VDLL)
3100*4882a593Smuzhiyun 		return wlan_sdio_send_vdll(pmadapter, pmbuf);
3101*4882a593Smuzhiyun #endif
3102*4882a593Smuzhiyun 	ret = wlan_sdio_host_to_card(pmadapter, type, pmbuf, tx_param);
3103*4882a593Smuzhiyun 
3104*4882a593Smuzhiyun 	if (type == MLAN_TYPE_DATA && ret == MLAN_STATUS_FAILURE)
3105*4882a593Smuzhiyun 		pmadapter->data_sent = MFALSE;
3106*4882a593Smuzhiyun 
3107*4882a593Smuzhiyun 	LEAVE();
3108*4882a593Smuzhiyun 	return ret;
3109*4882a593Smuzhiyun }
3110*4882a593Smuzhiyun 
3111*4882a593Smuzhiyun /**
3112*4882a593Smuzhiyun  *  @brief Deaggregate single port aggregation packet
3113*4882a593Smuzhiyun  *
3114*4882a593Smuzhiyun  *  @param pmadapter  A pointer to mlan_adapter structure
3115*4882a593Smuzhiyun  *  @param buf	A pointer to aggregated data packet
3116*4882a593Smuzhiyun  *  @param len
3117*4882a593Smuzhiyun  *
3118*4882a593Smuzhiyun  *  @return		N/A
3119*4882a593Smuzhiyun  */
wlan_decode_spa_buffer(mlan_adapter * pmadapter,t_u8 * buf,t_u32 len)3120*4882a593Smuzhiyun void wlan_decode_spa_buffer(mlan_adapter *pmadapter, t_u8 *buf, t_u32 len)
3121*4882a593Smuzhiyun {
3122*4882a593Smuzhiyun 	int total_pkt_len;
3123*4882a593Smuzhiyun 	t_u8 block_num = 0;
3124*4882a593Smuzhiyun 	t_u16 block_size = 0;
3125*4882a593Smuzhiyun 	t_u8 *data;
3126*4882a593Smuzhiyun 	t_u32 pkt_len;
3127*4882a593Smuzhiyun 	mlan_buffer *mbuf_deaggr = MNULL;
3128*4882a593Smuzhiyun 
3129*4882a593Smuzhiyun 	ENTER();
3130*4882a593Smuzhiyun 
3131*4882a593Smuzhiyun 	data = (t_u8 *)buf;
3132*4882a593Smuzhiyun 	total_pkt_len = len;
3133*4882a593Smuzhiyun 	if (total_pkt_len < pmadapter->pcard_sd->sdio_rx_block_size) {
3134*4882a593Smuzhiyun 		PRINTM(MERROR, "Invalid sp aggr packet size=%d\n",
3135*4882a593Smuzhiyun 		       total_pkt_len);
3136*4882a593Smuzhiyun 		goto done;
3137*4882a593Smuzhiyun 	}
3138*4882a593Smuzhiyun 	while (total_pkt_len >=
3139*4882a593Smuzhiyun 	       (OFFSET_OF_SDIO_HEADER + SDIO_INTF_HEADER_LEN)) {
3140*4882a593Smuzhiyun 		block_num = *(data + OFFSET_OF_BLOCK_NUMBER);
3141*4882a593Smuzhiyun 		block_size =
3142*4882a593Smuzhiyun 			pmadapter->pcard_sd->sdio_rx_block_size * block_num;
3143*4882a593Smuzhiyun 		if (block_size > total_pkt_len) {
3144*4882a593Smuzhiyun 			PRINTM(MERROR,
3145*4882a593Smuzhiyun 			       "Error in pkt, block_num=%d, pkt_len=%d\n",
3146*4882a593Smuzhiyun 			       block_num, total_pkt_len);
3147*4882a593Smuzhiyun 			break;
3148*4882a593Smuzhiyun 		}
3149*4882a593Smuzhiyun 		pkt_len = wlan_le16_to_cpu(
3150*4882a593Smuzhiyun 			*(t_u16 *)(data + OFFSET_OF_SDIO_HEADER));
3151*4882a593Smuzhiyun 		if ((pkt_len + OFFSET_OF_SDIO_HEADER) > block_size) {
3152*4882a593Smuzhiyun 			PRINTM(MERROR,
3153*4882a593Smuzhiyun 			       "Error in pkt, pkt_len=%d, block_size=%d\n",
3154*4882a593Smuzhiyun 			       pkt_len, block_size);
3155*4882a593Smuzhiyun 			break;
3156*4882a593Smuzhiyun 		}
3157*4882a593Smuzhiyun 		mbuf_deaggr = wlan_alloc_mlan_buffer(
3158*4882a593Smuzhiyun 			pmadapter, pkt_len - SDIO_INTF_HEADER_LEN,
3159*4882a593Smuzhiyun 			MLAN_RX_HEADER_LEN, MOAL_ALLOC_MLAN_BUFFER);
3160*4882a593Smuzhiyun 		if (mbuf_deaggr == MNULL) {
3161*4882a593Smuzhiyun 			PRINTM(MERROR, "Error allocating daggr mlan_buffer\n");
3162*4882a593Smuzhiyun 			break;
3163*4882a593Smuzhiyun 		}
3164*4882a593Smuzhiyun 		memcpy_ext(pmadapter,
3165*4882a593Smuzhiyun 			   mbuf_deaggr->pbuf + mbuf_deaggr->data_offset,
3166*4882a593Smuzhiyun 			   data + OFFSET_OF_SDIO_HEADER + SDIO_INTF_HEADER_LEN,
3167*4882a593Smuzhiyun 			   pkt_len - SDIO_INTF_HEADER_LEN,
3168*4882a593Smuzhiyun 			   pkt_len - SDIO_INTF_HEADER_LEN);
3169*4882a593Smuzhiyun 		mbuf_deaggr->data_len = pkt_len - SDIO_INTF_HEADER_LEN;
3170*4882a593Smuzhiyun 		wlan_handle_rx_packet(pmadapter, mbuf_deaggr);
3171*4882a593Smuzhiyun 		data += block_size;
3172*4882a593Smuzhiyun 		total_pkt_len -= block_size;
3173*4882a593Smuzhiyun 		if (total_pkt_len < pmadapter->pcard_sd->sdio_rx_block_size)
3174*4882a593Smuzhiyun 			break;
3175*4882a593Smuzhiyun 	}
3176*4882a593Smuzhiyun done:
3177*4882a593Smuzhiyun 	LEAVE();
3178*4882a593Smuzhiyun 	return;
3179*4882a593Smuzhiyun }
3180*4882a593Smuzhiyun 
3181*4882a593Smuzhiyun /**
3182*4882a593Smuzhiyun  *  @brief This function deaggr rx pkt
3183*4882a593Smuzhiyun  *
3184*4882a593Smuzhiyun  *  @param pmadapter A pointer to mlan_adapter structure
3185*4882a593Smuzhiyun  *  @param pmbuf     A pointer to the SDIO mpa data
3186*4882a593Smuzhiyun  *  @return          N/A
3187*4882a593Smuzhiyun  */
wlan_sdio_deaggr_rx_pkt(pmlan_adapter pmadapter,mlan_buffer * pmbuf)3188*4882a593Smuzhiyun t_void wlan_sdio_deaggr_rx_pkt(pmlan_adapter pmadapter, mlan_buffer *pmbuf)
3189*4882a593Smuzhiyun {
3190*4882a593Smuzhiyun 	if (pmbuf->buf_type == MLAN_BUF_TYPE_SPA_DATA) {
3191*4882a593Smuzhiyun 		wlan_decode_spa_buffer(pmadapter,
3192*4882a593Smuzhiyun 				       pmbuf->pbuf + pmbuf->data_offset,
3193*4882a593Smuzhiyun 				       pmbuf->data_len);
3194*4882a593Smuzhiyun 		wlan_free_mlan_buffer(pmadapter, pmbuf);
3195*4882a593Smuzhiyun 	} else
3196*4882a593Smuzhiyun 		wlan_handle_rx_packet(pmadapter, pmbuf);
3197*4882a593Smuzhiyun }
3198*4882a593Smuzhiyun 
3199*4882a593Smuzhiyun /**
3200*4882a593Smuzhiyun  *  @brief This function allocates buffer for the SDIO aggregation buffer
3201*4882a593Smuzhiyun  *          related members of adapter structure
3202*4882a593Smuzhiyun  *
3203*4882a593Smuzhiyun  *  @param pmadapter       A pointer to mlan_adapter structure
3204*4882a593Smuzhiyun  *  @param mpa_tx_buf_size Tx buffer size to allocate
3205*4882a593Smuzhiyun  *  @param mpa_rx_buf_size Rx buffer size to allocate
3206*4882a593Smuzhiyun  *
3207*4882a593Smuzhiyun  *  @return        MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
3208*4882a593Smuzhiyun  */
wlan_alloc_sdio_mpa_buffers(mlan_adapter * pmadapter,t_u32 mpa_tx_buf_size,t_u32 mpa_rx_buf_size)3209*4882a593Smuzhiyun mlan_status wlan_alloc_sdio_mpa_buffers(mlan_adapter *pmadapter,
3210*4882a593Smuzhiyun 					t_u32 mpa_tx_buf_size,
3211*4882a593Smuzhiyun 					t_u32 mpa_rx_buf_size)
3212*4882a593Smuzhiyun {
3213*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
3214*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
3215*4882a593Smuzhiyun 	t_u8 mp_aggr_pkt_limit = pmadapter->pcard_sd->mp_aggr_pkt_limit;
3216*4882a593Smuzhiyun 
3217*4882a593Smuzhiyun 	ENTER();
3218*4882a593Smuzhiyun 
3219*4882a593Smuzhiyun 	if ((pmadapter->pcard_sd->max_segs < mp_aggr_pkt_limit) ||
3220*4882a593Smuzhiyun 	    (pmadapter->pcard_sd->max_seg_size <
3221*4882a593Smuzhiyun 	     pmadapter->pcard_sd->max_sp_tx_size)) {
3222*4882a593Smuzhiyun 		ret = pcb->moal_malloc(
3223*4882a593Smuzhiyun 			pmadapter->pmoal_handle,
3224*4882a593Smuzhiyun 			mpa_tx_buf_size + DMA_ALIGNMENT,
3225*4882a593Smuzhiyun 			MLAN_MEM_DEF | MLAN_MEM_DMA,
3226*4882a593Smuzhiyun 			(t_u8 **)&pmadapter->pcard_sd->mpa_tx.head_ptr);
3227*4882a593Smuzhiyun 		if (ret != MLAN_STATUS_SUCCESS ||
3228*4882a593Smuzhiyun 		    !pmadapter->pcard_sd->mpa_tx.head_ptr) {
3229*4882a593Smuzhiyun 			PRINTM(MERROR,
3230*4882a593Smuzhiyun 			       "Could not allocate buffer for SDIO MP TX aggr\n");
3231*4882a593Smuzhiyun 			ret = MLAN_STATUS_FAILURE;
3232*4882a593Smuzhiyun 			goto error;
3233*4882a593Smuzhiyun 		}
3234*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_tx.buf = (t_u8 *)ALIGN_ADDR(
3235*4882a593Smuzhiyun 			pmadapter->pcard_sd->mpa_tx.head_ptr, DMA_ALIGNMENT);
3236*4882a593Smuzhiyun 	} else {
3237*4882a593Smuzhiyun 		PRINTM(MMSG, "wlan: Enable TX SG mode\n");
3238*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_tx.head_ptr = MNULL;
3239*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_tx.buf = MNULL;
3240*4882a593Smuzhiyun 	}
3241*4882a593Smuzhiyun 	pmadapter->pcard_sd->mpa_tx.buf_size = mpa_tx_buf_size;
3242*4882a593Smuzhiyun 
3243*4882a593Smuzhiyun 	if ((pmadapter->pcard_sd->max_segs < mp_aggr_pkt_limit) ||
3244*4882a593Smuzhiyun 	    (pmadapter->pcard_sd->max_seg_size <
3245*4882a593Smuzhiyun 	     pmadapter->pcard_sd->max_sp_rx_size)) {
3246*4882a593Smuzhiyun 		ret = pcb->moal_malloc(
3247*4882a593Smuzhiyun 			pmadapter->pmoal_handle,
3248*4882a593Smuzhiyun 			mpa_rx_buf_size + DMA_ALIGNMENT,
3249*4882a593Smuzhiyun 			MLAN_MEM_DEF | MLAN_MEM_DMA,
3250*4882a593Smuzhiyun 			(t_u8 **)&pmadapter->pcard_sd->mpa_rx.head_ptr);
3251*4882a593Smuzhiyun 		if (ret != MLAN_STATUS_SUCCESS ||
3252*4882a593Smuzhiyun 		    !pmadapter->pcard_sd->mpa_rx.head_ptr) {
3253*4882a593Smuzhiyun 			PRINTM(MERROR,
3254*4882a593Smuzhiyun 			       "Could not allocate buffer for SDIO MP RX aggr\n");
3255*4882a593Smuzhiyun 			ret = MLAN_STATUS_FAILURE;
3256*4882a593Smuzhiyun 			goto error;
3257*4882a593Smuzhiyun 		}
3258*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_rx.buf = (t_u8 *)ALIGN_ADDR(
3259*4882a593Smuzhiyun 			pmadapter->pcard_sd->mpa_rx.head_ptr, DMA_ALIGNMENT);
3260*4882a593Smuzhiyun 	} else {
3261*4882a593Smuzhiyun 		PRINTM(MMSG, "wlan: Enable RX SG mode\n");
3262*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_rx.head_ptr = MNULL;
3263*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_rx.buf = MNULL;
3264*4882a593Smuzhiyun 	}
3265*4882a593Smuzhiyun 	pmadapter->pcard_sd->mpa_rx.buf_size = mpa_rx_buf_size;
3266*4882a593Smuzhiyun error:
3267*4882a593Smuzhiyun 	if (ret != MLAN_STATUS_SUCCESS)
3268*4882a593Smuzhiyun 		wlan_free_sdio_mpa_buffers(pmadapter);
3269*4882a593Smuzhiyun 
3270*4882a593Smuzhiyun 	LEAVE();
3271*4882a593Smuzhiyun 	return ret;
3272*4882a593Smuzhiyun }
3273*4882a593Smuzhiyun 
3274*4882a593Smuzhiyun /**
3275*4882a593Smuzhiyun  *  @brief This function frees buffers for the SDIO aggregation
3276*4882a593Smuzhiyun  *
3277*4882a593Smuzhiyun  *  @param pmadapter       A pointer to mlan_adapter structure
3278*4882a593Smuzhiyun  *
3279*4882a593Smuzhiyun  *  @return        MLAN_STATUS_SUCCESS
3280*4882a593Smuzhiyun  */
wlan_free_sdio_mpa_buffers(mlan_adapter * pmadapter)3281*4882a593Smuzhiyun mlan_status wlan_free_sdio_mpa_buffers(mlan_adapter *pmadapter)
3282*4882a593Smuzhiyun {
3283*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
3284*4882a593Smuzhiyun 
3285*4882a593Smuzhiyun 	ENTER();
3286*4882a593Smuzhiyun 
3287*4882a593Smuzhiyun 	if (pmadapter->pcard_sd->mpa_tx.buf) {
3288*4882a593Smuzhiyun 		pcb->moal_mfree(pmadapter->pmoal_handle,
3289*4882a593Smuzhiyun 				(t_u8 *)pmadapter->pcard_sd->mpa_tx.head_ptr);
3290*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_tx.head_ptr = MNULL;
3291*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_tx.buf = MNULL;
3292*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_tx.buf_size = 0;
3293*4882a593Smuzhiyun 	}
3294*4882a593Smuzhiyun 
3295*4882a593Smuzhiyun 	if (pmadapter->pcard_sd->mpa_rx.buf) {
3296*4882a593Smuzhiyun 		pcb->moal_mfree(pmadapter->pmoal_handle,
3297*4882a593Smuzhiyun 				(t_u8 *)pmadapter->pcard_sd->mpa_rx.head_ptr);
3298*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_rx.head_ptr = MNULL;
3299*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_rx.buf = MNULL;
3300*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_rx.buf_size = 0;
3301*4882a593Smuzhiyun 	}
3302*4882a593Smuzhiyun 
3303*4882a593Smuzhiyun 	LEAVE();
3304*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
3305*4882a593Smuzhiyun }
3306*4882a593Smuzhiyun 
3307*4882a593Smuzhiyun /**
3308*4882a593Smuzhiyun  *  @brief This function re-allocate rx mpa buffer
3309*4882a593Smuzhiyun  *
3310*4882a593Smuzhiyun  *  @param pmadapter       A pointer to mlan_adapter structure
3311*4882a593Smuzhiyun  *
3312*4882a593Smuzhiyun  *  @return        MLAN_STATUS_SUCCESS
3313*4882a593Smuzhiyun  */
wlan_re_alloc_sdio_rx_mpa_buffer(mlan_adapter * pmadapter)3314*4882a593Smuzhiyun mlan_status wlan_re_alloc_sdio_rx_mpa_buffer(mlan_adapter *pmadapter)
3315*4882a593Smuzhiyun {
3316*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
3317*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
3318*4882a593Smuzhiyun 	t_u8 mp_aggr_pkt_limit = pmadapter->pcard_sd->mp_aggr_pkt_limit;
3319*4882a593Smuzhiyun 	t_u32 mpa_rx_buf_size = pmadapter->pcard_sd->mp_tx_aggr_buf_size;
3320*4882a593Smuzhiyun 
3321*4882a593Smuzhiyun 	if (pmadapter->pcard_sd->mpa_rx.buf) {
3322*4882a593Smuzhiyun 		pcb->moal_mfree(pmadapter->pmoal_handle,
3323*4882a593Smuzhiyun 				(t_u8 *)pmadapter->pcard_sd->mpa_rx.head_ptr);
3324*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_rx.head_ptr = MNULL;
3325*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_rx.buf = MNULL;
3326*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_rx.buf_size = 0;
3327*4882a593Smuzhiyun 	}
3328*4882a593Smuzhiyun 	if (pmadapter->pcard_sd->sdio_rx_aggr_enable) {
3329*4882a593Smuzhiyun 		mpa_rx_buf_size = MAX(mpa_rx_buf_size, SDIO_CMD53_MAX_SIZE);
3330*4882a593Smuzhiyun 		/** reallocate rx buffer for recover when single port rx
3331*4882a593Smuzhiyun 		 * aggregation enabled */
3332*4882a593Smuzhiyun 		if (pmadapter->pcard_sd->rx_buffer) {
3333*4882a593Smuzhiyun 			pcb->moal_mfree(pmadapter->pmoal_handle,
3334*4882a593Smuzhiyun 					(t_u8 *)pmadapter->pcard_sd->rx_buffer);
3335*4882a593Smuzhiyun 			pmadapter->pcard_sd->rx_buffer = MNULL;
3336*4882a593Smuzhiyun 			pmadapter->pcard_sd->rx_buf = MNULL;
3337*4882a593Smuzhiyun 		}
3338*4882a593Smuzhiyun 		ret = pmadapter->callbacks.moal_malloc(
3339*4882a593Smuzhiyun 			pmadapter->pmoal_handle,
3340*4882a593Smuzhiyun 			SDIO_CMD53_MAX_SIZE + DMA_ALIGNMENT,
3341*4882a593Smuzhiyun 			MLAN_MEM_DEF | MLAN_MEM_DMA,
3342*4882a593Smuzhiyun 			(t_u8 **)&pmadapter->pcard_sd->rx_buffer);
3343*4882a593Smuzhiyun 
3344*4882a593Smuzhiyun 		if (ret != MLAN_STATUS_SUCCESS ||
3345*4882a593Smuzhiyun 		    !pmadapter->pcard_sd->rx_buffer) {
3346*4882a593Smuzhiyun 			PRINTM(MERROR, "Failed to allocate receive buffer\n");
3347*4882a593Smuzhiyun 			ret = MLAN_STATUS_FAILURE;
3348*4882a593Smuzhiyun 			goto error;
3349*4882a593Smuzhiyun 		}
3350*4882a593Smuzhiyun 		pmadapter->pcard_sd->rx_buf = (t_u8 *)ALIGN_ADDR(
3351*4882a593Smuzhiyun 			pmadapter->pcard_sd->rx_buffer, DMA_ALIGNMENT);
3352*4882a593Smuzhiyun 	}
3353*4882a593Smuzhiyun 	if ((pmadapter->pcard_sd->max_segs < mp_aggr_pkt_limit) ||
3354*4882a593Smuzhiyun 	    (pmadapter->pcard_sd->max_seg_size <
3355*4882a593Smuzhiyun 	     pmadapter->pcard_sd->max_sp_rx_size)) {
3356*4882a593Smuzhiyun 		ret = pcb->moal_malloc(
3357*4882a593Smuzhiyun 			pmadapter->pmoal_handle,
3358*4882a593Smuzhiyun 			mpa_rx_buf_size + DMA_ALIGNMENT,
3359*4882a593Smuzhiyun 			MLAN_MEM_DEF | MLAN_MEM_DMA,
3360*4882a593Smuzhiyun 			(t_u8 **)&pmadapter->pcard_sd->mpa_rx.head_ptr);
3361*4882a593Smuzhiyun 		if (ret != MLAN_STATUS_SUCCESS ||
3362*4882a593Smuzhiyun 		    !pmadapter->pcard_sd->mpa_rx.head_ptr) {
3363*4882a593Smuzhiyun 			PRINTM(MERROR,
3364*4882a593Smuzhiyun 			       "Could not allocate buffer for SDIO MP RX aggr\n");
3365*4882a593Smuzhiyun 			ret = MLAN_STATUS_FAILURE;
3366*4882a593Smuzhiyun 			goto error;
3367*4882a593Smuzhiyun 		}
3368*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_rx.buf = (t_u8 *)ALIGN_ADDR(
3369*4882a593Smuzhiyun 			pmadapter->pcard_sd->mpa_rx.head_ptr, DMA_ALIGNMENT);
3370*4882a593Smuzhiyun 	} else {
3371*4882a593Smuzhiyun 		PRINTM(MMSG, "wlan: Enable RX SG mode\n");
3372*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_rx.head_ptr = MNULL;
3373*4882a593Smuzhiyun 		pmadapter->pcard_sd->mpa_rx.buf = MNULL;
3374*4882a593Smuzhiyun 	}
3375*4882a593Smuzhiyun 	pmadapter->pcard_sd->mpa_rx.buf_size = mpa_rx_buf_size;
3376*4882a593Smuzhiyun 	PRINTM(MMSG, "mpa_rx_buf_size=%d\n", mpa_rx_buf_size);
3377*4882a593Smuzhiyun error:
3378*4882a593Smuzhiyun 	return ret;
3379*4882a593Smuzhiyun }
3380*4882a593Smuzhiyun 
3381*4882a593Smuzhiyun /**
3382*4882a593Smuzhiyun  *  @brief This function wakes up the card.
3383*4882a593Smuzhiyun  *
3384*4882a593Smuzhiyun  *  @param pmadapter		A pointer to mlan_adapter structure
3385*4882a593Smuzhiyun  *  @param timeout          set timeout flag
3386*4882a593Smuzhiyun  *
3387*4882a593Smuzhiyun  *  @return			MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
3388*4882a593Smuzhiyun  */
wlan_pm_sdio_wakeup_card(pmlan_adapter pmadapter,t_u8 timeout)3389*4882a593Smuzhiyun static mlan_status wlan_pm_sdio_wakeup_card(pmlan_adapter pmadapter,
3390*4882a593Smuzhiyun 					    t_u8 timeout)
3391*4882a593Smuzhiyun {
3392*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
3393*4882a593Smuzhiyun 	t_u32 age_ts_usec;
3394*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
3395*4882a593Smuzhiyun 
3396*4882a593Smuzhiyun 	ENTER();
3397*4882a593Smuzhiyun 	PRINTM(MEVENT, "Wakeup device...\n");
3398*4882a593Smuzhiyun 	pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
3399*4882a593Smuzhiyun 						  &pmadapter->pm_wakeup_in_secs,
3400*4882a593Smuzhiyun 						  &age_ts_usec);
3401*4882a593Smuzhiyun 
3402*4882a593Smuzhiyun 	if (timeout) {
3403*4882a593Smuzhiyun 		pmadapter->callbacks.moal_start_timer(
3404*4882a593Smuzhiyun 			pmadapter->pmoal_handle, pmadapter->pwakeup_fw_timer,
3405*4882a593Smuzhiyun 			MFALSE, MRVDRV_TIMER_3S);
3406*4882a593Smuzhiyun 		pmadapter->wakeup_fw_timer_is_set = MTRUE;
3407*4882a593Smuzhiyun 	}
3408*4882a593Smuzhiyun 
3409*4882a593Smuzhiyun 	ret = pcb->moal_write_reg(pmadapter->pmoal_handle,
3410*4882a593Smuzhiyun 				  HOST_TO_CARD_EVENT_REG, HOST_POWER_UP);
3411*4882a593Smuzhiyun 
3412*4882a593Smuzhiyun 	LEAVE();
3413*4882a593Smuzhiyun 	return ret;
3414*4882a593Smuzhiyun }
3415*4882a593Smuzhiyun 
3416*4882a593Smuzhiyun /**
3417*4882a593Smuzhiyun  *  @brief This function resets the PM setting of the card.
3418*4882a593Smuzhiyun  *
3419*4882a593Smuzhiyun  *  @param pmadapter		A pointer to mlan_adapter structure
3420*4882a593Smuzhiyun  *
3421*4882a593Smuzhiyun  *  @return			MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
3422*4882a593Smuzhiyun  */
wlan_pm_sdio_reset_card(pmlan_adapter pmadapter)3423*4882a593Smuzhiyun static mlan_status wlan_pm_sdio_reset_card(pmlan_adapter pmadapter)
3424*4882a593Smuzhiyun {
3425*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
3426*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
3427*4882a593Smuzhiyun 
3428*4882a593Smuzhiyun 	ENTER();
3429*4882a593Smuzhiyun 
3430*4882a593Smuzhiyun 	ret = pcb->moal_write_reg(pmadapter->pmoal_handle,
3431*4882a593Smuzhiyun 				  HOST_TO_CARD_EVENT_REG, 0);
3432*4882a593Smuzhiyun 
3433*4882a593Smuzhiyun 	LEAVE();
3434*4882a593Smuzhiyun 	return ret;
3435*4882a593Smuzhiyun }
3436*4882a593Smuzhiyun 
3437*4882a593Smuzhiyun /**
3438*4882a593Smuzhiyun  *  @brief  This function issues commands to initialize firmware
3439*4882a593Smuzhiyun  *
3440*4882a593Smuzhiyun  *  @param priv     A pointer to mlan_private structure
3441*4882a593Smuzhiyun  *
3442*4882a593Smuzhiyun  *  @return         MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
3443*4882a593Smuzhiyun  */
wlan_set_sdio_gpio_int(pmlan_private priv)3444*4882a593Smuzhiyun mlan_status wlan_set_sdio_gpio_int(pmlan_private priv)
3445*4882a593Smuzhiyun {
3446*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
3447*4882a593Smuzhiyun 	pmlan_adapter pmadapter = MNULL;
3448*4882a593Smuzhiyun 	HostCmd_DS_SDIO_GPIO_INT_CONFIG sdio_int_cfg;
3449*4882a593Smuzhiyun 
3450*4882a593Smuzhiyun 	if (!priv) {
3451*4882a593Smuzhiyun 		LEAVE();
3452*4882a593Smuzhiyun 		return MLAN_STATUS_FAILURE;
3453*4882a593Smuzhiyun 	}
3454*4882a593Smuzhiyun 	pmadapter = priv->adapter;
3455*4882a593Smuzhiyun 
3456*4882a593Smuzhiyun 	ENTER();
3457*4882a593Smuzhiyun 
3458*4882a593Smuzhiyun 	if (pmadapter->pcard_sd->int_mode == INT_MODE_GPIO) {
3459*4882a593Smuzhiyun 		if (pmadapter->pcard_sd->gpio_pin != GPIO_INT_NEW_MODE) {
3460*4882a593Smuzhiyun 			PRINTM(MINFO,
3461*4882a593Smuzhiyun 			       "SDIO_GPIO_INT_CONFIG: interrupt mode is GPIO\n");
3462*4882a593Smuzhiyun 			sdio_int_cfg.action = HostCmd_ACT_GEN_SET;
3463*4882a593Smuzhiyun 			sdio_int_cfg.gpio_pin = pmadapter->pcard_sd->gpio_pin;
3464*4882a593Smuzhiyun 			sdio_int_cfg.gpio_int_edge = INT_FALLING_EDGE;
3465*4882a593Smuzhiyun 			sdio_int_cfg.gpio_pulse_width = DELAY_1_US;
3466*4882a593Smuzhiyun 			ret = wlan_prepare_cmd(priv,
3467*4882a593Smuzhiyun 					       HostCmd_CMD_SDIO_GPIO_INT_CONFIG,
3468*4882a593Smuzhiyun 					       HostCmd_ACT_GEN_SET, 0, MNULL,
3469*4882a593Smuzhiyun 					       &sdio_int_cfg);
3470*4882a593Smuzhiyun 
3471*4882a593Smuzhiyun 			if (ret) {
3472*4882a593Smuzhiyun 				PRINTM(MERROR,
3473*4882a593Smuzhiyun 				       "SDIO_GPIO_INT_CONFIG: send command fail\n");
3474*4882a593Smuzhiyun 				ret = MLAN_STATUS_FAILURE;
3475*4882a593Smuzhiyun 			}
3476*4882a593Smuzhiyun 		}
3477*4882a593Smuzhiyun 	} else {
3478*4882a593Smuzhiyun 		PRINTM(MINFO, "SDIO_GPIO_INT_CONFIG: interrupt mode is SDIO\n");
3479*4882a593Smuzhiyun 	}
3480*4882a593Smuzhiyun 
3481*4882a593Smuzhiyun 	LEAVE();
3482*4882a593Smuzhiyun 	return ret;
3483*4882a593Smuzhiyun }
3484*4882a593Smuzhiyun 
3485*4882a593Smuzhiyun /**
3486*4882a593Smuzhiyun  *  @brief This function prepares command of SDIO GPIO interrupt
3487*4882a593Smuzhiyun  *
3488*4882a593Smuzhiyun  *  @param pmpriv   A pointer to mlan_private structure
3489*4882a593Smuzhiyun  *  @param cmd      A pointer to HostCmd_DS_COMMAND structure
3490*4882a593Smuzhiyun  *  @param cmd_action   The action: GET or SET
3491*4882a593Smuzhiyun  *  @param pdata_buf    A pointer to data buffer
3492*4882a593Smuzhiyun  *  @return             MLAN_STATUS_SUCCESS
3493*4882a593Smuzhiyun  */
wlan_cmd_sdio_gpio_int(pmlan_private pmpriv,HostCmd_DS_COMMAND * cmd,t_u16 cmd_action,t_void * pdata_buf)3494*4882a593Smuzhiyun mlan_status wlan_cmd_sdio_gpio_int(pmlan_private pmpriv,
3495*4882a593Smuzhiyun 				   HostCmd_DS_COMMAND *cmd, t_u16 cmd_action,
3496*4882a593Smuzhiyun 				   t_void *pdata_buf)
3497*4882a593Smuzhiyun {
3498*4882a593Smuzhiyun 	HostCmd_DS_SDIO_GPIO_INT_CONFIG *psdio_gpio_int =
3499*4882a593Smuzhiyun 		&cmd->params.sdio_gpio_int;
3500*4882a593Smuzhiyun 
3501*4882a593Smuzhiyun 	ENTER();
3502*4882a593Smuzhiyun 
3503*4882a593Smuzhiyun 	cmd->command = wlan_cpu_to_le16(HostCmd_CMD_SDIO_GPIO_INT_CONFIG);
3504*4882a593Smuzhiyun 	cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_SDIO_GPIO_INT_CONFIG)) +
3505*4882a593Smuzhiyun 				     S_DS_GEN);
3506*4882a593Smuzhiyun 
3507*4882a593Smuzhiyun 	memset(pmpriv->adapter, psdio_gpio_int, 0,
3508*4882a593Smuzhiyun 	       sizeof(HostCmd_DS_SDIO_GPIO_INT_CONFIG));
3509*4882a593Smuzhiyun 	if (cmd_action == HostCmd_ACT_GEN_SET) {
3510*4882a593Smuzhiyun 		memcpy_ext(pmpriv->adapter, psdio_gpio_int, pdata_buf,
3511*4882a593Smuzhiyun 			   sizeof(HostCmd_DS_SDIO_GPIO_INT_CONFIG),
3512*4882a593Smuzhiyun 			   sizeof(HostCmd_DS_SDIO_GPIO_INT_CONFIG));
3513*4882a593Smuzhiyun 		psdio_gpio_int->action =
3514*4882a593Smuzhiyun 			wlan_cpu_to_le16(psdio_gpio_int->action);
3515*4882a593Smuzhiyun 		psdio_gpio_int->gpio_pin =
3516*4882a593Smuzhiyun 			wlan_cpu_to_le16(psdio_gpio_int->gpio_pin);
3517*4882a593Smuzhiyun 		psdio_gpio_int->gpio_int_edge =
3518*4882a593Smuzhiyun 			wlan_cpu_to_le16(psdio_gpio_int->gpio_int_edge);
3519*4882a593Smuzhiyun 		psdio_gpio_int->gpio_pulse_width =
3520*4882a593Smuzhiyun 			wlan_cpu_to_le16(psdio_gpio_int->gpio_pulse_width);
3521*4882a593Smuzhiyun 	}
3522*4882a593Smuzhiyun 
3523*4882a593Smuzhiyun 	LEAVE();
3524*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
3525*4882a593Smuzhiyun }
3526*4882a593Smuzhiyun 
wlan_reset_fw(pmlan_adapter pmadapter)3527*4882a593Smuzhiyun mlan_status wlan_reset_fw(pmlan_adapter pmadapter)
3528*4882a593Smuzhiyun {
3529*4882a593Smuzhiyun 	t_u32 tries = 0;
3530*4882a593Smuzhiyun 	t_u32 value = 1;
3531*4882a593Smuzhiyun 	t_u32 reset_reg = pmadapter->pcard_sd->reg->fw_reset_reg;
3532*4882a593Smuzhiyun 	t_u8 reset_val = pmadapter->pcard_sd->reg->fw_reset_val;
3533*4882a593Smuzhiyun 	pmlan_callbacks pcb = &pmadapter->callbacks;
3534*4882a593Smuzhiyun 	mlan_status ret = MLAN_STATUS_SUCCESS;
3535*4882a593Smuzhiyun 
3536*4882a593Smuzhiyun 	ENTER();
3537*4882a593Smuzhiyun 	wlan_pm_sdio_wakeup_card(pmadapter, MFALSE);
3538*4882a593Smuzhiyun 
3539*4882a593Smuzhiyun 	/** wait SOC fully wake up */
3540*4882a593Smuzhiyun 	for (tries = 0; tries < MAX_POLL_TRIES; ++tries) {
3541*4882a593Smuzhiyun 		if (MLAN_STATUS_SUCCESS ==
3542*4882a593Smuzhiyun 		    pcb->moal_write_reg(pmadapter->pmoal_handle, reset_reg,
3543*4882a593Smuzhiyun 					0xba)) {
3544*4882a593Smuzhiyun 			pcb->moal_read_reg(pmadapter->pmoal_handle, reset_reg,
3545*4882a593Smuzhiyun 					   &value);
3546*4882a593Smuzhiyun 			if (value == 0xba) {
3547*4882a593Smuzhiyun 				PRINTM(MMSG, "FW wake up\n");
3548*4882a593Smuzhiyun 				break;
3549*4882a593Smuzhiyun 			}
3550*4882a593Smuzhiyun 		}
3551*4882a593Smuzhiyun 		pcb->moal_udelay(pmadapter->pmoal_handle, 1000);
3552*4882a593Smuzhiyun 	}
3553*4882a593Smuzhiyun 	/* Write register to notify FW */
3554*4882a593Smuzhiyun 	if (MLAN_STATUS_FAILURE == pcb->moal_write_reg(pmadapter->pmoal_handle,
3555*4882a593Smuzhiyun 						       reset_reg, reset_val)) {
3556*4882a593Smuzhiyun 		PRINTM(MERROR, "Failed to write register.\n");
3557*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
3558*4882a593Smuzhiyun 		goto done;
3559*4882a593Smuzhiyun 	}
3560*4882a593Smuzhiyun #if defined(SD8997) || defined(SD8977) || defined(SD8987) ||                   \
3561*4882a593Smuzhiyun 	defined(SD9098) || defined(SD9097) || defined(SDNW62X) ||              \
3562*4882a593Smuzhiyun 	defined(SD8978) || defined(SD9177)
3563*4882a593Smuzhiyun 	if (MFALSE
3564*4882a593Smuzhiyun #ifdef SD8997
3565*4882a593Smuzhiyun 	    || IS_SD8997(pmadapter->card_type)
3566*4882a593Smuzhiyun #endif
3567*4882a593Smuzhiyun #ifdef SD8977
3568*4882a593Smuzhiyun 	    || IS_SD8977(pmadapter->card_type)
3569*4882a593Smuzhiyun #endif
3570*4882a593Smuzhiyun #ifdef SD8978
3571*4882a593Smuzhiyun 	    || IS_SD8978(pmadapter->card_type)
3572*4882a593Smuzhiyun #endif
3573*4882a593Smuzhiyun #ifdef SD8987
3574*4882a593Smuzhiyun 	    || IS_SD8987(pmadapter->card_type)
3575*4882a593Smuzhiyun #endif
3576*4882a593Smuzhiyun #ifdef SD9098
3577*4882a593Smuzhiyun 	    || IS_SD9098(pmadapter->card_type)
3578*4882a593Smuzhiyun #endif
3579*4882a593Smuzhiyun #ifdef SD9097
3580*4882a593Smuzhiyun 	    || IS_SD9097(pmadapter->card_type)
3581*4882a593Smuzhiyun #endif
3582*4882a593Smuzhiyun #ifdef SDNW62X
3583*4882a593Smuzhiyun 	    || IS_SDNW62X(pmadapter->card_type)
3584*4882a593Smuzhiyun #endif
3585*4882a593Smuzhiyun #ifdef SD9177
3586*4882a593Smuzhiyun 	    || IS_SD9177(pmadapter->card_type)
3587*4882a593Smuzhiyun #endif
3588*4882a593Smuzhiyun 	) {
3589*4882a593Smuzhiyun 		pcb->moal_read_reg(pmadapter->pmoal_handle,
3590*4882a593Smuzhiyun 				   HOST_TO_CARD_EVENT_REG, &value);
3591*4882a593Smuzhiyun 		pcb->moal_write_reg(pmadapter->pmoal_handle,
3592*4882a593Smuzhiyun 				    HOST_TO_CARD_EVENT_REG,
3593*4882a593Smuzhiyun 				    value | HOST_POWER_UP);
3594*4882a593Smuzhiyun 	}
3595*4882a593Smuzhiyun #endif
3596*4882a593Smuzhiyun 	/* Poll register around 100 ms */
3597*4882a593Smuzhiyun 	for (tries = 0; tries < MAX_POLL_TRIES; ++tries) {
3598*4882a593Smuzhiyun 		pcb->moal_read_reg(pmadapter->pmoal_handle, reset_reg, &value);
3599*4882a593Smuzhiyun 		if (value == 0)
3600*4882a593Smuzhiyun 			/* FW is ready */
3601*4882a593Smuzhiyun 			break;
3602*4882a593Smuzhiyun 		pcb->moal_udelay(pmadapter->pmoal_handle, 1000);
3603*4882a593Smuzhiyun 	}
3604*4882a593Smuzhiyun 
3605*4882a593Smuzhiyun 	if (value) {
3606*4882a593Smuzhiyun 		PRINTM(MERROR, "Failed to poll FW reset register %X=0x%x\n",
3607*4882a593Smuzhiyun 		       reset_reg, value);
3608*4882a593Smuzhiyun 		ret = MLAN_STATUS_FAILURE;
3609*4882a593Smuzhiyun 		goto done;
3610*4882a593Smuzhiyun 	}
3611*4882a593Smuzhiyun 	PRINTM(MMSG, "FW Reset success\n");
3612*4882a593Smuzhiyun 	ret = wlan_sdio_probe(pmadapter);
3613*4882a593Smuzhiyun done:
3614*4882a593Smuzhiyun 	LEAVE();
3615*4882a593Smuzhiyun 	return ret;
3616*4882a593Smuzhiyun }
3617*4882a593Smuzhiyun 
3618*4882a593Smuzhiyun /**
3619*4882a593Smuzhiyun  *  @brief This function handle event/data/cmd complete
3620*4882a593Smuzhiyun  *
3621*4882a593Smuzhiyun  *  @param pmadapter A pointer to mlan_adapter structure
3622*4882a593Smuzhiyun  *  @param pmbuf     A pointer to the mlan_buffer
3623*4882a593Smuzhiyun  *  @return          N/A
3624*4882a593Smuzhiyun  */
wlan_sdio_data_evt_complete(pmlan_adapter pmadapter,mlan_buffer * pmbuf,mlan_status status)3625*4882a593Smuzhiyun static mlan_status wlan_sdio_data_evt_complete(pmlan_adapter pmadapter,
3626*4882a593Smuzhiyun 					       mlan_buffer *pmbuf,
3627*4882a593Smuzhiyun 					       mlan_status status)
3628*4882a593Smuzhiyun {
3629*4882a593Smuzhiyun 	ENTER();
3630*4882a593Smuzhiyun 
3631*4882a593Smuzhiyun 	wlan_free_mlan_buffer(pmadapter, pmbuf);
3632*4882a593Smuzhiyun 
3633*4882a593Smuzhiyun 	LEAVE();
3634*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
3635*4882a593Smuzhiyun }
3636*4882a593Smuzhiyun 
3637*4882a593Smuzhiyun /**
3638*4882a593Smuzhiyun  *  @brief This function handle receive packet
3639*4882a593Smuzhiyun  *
3640*4882a593Smuzhiyun  *  @param pmadapter A pointer to mlan_adapter structure
3641*4882a593Smuzhiyun  *  @param pmbuf     A pointer to the mlan_buffer
3642*4882a593Smuzhiyun  *  @return
3643*4882a593Smuzhiyun  */
wlan_sdio_handle_rx_packet(mlan_adapter * pmadapter,pmlan_buffer pmbuf)3644*4882a593Smuzhiyun static mlan_status wlan_sdio_handle_rx_packet(mlan_adapter *pmadapter,
3645*4882a593Smuzhiyun 					      pmlan_buffer pmbuf)
3646*4882a593Smuzhiyun {
3647*4882a593Smuzhiyun 	ENTER();
3648*4882a593Smuzhiyun 
3649*4882a593Smuzhiyun 	wlan_sdio_deaggr_rx_pkt(pmadapter, pmbuf);
3650*4882a593Smuzhiyun 
3651*4882a593Smuzhiyun 	LEAVE();
3652*4882a593Smuzhiyun 	return MLAN_STATUS_SUCCESS;
3653*4882a593Smuzhiyun }
3654*4882a593Smuzhiyun 
3655*4882a593Smuzhiyun mlan_adapter_operations mlan_sdio_ops = {
3656*4882a593Smuzhiyun 	.dnld_fw = wlan_sdio_dnld_fw,
3657*4882a593Smuzhiyun 	.interrupt = wlan_sdio_interrupt,
3658*4882a593Smuzhiyun 	.process_int_status = wlan_process_sdio_int_status,
3659*4882a593Smuzhiyun 	.host_to_card = wlan_sdio_host_to_card_ext,
3660*4882a593Smuzhiyun 	.wakeup_card = wlan_pm_sdio_wakeup_card,
3661*4882a593Smuzhiyun 	.reset_card = wlan_pm_sdio_reset_card,
3662*4882a593Smuzhiyun 	.event_complete = wlan_sdio_data_evt_complete,
3663*4882a593Smuzhiyun 	.data_complete = wlan_sdio_data_evt_complete,
3664*4882a593Smuzhiyun 	.cmdrsp_complete = wlan_sdio_data_evt_complete,
3665*4882a593Smuzhiyun 	.handle_rx_packet = wlan_sdio_handle_rx_packet,
3666*4882a593Smuzhiyun 	.disable_host_int = wlan_disable_sdio_host_int,
3667*4882a593Smuzhiyun 	.enable_host_int = wlan_enable_sdio_host_int,
3668*4882a593Smuzhiyun 
3669*4882a593Smuzhiyun 	.intf_header_len = SDIO_INTF_HEADER_LEN,
3670*4882a593Smuzhiyun };
3671