/****************************************************************************** * * Copyright(c) 2007 - 2017 Realtek Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * *****************************************************************************/ #define _HAL_SDIO_C_ #include #include #ifndef RTW_HALMAC const char *_sdio_tx_queue_str[] = { "H", "M", "L", }; static void dump_mac_page0(PADAPTER padapter) { char str_out[128]; char str_val[8]; char *p = NULL; int index = 0, i = 0; u8 val8 = 0, len = 0; RTW_ERR("Dump MAC Page0 register:\n"); for (index = 0 ; index < 0x100 ; index += 16) { p = &str_out[0]; len = snprintf(str_val, sizeof(str_val), "0x%02x: ", index); strncpy(str_out, str_val, len); p += len; for (i = 0 ; i < 16 ; i++) { len = snprintf(str_val, sizeof(str_val), "%02x ", rtw_read8(padapter, index + i)); strncpy(p, str_val, len); p += len; } RTW_INFO("%s\n", str_out); _rtw_memset(&str_out, '\0', sizeof(str_out)); } } /* * Description: * Call this function to make sure power on successfully * * Return: * _SUCCESS enable success * _FAIL enable fail */ bool sdio_power_on_check(PADAPTER padapter) { u32 val_offset0, val_offset1, val_offset2, val_offset3; u32 val_mix = 0; u32 res = 0; bool ret = _FAIL; int index = 0; val_offset0 = rtw_read8(padapter, REG_CR); val_offset1 = rtw_read8(padapter, REG_CR + 1); val_offset2 = rtw_read8(padapter, REG_CR + 2); val_offset3 = rtw_read8(padapter, REG_CR + 3); if (val_offset0 == 0xEA || val_offset1 == 0xEA || val_offset2 == 0xEA || val_offset3 == 0xEA) { RTW_INFO("%s: power on fail, do Power on again\n", __func__); return ret; } val_mix = val_offset3 << 24 | val_mix; val_mix = val_offset2 << 16 | val_mix; val_mix = val_offset1 << 8 | val_mix; val_mix = val_offset0 | val_mix; res = rtw_read32(padapter, REG_CR); RTW_INFO("%s: val_mix:0x%08x, res:0x%08x\n", __func__, val_mix, res); while (index < 100) { if (res == val_mix) { RTW_INFO("%s: 0x100 the result of cmd52 and cmd53 is the same.\n", __func__); ret = _SUCCESS; break; } else { RTW_INFO("%s: 0x100 cmd52 and cmd53 is not the same(index:%d).\n", __func__, index); res = rtw_read32(padapter, REG_CR); index++; ret = _FAIL; } } if (ret) { index = 0; while (index < 100) { rtw_write32(padapter, 0x1B8, 0x12345678); res = rtw_read32(padapter, 0x1B8); if (res == 0x12345678) { RTW_INFO("%s: 0x1B8 test Pass.\n", __func__); ret = _SUCCESS; break; } else { index++; RTW_INFO("%s: 0x1B8 test Fail(index: %d).\n", __func__, index); ret = _FAIL; } } } else RTW_INFO("%s: fail at cmd52, cmd53.\n", __func__); if (ret == _FAIL) dump_mac_page0(padapter); return ret; } u8 rtw_hal_sdio_max_txoqt_free_space(_adapter *padapter) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); if (pHalData->SdioTxOQTMaxFreeSpace < 8) pHalData->SdioTxOQTMaxFreeSpace = 8; return pHalData->SdioTxOQTMaxFreeSpace; } u8 rtw_hal_sdio_query_tx_freepage(_adapter *padapter, u8 PageIdx, u8 RequiredPageNum) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); if ((pHalData->SdioTxFIFOFreePage[PageIdx] + pHalData->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX]) >= (RequiredPageNum)) return _TRUE; else return _FALSE; } void rtw_hal_sdio_update_tx_freepage(_adapter *padapter, u8 PageIdx, u8 RequiredPageNum) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); u8 DedicatedPgNum = 0; u8 RequiredPublicFreePgNum = 0; /* _irqL irql; */ /* _enter_critical_bh(&pHalData->SdioTxFIFOFreePageLock, &irql); */ DedicatedPgNum = pHalData->SdioTxFIFOFreePage[PageIdx]; if (RequiredPageNum <= DedicatedPgNum) pHalData->SdioTxFIFOFreePage[PageIdx] -= RequiredPageNum; else { pHalData->SdioTxFIFOFreePage[PageIdx] = 0; RequiredPublicFreePgNum = RequiredPageNum - DedicatedPgNum; pHalData->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX] -= RequiredPublicFreePgNum; } /* _exit_critical_bh(&pHalData->SdioTxFIFOFreePageLock, &irql); */ } void rtw_hal_set_sdio_tx_max_length(PADAPTER padapter, u8 numHQ, u8 numNQ, u8 numLQ, u8 numPubQ, u8 div_num) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); u32 page_size; u32 lenHQ, lenNQ, lenLQ; rtw_hal_get_def_var(padapter, HAL_DEF_TX_PAGE_SIZE, &page_size); lenHQ = ((numHQ + numPubQ) / div_num) * page_size; lenNQ = ((numNQ + numPubQ) / div_num) * page_size; lenLQ = ((numLQ + numPubQ) / div_num) * page_size; pHalData->sdio_tx_max_len[HI_QUEUE_IDX] = (lenHQ > MAX_XMITBUF_SZ) ? MAX_XMITBUF_SZ : lenHQ; pHalData->sdio_tx_max_len[MID_QUEUE_IDX] = (lenNQ > MAX_XMITBUF_SZ) ? MAX_XMITBUF_SZ : lenNQ; pHalData->sdio_tx_max_len[LOW_QUEUE_IDX] = (lenLQ > MAX_XMITBUF_SZ) ? MAX_XMITBUF_SZ : lenLQ; #ifdef DBG_TX_FREE_PAGE 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); RTW_INFO("pHalData->sdio_tx_max_len[HI_QUEUE_IDX] :%u\n",pHalData->sdio_tx_max_len[HI_QUEUE_IDX] ); RTW_INFO("pHalData->sdio_tx_max_len[MID_QUEUE_IDX] :%u\n",pHalData->sdio_tx_max_len[MID_QUEUE_IDX] ); 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] ); #endif } u32 rtw_hal_get_sdio_tx_max_length(PADAPTER padapter, u8 queue_idx) { struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); u32 deviceId, max_len; deviceId = ffaddr2deviceId(pdvobjpriv, queue_idx); switch (deviceId) { case WLAN_TX_HIQ_DEVICE_ID: max_len = pHalData->sdio_tx_max_len[HI_QUEUE_IDX]; break; case WLAN_TX_MIQ_DEVICE_ID: max_len = pHalData->sdio_tx_max_len[MID_QUEUE_IDX]; break; case WLAN_TX_LOQ_DEVICE_ID: max_len = pHalData->sdio_tx_max_len[LOW_QUEUE_IDX]; break; default: max_len = pHalData->sdio_tx_max_len[MID_QUEUE_IDX]; break; } return max_len; } #ifdef CONFIG_SDIO_TX_ENABLE_AVAL_INT #if defined(CONFIG_RTL8188F) || defined(CONFIG_RTL8188GTV) ||defined(CONFIG_RTL8188E) || defined(CONFIG_RTL8821A) || defined(CONFIG_RTL8192F)|| defined(CONFIG_RTL8723D) void rtw_hal_sdio_avail_page_threshold_init(_adapter *adapter) { HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); hal_data->sdio_avail_int_en_q = 0xFF; rtw_write32(adapter, REG_TQPNT1, 0xFFFFFFFF); rtw_write32(adapter, REG_TQPNT2, 0xFFFFFFFF); #ifdef CONFIG_RTL8192F rtw_write32(adapter, REG_TQPNT3_V1_8192F, 0xFFFFFFFF); #endif } void rtw_hal_sdio_avail_page_threshold_en(_adapter *adapter, u8 qidx, u8 page) { HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); if (hal_data->sdio_avail_int_en_q != qidx) { u32 page_size; u32 tx_max_len; u32 threshold_reg[] = {REG_TQPNT1, REG_TQPNT1 + 2, REG_TQPNT2, REG_TQPNT2 + 2}; /* H, M, L, E */ u8 dw_shift[] = {0, 16, 0, 16}; /* H, M, L, E */ u32 threshold = 0; /* use same low-high threshold as page num from tx_max_len */ if(dvobj->tx_aval_int_thr_mode == 0) /*default setting by requirement*/ threshold = page; else if (dvobj->tx_aval_int_thr_mode == 1 && dvobj->tx_aval_int_thr_value) threshold = dvobj->tx_aval_int_thr_value; else { rtw_hal_get_def_var(adapter, HAL_DEF_TX_PAGE_SIZE, &page_size); tx_max_len = hal_data->sdio_tx_max_len[qidx]; threshold = PageNum(tx_max_len, page_size); } threshold |= (threshold) << 8; if (hal_data->sdio_avail_int_en_q == 0xFF) rtw_write16(adapter, threshold_reg[qidx], threshold); else if (hal_data->sdio_avail_int_en_q >> 1 == qidx >> 1) {/* same dword */ rtw_write16(adapter, threshold_reg[hal_data->sdio_avail_int_en_q], 0); rtw_write32(adapter, threshold_reg[qidx & 0xFE] , (0xFFFF << dw_shift[hal_data->sdio_avail_int_en_q]) | (threshold << dw_shift[qidx])); } else { rtw_write16(adapter, threshold_reg[hal_data->sdio_avail_int_en_q], 0); rtw_write16(adapter, threshold_reg[hal_data->sdio_avail_int_en_q], 0xFFFF); rtw_write16(adapter, threshold_reg[qidx], threshold); } hal_data->sdio_avail_int_en_q = qidx; #ifdef DBG_TX_FREE_PAGE RTW_INFO("DWQP enable avail page threshold %s:%u-%u\n", sdio_tx_queue_str(qidx) , threshold & 0xFF, threshold >> 8); #endif } } #endif #endif /* CONFIG_SDIO_TX_ENABLE_AVAL_INT */ #ifdef CONFIG_FW_C2H_REG void sd_c2h_hisr_hdl(_adapter *adapter) { u8 c2h_evt[C2H_REG_LEN] = {0}; u8 id, seq, plen; u8 *payload; if (rtw_hal_c2h_evt_read(adapter, c2h_evt) != _SUCCESS) goto exit; if (rtw_hal_c2h_reg_hdr_parse(adapter, c2h_evt, &id, &seq, &plen, &payload) != _SUCCESS) goto exit; if (rtw_hal_c2h_id_handle_directly(adapter, id, seq, plen, payload)) { /* Handle directly */ rtw_hal_c2h_handler(adapter, id, seq, plen, payload); goto exit; } if (rtw_c2h_reg_wk_cmd(adapter, c2h_evt) != _SUCCESS) RTW_ERR("%s rtw_c2h_reg_wk_cmd fail\n", __func__); exit: return; } #endif #ifdef CONFIG_SDIO_CHK_HCI_RESUME #ifndef SDIO_HCI_RESUME_PWR_RDY_TIMEOUT_MS #define SDIO_HCI_RESUME_PWR_RDY_TIMEOUT_MS 200 #endif #ifndef DBG_SDIO_CHK_HCI_RESUME #define DBG_SDIO_CHK_HCI_RESUME 0 #endif bool sdio_chk_hci_resume(struct intf_hdl *pintfhdl) { _adapter *adapter = pintfhdl->padapter; u8 hci_sus_state; u8 sus_ctl, sus_ctl_ori = 0xEA; u8 do_leave = 0; systime start = 0, end = 0; u32 poll_cnt = 0; u8 timeout = 0; u8 sr = 0; s32 err = 0; rtw_hal_get_hwreg(adapter, HW_VAR_HCI_SUS_STATE, &hci_sus_state); if (hci_sus_state == HCI_SUS_LEAVE || hci_sus_state == HCI_SUS_ERR) goto no_hdl; err = sd_cmd52_read(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_HSUS_CTRL), 1, &sus_ctl); if (err) goto exit; sus_ctl_ori = sus_ctl; if ((sus_ctl & HCI_RESUME_PWR_RDY) && !(sus_ctl & HCI_SUS_CTRL)) goto exit; if (sus_ctl & HCI_SUS_CTRL) { sus_ctl &= ~(HCI_SUS_CTRL); err = sd_cmd52_write(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_HSUS_CTRL), 1, &sus_ctl); if (err) goto exit; } do_leave = 1; /* polling for HCI_RESUME_PWR_RDY && !HCI_SUS_CTRL */ start = rtw_get_current_time(); while (1) { if (rtw_is_surprise_removed(adapter)) { sr = 1; break; } err = sd_cmd52_read(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_HSUS_CTRL), 1, &sus_ctl); poll_cnt++; if (!err && (sus_ctl & HCI_RESUME_PWR_RDY) && !(sus_ctl & HCI_SUS_CTRL)) break; if (rtw_get_passing_time_ms(start) > SDIO_HCI_RESUME_PWR_RDY_TIMEOUT_MS) { timeout = 1; break; } } end = rtw_get_current_time(); exit: if (DBG_SDIO_CHK_HCI_RESUME) { RTW_INFO(FUNC_ADPT_FMT" hci_sus_state:%u, sus_ctl:0x%02x(0x%02x), do_leave:%u, to:%u, err:%u\n" , FUNC_ADPT_ARG(adapter), hci_sus_state, sus_ctl, sus_ctl_ori, do_leave, timeout, err); if (start != 0 || end != 0) { RTW_INFO(FUNC_ADPT_FMT" polling %d ms, cnt:%u\n" , FUNC_ADPT_ARG(adapter), rtw_get_time_interval_ms(start, end), poll_cnt); } } if (timeout) { RTW_ERR(FUNC_ADPT_FMT" timeout(err:%d) sus_ctl:0x%02x\n" , FUNC_ADPT_ARG(adapter), err, sus_ctl); } else if (err) { RTW_ERR(FUNC_ADPT_FMT" err:%d\n" , FUNC_ADPT_ARG(adapter), err); } no_hdl: return do_leave ? _TRUE : _FALSE; } void sdio_chk_hci_suspend(struct intf_hdl *pintfhdl) { #define SDIO_CHK_HCI_SUSPEND_POLLING 0 _adapter *adapter = pintfhdl->padapter; u8 hci_sus_state; u8 sus_ctl, sus_ctl_ori = 0xEA; systime start = 0, end = 0; u32 poll_cnt = 0; u8 timeout = 0; u8 sr = 0; s32 err = 0; u8 device_id; u16 offset; rtw_hal_get_hwreg(adapter, HW_VAR_HCI_SUS_STATE, &hci_sus_state); if (hci_sus_state == HCI_SUS_LEAVE || hci_sus_state == HCI_SUS_LEAVING || hci_sus_state == HCI_SUS_ERR) goto no_hdl; err = sd_cmd52_read(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_HSUS_CTRL), 1, &sus_ctl); if (err) goto exit; sus_ctl_ori = sus_ctl; if (!(sus_ctl & HCI_RESUME_PWR_RDY)) goto exit; sus_ctl |= HCI_SUS_CTRL; err = sd_cmd52_write(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_HSUS_CTRL), 1, &sus_ctl); if (err) goto exit; #if SDIO_CHK_HCI_SUSPEND_POLLING /* polling for HCI_RESUME_PWR_RDY cleared */ start = rtw_get_current_time(); while (1) { if (rtw_is_surprise_removed(adapter)) { sr = 1; break; } err = sd_cmd52_read(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_HSUS_CTRL), 1, &sus_ctl); poll_cnt++; if (!err && !(sus_ctl & HCI_RESUME_PWR_RDY)) break; if (rtw_get_passing_time_ms(start) > SDIO_HCI_RESUME_PWR_RDY_TIMEOUT_MS) { timeout = 1; break; } } end = rtw_get_current_time(); #endif /* SDIO_CHK_HCI_SUSPEND_POLLING */ exit: if (DBG_SDIO_CHK_HCI_RESUME) { RTW_INFO(FUNC_ADPT_FMT" hci_sus_state:%u, sus_ctl:0x%02x(0x%02x), to:%u, err:%u\n" , FUNC_ADPT_ARG(adapter), hci_sus_state, sus_ctl, sus_ctl_ori, timeout, err); if (start != 0 || end != 0) { RTW_INFO(FUNC_ADPT_FMT" polling %d ms, cnt:%u\n" , FUNC_ADPT_ARG(adapter), rtw_get_time_interval_ms(start, end), poll_cnt); } } #if SDIO_CHK_HCI_SUSPEND_POLLING if (timeout) { RTW_ERR(FUNC_ADPT_FMT" timeout(err:%d) sus_ctl:0x%02x\n" , FUNC_ADPT_ARG(adapter), err, sus_ctl); } else #endif if (err) { RTW_ERR(FUNC_ADPT_FMT" err:%d\n" , FUNC_ADPT_ARG(adapter), err); } no_hdl: return; } #endif /* CONFIG_SDIO_CHK_HCI_RESUME */ #ifdef CONFIG_SDIO_INDIRECT_ACCESS /* program indirect access register in sdio local to read/write page0 registers */ #ifndef INDIRECT_ACCESS_TIMEOUT_MS #define INDIRECT_ACCESS_TIMEOUT_MS 200 #endif #ifndef DBG_SDIO_INDIRECT_ACCESS #define DBG_SDIO_INDIRECT_ACCESS 0 #endif s32 sdio_iread(PADAPTER padapter, u32 addr, u8 size, u8 *v) { struct intf_hdl *pintfhdl = &padapter->iopriv.intf; _mutex *mutex = &adapter_to_dvobj(padapter)->sd_indirect_access_mutex; u8 val[4] = {0}; u8 cmd[4] = {0}; /* mapping to indirect access register, little endien */ systime start = 0, end = 0; u8 timeout = 0; u8 sr = 0; s32 err = 0; if (size == 1) SET_INDIRECT_REG_SIZE_1BYTE(cmd); else if (size == 2) SET_INDIRECT_REG_SIZE_2BYTE(cmd); else if (size == 4) SET_INDIRECT_REG_SIZE_4BYTE(cmd); SET_INDIRECT_REG_ADDR(cmd, addr); /* acquire indirect access lock */ _enter_critical_mutex(mutex, NULL); if (DBG_SDIO_INDIRECT_ACCESS) RTW_INFO(FUNC_ADPT_FMT" cmd:%02x %02x %02x %02x\n", FUNC_ADPT_ARG(padapter), cmd[0], cmd[1], cmd[2], cmd[3]); err = sd_cmd52_write(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_INDIRECT_REG_CFG), 3, cmd); if (err) goto exit; /* trigger */ SET_INDIRECT_REG_READ(cmd); if (DBG_SDIO_INDIRECT_ACCESS) RTW_INFO(FUNC_ADPT_FMT" cmd:%02x %02x %02x %02x\n", FUNC_ADPT_ARG(padapter), cmd[0], cmd[1], cmd[2], cmd[3]); err = sd_cmd52_write(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_INDIRECT_REG_CFG + 2), 1, cmd + 2); if (err) goto exit; /* polling for indirect access done */ start = rtw_get_current_time(); while (1) { if (rtw_is_surprise_removed(padapter)) { sr = 1; break; } err = sd_cmd52_read(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_INDIRECT_REG_CFG + 2), 1, cmd + 2); if (!err && GET_INDIRECT_REG_RDY(cmd)) break; if (rtw_get_passing_time_ms(start) > INDIRECT_ACCESS_TIMEOUT_MS) { timeout = 1; break; } } end = rtw_get_current_time(); if (timeout || sr) goto exit; /* read result */ err = sd_cmd52_read(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_INDIRECT_REG_DATA), size, val); if (size == 2) *((u16 *)(val)) = le16_to_cpu(*((u16 *)(val))); else if (size == 4) *((u32 *)(val)) = le32_to_cpu(*((u32 *)(val))); if (DBG_SDIO_INDIRECT_ACCESS) { if (size == 1) RTW_INFO(FUNC_ADPT_FMT" val:0x%02x\n", FUNC_ADPT_ARG(padapter), *((u8 *)(val))); else if (size == 2) RTW_INFO(FUNC_ADPT_FMT" val:0x%04x\n", FUNC_ADPT_ARG(padapter), *((u16 *)(val))); else if (size == 4) RTW_INFO(FUNC_ADPT_FMT" val:0x%08x\n", FUNC_ADPT_ARG(padapter), *((u32 *)(val))); } exit: /* release indirect access lock */ _exit_critical_mutex(mutex, NULL); if (DBG_SDIO_INDIRECT_ACCESS) { RTW_INFO(FUNC_ADPT_FMT" addr:0x%0x size:%u, cmd:%02x %02x %02x %02x, to:%u, err:%u\n" , FUNC_ADPT_ARG(padapter), addr, size, cmd[0], cmd[1], cmd[2], cmd[3], timeout, err); if (start != 0 || end != 0) { RTW_INFO(FUNC_ADPT_FMT" polling %d ms\n" , FUNC_ADPT_ARG(padapter), rtw_get_time_interval_ms(start, end)); } } if (timeout) { RTW_ERR(FUNC_ADPT_FMT" addr:0x%0x timeout(err:%d), cmd\n" , FUNC_ADPT_ARG(padapter), addr, err); if (!err) err = -1; /* just for return value */ } else if (err) { RTW_ERR(FUNC_ADPT_FMT" addr:0x%0x err:%d\n" , FUNC_ADPT_ARG(padapter), addr, err); } else if (sr) { /* just for return value */ err = -1; } if (!err && !timeout && !sr) _rtw_memcpy(v, val, size); return err; } s32 sdio_iwrite(PADAPTER padapter, u32 addr, u8 size, u8 *v) { struct intf_hdl *pintfhdl = &padapter->iopriv.intf; _mutex *mutex = &adapter_to_dvobj(padapter)->sd_indirect_access_mutex; u8 val[4] = {0}; u8 cmd[4] = {0}; /* mapping to indirect access register, little endien */ systime start = 0, end = 0; u8 timeout = 0; u8 sr = 0; s32 err = 0; if (size == 1) SET_INDIRECT_REG_SIZE_1BYTE(cmd); else if (size == 2) SET_INDIRECT_REG_SIZE_2BYTE(cmd); else if (size == 4) SET_INDIRECT_REG_SIZE_4BYTE(cmd); SET_INDIRECT_REG_ADDR(cmd, addr); /* acquire indirect access lock */ _enter_critical_mutex(mutex, NULL); if (DBG_SDIO_INDIRECT_ACCESS) RTW_INFO(FUNC_ADPT_FMT" cmd:%02x %02x %02x %02x\n", FUNC_ADPT_ARG(padapter), cmd[0], cmd[1], cmd[2], cmd[3]); err = sd_cmd52_write(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_INDIRECT_REG_CFG), 3, cmd); if (err) goto exit; /* data to write */ _rtw_memcpy(val, v, size); if (DBG_SDIO_INDIRECT_ACCESS) { if (size == 1) RTW_INFO(FUNC_ADPT_FMT" val:0x%02x\n", FUNC_ADPT_ARG(padapter), *((u8 *)(val))); else if (size == 2) RTW_INFO(FUNC_ADPT_FMT" val:0x%04x\n", FUNC_ADPT_ARG(padapter), *((u16 *)(val))); else if (size == 4) RTW_INFO(FUNC_ADPT_FMT" val:0x%08x\n", FUNC_ADPT_ARG(padapter), *((u32 *)(val))); } if (size == 2) *((u16 *)(val)) = cpu_to_le16(*((u16 *)(val))); else if (size == 4) *((u32 *)(val)) = cpu_to_le32(*((u32 *)(val))); err = sd_cmd52_write(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_INDIRECT_REG_DATA), size, val); if (err) goto exit; /* trigger */ SET_INDIRECT_REG_WRITE(cmd); if (DBG_SDIO_INDIRECT_ACCESS) RTW_INFO(FUNC_ADPT_FMT" cmd:%02x %02x %02x %02x\n", FUNC_ADPT_ARG(padapter), cmd[0], cmd[1], cmd[2], cmd[3]); err = sd_cmd52_write(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_INDIRECT_REG_CFG + 2), 1, cmd + 2); if (err) goto exit; /* polling for indirect access done */ start = rtw_get_current_time(); while (1) { if (rtw_is_surprise_removed(padapter)) { sr = 1; break; } err = sd_cmd52_read(pintfhdl, SDIO_LOCAL_CMD_ADDR(SDIO_REG_INDIRECT_REG_CFG + 2), 1, cmd + 2); if (!err && GET_INDIRECT_REG_RDY(cmd)) break; if (rtw_get_passing_time_ms(start) > INDIRECT_ACCESS_TIMEOUT_MS) { timeout = 1; break; } } end = rtw_get_current_time(); if (timeout || sr) goto exit; exit: /* release indirect access lock */ _exit_critical_mutex(mutex, NULL); if (DBG_SDIO_INDIRECT_ACCESS) { RTW_INFO(FUNC_ADPT_FMT" addr:0x%0x size:%u, cmd:%02x %02x %02x %02x, to:%u, err:%u\n" , FUNC_ADPT_ARG(padapter), addr, size, cmd[0], cmd[1], cmd[2], cmd[3], timeout, err); if (start != 0 || end != 0) { RTW_INFO(FUNC_ADPT_FMT" polling %d ms\n" , FUNC_ADPT_ARG(padapter), rtw_get_time_interval_ms(start, end)); } } if (timeout) { RTW_ERR(FUNC_ADPT_FMT" addr:0x%0x timeout(err:%d), cmd\n" , FUNC_ADPT_ARG(padapter), addr, err); if (!err) err = -1; /* just for return value */ } else if (err) { RTW_ERR(FUNC_ADPT_FMT" addr:0x%0x err:%d\n" , FUNC_ADPT_ARG(padapter), addr, err); } else if (sr) { /* just for return value */ err = -1; } return err; } u8 sdio_iread8(struct intf_hdl *pintfhdl, u32 addr) { u8 val; if (sdio_iread(pintfhdl->padapter, addr, 1, (u8 *)&val) != 0) val = SDIO_ERR_VAL8; return val; } u16 sdio_iread16(struct intf_hdl *pintfhdl, u32 addr) { u16 val; if (sdio_iread(pintfhdl->padapter, addr, 2, (u8 *)&val) != 0) val = SDIO_ERR_VAL16; return val; } u32 sdio_iread32(struct intf_hdl *pintfhdl, u32 addr) { u32 val; if (sdio_iread(pintfhdl->padapter, addr, 4, (u8 *)&val) != 0) val = SDIO_ERR_VAL32; return val; } s32 sdio_iwrite8(struct intf_hdl *pintfhdl, u32 addr, u8 val) { return sdio_iwrite(pintfhdl->padapter, addr, 1, (u8 *)&val); } s32 sdio_iwrite16(struct intf_hdl *pintfhdl, u32 addr, u16 val) { return sdio_iwrite(pintfhdl->padapter, addr, 2, (u8 *)&val); } s32 sdio_iwrite32(struct intf_hdl *pintfhdl, u32 addr, u32 val) { return sdio_iwrite(pintfhdl->padapter, addr, 4, (u8 *)&val); } #endif /* CONFIG_SDIO_INDIRECT_ACCESS */ u32 cmd53_4byte_alignment(struct intf_hdl *pintfhdl, u32 addr) { u32 addr_rdr; u32 value; value = 0; addr_rdr = addr % 4; if (addr_rdr) { u8 shift_bit; shift_bit = addr_rdr * 8; value = (sd_read32(pintfhdl, (addr - addr_rdr), NULL)) >> shift_bit; } else value = sd_read32(pintfhdl, addr, NULL); return value; } #endif /* !RTW_HALMAC */ #ifndef CONFIG_SDIO_TX_TASKLET #ifdef SDIO_FREE_XMIT_BUF_SEMA void _rtw_sdio_free_xmitbuf_sema_up(struct xmit_priv *xmit) { _rtw_up_sema(&xmit->sdio_free_xmitbuf_sema); } void _rtw_sdio_free_xmitbuf_sema_down(struct xmit_priv *xmit) { _rtw_down_sema(&xmit->sdio_free_xmitbuf_sema); } #ifdef DBG_SDIO_FREE_XMIT_BUF_SEMA void dbg_rtw_sdio_free_xmitbuf_sema_up(struct xmit_priv *xmit, const char *caller) { /* just for debug usage only, pleae take care for the different of count implementaton */ RTW_INFO("%s("ADPT_FMT") before up sdio_free_xmitbuf_sema, count:%u\n" , caller, ADPT_ARG(xmit->adapter), xmit->sdio_free_xmitbuf_sema.count); _rtw_sdio_free_xmitbuf_sema_up(xmit); } void dbg_rtw_sdio_free_xmitbuf_sema_down(struct xmit_priv *xmit, const char *caller) { /* just for debug usage only, pleae take care for the different of count implementaton */ RTW_INFO("%s("ADPT_FMT") before down sdio_free_xmitbuf_sema, count:%u\n" , caller, ADPT_ARG(xmit->adapter), xmit->sdio_free_xmitbuf_sema.count); _rtw_sdio_free_xmitbuf_sema_down(xmit); } #endif /* DBG_SDIO_FREE_XMIT_BUF_SEMA */ #endif /* SDIO_FREE_XMIT_BUF_SEMA */ #endif /* !CONFIG_SDIO_TX_TASKLET */ s32 sdio_initrecvbuf(struct recv_buf *recvbuf, _adapter *adapter) { _rtw_init_listhead(&recvbuf->list); #ifdef PLATFORM_WINDOWS _rtw_spinlock_init(&recvbuf->recvbuf_lock); #endif recvbuf->adapter = adapter; return _SUCCESS; } void sdio_freerecvbuf(struct recv_buf *recvbuf) { #ifdef PLATFORM_WINDOWS _rtw_spinlock_free(&recvbuf->recvbuf_lock); #endif } #ifdef CONFIG_SDIO_RECVBUF_PWAIT void dump_recvbuf_pwait_conf(void *sel, struct recv_priv *recvpriv) { struct rtw_pwait_conf *conf = &recvpriv->recvbuf_pwait.conf; RTW_PRINT_SEL(sel, "%-4s %-10s %-10s\n" , "type", "time", "cnt_lmt"); RTW_PRINT_SEL(sel, "%4s %10d %10d\n" , rtw_pwait_type_str(conf->type), conf->wait_time, conf->wait_cnt_lmt); } #ifdef CONFIG_SDIO_RECVBUF_PWAIT_RUNTIME_ADJUST int recvbuf_pwait_config_req(struct recv_priv *recvpriv, enum rtw_pwait_type type, s32 time, s32 cnt_lmt) { struct recv_buf *rbuf; struct rtw_pwait_conf *conf; int ret = _FAIL; rbuf = rtw_malloc(sizeof(*rbuf) + sizeof(struct rtw_pwait_conf)); if (!rbuf) goto exit; sdio_initrecvbuf(rbuf, recvpriv->adapter); rbuf->type = RBUF_TYPE_PWAIT_ADJ; rbuf->pbuf = ((u8*)rbuf) + sizeof(*rbuf); conf = (struct rtw_pwait_conf *)rbuf->pbuf; conf->type = type; conf->wait_time = time; conf->wait_cnt_lmt = cnt_lmt; ret = rtw_enqueue_recvbuf(rbuf, &recvpriv->free_recv_buf_queue); if (0 && ret == _SUCCESS) { RTW_INFO("request recvbuf_pwait with type=%s time=%d cnt_lmt=%d\n" , rtw_pwait_type_str(type), time, cnt_lmt); } exit: return ret; } int recvbuf_pwait_config_hdl(struct recv_priv *recvpriv, struct recv_buf *rbuf) { struct rtw_pwait_conf *conf = (struct rtw_pwait_conf *)rbuf->pbuf; int ret = rtw_pwctx_config(&recvpriv->recvbuf_pwait, conf->type, conf->wait_time, conf->wait_cnt_lmt); if (0 && ret == _SUCCESS) { RTW_INFO("config recvbuf_pwait with type=%s time=%d cnt_lmt=%d\n" , rtw_pwait_type_str(conf->type), conf->wait_time, conf->wait_cnt_lmt); } sdio_freerecvbuf(rbuf); rtw_mfree(rbuf, sizeof(*rbuf) + sizeof(*conf)); return ret; } #endif /* CONFIG_SDIO_RECVBUF_PWAIT_RUNTIME_ADJUST */ #endif /* CONFIG_SDIO_RECVBUF_PWAIT */