1 /******************************************************************************
3 * Copyright(c) 2016 Realtek Corporation.
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.
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
14 * The full GNU General Public License is included in this distribution in the
15 * file called LICENSE.
17 * Contact Information:
18 * wlanfae <wlanfae@realtek.com>
19 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
20 * Hsinchu 300, Taiwan.
22 * Larry Finger <Larry.Finger@lwfinger.net>
24 *****************************************************************************/
26 #include "halmac_api.h"
27 #include "rtl_halmac.h"
28 #include <linux/module.h>
29 #include <linux/vmalloc.h>
31 #define DEFAULT_INDICATOR_TIMELMT msecs_to_jiffies(1000) /* ms */
32 #define FIRMWARE_MAX_SIZE HALMAC_FW_SIZE_MAX_88XX
34 static struct rtl_halmac_ops rtl_halmac_operation = {
35 .halmac_init_adapter = rtl_halmac_init_adapter,
36 .halmac_deinit_adapter = rtl_halmac_deinit_adapter,
37 .halmac_init_hal = rtl_halmac_init_hal,
38 .halmac_deinit_hal = rtl_halmac_deinit_hal,
39 .halmac_poweron = rtl_halmac_poweron,
40 .halmac_poweroff = rtl_halmac_poweroff,
42 .halmac_phy_power_switch = rtl_halmac_phy_power_switch,
43 .halmac_set_mac_address = rtl_halmac_set_mac_address,
44 .halmac_set_bssid = rtl_halmac_set_bssid,
46 .halmac_get_physical_efuse_size = rtl_halmac_get_physical_efuse_size,
47 .halmac_read_physical_efuse_map = rtl_halmac_read_physical_efuse_map,
48 .halmac_get_logical_efuse_size = rtl_halmac_get_logical_efuse_size,
49 .halmac_read_logical_efuse_map = rtl_halmac_read_logical_efuse_map,
51 .halmac_set_bandwidth = rtl_halmac_set_bandwidth,
53 .halmac_c2h_handle = rtl_halmac_c2h_handle,
55 .halmac_chk_txdesc = rtl_halmac_chk_txdesc,
58 struct rtl_halmac_ops *rtl_halmac_get_ops_pointer(void)
60 return &rtl_halmac_operation;
62 EXPORT_SYMBOL(rtl_halmac_get_ops_pointer);
65 * Driver API for HALMAC operations
68 static u8 _halmac_reg_read_8(void *p, u32 offset)
70 struct rtl_priv *rtlpriv = (struct rtl_priv *)p;
72 return rtl_read_byte(rtlpriv, offset);
75 static u16 _halmac_reg_read_16(void *p, u32 offset)
77 struct rtl_priv *rtlpriv = (struct rtl_priv *)p;
79 return rtl_read_word(rtlpriv, offset);
82 static u32 _halmac_reg_read_32(void *p, u32 offset)
84 struct rtl_priv *rtlpriv = (struct rtl_priv *)p;
86 return rtl_read_dword(rtlpriv, offset);
89 static void _halmac_reg_write_8(void *p, u32 offset, u8 val)
91 struct rtl_priv *rtlpriv = (struct rtl_priv *)p;
93 rtl_write_byte(rtlpriv, offset, val);
96 static void _halmac_reg_write_16(void *p, u32 offset, u16 val)
98 struct rtl_priv *rtlpriv = (struct rtl_priv *)p;
100 rtl_write_word(rtlpriv, offset, val);
103 static void _halmac_reg_write_32(void *p, u32 offset, u32 val)
105 struct rtl_priv *rtlpriv = (struct rtl_priv *)p;
107 rtl_write_dword(rtlpriv, offset, val);
110 static bool _halmac_write_data_rsvd_page(void *p, u8 *buf, u32 size)
112 struct rtl_priv *rtlpriv = (struct rtl_priv *)p;
114 if (rtlpriv->cfg->ops->halmac_cb_write_data_rsvd_page &&
115 rtlpriv->cfg->ops->halmac_cb_write_data_rsvd_page(rtlpriv, buf,
122 static bool _halmac_write_data_h2c(void *p, u8 *buf, u32 size)
124 struct rtl_priv *rtlpriv = (struct rtl_priv *)p;
126 if (rtlpriv->cfg->ops->halmac_cb_write_data_h2c &&
127 rtlpriv->cfg->ops->halmac_cb_write_data_h2c(rtlpriv, buf, size))
133 static const char *const RTL_HALMAC_FEATURE_NAME[] = {
134 "HALMAC_FEATURE_CFG_PARA",
135 "HALMAC_FEATURE_DUMP_PHYSICAL_EFUSE",
136 "HALMAC_FEATURE_DUMP_LOGICAL_EFUSE",
137 "HALMAC_FEATURE_UPDATE_PACKET",
138 "HALMAC_FEATURE_UPDATE_DATAPACK",
139 "HALMAC_FEATURE_RUN_DATAPACK",
140 "HALMAC_FEATURE_CHANNEL_SWITCH",
141 "HALMAC_FEATURE_IQK",
142 "HALMAC_FEATURE_POWER_TRACKING",
143 "HALMAC_FEATURE_PSD",
144 "HALMAC_FEATURE_ALL"};
146 static inline bool is_valid_id_status(struct rtl_priv *rtlpriv,
147 enum halmac_feature_id id,
148 enum halmac_cmd_process_status status)
151 case HALMAC_FEATURE_CFG_PARA:
152 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__,
153 RTL_HALMAC_FEATURE_NAME[id]);
155 case HALMAC_FEATURE_DUMP_PHYSICAL_EFUSE:
156 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__,
157 RTL_HALMAC_FEATURE_NAME[id]);
158 if (status != HALMAC_CMD_PROCESS_DONE) {
159 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD,
160 "%s: <WARN> id(%d) unspecified status(%d)!\n",
161 __func__, id, status);
164 case HALMAC_FEATURE_DUMP_LOGICAL_EFUSE:
165 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__,
166 RTL_HALMAC_FEATURE_NAME[id]);
167 if (status != HALMAC_CMD_PROCESS_DONE) {
168 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD,
169 "%s: <WARN> id(%d) unspecified status(%d)!\n",
170 __func__, id, status);
173 case HALMAC_FEATURE_UPDATE_PACKET:
174 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__,
175 RTL_HALMAC_FEATURE_NAME[id]);
177 case HALMAC_FEATURE_UPDATE_DATAPACK:
178 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__,
179 RTL_HALMAC_FEATURE_NAME[id]);
181 case HALMAC_FEATURE_RUN_DATAPACK:
182 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__,
183 RTL_HALMAC_FEATURE_NAME[id]);
185 case HALMAC_FEATURE_CHANNEL_SWITCH:
186 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__,
187 RTL_HALMAC_FEATURE_NAME[id]);
189 case HALMAC_FEATURE_IQK:
190 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__,
191 RTL_HALMAC_FEATURE_NAME[id]);
193 case HALMAC_FEATURE_POWER_TRACKING:
194 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__,
195 RTL_HALMAC_FEATURE_NAME[id]);
197 case HALMAC_FEATURE_PSD:
198 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__,
199 RTL_HALMAC_FEATURE_NAME[id]);
201 case HALMAC_FEATURE_ALL:
202 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: %s\n", __func__,
203 RTL_HALMAC_FEATURE_NAME[id]);
206 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD,
207 "%s: unknown feature id(%d)\n", __func__, id);
214 static int init_halmac_event_with_waittime(struct rtl_priv *rtlpriv,
215 enum halmac_feature_id id, u8 *buf,
218 struct completion *comp;
220 if (!rtlpriv->halmac.indicator[id].comp) {
221 comp = kzalloc(sizeof(*comp), GFP_KERNEL);
225 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD,
226 "%s: <WARN> id(%d) sctx is not NULL!!\n", __func__,
228 comp = rtlpriv->halmac.indicator[id].comp;
229 rtlpriv->halmac.indicator[id].comp = NULL;
232 init_completion(comp);
233 rtlpriv->halmac.indicator[id].wait_ms = time;
235 rtlpriv->halmac.indicator[id].buffer = buf;
236 rtlpriv->halmac.indicator[id].buf_size = size;
237 rtlpriv->halmac.indicator[id].ret_size = 0;
238 rtlpriv->halmac.indicator[id].status = 0;
239 /* fill sctx at least to sure other variables are all ready! */
240 rtlpriv->halmac.indicator[id].comp = comp;
245 static inline int init_halmac_event(struct rtl_priv *rtlpriv,
246 enum halmac_feature_id id, u8 *buf,
249 return init_halmac_event_with_waittime(rtlpriv, id, buf, size,
250 DEFAULT_INDICATOR_TIMELMT);
253 static void free_halmac_event(struct rtl_priv *rtlpriv,
254 enum halmac_feature_id id)
256 struct completion *comp;
258 if (!rtlpriv->halmac.indicator[id].comp)
261 comp = rtlpriv->halmac.indicator[id].comp;
262 rtlpriv->halmac.indicator[id].comp = NULL;
266 static int wait_halmac_event(struct rtl_priv *rtlpriv,
267 enum halmac_feature_id id)
269 struct completion *comp;
272 comp = rtlpriv->halmac.indicator[id].comp;
276 ret = wait_for_completion_timeout(
277 comp, rtlpriv->halmac.indicator[id].wait_ms);
278 free_halmac_event(rtlpriv, id);
287 * Always return true, HALMAC don't care the return value.
290 _halmac_event_indication(void *p, enum halmac_feature_id feature_id,
291 enum halmac_cmd_process_status process_status, u8 *buf,
294 struct rtl_priv *rtlpriv;
295 struct rtl_halmac_indicator *tbl, *indicator;
296 struct completion *comp;
300 rtlpriv = (struct rtl_priv *)p;
301 tbl = rtlpriv->halmac.indicator;
303 ret = is_valid_id_status(rtlpriv, feature_id, process_status);
307 indicator = &tbl[feature_id];
308 indicator->status = process_status;
309 indicator->ret_size = size;
310 if (!indicator->comp) {
311 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD,
312 "%s: No feature id(%d) waiting!!\n", __func__,
316 comp = indicator->comp;
318 if (process_status == HALMAC_CMD_PROCESS_ERROR) {
319 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD,
320 "%s: Something wrong id(%d)!!\n", __func__,
322 complete(comp); /* may provide error code */
326 if (size > indicator->buf_size) {
328 rtlpriv, COMP_HALMAC, DBG_LOUD,
329 "%s: <WARN> id(%d) buffer is not enough(%d<%d), data will be truncated!\n",
330 __func__, feature_id, indicator->buf_size, size);
331 cpsz = indicator->buf_size;
336 if (cpsz && indicator->buffer)
337 memcpy(indicator->buffer, buf, cpsz);
345 static struct halmac_platform_api rtl_halmac_platform_api = {
347 .REG_READ_8 = _halmac_reg_read_8,
348 .REG_READ_16 = _halmac_reg_read_16,
349 .REG_READ_32 = _halmac_reg_read_32,
350 .REG_WRITE_8 = _halmac_reg_write_8,
351 .REG_WRITE_16 = _halmac_reg_write_16,
352 .REG_WRITE_32 = _halmac_reg_write_32,
355 /* impletement in HAL-IC level */
356 .SEND_RSVD_PAGE = _halmac_write_data_rsvd_page,
357 .SEND_H2C_PKT = _halmac_write_data_h2c,
359 .EVENT_INDICATION = _halmac_event_indication,
362 static int init_priv(struct rtl_halmac *halmac)
364 struct rtl_halmac_indicator *indicator;
367 halmac->send_general_info = 0;
369 count = HALMAC_FEATURE_ALL + 1;
370 size = sizeof(*indicator) * count;
371 indicator = kzalloc(size, GFP_KERNEL);
374 halmac->indicator = indicator;
379 static void deinit_priv(struct rtl_halmac *halmac)
381 struct rtl_halmac_indicator *indicator;
383 indicator = halmac->indicator;
384 halmac->indicator = NULL;
388 int rtl_halmac_init_adapter(struct rtl_priv *rtlpriv)
390 struct halmac_adapter *halmac;
391 struct halmac_api *api;
392 enum halmac_interface intf;
393 enum halmac_ret_status status;
395 struct halmac_platform_api *pf_api = &rtl_halmac_platform_api;
397 halmac = rtlpriv_to_halmac(rtlpriv);
403 err = init_priv(&rtlpriv->halmac);
407 intf = HALMAC_INTERFACE_PCIE;
408 status = halmac_init_adapter(rtlpriv, pf_api, intf, &halmac, &api);
409 if (status != HALMAC_RET_SUCCESS) {
410 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD,
411 "%s: halmac_init_adapter fail!(status=%d)\n", __func__,
417 rtlpriv->halmac.internal = halmac;
421 rtl_halmac_deinit_adapter(rtlpriv);
426 int rtl_halmac_deinit_adapter(struct rtl_priv *rtlpriv)
428 struct halmac_adapter *halmac;
429 enum halmac_ret_status status;
432 halmac = rtlpriv_to_halmac(rtlpriv);
438 deinit_priv(&rtlpriv->halmac);
440 halmac_halt_api(halmac);
442 status = halmac_deinit_adapter(halmac);
443 rtlpriv->halmac.internal = NULL;
444 if (status != HALMAC_RET_SUCCESS) {
453 int rtl_halmac_poweron(struct rtl_priv *rtlpriv)
455 struct halmac_adapter *halmac;
456 struct halmac_api *api;
457 enum halmac_ret_status status;
460 halmac = rtlpriv_to_halmac(rtlpriv);
464 api = HALMAC_GET_API(halmac);
466 status = api->halmac_pre_init_system_cfg(halmac);
467 if (status != HALMAC_RET_SUCCESS)
470 status = api->halmac_mac_power_switch(halmac, HALMAC_MAC_POWER_ON);
471 if (status != HALMAC_RET_SUCCESS)
474 status = api->halmac_init_system_cfg(halmac);
475 if (status != HALMAC_RET_SUCCESS)
483 int rtl_halmac_poweroff(struct rtl_priv *rtlpriv)
485 struct halmac_adapter *halmac;
486 struct halmac_api *api;
487 enum halmac_ret_status status;
490 halmac = rtlpriv_to_halmac(rtlpriv);
494 api = HALMAC_GET_API(halmac);
496 status = api->halmac_mac_power_switch(halmac, HALMAC_MAC_POWER_OFF);
497 if (status != HALMAC_RET_SUCCESS)
507 * When this function return, the register REG_RCR may be changed.
509 int rtl_halmac_config_rx_info(struct rtl_priv *rtlpriv,
510 enum halmac_drv_info info)
512 struct halmac_adapter *halmac;
513 struct halmac_api *api;
514 enum halmac_ret_status status;
517 halmac = rtlpriv_to_halmac(rtlpriv);
518 api = HALMAC_GET_API(halmac);
520 status = api->halmac_cfg_drv_info(halmac, info);
521 if (status != HALMAC_RET_SUCCESS)
529 static enum halmac_ret_status init_mac_flow(struct rtl_priv *rtlpriv)
531 struct halmac_adapter *halmac;
532 struct halmac_api *api;
533 enum halmac_ret_status status;
537 halmac = rtlpriv_to_halmac(rtlpriv);
538 api = HALMAC_GET_API(halmac);
541 status = api->halmac_init_mac_cfg(halmac, HALMAC_TRX_MODE_WMM);
543 status = api->halmac_init_mac_cfg(halmac,
544 HALMAC_TRX_MODE_NORMAL);
545 if (status != HALMAC_RET_SUCCESS)
548 err = rtl_halmac_rx_agg_switch(rtlpriv, true);
552 if (rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS7])
553 status = api->halmac_cfg_operation_mode(
554 halmac, HALMAC_WIRELESS_MODE_AC);
555 else if (rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS7])
556 status = api->halmac_cfg_operation_mode(halmac,
557 HALMAC_WIRELESS_MODE_N);
558 else if (rtlpriv->cfg->maps[RTL_RC_OFDM_RATE6M])
559 status = api->halmac_cfg_operation_mode(halmac,
560 HALMAC_WIRELESS_MODE_G);
562 status = api->halmac_cfg_operation_mode(halmac,
563 HALMAC_WIRELESS_MODE_B);
564 if (status != HALMAC_RET_SUCCESS)
571 static inline enum halmac_rf_type _rf_type_drv2halmac(enum rf_type rf_drv)
573 enum halmac_rf_type rf_mac;
577 rf_mac = HALMAC_RF_1T2R;
580 rf_mac = HALMAC_RF_2T2R;
583 rf_mac = HALMAC_RF_1T1R;
586 rf_mac = HALMAC_RF_2T2R_GREEN;
589 rf_mac = (enum halmac_rf_type)rf_drv;
596 static int _send_general_info(struct rtl_priv *rtlpriv)
598 struct halmac_adapter *halmac;
599 struct halmac_api *api;
600 struct halmac_general_info info;
601 enum halmac_ret_status status;
603 halmac = rtlpriv_to_halmac(rtlpriv);
606 api = HALMAC_GET_API(halmac);
608 memset(&info, 0, sizeof(info));
609 info.rfe_type = rtlpriv->rtlhal.rfe_type;
610 info.rf_type = _rf_type_drv2halmac(rtlpriv->phy.rf_type);
612 status = api->halmac_send_general_info(halmac, &info);
614 case HALMAC_RET_SUCCESS:
616 case HALMAC_RET_NO_DLFW:
617 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_WARNING,
618 "%s: halmac_send_general_info() fail because fw not dl!\n",
620 /* fallthrough here */
631 * 1. rtl_hal_get_hwreg(HW_VAR_RF_TYPE)
632 * 2. HAL_DATA_TYPE.rfe_type
633 * already ready for use before calling this function.
635 static int _halmac_init_hal(struct rtl_priv *rtlpriv, u8 *fw, u32 fwsize)
637 struct halmac_adapter *halmac;
638 struct halmac_api *api;
639 enum halmac_ret_status status;
642 int err, err_ret = -1;
644 halmac = rtlpriv_to_halmac(rtlpriv);
647 api = HALMAC_GET_API(halmac);
651 /* SKIP: halmac_init_adapter (Already done before) */
653 /* halmac_pre_Init_system_cfg */
654 /* halmac_mac_power_switch(on) */
655 /* halmac_Init_system_cfg */
656 err = rtl_halmac_poweron(rtlpriv);
663 rtlpriv->halmac.send_general_info = 0;
665 err = rtl_halmac_dlfw(rtlpriv, fw, fwsize);
672 status = init_mac_flow(rtlpriv);
673 if (status != HALMAC_RET_SUCCESS)
676 /* halmac_send_general_info */
678 rtlpriv->halmac.send_general_info = 0;
679 err = _send_general_info(rtlpriv);
683 rtlpriv->halmac.send_general_info = 1;
686 /* Init Phy parameter-MAC */
687 if (rtlpriv->cfg->ops->halmac_cb_init_mac_register)
688 ok = rtlpriv->cfg->ops->halmac_cb_init_mac_register(rtlpriv);
695 /* StateMacInitialized */
697 /* halmac_cfg_drv_info */
698 err = rtl_halmac_config_rx_info(rtlpriv, HALMAC_DRV_INFO_PHY_STATUS);
702 /* halmac_set_hw_value(HALMAC_HW_EN_BB_RF) */
704 if (rtlpriv->cfg->ops->halmac_cb_init_bb_rf_register)
705 ok = rtlpriv->cfg->ops->halmac_cb_init_bb_rf_register(rtlpriv);
712 status = api->halmac_init_interface_cfg(halmac);
713 if (status != HALMAC_RET_SUCCESS)
716 /* SKIP: halmac_verify_platform_api */
717 /* SKIP: halmac_h2c_lb */
726 int rtl_halmac_init_hal(struct rtl_priv *rtlpriv)
728 if (!rtlpriv->rtlhal.pfirmware || rtlpriv->rtlhal.fwsize == 0)
731 return _halmac_init_hal(rtlpriv, rtlpriv->rtlhal.pfirmware,
732 rtlpriv->rtlhal.fwsize);
735 int rtl_halmac_deinit_hal(struct rtl_priv *rtlpriv)
737 struct halmac_adapter *halmac;
738 struct halmac_api *api;
739 enum halmac_ret_status status;
742 halmac = rtlpriv_to_halmac(rtlpriv);
745 api = HALMAC_GET_API(halmac);
747 status = api->halmac_deinit_interface_cfg(halmac);
748 if (status != HALMAC_RET_SUCCESS)
751 /* rtw_hal_power_off(adapter); */
752 status = api->halmac_mac_power_switch(halmac, HALMAC_MAC_POWER_OFF);
753 if (status != HALMAC_RET_SUCCESS)
761 int rtl_halmac_self_verify(struct rtl_priv *rtlpriv)
763 struct halmac_adapter *mac;
764 struct halmac_api *api;
765 enum halmac_ret_status status;
768 mac = rtlpriv_to_halmac(rtlpriv);
769 api = HALMAC_GET_API(mac);
771 status = api->halmac_verify_platform_api(mac);
772 if (status != HALMAC_RET_SUCCESS)
775 status = api->halmac_h2c_lb(mac);
776 if (status != HALMAC_RET_SUCCESS)
784 int rtl_halmac_dlfw(struct rtl_priv *rtlpriv, u8 *fw, u32 fwsize)
786 struct halmac_adapter *mac;
787 struct halmac_api *api;
788 enum halmac_ret_status status;
789 struct halmac_fw_version fw_version;
792 mac = rtlpriv_to_halmac(rtlpriv);
793 api = HALMAC_GET_API(mac);
795 if ((!fw) || (!fwsize))
798 /* 1. Driver Stop Tx */
801 /* 2. Driver Check Tx FIFO is empty */
804 /* 3. Config MAX download size */
805 api->halmac_cfg_max_dl_size(mac, 0x1000);
807 /* 4. Download Firmware */
808 mac->h2c_packet_seq = 0;
809 status = api->halmac_download_firmware(mac, fw, fwsize);
810 if (status != HALMAC_RET_SUCCESS)
813 status = api->halmac_get_fw_version(mac, &fw_version);
814 if (status == HALMAC_RET_SUCCESS) {
815 rtlpriv->rtlhal.fw_version = fw_version.version;
816 rtlpriv->rtlhal.fw_subversion =
817 (fw_version.sub_version << 8) | (fw_version.sub_index);
820 rtlpriv, COMP_HALMAC, DBG_DMESG,
821 "halmac report firmware version %04X.%04X\n",
822 rtlpriv->rtlhal.fw_version,
823 rtlpriv->rtlhal.fw_subversion);
826 if (rtlpriv->halmac.send_general_info) {
827 rtlpriv->halmac.send_general_info = 0;
828 err = _send_general_info(rtlpriv);
831 /* 5. Driver resume TX if needed */
834 /* 6. Reset driver variables if needed */
835 /*hal->LastHMEBoxNum = 0;*/
842 * Power on/off BB/RF domain.
845 * enable true/false for power on/off
851 int rtl_halmac_phy_power_switch(struct rtl_priv *rtlpriv, u8 enable)
853 struct halmac_adapter *halmac;
854 struct halmac_api *api;
855 enum halmac_ret_status status;
857 halmac = rtlpriv_to_halmac(rtlpriv);
860 api = HALMAC_GET_API(halmac);
862 status = api->halmac_set_hw_value(halmac, HALMAC_HW_EN_BB_RF, &enable);
863 if (status != HALMAC_RET_SUCCESS)
869 static bool _is_fw_read_cmd_down(struct rtl_priv *rtlpriv, u8 msgbox_num)
871 bool read_down = false;
872 int retry_cnts = 100;
875 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD,
876 "%s, reg_1cc(%x), msg_box(%d)...\n", __func__,
877 rtl_read_byte(rtlpriv, REG_HMETFR), msgbox_num);
880 valid = rtl_read_byte(rtlpriv, REG_HMETFR) & BIT(msgbox_num);
885 } while ((!read_down) && (retry_cnts--));
890 int rtl_halmac_send_h2c(struct rtl_priv *rtlpriv, u8 *h2c)
894 u32 msgbox_ex_addr = 0;
896 __le32 h2c_cmd_ex = 0;
898 unsigned long flag = 0;
899 struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
902 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD, "%s: pbuf is NULL\n",
907 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
909 /* pay attention to if race condition happened in H2C cmd setting */
910 h2c_box_num = rtlhal->last_hmeboxnum;
912 if (!_is_fw_read_cmd_down(rtlpriv, h2c_box_num)) {
913 RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD,
914 " fw read cmd failed...\n");
918 /* Write Ext command(byte 4 -7) */
919 msgbox_ex_addr = REG_HMEBOX_E0 + (h2c_box_num * EX_MESSAGE_BOX_SIZE);
920 memcpy((u8 *)(&h2c_cmd_ex), h2c + 4, EX_MESSAGE_BOX_SIZE);
921 rtl_write_dword(rtlpriv, msgbox_ex_addr, le32_to_cpu(h2c_cmd_ex));
923 /* Write command (byte 0 -3 ) */
924 msgbox_addr = REG_HMEBOX0 + (h2c_box_num * MESSAGE_BOX_SIZE);
925 memcpy((u8 *)(&h2c_cmd), h2c, 4);
926 rtl_write_dword(rtlpriv, msgbox_addr, le32_to_cpu(h2c_cmd));
928 /* update last msg box number */
929 rtlhal->last_hmeboxnum = (h2c_box_num + 1) % MAX_H2C_BOX_NUMS;
933 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
937 int rtl_halmac_c2h_handle(struct rtl_priv *rtlpriv, u8 *c2h, u32 size)
939 struct halmac_adapter *mac;
940 struct halmac_api *api;
941 enum halmac_ret_status status;
943 mac = rtlpriv_to_halmac(rtlpriv);
944 api = HALMAC_GET_API(mac);
946 status = api->halmac_get_c2h_info(mac, c2h, size);
947 if (status != HALMAC_RET_SUCCESS)
953 int rtl_halmac_get_physical_efuse_size(struct rtl_priv *rtlpriv, u32 *size)
955 struct halmac_adapter *mac;
956 struct halmac_api *api;
957 enum halmac_ret_status status;
960 mac = rtlpriv_to_halmac(rtlpriv);
961 api = HALMAC_GET_API(mac);
963 status = api->halmac_get_efuse_size(mac, &val);
964 if (status != HALMAC_RET_SUCCESS)
971 int rtl_halmac_read_physical_efuse_map(struct rtl_priv *rtlpriv, u8 *map,
974 struct halmac_adapter *mac;
975 struct halmac_api *api;
976 enum halmac_ret_status status;
977 enum halmac_feature_id id;
980 mac = rtlpriv_to_halmac(rtlpriv);
981 api = HALMAC_GET_API(mac);
982 id = HALMAC_FEATURE_DUMP_PHYSICAL_EFUSE;
984 ret = init_halmac_event(rtlpriv, id, map, size);
988 status = api->halmac_dump_efuse_map(mac, HALMAC_EFUSE_R_DRV);
989 if (status != HALMAC_RET_SUCCESS) {
990 free_halmac_event(rtlpriv, id);
994 ret = wait_halmac_event(rtlpriv, id);
1001 int rtl_halmac_read_physical_efuse(struct rtl_priv *rtlpriv, u32 offset,
1004 struct halmac_adapter *mac;
1005 struct halmac_api *api;
1006 enum halmac_ret_status status;
1010 mac = rtlpriv_to_halmac(rtlpriv);
1011 api = HALMAC_GET_API(mac);
1013 for (i = 0; i < cnt; i++) {
1014 status = api->halmac_read_efuse(mac, offset + i, &v);
1015 if (status != HALMAC_RET_SUCCESS)
1023 int rtl_halmac_write_physical_efuse(struct rtl_priv *rtlpriv, u32 offset,
1026 struct halmac_adapter *mac;
1027 struct halmac_api *api;
1028 enum halmac_ret_status status;
1031 mac = rtlpriv_to_halmac(rtlpriv);
1032 api = HALMAC_GET_API(mac);
1034 for (i = 0; i < cnt; i++) {
1035 status = api->halmac_write_efuse(mac, offset + i, data[i]);
1036 if (status != HALMAC_RET_SUCCESS)
1043 int rtl_halmac_get_logical_efuse_size(struct rtl_priv *rtlpriv, u32 *size)
1045 struct halmac_adapter *mac;
1046 struct halmac_api *api;
1047 enum halmac_ret_status status;
1050 mac = rtlpriv_to_halmac(rtlpriv);
1051 api = HALMAC_GET_API(mac);
1053 status = api->halmac_get_logical_efuse_size(mac, &val);
1054 if (status != HALMAC_RET_SUCCESS)
1061 int rtl_halmac_read_logical_efuse_map(struct rtl_priv *rtlpriv, u8 *map,
1064 struct halmac_adapter *mac;
1065 struct halmac_api *api;
1066 enum halmac_ret_status status;
1067 enum halmac_feature_id id;
1070 mac = rtlpriv_to_halmac(rtlpriv);
1071 api = HALMAC_GET_API(mac);
1072 id = HALMAC_FEATURE_DUMP_LOGICAL_EFUSE;
1074 ret = init_halmac_event(rtlpriv, id, map, size);
1078 status = api->halmac_dump_logical_efuse_map(mac, HALMAC_EFUSE_R_AUTO);
1079 if (status != HALMAC_RET_SUCCESS) {
1080 free_halmac_event(rtlpriv, id);
1084 ret = wait_halmac_event(rtlpriv, id);
1091 int rtl_halmac_write_logical_efuse_map(struct rtl_priv *rtlpriv, u8 *map,
1092 u32 size, u8 *maskmap, u32 masksize)
1094 struct halmac_adapter *mac;
1095 struct halmac_api *api;
1096 struct halmac_pg_efuse_info pginfo;
1097 enum halmac_ret_status status;
1099 mac = rtlpriv_to_halmac(rtlpriv);
1100 api = HALMAC_GET_API(mac);
1102 pginfo.efuse_map = map;
1103 pginfo.efuse_map_size = size;
1104 pginfo.efuse_mask = maskmap;
1105 pginfo.efuse_mask_size = masksize;
1107 status = api->halmac_pg_efuse_by_map(mac, &pginfo, HALMAC_EFUSE_R_AUTO);
1108 if (status != HALMAC_RET_SUCCESS)
1114 int rtl_halmac_read_logical_efuse(struct rtl_priv *rtlpriv, u32 offset, u32 cnt,
1117 struct halmac_adapter *mac;
1118 struct halmac_api *api;
1119 enum halmac_ret_status status;
1123 mac = rtlpriv_to_halmac(rtlpriv);
1124 api = HALMAC_GET_API(mac);
1126 for (i = 0; i < cnt; i++) {
1127 status = api->halmac_read_logical_efuse(mac, offset + i, &v);
1128 if (status != HALMAC_RET_SUCCESS)
1136 int rtl_halmac_write_logical_efuse(struct rtl_priv *rtlpriv, u32 offset,
1139 struct halmac_adapter *mac;
1140 struct halmac_api *api;
1141 enum halmac_ret_status status;
1144 mac = rtlpriv_to_halmac(rtlpriv);
1145 api = HALMAC_GET_API(mac);
1147 for (i = 0; i < cnt; i++) {
1148 status = api->halmac_write_logical_efuse(mac, offset + i,
1150 if (status != HALMAC_RET_SUCCESS)
1157 int rtl_halmac_set_mac_address(struct rtl_priv *rtlpriv, u8 hwport, u8 *addr)
1159 struct halmac_adapter *halmac;
1160 struct halmac_api *api;
1162 union halmac_wlan_addr hwa;
1163 enum halmac_ret_status status;
1166 halmac = rtlpriv_to_halmac(rtlpriv);
1167 api = HALMAC_GET_API(halmac);
1170 memset(&hwa, 0, sizeof(hwa));
1171 memcpy(hwa.address, addr, 6);
1173 status = api->halmac_cfg_mac_addr(halmac, port, &hwa);
1174 if (status != HALMAC_RET_SUCCESS)
1182 int rtl_halmac_set_bssid(struct rtl_priv *rtlpriv, u8 hwport, u8 *addr)
1184 struct halmac_adapter *halmac;
1185 struct halmac_api *api;
1187 union halmac_wlan_addr hwa;
1188 enum halmac_ret_status status;
1191 halmac = rtlpriv_to_halmac(rtlpriv);
1192 api = HALMAC_GET_API(halmac);
1195 memset(&hwa, 0, sizeof(union halmac_wlan_addr));
1196 memcpy(hwa.address, addr, 6);
1197 status = api->halmac_cfg_bssid(halmac, port, &hwa);
1198 if (status != HALMAC_RET_SUCCESS)
1206 int rtl_halmac_set_bandwidth(struct rtl_priv *rtlpriv, u8 channel,
1207 u8 pri_ch_idx, u8 bw)
1209 struct halmac_adapter *mac;
1210 struct halmac_api *api;
1211 enum halmac_ret_status status;
1213 mac = rtlpriv_to_halmac(rtlpriv);
1214 api = HALMAC_GET_API(mac);
1216 status = api->halmac_cfg_ch_bw(mac, channel, pri_ch_idx, bw);
1217 if (status != HALMAC_RET_SUCCESS)
1223 int rtl_halmac_get_hw_value(struct rtl_priv *rtlpriv, enum halmac_hw_id hw_id,
1226 struct halmac_adapter *mac;
1227 struct halmac_api *api;
1228 enum halmac_ret_status status;
1230 mac = rtlpriv_to_halmac(rtlpriv);
1231 api = HALMAC_GET_API(mac);
1233 status = api->halmac_get_hw_value(mac, hw_id, pvalue);
1234 if (status != HALMAC_RET_SUCCESS)
1240 int rtl_halmac_dump_fifo(struct rtl_priv *rtlpriv,
1241 enum hal_fifo_sel halmac_fifo_sel)
1243 struct halmac_adapter *mac;
1244 struct halmac_api *api;
1245 enum halmac_ret_status status;
1246 u8 *pfifo_map = NULL;
1250 mac = rtlpriv_to_halmac(rtlpriv);
1251 api = HALMAC_GET_API(mac);
1253 fifo_size = api->halmac_get_fifo_size(mac, halmac_fifo_sel);
1255 pfifo_map = vmalloc(fifo_size);
1259 status = api->halmac_dump_fifo(mac, halmac_fifo_sel, 0, fifo_size,
1262 if (status != HALMAC_RET_SUCCESS) {
1273 int rtl_halmac_rx_agg_switch(struct rtl_priv *rtlpriv, bool enable)
1275 struct halmac_adapter *halmac;
1276 struct halmac_api *api;
1277 struct halmac_rxagg_cfg rxaggcfg;
1278 enum halmac_ret_status status;
1281 halmac = rtlpriv_to_halmac(rtlpriv);
1282 api = HALMAC_GET_API(halmac);
1283 memset((void *)&rxaggcfg, 0, sizeof(rxaggcfg));
1286 /* enable RX agg. */
1287 /* PCIE do nothing */
1289 /* disable RX agg. */
1290 rxaggcfg.mode = HALMAC_RX_AGG_MODE_NONE;
1293 status = api->halmac_cfg_rx_aggregation(halmac, &rxaggcfg);
1294 if (status != HALMAC_RET_SUCCESS)
1302 int rtl_halmac_get_wow_reason(struct rtl_priv *rtlpriv, u8 *reason)
1307 val8 = rtl_read_byte(rtlpriv, 0x1C7);
1319 * Get RX driver info size. RX driver info is a small memory space between
1320 * scriptor and RX payload.
1322 * +-------------------------+
1324 * | usually 24 bytes |
1325 * +-------------------------+
1326 * | RX driver info |
1327 * | depends on driver cfg |
1328 * +-------------------------+
1331 * +-------------------------+
1334 * d pointer to struct dvobj_priv of driver
1335 * sz rx driver info size in bytes.
1341 int rtl_halmac_get_drv_info_sz(struct rtl_priv *rtlpriv, u8 *sz)
1343 /* enum halmac_ret_status status; */
1344 u8 dw = 6; /* max number */
1350 int rtl_halmac_get_rsvd_drv_pg_bndy(struct rtl_priv *rtlpriv, u16 *drv_pg)
1352 enum halmac_ret_status status;
1353 struct halmac_adapter *halmac = rtlpriv_to_halmac(rtlpriv);
1354 struct halmac_api *api = HALMAC_GET_API(halmac);
1356 status = api->halmac_get_hw_value(halmac, HALMAC_HW_RSVD_PG_BNDY,
1358 if (status != HALMAC_RET_SUCCESS)
1364 int rtl_halmac_chk_txdesc(struct rtl_priv *rtlpriv, u8 *txdesc, u32 size)
1366 struct halmac_adapter *mac;
1367 struct halmac_api *api;
1368 enum halmac_ret_status status;
1370 mac = rtlpriv_to_halmac(rtlpriv);
1371 api = HALMAC_GET_API(mac);
1373 status = api->halmac_chk_txdesc(mac, txdesc, size);
1375 if (status != HALMAC_RET_SUCCESS)
1381 MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
1382 MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>");
1383 MODULE_LICENSE("GPL");
1384 MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core");