1 /******************************************************************************
2 *
3 * Copyright(c) 2007 - 2017 Realtek Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 *****************************************************************************/
15 #define _HAL_SDIO_C_
16
17 #include <drv_types.h>
18 #include <hal_data.h>
19
20 #ifndef RTW_HALMAC
21 const char *_sdio_tx_queue_str[] = {
22 "H",
23 "M",
24 "L",
25 };
26
dump_mac_page0(PADAPTER padapter)27 static void dump_mac_page0(PADAPTER padapter)
28 {
29 char str_out[128];
30 char str_val[8];
31 char *p = NULL;
32 int index = 0, i = 0;
33 u8 val8 = 0, len = 0;
34
35 RTW_ERR("Dump MAC Page0 register:\n");
36 for (index = 0 ; index < 0x100 ; index += 16) {
37 p = &str_out[0];
38 len = snprintf(str_val, sizeof(str_val),
39 "0x%02x: ", index);
40 strncpy(str_out, str_val, len);
41 p += len;
42
43 for (i = 0 ; i < 16 ; i++) {
44 len = snprintf(str_val, sizeof(str_val), "%02x ",
45 rtw_read8(padapter, index + i));
46 strncpy(p, str_val, len);
47 p += len;
48 }
49 RTW_INFO("%s\n", str_out);
50 _rtw_memset(&str_out, '\0', sizeof(str_out));
51 }
52 }
53
54 /*
55 * Description:
56 * Call this function to make sure power on successfully
57 *
58 * Return:
59 * _SUCCESS enable success
60 * _FAIL enable fail
61 */
sdio_power_on_check(PADAPTER padapter)62 bool sdio_power_on_check(PADAPTER padapter) {
63 u32 val_offset0, val_offset1, val_offset2, val_offset3;
64 u32 val_mix = 0;
65 u32 res = 0;
66 bool ret = _FAIL;
67 int index = 0;
68
69 val_offset0 = rtw_read8(padapter, REG_CR);
70 val_offset1 = rtw_read8(padapter, REG_CR + 1);
71 val_offset2 = rtw_read8(padapter, REG_CR + 2);
72 val_offset3 = rtw_read8(padapter, REG_CR + 3);
73
74 if (val_offset0 == 0xEA || val_offset1 == 0xEA ||
75 val_offset2 == 0xEA || val_offset3 == 0xEA) {
76 RTW_INFO("%s: power on fail, do Power on again\n", __func__);
77 return ret;
78 }
79
80 val_mix = val_offset3 << 24 | val_mix;
81 val_mix = val_offset2 << 16 | val_mix;
82 val_mix = val_offset1 << 8 | val_mix;
83 val_mix = val_offset0 | val_mix;
84
85 res = rtw_read32(padapter, REG_CR);
86
87 RTW_INFO("%s: val_mix:0x%08x, res:0x%08x\n", __func__, val_mix, res);
88
89 while (index < 100) {
90 if (res == val_mix) {
91 RTW_INFO("%s: 0x100 the result of cmd52 and cmd53 is the same.\n", __func__);
92 ret = _SUCCESS;
93 break;
94 } else {
95 RTW_INFO("%s: 0x100 cmd52 and cmd53 is not the same(index:%d).\n", __func__, index);
96 res = rtw_read32(padapter, REG_CR);
97 index++;
98 ret = _FAIL;
99 }
100 }
101
102 if (ret) {
103 index = 0;
104 while (index < 100) {
105 rtw_write32(padapter, 0x1B8, 0x12345678);
106 res = rtw_read32(padapter, 0x1B8);
107 if (res == 0x12345678) {
108 RTW_INFO("%s: 0x1B8 test Pass.\n", __func__);
109 ret = _SUCCESS;
110 break;
111 } else {
112 index++;
113 RTW_INFO("%s: 0x1B8 test Fail(index: %d).\n", __func__, index);
114 ret = _FAIL;
115 }
116 }
117 } else
118 RTW_INFO("%s: fail at cmd52, cmd53.\n", __func__);
119
120 if (ret == _FAIL)
121 dump_mac_page0(padapter);
122
123 return ret;
124 }
125
rtw_hal_sdio_max_txoqt_free_space(_adapter * padapter)126 u8 rtw_hal_sdio_max_txoqt_free_space(_adapter *padapter)
127 {
128 HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
129
130 if (pHalData->SdioTxOQTMaxFreeSpace < 8)
131 pHalData->SdioTxOQTMaxFreeSpace = 8;
132
133 return pHalData->SdioTxOQTMaxFreeSpace;
134 }
135
rtw_hal_sdio_query_tx_freepage(_adapter * padapter,u8 PageIdx,u8 RequiredPageNum)136 u8 rtw_hal_sdio_query_tx_freepage(_adapter *padapter, u8 PageIdx, u8 RequiredPageNum)
137 {
138 HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
139
140 if ((pHalData->SdioTxFIFOFreePage[PageIdx] + pHalData->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX]) >= (RequiredPageNum))
141 return _TRUE;
142 else
143 return _FALSE;
144 }
145
rtw_hal_sdio_update_tx_freepage(_adapter * padapter,u8 PageIdx,u8 RequiredPageNum)146 void rtw_hal_sdio_update_tx_freepage(_adapter *padapter, u8 PageIdx, u8 RequiredPageNum)
147 {
148 HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
149 u8 DedicatedPgNum = 0;
150 u8 RequiredPublicFreePgNum = 0;
151 /* _irqL irql; */
152
153 /* _enter_critical_bh(&pHalData->SdioTxFIFOFreePageLock, &irql); */
154
155 DedicatedPgNum = pHalData->SdioTxFIFOFreePage[PageIdx];
156 if (RequiredPageNum <= DedicatedPgNum)
157 pHalData->SdioTxFIFOFreePage[PageIdx] -= RequiredPageNum;
158 else {
159 pHalData->SdioTxFIFOFreePage[PageIdx] = 0;
160 RequiredPublicFreePgNum = RequiredPageNum - DedicatedPgNum;
161 pHalData->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX] -= RequiredPublicFreePgNum;
162 }
163
164 /* _exit_critical_bh(&pHalData->SdioTxFIFOFreePageLock, &irql); */
165 }
166
rtw_hal_set_sdio_tx_max_length(PADAPTER padapter,u8 numHQ,u8 numNQ,u8 numLQ,u8 numPubQ,u8 div_num)167 void rtw_hal_set_sdio_tx_max_length(PADAPTER padapter, u8 numHQ, u8 numNQ, u8 numLQ, u8 numPubQ, u8 div_num)
168 {
169 HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
170 u32 page_size;
171 u32 lenHQ, lenNQ, lenLQ;
172
173 rtw_hal_get_def_var(padapter, HAL_DEF_TX_PAGE_SIZE, &page_size);
174
175 lenHQ = ((numHQ + numPubQ) / div_num) * page_size;
176 lenNQ = ((numNQ + numPubQ) / div_num) * page_size;
177 lenLQ = ((numLQ + numPubQ) / div_num) * page_size;
178
179 pHalData->sdio_tx_max_len[HI_QUEUE_IDX] = (lenHQ > MAX_XMITBUF_SZ) ? MAX_XMITBUF_SZ : lenHQ;
180 pHalData->sdio_tx_max_len[MID_QUEUE_IDX] = (lenNQ > MAX_XMITBUF_SZ) ? MAX_XMITBUF_SZ : lenNQ;
181 pHalData->sdio_tx_max_len[LOW_QUEUE_IDX] = (lenLQ > MAX_XMITBUF_SZ) ? MAX_XMITBUF_SZ : lenLQ;
182 #ifdef DBG_TX_FREE_PAGE
183 RTW_INFO("rtw_hal_set_sdio_tx_max_length div_num :%u numHQ=%u numNQ=%u numLQ=%u numPubQ=%u\n",div_num ,numHQ,numNQ,numLQ,numPubQ);
184 RTW_INFO("pHalData->sdio_tx_max_len[HI_QUEUE_IDX] :%u\n",pHalData->sdio_tx_max_len[HI_QUEUE_IDX] );
185 RTW_INFO("pHalData->sdio_tx_max_len[MID_QUEUE_IDX] :%u\n",pHalData->sdio_tx_max_len[MID_QUEUE_IDX] );
186 RTW_INFO("rtw_hal_set_sdio_tx_max_length pHalData->sdio_tx_max_len[LOW_QUEUE_IDX] :%u\n",pHalData->sdio_tx_max_len[LOW_QUEUE_IDX] );
187 #endif
188 }
189
rtw_hal_get_sdio_tx_max_length(PADAPTER padapter,u8 queue_idx)190 u32 rtw_hal_get_sdio_tx_max_length(PADAPTER padapter, u8 queue_idx)
191 {
192 struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
193 HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
194 u32 deviceId, max_len;
195
196
197 deviceId = ffaddr2deviceId(pdvobjpriv, queue_idx);
198 switch (deviceId) {
199 case WLAN_TX_HIQ_DEVICE_ID:
200 max_len = pHalData->sdio_tx_max_len[HI_QUEUE_IDX];
201 break;
202
203 case WLAN_TX_MIQ_DEVICE_ID:
204 max_len = pHalData->sdio_tx_max_len[MID_QUEUE_IDX];
205 break;
206
207 case WLAN_TX_LOQ_DEVICE_ID:
208 max_len = pHalData->sdio_tx_max_len[LOW_QUEUE_IDX];
209 break;
210
211 default:
212 max_len = pHalData->sdio_tx_max_len[MID_QUEUE_IDX];
213 break;
214 }
215
216 return max_len;
217 }
218
219 #ifdef CONFIG_SDIO_TX_ENABLE_AVAL_INT
220 #if defined(CONFIG_RTL8188F) || defined(CONFIG_RTL8188GTV) ||defined(CONFIG_RTL8188E) || defined(CONFIG_RTL8821A) || defined(CONFIG_RTL8192F)|| defined(CONFIG_RTL8723D)
rtw_hal_sdio_avail_page_threshold_init(_adapter * adapter)221 void rtw_hal_sdio_avail_page_threshold_init(_adapter *adapter)
222 {
223 HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
224
225 hal_data->sdio_avail_int_en_q = 0xFF;
226 rtw_write32(adapter, REG_TQPNT1, 0xFFFFFFFF);
227 rtw_write32(adapter, REG_TQPNT2, 0xFFFFFFFF);
228 #ifdef CONFIG_RTL8192F
229 rtw_write32(adapter, REG_TQPNT3_V1_8192F, 0xFFFFFFFF);
230 #endif
231 }
232
rtw_hal_sdio_avail_page_threshold_en(_adapter * adapter,u8 qidx,u8 page)233 void rtw_hal_sdio_avail_page_threshold_en(_adapter *adapter, u8 qidx, u8 page)
234 {
235 HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
236 struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
237
238 if (hal_data->sdio_avail_int_en_q != qidx) {
239 u32 page_size;
240 u32 tx_max_len;
241 u32 threshold_reg[] = {REG_TQPNT1, REG_TQPNT1 + 2, REG_TQPNT2, REG_TQPNT2 + 2}; /* H, M, L, E */
242 u8 dw_shift[] = {0, 16, 0, 16}; /* H, M, L, E */
243 u32 threshold = 0;
244
245 /* use same low-high threshold as page num from tx_max_len */
246 if(dvobj->tx_aval_int_thr_mode == 0) /*default setting by requirement*/
247 threshold = page;
248 else if (dvobj->tx_aval_int_thr_mode == 1 && dvobj->tx_aval_int_thr_value)
249 threshold = dvobj->tx_aval_int_thr_value;
250 else {
251 rtw_hal_get_def_var(adapter, HAL_DEF_TX_PAGE_SIZE, &page_size);
252 tx_max_len = hal_data->sdio_tx_max_len[qidx];
253 threshold = PageNum(tx_max_len, page_size);
254 }
255 threshold |= (threshold) << 8;
256
257 if (hal_data->sdio_avail_int_en_q == 0xFF)
258 rtw_write16(adapter, threshold_reg[qidx], threshold);
259 else if (hal_data->sdio_avail_int_en_q >> 1 == qidx >> 1) {/* same dword */
260 rtw_write16(adapter, threshold_reg[hal_data->sdio_avail_int_en_q], 0);
261 rtw_write32(adapter, threshold_reg[qidx & 0xFE]
262 , (0xFFFF << dw_shift[hal_data->sdio_avail_int_en_q]) | (threshold << dw_shift[qidx]));
263 } else {
264 rtw_write16(adapter, threshold_reg[hal_data->sdio_avail_int_en_q], 0);
265 rtw_write16(adapter, threshold_reg[hal_data->sdio_avail_int_en_q], 0xFFFF);
266 rtw_write16(adapter, threshold_reg[qidx], threshold);
267 }
268
269 hal_data->sdio_avail_int_en_q = qidx;
270
271 #ifdef DBG_TX_FREE_PAGE
272 RTW_INFO("DWQP enable avail page threshold %s:%u-%u\n", sdio_tx_queue_str(qidx)
273 , threshold & 0xFF, threshold >> 8);
274 #endif
275 }
276 }
277 #endif
278 #endif /* CONFIG_SDIO_TX_ENABLE_AVAL_INT */
279
280 #ifdef CONFIG_FW_C2H_REG
sd_c2h_hisr_hdl(_adapter * adapter)281 void sd_c2h_hisr_hdl(_adapter *adapter)
282 {
283 u8 c2h_evt[C2H_REG_LEN] = {0};
284 u8 id, seq, plen;
285 u8 *payload;
286
287 if (rtw_hal_c2h_evt_read(adapter, c2h_evt) != _SUCCESS)
288 goto exit;
289
290 if (rtw_hal_c2h_reg_hdr_parse(adapter, c2h_evt, &id, &seq, &plen, &payload) != _SUCCESS)
291 goto exit;
292
293 if (rtw_hal_c2h_id_handle_directly(adapter, id, seq, plen, payload)) {
294 /* Handle directly */
295 rtw_hal_c2h_handler(adapter, id, seq, plen, payload);
296 goto exit;
297 }
298
299 if (rtw_c2h_reg_wk_cmd(adapter, c2h_evt) != _SUCCESS)
300 RTW_ERR("%s rtw_c2h_reg_wk_cmd fail\n", __func__);
301
302 exit:
303 return;
304 }
305 #endif
306
307 #ifdef CONFIG_SDIO_CHK_HCI_RESUME
308
309 #ifndef SDIO_HCI_RESUME_PWR_RDY_TIMEOUT_MS
310 #define SDIO_HCI_RESUME_PWR_RDY_TIMEOUT_MS 200
311 #endif
312 #ifndef DBG_SDIO_CHK_HCI_RESUME
313 #define DBG_SDIO_CHK_HCI_RESUME 0
314 #endif
315
sdio_chk_hci_resume(struct intf_hdl * pintfhdl)316 bool sdio_chk_hci_resume(struct intf_hdl *pintfhdl)
317 {
318 _adapter *adapter = pintfhdl->padapter;
319 u8 hci_sus_state;
320 u8 sus_ctl, sus_ctl_ori = 0xEA;
321 u8 do_leave = 0;
322 systime start = 0, end = 0;
323 u32 poll_cnt = 0;
324 u8 timeout = 0;
325 u8 sr = 0;
326 s32 err = 0;
327
328 rtw_hal_get_hwreg(adapter, HW_VAR_HCI_SUS_STATE, &hci_sus_state);
329 if (hci_sus_state == HCI_SUS_LEAVE || hci_sus_state == HCI_SUS_ERR)
330 goto no_hdl;
331
332 err = sd_cmd52_read(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_HSUS_CTRL), 1, &sus_ctl);
333 if (err)
334 goto exit;
335 sus_ctl_ori = sus_ctl;
336
337 if ((sus_ctl & HCI_RESUME_PWR_RDY) && !(sus_ctl & HCI_SUS_CTRL))
338 goto exit;
339
340 if (sus_ctl & HCI_SUS_CTRL) {
341 sus_ctl &= ~(HCI_SUS_CTRL);
342 err = sd_cmd52_write(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_HSUS_CTRL), 1, &sus_ctl);
343 if (err)
344 goto exit;
345 }
346
347 do_leave = 1;
348
349 /* polling for HCI_RESUME_PWR_RDY && !HCI_SUS_CTRL */
350 start = rtw_get_current_time();
351 while (1) {
352 if (rtw_is_surprise_removed(adapter)) {
353 sr = 1;
354 break;
355 }
356
357 err = sd_cmd52_read(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_HSUS_CTRL), 1, &sus_ctl);
358 poll_cnt++;
359
360 if (!err && (sus_ctl & HCI_RESUME_PWR_RDY) && !(sus_ctl & HCI_SUS_CTRL))
361 break;
362
363 if (rtw_get_passing_time_ms(start) > SDIO_HCI_RESUME_PWR_RDY_TIMEOUT_MS) {
364 timeout = 1;
365 break;
366 }
367 }
368 end = rtw_get_current_time();
369
370 exit:
371
372 if (DBG_SDIO_CHK_HCI_RESUME) {
373 RTW_INFO(FUNC_ADPT_FMT" hci_sus_state:%u, sus_ctl:0x%02x(0x%02x), do_leave:%u, to:%u, err:%u\n"
374 , FUNC_ADPT_ARG(adapter), hci_sus_state, sus_ctl, sus_ctl_ori, do_leave, timeout, err);
375 if (start != 0 || end != 0) {
376 RTW_INFO(FUNC_ADPT_FMT" polling %d ms, cnt:%u\n"
377 , FUNC_ADPT_ARG(adapter), rtw_get_time_interval_ms(start, end), poll_cnt);
378 }
379 }
380
381 if (timeout) {
382 RTW_ERR(FUNC_ADPT_FMT" timeout(err:%d) sus_ctl:0x%02x\n"
383 , FUNC_ADPT_ARG(adapter), err, sus_ctl);
384 } else if (err) {
385 RTW_ERR(FUNC_ADPT_FMT" err:%d\n"
386 , FUNC_ADPT_ARG(adapter), err);
387 }
388
389 no_hdl:
390 return do_leave ? _TRUE : _FALSE;
391 }
392
sdio_chk_hci_suspend(struct intf_hdl * pintfhdl)393 void sdio_chk_hci_suspend(struct intf_hdl *pintfhdl)
394 {
395 #define SDIO_CHK_HCI_SUSPEND_POLLING 0
396
397 _adapter *adapter = pintfhdl->padapter;
398 u8 hci_sus_state;
399 u8 sus_ctl, sus_ctl_ori = 0xEA;
400 systime start = 0, end = 0;
401 u32 poll_cnt = 0;
402 u8 timeout = 0;
403 u8 sr = 0;
404 s32 err = 0;
405 u8 device_id;
406 u16 offset;
407
408 rtw_hal_get_hwreg(adapter, HW_VAR_HCI_SUS_STATE, &hci_sus_state);
409 if (hci_sus_state == HCI_SUS_LEAVE || hci_sus_state == HCI_SUS_LEAVING || hci_sus_state == HCI_SUS_ERR)
410 goto no_hdl;
411
412 err = sd_cmd52_read(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_HSUS_CTRL), 1, &sus_ctl);
413 if (err)
414 goto exit;
415 sus_ctl_ori = sus_ctl;
416
417 if (!(sus_ctl & HCI_RESUME_PWR_RDY))
418 goto exit;
419
420 sus_ctl |= HCI_SUS_CTRL;
421 err = sd_cmd52_write(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_HSUS_CTRL), 1, &sus_ctl);
422 if (err)
423 goto exit;
424
425 #if SDIO_CHK_HCI_SUSPEND_POLLING
426 /* polling for HCI_RESUME_PWR_RDY cleared */
427 start = rtw_get_current_time();
428 while (1) {
429 if (rtw_is_surprise_removed(adapter)) {
430 sr = 1;
431 break;
432 }
433
434 err = sd_cmd52_read(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_HSUS_CTRL), 1, &sus_ctl);
435 poll_cnt++;
436
437 if (!err && !(sus_ctl & HCI_RESUME_PWR_RDY))
438 break;
439
440 if (rtw_get_passing_time_ms(start) > SDIO_HCI_RESUME_PWR_RDY_TIMEOUT_MS) {
441 timeout = 1;
442 break;
443 }
444 }
445 end = rtw_get_current_time();
446 #endif /* SDIO_CHK_HCI_SUSPEND_POLLING */
447
448 exit:
449
450 if (DBG_SDIO_CHK_HCI_RESUME) {
451 RTW_INFO(FUNC_ADPT_FMT" hci_sus_state:%u, sus_ctl:0x%02x(0x%02x), to:%u, err:%u\n"
452 , FUNC_ADPT_ARG(adapter), hci_sus_state, sus_ctl, sus_ctl_ori, timeout, err);
453 if (start != 0 || end != 0) {
454 RTW_INFO(FUNC_ADPT_FMT" polling %d ms, cnt:%u\n"
455 , FUNC_ADPT_ARG(adapter), rtw_get_time_interval_ms(start, end), poll_cnt);
456 }
457 }
458
459 #if SDIO_CHK_HCI_SUSPEND_POLLING
460 if (timeout) {
461 RTW_ERR(FUNC_ADPT_FMT" timeout(err:%d) sus_ctl:0x%02x\n"
462 , FUNC_ADPT_ARG(adapter), err, sus_ctl);
463 } else
464 #endif
465 if (err) {
466 RTW_ERR(FUNC_ADPT_FMT" err:%d\n"
467 , FUNC_ADPT_ARG(adapter), err);
468 }
469
470 no_hdl:
471 return;
472 }
473 #endif /* CONFIG_SDIO_CHK_HCI_RESUME */
474
475
476 #ifdef CONFIG_SDIO_INDIRECT_ACCESS
477
478 /* program indirect access register in sdio local to read/write page0 registers */
479 #ifndef INDIRECT_ACCESS_TIMEOUT_MS
480 #define INDIRECT_ACCESS_TIMEOUT_MS 200
481 #endif
482 #ifndef DBG_SDIO_INDIRECT_ACCESS
483 #define DBG_SDIO_INDIRECT_ACCESS 0
484 #endif
485
sdio_iread(PADAPTER padapter,u32 addr,u8 size,u8 * v)486 s32 sdio_iread(PADAPTER padapter, u32 addr, u8 size, u8 *v)
487 {
488 struct intf_hdl *pintfhdl = &padapter->iopriv.intf;
489 _mutex *mutex = &adapter_to_dvobj(padapter)->sd_indirect_access_mutex;
490
491 u8 val[4] = {0};
492 u8 cmd[4] = {0}; /* mapping to indirect access register, little endien */
493 systime start = 0, end = 0;
494 u8 timeout = 0;
495 u8 sr = 0;
496 s32 err = 0;
497
498 if (size == 1)
499 SET_INDIRECT_REG_SIZE_1BYTE(cmd);
500 else if (size == 2)
501 SET_INDIRECT_REG_SIZE_2BYTE(cmd);
502 else if (size == 4)
503 SET_INDIRECT_REG_SIZE_4BYTE(cmd);
504
505 SET_INDIRECT_REG_ADDR(cmd, addr);
506
507 /* acquire indirect access lock */
508 _enter_critical_mutex(mutex, NULL);
509
510 if (DBG_SDIO_INDIRECT_ACCESS)
511 RTW_INFO(FUNC_ADPT_FMT" cmd:%02x %02x %02x %02x\n", FUNC_ADPT_ARG(padapter), cmd[0], cmd[1], cmd[2], cmd[3]);
512
513 err = sd_cmd52_write(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_INDIRECT_REG_CFG), 3, cmd);
514 if (err)
515 goto exit;
516
517 /* trigger */
518 SET_INDIRECT_REG_READ(cmd);
519
520 if (DBG_SDIO_INDIRECT_ACCESS)
521 RTW_INFO(FUNC_ADPT_FMT" cmd:%02x %02x %02x %02x\n", FUNC_ADPT_ARG(padapter), cmd[0], cmd[1], cmd[2], cmd[3]);
522
523 err = sd_cmd52_write(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_INDIRECT_REG_CFG + 2), 1, cmd + 2);
524 if (err)
525 goto exit;
526
527 /* polling for indirect access done */
528 start = rtw_get_current_time();
529 while (1) {
530 if (rtw_is_surprise_removed(padapter)) {
531 sr = 1;
532 break;
533 }
534
535 err = sd_cmd52_read(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_INDIRECT_REG_CFG + 2), 1, cmd + 2);
536
537 if (!err && GET_INDIRECT_REG_RDY(cmd))
538 break;
539
540 if (rtw_get_passing_time_ms(start) > INDIRECT_ACCESS_TIMEOUT_MS) {
541 timeout = 1;
542 break;
543 }
544 }
545 end = rtw_get_current_time();
546
547 if (timeout || sr)
548 goto exit;
549
550 /* read result */
551 err = sd_cmd52_read(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_INDIRECT_REG_DATA), size, val);
552 if (size == 2)
553 *((u16 *)(val)) = le16_to_cpu(*((u16 *)(val)));
554 else if (size == 4)
555 *((u32 *)(val)) = le32_to_cpu(*((u32 *)(val)));
556
557 if (DBG_SDIO_INDIRECT_ACCESS) {
558 if (size == 1)
559 RTW_INFO(FUNC_ADPT_FMT" val:0x%02x\n", FUNC_ADPT_ARG(padapter), *((u8 *)(val)));
560 else if (size == 2)
561 RTW_INFO(FUNC_ADPT_FMT" val:0x%04x\n", FUNC_ADPT_ARG(padapter), *((u16 *)(val)));
562 else if (size == 4)
563 RTW_INFO(FUNC_ADPT_FMT" val:0x%08x\n", FUNC_ADPT_ARG(padapter), *((u32 *)(val)));
564 }
565
566 exit:
567 /* release indirect access lock */
568 _exit_critical_mutex(mutex, NULL);
569
570 if (DBG_SDIO_INDIRECT_ACCESS) {
571 RTW_INFO(FUNC_ADPT_FMT" addr:0x%0x size:%u, cmd:%02x %02x %02x %02x, to:%u, err:%u\n"
572 , FUNC_ADPT_ARG(padapter), addr, size, cmd[0], cmd[1], cmd[2], cmd[3], timeout, err);
573 if (start != 0 || end != 0) {
574 RTW_INFO(FUNC_ADPT_FMT" polling %d ms\n"
575 , FUNC_ADPT_ARG(padapter), rtw_get_time_interval_ms(start, end));
576 }
577 }
578
579 if (timeout) {
580 RTW_ERR(FUNC_ADPT_FMT" addr:0x%0x timeout(err:%d), cmd\n"
581 , FUNC_ADPT_ARG(padapter), addr, err);
582 if (!err)
583 err = -1; /* just for return value */
584 } else if (err) {
585 RTW_ERR(FUNC_ADPT_FMT" addr:0x%0x err:%d\n"
586 , FUNC_ADPT_ARG(padapter), addr, err);
587 } else if (sr) {
588 /* just for return value */
589 err = -1;
590 }
591
592 if (!err && !timeout && !sr)
593 _rtw_memcpy(v, val, size);
594
595 return err;
596 }
597
sdio_iwrite(PADAPTER padapter,u32 addr,u8 size,u8 * v)598 s32 sdio_iwrite(PADAPTER padapter, u32 addr, u8 size, u8 *v)
599 {
600 struct intf_hdl *pintfhdl = &padapter->iopriv.intf;
601 _mutex *mutex = &adapter_to_dvobj(padapter)->sd_indirect_access_mutex;
602
603 u8 val[4] = {0};
604 u8 cmd[4] = {0}; /* mapping to indirect access register, little endien */
605 systime start = 0, end = 0;
606 u8 timeout = 0;
607 u8 sr = 0;
608 s32 err = 0;
609
610 if (size == 1)
611 SET_INDIRECT_REG_SIZE_1BYTE(cmd);
612 else if (size == 2)
613 SET_INDIRECT_REG_SIZE_2BYTE(cmd);
614 else if (size == 4)
615 SET_INDIRECT_REG_SIZE_4BYTE(cmd);
616
617 SET_INDIRECT_REG_ADDR(cmd, addr);
618
619 /* acquire indirect access lock */
620 _enter_critical_mutex(mutex, NULL);
621
622 if (DBG_SDIO_INDIRECT_ACCESS)
623 RTW_INFO(FUNC_ADPT_FMT" cmd:%02x %02x %02x %02x\n", FUNC_ADPT_ARG(padapter), cmd[0], cmd[1], cmd[2], cmd[3]);
624
625 err = sd_cmd52_write(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_INDIRECT_REG_CFG), 3, cmd);
626 if (err)
627 goto exit;
628
629 /* data to write */
630 _rtw_memcpy(val, v, size);
631
632 if (DBG_SDIO_INDIRECT_ACCESS) {
633 if (size == 1)
634 RTW_INFO(FUNC_ADPT_FMT" val:0x%02x\n", FUNC_ADPT_ARG(padapter), *((u8 *)(val)));
635 else if (size == 2)
636 RTW_INFO(FUNC_ADPT_FMT" val:0x%04x\n", FUNC_ADPT_ARG(padapter), *((u16 *)(val)));
637 else if (size == 4)
638 RTW_INFO(FUNC_ADPT_FMT" val:0x%08x\n", FUNC_ADPT_ARG(padapter), *((u32 *)(val)));
639 }
640
641 if (size == 2)
642 *((u16 *)(val)) = cpu_to_le16(*((u16 *)(val)));
643 else if (size == 4)
644 *((u32 *)(val)) = cpu_to_le32(*((u32 *)(val)));
645
646 err = sd_cmd52_write(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_INDIRECT_REG_DATA), size, val);
647 if (err)
648 goto exit;
649
650 /* trigger */
651 SET_INDIRECT_REG_WRITE(cmd);
652
653 if (DBG_SDIO_INDIRECT_ACCESS)
654 RTW_INFO(FUNC_ADPT_FMT" cmd:%02x %02x %02x %02x\n", FUNC_ADPT_ARG(padapter), cmd[0], cmd[1], cmd[2], cmd[3]);
655
656 err = sd_cmd52_write(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_INDIRECT_REG_CFG + 2), 1, cmd + 2);
657 if (err)
658 goto exit;
659
660 /* polling for indirect access done */
661 start = rtw_get_current_time();
662 while (1) {
663 if (rtw_is_surprise_removed(padapter)) {
664 sr = 1;
665 break;
666 }
667
668 err = sd_cmd52_read(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_INDIRECT_REG_CFG + 2), 1, cmd + 2);
669
670 if (!err && GET_INDIRECT_REG_RDY(cmd))
671 break;
672
673 if (rtw_get_passing_time_ms(start) > INDIRECT_ACCESS_TIMEOUT_MS) {
674 timeout = 1;
675 break;
676 }
677 }
678 end = rtw_get_current_time();
679
680 if (timeout || sr)
681 goto exit;
682
683 exit:
684 /* release indirect access lock */
685 _exit_critical_mutex(mutex, NULL);
686
687 if (DBG_SDIO_INDIRECT_ACCESS) {
688 RTW_INFO(FUNC_ADPT_FMT" addr:0x%0x size:%u, cmd:%02x %02x %02x %02x, to:%u, err:%u\n"
689 , FUNC_ADPT_ARG(padapter), addr, size, cmd[0], cmd[1], cmd[2], cmd[3], timeout, err);
690 if (start != 0 || end != 0) {
691 RTW_INFO(FUNC_ADPT_FMT" polling %d ms\n"
692 , FUNC_ADPT_ARG(padapter), rtw_get_time_interval_ms(start, end));
693 }
694 }
695
696 if (timeout) {
697 RTW_ERR(FUNC_ADPT_FMT" addr:0x%0x timeout(err:%d), cmd\n"
698 , FUNC_ADPT_ARG(padapter), addr, err);
699 if (!err)
700 err = -1; /* just for return value */
701 } else if (err) {
702 RTW_ERR(FUNC_ADPT_FMT" addr:0x%0x err:%d\n"
703 , FUNC_ADPT_ARG(padapter), addr, err);
704 } else if (sr) {
705 /* just for return value */
706 err = -1;
707 }
708
709 return err;
710 }
711
sdio_iread8(struct intf_hdl * pintfhdl,u32 addr)712 u8 sdio_iread8(struct intf_hdl *pintfhdl, u32 addr)
713 {
714 u8 val;
715
716 if (sdio_iread(pintfhdl->padapter, addr, 1, (u8 *)&val) != 0)
717 val = SDIO_ERR_VAL8;
718
719 return val;
720 }
721
sdio_iread16(struct intf_hdl * pintfhdl,u32 addr)722 u16 sdio_iread16(struct intf_hdl *pintfhdl, u32 addr)
723 {
724 u16 val;
725
726 if (sdio_iread(pintfhdl->padapter, addr, 2, (u8 *)&val) != 0)
727 val = SDIO_ERR_VAL16;
728
729 return val;
730 }
731
sdio_iread32(struct intf_hdl * pintfhdl,u32 addr)732 u32 sdio_iread32(struct intf_hdl *pintfhdl, u32 addr)
733 {
734 u32 val;
735
736 if (sdio_iread(pintfhdl->padapter, addr, 4, (u8 *)&val) != 0)
737 val = SDIO_ERR_VAL32;
738
739 return val;
740 }
741
sdio_iwrite8(struct intf_hdl * pintfhdl,u32 addr,u8 val)742 s32 sdio_iwrite8(struct intf_hdl *pintfhdl, u32 addr, u8 val)
743 {
744 return sdio_iwrite(pintfhdl->padapter, addr, 1, (u8 *)&val);
745 }
746
sdio_iwrite16(struct intf_hdl * pintfhdl,u32 addr,u16 val)747 s32 sdio_iwrite16(struct intf_hdl *pintfhdl, u32 addr, u16 val)
748 {
749 return sdio_iwrite(pintfhdl->padapter, addr, 2, (u8 *)&val);
750 }
751
sdio_iwrite32(struct intf_hdl * pintfhdl,u32 addr,u32 val)752 s32 sdio_iwrite32(struct intf_hdl *pintfhdl, u32 addr, u32 val)
753 {
754 return sdio_iwrite(pintfhdl->padapter, addr, 4, (u8 *)&val);
755 }
756 #endif /* CONFIG_SDIO_INDIRECT_ACCESS */
cmd53_4byte_alignment(struct intf_hdl * pintfhdl,u32 addr)757 u32 cmd53_4byte_alignment(struct intf_hdl *pintfhdl, u32 addr)
758 {
759 u32 addr_rdr;
760 u32 value;
761
762 value = 0;
763 addr_rdr = addr % 4;
764
765 if (addr_rdr) {
766 u8 shift_bit;
767
768 shift_bit = addr_rdr * 8;
769 value = (sd_read32(pintfhdl, (addr - addr_rdr), NULL)) >> shift_bit;
770 } else
771 value = sd_read32(pintfhdl, addr, NULL);
772
773 return value;
774 }
775
776 #endif /* !RTW_HALMAC */
777
778 #ifndef CONFIG_SDIO_TX_TASKLET
779 #ifdef SDIO_FREE_XMIT_BUF_SEMA
_rtw_sdio_free_xmitbuf_sema_up(struct xmit_priv * xmit)780 void _rtw_sdio_free_xmitbuf_sema_up(struct xmit_priv *xmit)
781 {
782 _rtw_up_sema(&xmit->sdio_free_xmitbuf_sema);
783 }
784
_rtw_sdio_free_xmitbuf_sema_down(struct xmit_priv * xmit)785 void _rtw_sdio_free_xmitbuf_sema_down(struct xmit_priv *xmit)
786 {
787 _rtw_down_sema(&xmit->sdio_free_xmitbuf_sema);
788 }
789
790 #ifdef DBG_SDIO_FREE_XMIT_BUF_SEMA
dbg_rtw_sdio_free_xmitbuf_sema_up(struct xmit_priv * xmit,const char * caller)791 void dbg_rtw_sdio_free_xmitbuf_sema_up(struct xmit_priv *xmit, const char *caller)
792 {
793 /* just for debug usage only, pleae take care for the different of count implementaton */
794 RTW_INFO("%s("ADPT_FMT") before up sdio_free_xmitbuf_sema, count:%u\n"
795 , caller, ADPT_ARG(xmit->adapter), xmit->sdio_free_xmitbuf_sema.count);
796 _rtw_sdio_free_xmitbuf_sema_up(xmit);
797 }
798
dbg_rtw_sdio_free_xmitbuf_sema_down(struct xmit_priv * xmit,const char * caller)799 void dbg_rtw_sdio_free_xmitbuf_sema_down(struct xmit_priv *xmit, const char *caller)
800 {
801 /* just for debug usage only, pleae take care for the different of count implementaton */
802 RTW_INFO("%s("ADPT_FMT") before down sdio_free_xmitbuf_sema, count:%u\n"
803 , caller, ADPT_ARG(xmit->adapter), xmit->sdio_free_xmitbuf_sema.count);
804 _rtw_sdio_free_xmitbuf_sema_down(xmit);
805 }
806 #endif /* DBG_SDIO_FREE_XMIT_BUF_SEMA */
807
808 #endif /* SDIO_FREE_XMIT_BUF_SEMA */
809 #endif /* !CONFIG_SDIO_TX_TASKLET */
810
sdio_initrecvbuf(struct recv_buf * recvbuf,_adapter * adapter)811 s32 sdio_initrecvbuf(struct recv_buf *recvbuf, _adapter *adapter)
812 {
813 _rtw_init_listhead(&recvbuf->list);
814 #ifdef PLATFORM_WINDOWS
815 _rtw_spinlock_init(&recvbuf->recvbuf_lock);
816 #endif
817 recvbuf->adapter = adapter;
818
819 return _SUCCESS;
820 }
821
sdio_freerecvbuf(struct recv_buf * recvbuf)822 void sdio_freerecvbuf(struct recv_buf *recvbuf)
823 {
824 #ifdef PLATFORM_WINDOWS
825 _rtw_spinlock_free(&recvbuf->recvbuf_lock);
826 #endif
827 }
828
829 #ifdef CONFIG_SDIO_RECVBUF_PWAIT
dump_recvbuf_pwait_conf(void * sel,struct recv_priv * recvpriv)830 void dump_recvbuf_pwait_conf(void *sel, struct recv_priv *recvpriv)
831 {
832 struct rtw_pwait_conf *conf = &recvpriv->recvbuf_pwait.conf;
833
834 RTW_PRINT_SEL(sel, "%-4s %-10s %-10s\n"
835 , "type", "time", "cnt_lmt");
836 RTW_PRINT_SEL(sel, "%4s %10d %10d\n"
837 , rtw_pwait_type_str(conf->type), conf->wait_time, conf->wait_cnt_lmt);
838 }
839
840 #ifdef CONFIG_SDIO_RECVBUF_PWAIT_RUNTIME_ADJUST
recvbuf_pwait_config_req(struct recv_priv * recvpriv,enum rtw_pwait_type type,s32 time,s32 cnt_lmt)841 int recvbuf_pwait_config_req(struct recv_priv *recvpriv, enum rtw_pwait_type type, s32 time, s32 cnt_lmt)
842 {
843 struct recv_buf *rbuf;
844 struct rtw_pwait_conf *conf;
845 int ret = _FAIL;
846
847 rbuf = rtw_malloc(sizeof(*rbuf) + sizeof(struct rtw_pwait_conf));
848 if (!rbuf)
849 goto exit;
850
851 sdio_initrecvbuf(rbuf, recvpriv->adapter);
852 rbuf->type = RBUF_TYPE_PWAIT_ADJ;
853 rbuf->pbuf = ((u8*)rbuf) + sizeof(*rbuf);
854 conf = (struct rtw_pwait_conf *)rbuf->pbuf;
855 conf->type = type;
856 conf->wait_time = time;
857 conf->wait_cnt_lmt = cnt_lmt;
858
859 ret = rtw_enqueue_recvbuf(rbuf, &recvpriv->free_recv_buf_queue);
860 if (0 && ret == _SUCCESS) {
861 RTW_INFO("request recvbuf_pwait with type=%s time=%d cnt_lmt=%d\n"
862 , rtw_pwait_type_str(type), time, cnt_lmt);
863 }
864
865 exit:
866 return ret;
867 }
868
recvbuf_pwait_config_hdl(struct recv_priv * recvpriv,struct recv_buf * rbuf)869 int recvbuf_pwait_config_hdl(struct recv_priv *recvpriv, struct recv_buf *rbuf)
870 {
871 struct rtw_pwait_conf *conf = (struct rtw_pwait_conf *)rbuf->pbuf;
872 int ret = rtw_pwctx_config(&recvpriv->recvbuf_pwait, conf->type, conf->wait_time, conf->wait_cnt_lmt);
873
874 if (0 && ret == _SUCCESS) {
875 RTW_INFO("config recvbuf_pwait with type=%s time=%d cnt_lmt=%d\n"
876 , rtw_pwait_type_str(conf->type), conf->wait_time, conf->wait_cnt_lmt);
877 }
878 sdio_freerecvbuf(rbuf);
879 rtw_mfree(rbuf, sizeof(*rbuf) + sizeof(*conf));
880
881 return ret;
882 }
883 #endif /* CONFIG_SDIO_RECVBUF_PWAIT_RUNTIME_ADJUST */
884 #endif /* CONFIG_SDIO_RECVBUF_PWAIT */
885
886