• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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