diff options
Diffstat (limited to 'drivers/net/wireless')
199 files changed, 18974 insertions, 7868 deletions
diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index 0e9bad33fac8..141c1b5a7b1f 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -153,6 +153,10 @@ static void ar5523_cmd_rx_cb(struct urb *urb) ar5523_err(ar, "Invalid reply to WDCMSG_TARGET_START"); return; } + if (!cmd->odata) { + ar5523_err(ar, "Unexpected WDCMSG_TARGET_START reply"); + return; + } memcpy(cmd->odata, hdr + 1, sizeof(u32)); cmd->olen = sizeof(u32); cmd->res = 0; diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 5935e0973d14..8f5b8eb368fa 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -12,6 +12,7 @@ #include <linux/dmi.h> #include <linux/ctype.h> #include <linux/pm_qos.h> +#include <linux/nvmem-consumer.h> #include <asm/byteorder.h> #include "core.h" @@ -89,6 +90,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rri_on_ddr = false, .hw_filter_reset_required = true, .fw_diag_ce_download = false, + .credit_size_workaround = false, .tx_stats_over_pktlog = true, .dynamic_sar_support = false, }, @@ -124,6 +126,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rri_on_ddr = false, .hw_filter_reset_required = true, .fw_diag_ce_download = false, + .credit_size_workaround = false, .tx_stats_over_pktlog = true, .dynamic_sar_support = false, }, @@ -160,6 +163,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rri_on_ddr = false, .hw_filter_reset_required = true, .fw_diag_ce_download = false, + .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = false, }, @@ -190,6 +194,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .uart_pin_workaround = true, .tx_stats_over_pktlog = false, + .credit_size_workaround = false, .bmi_large_size_download = true, .supports_peer_stats_info = true, .dynamic_sar_support = true, @@ -226,6 +231,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rri_on_ddr = false, .hw_filter_reset_required = true, .fw_diag_ce_download = false, + .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = false, }, @@ -261,6 +267,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rri_on_ddr = false, .hw_filter_reset_required = true, .fw_diag_ce_download = false, + .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = false, }, @@ -296,6 +303,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rri_on_ddr = false, .hw_filter_reset_required = true, .fw_diag_ce_download = false, + .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = false, }, @@ -334,6 +342,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rri_on_ddr = false, .hw_filter_reset_required = true, .fw_diag_ce_download = true, + .credit_size_workaround = false, .tx_stats_over_pktlog = false, .supports_peer_stats_info = true, .dynamic_sar_support = true, @@ -376,6 +385,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rri_on_ddr = false, .hw_filter_reset_required = true, .fw_diag_ce_download = false, + .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = false, }, @@ -424,6 +434,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rri_on_ddr = false, .hw_filter_reset_required = true, .fw_diag_ce_download = false, + .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = false, }, @@ -469,6 +480,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rri_on_ddr = false, .hw_filter_reset_required = true, .fw_diag_ce_download = false, + .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = false, }, @@ -504,6 +516,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rri_on_ddr = false, .hw_filter_reset_required = true, .fw_diag_ce_download = false, + .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = false, }, @@ -541,6 +554,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rri_on_ddr = false, .hw_filter_reset_required = true, .fw_diag_ce_download = true, + .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = false, }, @@ -570,6 +584,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .uart_pin_workaround = true, + .credit_size_workaround = true, .dynamic_sar_support = false, }, { @@ -611,6 +626,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rri_on_ddr = false, .hw_filter_reset_required = true, .fw_diag_ce_download = false, + .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = false, }, @@ -639,6 +655,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rri_on_ddr = true, .hw_filter_reset_required = false, .fw_diag_ce_download = false, + .credit_size_workaround = false, .tx_stats_over_pktlog = false, .dynamic_sar_support = true, }, @@ -714,6 +731,7 @@ static void ath10k_send_suspend_complete(struct ath10k *ar) static int ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode) { + bool mtu_workaround = ar->hw_params.credit_size_workaround; int ret; u32 param = 0; @@ -731,7 +749,7 @@ static int ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode) param |= HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET; - if (mode == ATH10K_FIRMWARE_MODE_NORMAL) + if (mode == ATH10K_FIRMWARE_MODE_NORMAL && !mtu_workaround) param |= HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE; else param &= ~HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE; @@ -935,7 +953,8 @@ static int ath10k_core_get_board_id_from_otp(struct ath10k *ar) } if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT || - ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE) + ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE || + ar->cal_mode == ATH10K_PRE_CAL_MODE_NVMEM) bmi_board_id_param = BMI_PARAM_GET_FLASH_BOARD_ID; else bmi_board_id_param = BMI_PARAM_GET_EEPROM_BOARD_ID; @@ -1726,7 +1745,8 @@ static int ath10k_download_and_run_otp(struct ath10k *ar) /* As of now pre-cal is valid for 10_4 variants */ if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT || - ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE) + ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE || + ar->cal_mode == ATH10K_PRE_CAL_MODE_NVMEM) bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL; ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result); @@ -1853,6 +1873,39 @@ out_free: return ret; } +static int ath10k_download_cal_nvmem(struct ath10k *ar, const char *cell_name) +{ + struct nvmem_cell *cell; + void *buf; + size_t len; + int ret; + + cell = devm_nvmem_cell_get(ar->dev, cell_name); + if (IS_ERR(cell)) { + ret = PTR_ERR(cell); + return ret; + } + + buf = nvmem_cell_read(cell, &len); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + if (ar->hw_params.cal_data_len != len) { + kfree(buf); + ath10k_warn(ar, "invalid calibration data length in nvmem-cell '%s': %zu != %u\n", + cell_name, len, ar->hw_params.cal_data_len); + return -EMSGSIZE; + } + + ret = ath10k_download_board_data(ar, buf, len); + kfree(buf); + if (ret) + ath10k_warn(ar, "failed to download calibration data from nvmem-cell '%s': %d\n", + cell_name, ret); + + return ret; +} + int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name, struct ath10k_fw_file *fw_file) { @@ -2087,6 +2140,18 @@ static int ath10k_core_pre_cal_download(struct ath10k *ar) { int ret; + ret = ath10k_download_cal_nvmem(ar, "pre-calibration"); + if (ret == 0) { + ar->cal_mode = ATH10K_PRE_CAL_MODE_NVMEM; + goto success; + } else if (ret == -EPROBE_DEFER) { + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot did not find a pre-calibration nvmem-cell, try file next: %d\n", + ret); + ret = ath10k_download_cal_file(ar, ar->pre_cal_file); if (ret == 0) { ar->cal_mode = ATH10K_PRE_CAL_MODE_FILE; @@ -2153,6 +2218,18 @@ static int ath10k_download_cal_data(struct ath10k *ar) "pre cal download procedure failed, try cal file: %d\n", ret); + ret = ath10k_download_cal_nvmem(ar, "calibration"); + if (ret == 0) { + ar->cal_mode = ATH10K_CAL_MODE_NVMEM; + goto done; + } else if (ret == -EPROBE_DEFER) { + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot did not find a calibration nvmem-cell, try file next: %d\n", + ret); + ret = ath10k_download_cal_file(ar, ar->cal_file); if (ret == 0) { ar->cal_mode = ATH10K_CAL_MODE_FILE; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 5aeff2d9f6cf..9f6680b3be0a 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -877,8 +877,10 @@ enum ath10k_cal_mode { ATH10K_CAL_MODE_FILE, ATH10K_CAL_MODE_OTP, ATH10K_CAL_MODE_DT, + ATH10K_CAL_MODE_NVMEM, ATH10K_PRE_CAL_MODE_FILE, ATH10K_PRE_CAL_MODE_DT, + ATH10K_PRE_CAL_MODE_NVMEM, ATH10K_CAL_MODE_EEPROM, }; @@ -898,10 +900,14 @@ static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode) return "otp"; case ATH10K_CAL_MODE_DT: return "dt"; + case ATH10K_CAL_MODE_NVMEM: + return "nvmem"; case ATH10K_PRE_CAL_MODE_FILE: return "pre-cal-file"; case ATH10K_PRE_CAL_MODE_DT: return "pre-cal-dt"; + case ATH10K_PRE_CAL_MODE_NVMEM: + return "pre-cal-nvmem"; case ATH10K_CAL_MODE_EEPROM: return "eeprom"; } diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index a6de08d3bf4a..9a3a8907389b 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -1401,115 +1401,6 @@ enum htt_dbg_stats_status { }; /* - * target -> host statistics upload - * - * The following field definitions describe the format of the HTT target - * to host stats upload confirmation message. - * The message contains a cookie echoed from the HTT host->target stats - * upload request, which identifies which request the confirmation is - * for, and a series of tag-length-value stats information elements. - * The tag-length header for each stats info element also includes a - * status field, to indicate whether the request for the stat type in - * question was fully met, partially met, unable to be met, or invalid - * (if the stat type in question is disabled in the target). - * A special value of all 1's in this status field is used to indicate - * the end of the series of stats info elements. - * - * - * |31 16|15 8|7 5|4 0| - * |------------------------------------------------------------| - * | reserved | msg type | - * |------------------------------------------------------------| - * | cookie LSBs | - * |------------------------------------------------------------| - * | cookie MSBs | - * |------------------------------------------------------------| - * | stats entry length | reserved | S |stat type| - * |------------------------------------------------------------| - * | | - * | type-specific stats info | - * | | - * |------------------------------------------------------------| - * | stats entry length | reserved | S |stat type| - * |------------------------------------------------------------| - * | | - * | type-specific stats info | - * | | - * |------------------------------------------------------------| - * | n/a | reserved | 111 | n/a | - * |------------------------------------------------------------| - * Header fields: - * - MSG_TYPE - * Bits 7:0 - * Purpose: identifies this is a statistics upload confirmation message - * Value: 0x9 - * - COOKIE_LSBS - * Bits 31:0 - * Purpose: Provide a mechanism to match a target->host stats confirmation - * message with its preceding host->target stats request message. - * Value: LSBs of the opaque cookie specified by the host-side requestor - * - COOKIE_MSBS - * Bits 31:0 - * Purpose: Provide a mechanism to match a target->host stats confirmation - * message with its preceding host->target stats request message. - * Value: MSBs of the opaque cookie specified by the host-side requestor - * - * Stats Information Element tag-length header fields: - * - STAT_TYPE - * Bits 4:0 - * Purpose: identifies the type of statistics info held in the - * following information element - * Value: htt_dbg_stats_type - * - STATUS - * Bits 7:5 - * Purpose: indicate whether the requested stats are present - * Value: htt_dbg_stats_status, including a special value (0x7) to mark - * the completion of the stats entry series - * - LENGTH - * Bits 31:16 - * Purpose: indicate the stats information size - * Value: This field specifies the number of bytes of stats information - * that follows the element tag-length header. - * It is expected but not required that this length is a multiple of - * 4 bytes. Even if the length is not an integer multiple of 4, the - * subsequent stats entry header will begin on a 4-byte aligned - * boundary. - */ - -#define HTT_STATS_CONF_ITEM_INFO_STAT_TYPE_MASK 0x1F -#define HTT_STATS_CONF_ITEM_INFO_STAT_TYPE_LSB 0 -#define HTT_STATS_CONF_ITEM_INFO_STATUS_MASK 0xE0 -#define HTT_STATS_CONF_ITEM_INFO_STATUS_LSB 5 - -struct htt_stats_conf_item { - union { - u8 info; - struct { - u8 stat_type:5; /* %HTT_DBG_STATS_ */ - u8 status:3; /* %HTT_DBG_STATS_STATUS_ */ - } __packed; - } __packed; - u8 pad; - __le16 length; - u8 payload[]; /* roundup(length, 4) long */ -} __packed; - -struct htt_stats_conf { - u8 pad[3]; - __le32 cookie_lsb; - __le32 cookie_msb; - - /* each item has variable length! */ - struct htt_stats_conf_item items[]; -} __packed; - -static inline struct htt_stats_conf_item *htt_stats_conf_next_item( - const struct htt_stats_conf_item *item) -{ - return (void *)item + sizeof(*item) + roundup(item->length, 4); -} - -/* * host -> target FRAG DESCRIPTOR/MSDU_EXT DESC bank * * The following field definitions describe the format of the HTT host @@ -1828,7 +1719,6 @@ struct htt_resp { struct htt_rc_update rc_update; struct htt_rx_test rx_test; struct htt_pktlog_msg pktlog_msg; - struct htt_stats_conf stats_conf; struct htt_rx_pn_ind rx_pn_ind; struct htt_rx_offload_ind rx_offload_ind; struct htt_rx_in_ord_ind rx_in_ord_ind; diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index d6b8bdcef416..b793eac2cfac 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -147,6 +147,9 @@ void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt) htt->num_pending_tx--; if (htt->num_pending_tx == htt->max_num_pending_tx - 1) ath10k_mac_tx_unlock(htt->ar, ATH10K_TX_PAUSE_Q_FULL); + + if (htt->num_pending_tx == 0) + wake_up(&htt->empty_tx_wq); } int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt) diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 6b03c7787e36..591ef7416b61 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -618,6 +618,9 @@ struct ath10k_hw_params { */ bool uart_pin_workaround; + /* Workaround for the credit size calculation */ + bool credit_size_workaround; + /* tx stats support over pktlog */ bool tx_stats_over_pktlog; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 1f73fbfee0c0..b11aaee8b8c0 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6380,13 +6380,14 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, scan_timeout = min_t(u32, arg.max_rest_time * (arg.n_channels - 1) + (req->duration + ATH10K_SCAN_CHANNEL_SWITCH_WMI_EVT_OVERHEAD) * - arg.n_channels, arg.max_scan_time + 200); - + arg.n_channels, arg.max_scan_time); } else { - /* Add a 200ms margin to account for event/command processing */ - scan_timeout = arg.max_scan_time + 200; + scan_timeout = arg.max_scan_time; } + /* Add a 200ms margin to account for event/command processing */ + scan_timeout += 200; + ret = ath10k_start_scan(ar, &arg); if (ret) { ath10k_warn(ar, "failed to start hw scan: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 7c9ea0c073d8..6f8b64218894 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -82,8 +82,6 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt, flags = skb_cb->flags; ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); ath10k_htt_tx_dec_pending(htt); - if (htt->num_pending_tx == 0) - wake_up(&htt->empty_tx_wq); spin_unlock_bh(&htt->tx_lock); rcu_read_lock(); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 7c1c2658cb5f..62c453a21e49 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2611,9 +2611,36 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) ath10k_mac_handle_beacon(ar, skb); if (ieee80211_is_beacon(hdr->frame_control) || - ieee80211_is_probe_resp(hdr->frame_control)) + ieee80211_is_probe_resp(hdr->frame_control)) { + struct ieee80211_mgmt *mgmt = (void *)skb->data; + enum cfg80211_bss_frame_type ftype; + u8 *ies; + int ies_ch; + status->boottime_ns = ktime_get_boottime_ns(); + if (!ar->scan_channel) + goto drop; + + ies = mgmt->u.beacon.variable; + + if (ieee80211_is_beacon(mgmt->frame_control)) + ftype = CFG80211_BSS_FTYPE_BEACON; + else + ftype = CFG80211_BSS_FTYPE_PRESP; + + ies_ch = cfg80211_get_ies_channel_number(mgmt->u.beacon.variable, + skb_tail_pointer(skb) - ies, + sband->band, ftype); + + if (ies_ch > 0 && ies_ch != channel) { + ath10k_dbg(ar, ATH10K_DBG_MGMT, + "channel mismatched ds channel %d scan channel %d\n", + ies_ch, channel); + goto drop; + } + } + ath10k_dbg(ar, ATH10K_DBG_MGMT, "event mgmt rx skb %pK len %d ftype %02x stype %02x\n", skb, skb->len, @@ -2627,6 +2654,10 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) ieee80211_rx_ni(ar->hw, skb); return 0; + +drop: + dev_kfree_skb(skb); + return 0; } static int freq_to_idx(struct ath10k *ar, int freq) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 01bfd09a9d88..4abd12e78028 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3478,7 +3478,9 @@ struct wmi_phyerr_event { __le32 num_phyerrs; __le32 tsf_l32; __le32 tsf_u32; - struct wmi_phyerr phyerrs[]; + + /* array of struct wmi_phyerr */ + u8 phyerrs[]; } __packed; struct wmi_10_4_phyerr_event { diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 8c9c781afc3e..096c502cce38 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -206,13 +206,13 @@ static void ath11k_ahb_clearbit32(struct ath11k_base *ab, u8 bit, u32 offset) static void ath11k_ahb_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) { - const struct ce_pipe_config *ce_config; + const struct ce_attr *ce_attr; - ce_config = &ab->hw_params.target_ce_config[ce_id]; - if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_OUT) + ce_attr = &ab->hw_params.host_ce_config[ce_id]; + if (ce_attr->src_nentries) ath11k_ahb_setbit32(ab, ce_id, CE_HOST_IE_ADDRESS); - if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_IN) { + if (ce_attr->dest_nentries) { ath11k_ahb_setbit32(ab, ce_id, CE_HOST_IE_2_ADDRESS); ath11k_ahb_setbit32(ab, ce_id + CE_HOST_IE_3_SHIFT, CE_HOST_IE_3_ADDRESS); @@ -221,13 +221,13 @@ static void ath11k_ahb_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) static void ath11k_ahb_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) { - const struct ce_pipe_config *ce_config; + const struct ce_attr *ce_attr; - ce_config = &ab->hw_params.target_ce_config[ce_id]; - if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_OUT) + ce_attr = &ab->hw_params.host_ce_config[ce_id]; + if (ce_attr->src_nentries) ath11k_ahb_clearbit32(ab, ce_id, CE_HOST_IE_ADDRESS); - if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_IN) { + if (ce_attr->dest_nentries) { ath11k_ahb_clearbit32(ab, ce_id, CE_HOST_IE_2_ADDRESS); ath11k_ahb_clearbit32(ab, ce_id + CE_HOST_IE_3_SHIFT, CE_HOST_IE_3_ADDRESS); diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index de8b632b058c..aaa7b05ff49d 100644 --- a/drivers/net/wireless/ath/ath11k/ce.c +++ b/drivers/net/wireless/ath/ath11k/ce.c @@ -14,6 +14,7 @@ const struct ce_attr ath11k_host_ce_config_ipq8074[] = { .src_nentries = 16, .src_sz_max = 2048, .dest_nentries = 0, + .send_cb = ath11k_htc_tx_completion_handler, }, /* CE1: target->host HTT + HTC control */ @@ -40,6 +41,7 @@ const struct ce_attr ath11k_host_ce_config_ipq8074[] = { .src_nentries = 32, .src_sz_max = 2048, .dest_nentries = 0, + .send_cb = ath11k_htc_tx_completion_handler, }, /* CE4: host->target HTT */ @@ -73,11 +75,12 @@ const struct ce_attr ath11k_host_ce_config_ipq8074[] = { .src_nentries = 32, .src_sz_max = 2048, .dest_nentries = 0, + .send_cb = ath11k_htc_tx_completion_handler, }, /* CE8: target autonomous hif_memcpy */ { - .flags = CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, .src_nentries = 0, .src_sz_max = 0, .dest_nentries = 0, @@ -89,6 +92,7 @@ const struct ce_attr ath11k_host_ce_config_ipq8074[] = { .src_nentries = 32, .src_sz_max = 2048, .dest_nentries = 0, + .send_cb = ath11k_htc_tx_completion_handler, }, /* CE10: target->host HTT */ @@ -142,6 +146,7 @@ const struct ce_attr ath11k_host_ce_config_qca6390[] = { .src_nentries = 32, .src_sz_max = 2048, .dest_nentries = 0, + .send_cb = ath11k_htc_tx_completion_handler, }, /* CE4: host->target HTT */ @@ -175,6 +180,7 @@ const struct ce_attr ath11k_host_ce_config_qca6390[] = { .src_nentries = 32, .src_sz_max = 2048, .dest_nentries = 0, + .send_cb = ath11k_htc_tx_completion_handler, }, /* CE8: target autonomous hif_memcpy */ @@ -220,6 +226,7 @@ const struct ce_attr ath11k_host_ce_config_qcn9074[] = { .src_nentries = 32, .src_sz_max = 2048, .dest_nentries = 0, + .send_cb = ath11k_htc_tx_completion_handler, }, /* CE4: host->target HTT */ @@ -489,18 +496,32 @@ err_unlock: return skb; } -static void ath11k_ce_send_done_cb(struct ath11k_ce_pipe *pipe) +static void ath11k_ce_tx_process_cb(struct ath11k_ce_pipe *pipe) { struct ath11k_base *ab = pipe->ab; struct sk_buff *skb; + struct sk_buff_head list; + __skb_queue_head_init(&list); while (!IS_ERR(skb = ath11k_ce_completed_send_next(pipe))) { if (!skb) continue; dma_unmap_single(ab->dev, ATH11K_SKB_CB(skb)->paddr, skb->len, DMA_TO_DEVICE); - dev_kfree_skb_any(skb); + + if ((!pipe->send_cb) || ab->hw_params.credit_flow) { + dev_kfree_skb_any(skb); + continue; + } + + __skb_queue_tail(&list, skb); + } + + while ((skb = __skb_dequeue(&list))) { + ath11k_dbg(ab, ATH11K_DBG_AHB, "tx ce pipe %d len %d\n", + pipe->pipe_num, skb->len); + pipe->send_cb(ab, skb); } } @@ -636,7 +657,7 @@ static int ath11k_ce_alloc_pipe(struct ath11k_base *ab, int ce_id) pipe->attr_flags = attr->flags; if (attr->src_nentries) { - pipe->send_cb = ath11k_ce_send_done_cb; + pipe->send_cb = attr->send_cb; nentries = roundup_pow_of_two(attr->src_nentries); desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_SRC); ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); @@ -667,9 +688,10 @@ static int ath11k_ce_alloc_pipe(struct ath11k_base *ab, int ce_id) void ath11k_ce_per_engine_service(struct ath11k_base *ab, u16 ce_id) { struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[ce_id]; + const struct ce_attr *attr = &ab->hw_params.host_ce_config[ce_id]; - if (pipe->send_cb) - pipe->send_cb(pipe); + if (attr->src_nentries) + ath11k_ce_tx_process_cb(pipe); if (pipe->recv_cb) ath11k_ce_recv_process_cb(pipe); @@ -678,9 +700,10 @@ void ath11k_ce_per_engine_service(struct ath11k_base *ab, u16 ce_id) void ath11k_ce_poll_send_completed(struct ath11k_base *ab, u8 pipe_id) { struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[pipe_id]; + const struct ce_attr *attr = &ab->hw_params.host_ce_config[pipe_id]; - if ((pipe->attr_flags & CE_ATTR_DIS_INTR) && pipe->send_cb) - pipe->send_cb(pipe); + if ((pipe->attr_flags & CE_ATTR_DIS_INTR) && attr->src_nentries) + ath11k_ce_tx_process_cb(pipe); } EXPORT_SYMBOL(ath11k_ce_per_engine_service); @@ -953,6 +976,7 @@ int ath11k_ce_init_pipes(struct ath11k_base *ab) void ath11k_ce_free_pipes(struct ath11k_base *ab) { struct ath11k_ce_pipe *pipe; + struct ath11k_ce_ring *ce_ring; int desc_sz; int i; @@ -964,22 +988,24 @@ void ath11k_ce_free_pipes(struct ath11k_base *ab) if (pipe->src_ring) { desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_SRC); + ce_ring = pipe->src_ring; dma_free_coherent(ab->dev, pipe->src_ring->nentries * desc_sz + CE_DESC_RING_ALIGN, - pipe->src_ring->base_addr_owner_space, - pipe->src_ring->base_addr_ce_space); + ce_ring->base_addr_owner_space_unaligned, + ce_ring->base_addr_ce_space_unaligned); kfree(pipe->src_ring); pipe->src_ring = NULL; } if (pipe->dest_ring) { desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST); + ce_ring = pipe->dest_ring; dma_free_coherent(ab->dev, pipe->dest_ring->nentries * desc_sz + CE_DESC_RING_ALIGN, - pipe->dest_ring->base_addr_owner_space, - pipe->dest_ring->base_addr_ce_space); + ce_ring->base_addr_owner_space_unaligned, + ce_ring->base_addr_ce_space_unaligned); kfree(pipe->dest_ring); pipe->dest_ring = NULL; } @@ -987,11 +1013,12 @@ void ath11k_ce_free_pipes(struct ath11k_base *ab) if (pipe->status_ring) { desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST_STATUS); + ce_ring = pipe->status_ring; dma_free_coherent(ab->dev, pipe->status_ring->nentries * desc_sz + CE_DESC_RING_ALIGN, - pipe->status_ring->base_addr_owner_space, - pipe->status_ring->base_addr_ce_space); + ce_ring->base_addr_owner_space_unaligned, + ce_ring->base_addr_ce_space_unaligned); kfree(pipe->status_ring); pipe->status_ring = NULL; } diff --git a/drivers/net/wireless/ath/ath11k/ce.h b/drivers/net/wireless/ath/ath11k/ce.h index 713f766cac22..8255b6cfab0c 100644 --- a/drivers/net/wireless/ath/ath11k/ce.h +++ b/drivers/net/wireless/ath/ath11k/ce.h @@ -101,6 +101,7 @@ struct ce_attr { unsigned int dest_nentries; void (*recv_cb)(struct ath11k_base *, struct sk_buff *); + void (*send_cb)(struct ath11k_base *, struct sk_buff *); }; #define CE_DESC_RING_ALIGN 8 @@ -154,7 +155,7 @@ struct ath11k_ce_pipe { unsigned int buf_sz; unsigned int rx_buf_needed; - void (*send_cb)(struct ath11k_ce_pipe *); + void (*send_cb)(struct ath11k_base *, struct sk_buff *); void (*recv_cb)(struct ath11k_base *, struct sk_buff *); struct tasklet_struct intr_tq; diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index b5a2af3ffc3e..606e867c36ec 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -74,14 +74,23 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MESH_POINT), .supports_monitor = true, + .full_monitor_mode = false, .supports_shadow_regs = false, .idle_ps = false, + .supports_sta_ps = false, .cold_boot_calib = true, + .fw_mem_mode = 0, + .num_vdevs = 16 + 1, + .num_peers = 512, .supports_suspend = false, .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), .fix_l1ss = true, + .credit_flow = false, .max_tx_ring = DP_TCL_NUM_RING_MAX, .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = true, + .wakeup_mhi = false, }, { .hw_rev = ATH11K_HW_IPQ6018_HW10, @@ -123,14 +132,23 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MESH_POINT), .supports_monitor = true, + .full_monitor_mode = false, .supports_shadow_regs = false, .idle_ps = false, + .supports_sta_ps = false, .cold_boot_calib = true, + .fw_mem_mode = 0, + .num_vdevs = 16 + 1, + .num_peers = 512, .supports_suspend = false, .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), .fix_l1ss = true, + .credit_flow = false, .max_tx_ring = DP_TCL_NUM_RING_MAX, .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = true, + .wakeup_mhi = false, }, { .name = "qca6390 hw2.0", @@ -171,14 +189,23 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP), .supports_monitor = false, + .full_monitor_mode = false, .supports_shadow_regs = true, .idle_ps = true, + .supports_sta_ps = true, .cold_boot_calib = false, + .fw_mem_mode = 0, + .num_vdevs = 16 + 1, + .num_peers = 512, .supports_suspend = true, .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), .fix_l1ss = true, + .credit_flow = true, .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, .hal_params = &ath11k_hw_hal_params_qca6390, + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = false, + .wakeup_mhi = true, }, { .name = "qcn9074 hw1.0", @@ -219,14 +246,23 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MESH_POINT), .supports_monitor = true, + .full_monitor_mode = true, .supports_shadow_regs = false, .idle_ps = false, + .supports_sta_ps = false, .cold_boot_calib = false, + .fw_mem_mode = 2, + .num_vdevs = 8, + .num_peers = 128, .supports_suspend = false, .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), .fix_l1ss = true, + .credit_flow = false, .max_tx_ring = DP_TCL_NUM_RING_MAX, .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = true, + .alloc_cacheable_memory = true, + .wakeup_mhi = false, }, { .name = "wcn6855 hw2.0", @@ -267,14 +303,79 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP), .supports_monitor = false, + .full_monitor_mode = false, .supports_shadow_regs = true, .idle_ps = true, + .supports_sta_ps = true, .cold_boot_calib = false, + .fw_mem_mode = 0, + .num_vdevs = 16 + 1, + .num_peers = 512, .supports_suspend = true, .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), .fix_l1ss = false, + .credit_flow = true, .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, .hal_params = &ath11k_hw_hal_params_qca6390, + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = false, + .wakeup_mhi = true, + }, + { + .name = "wcn6855 hw2.1", + .hw_rev = ATH11K_HW_WCN6855_HW21, + .fw = { + .dir = "WCN6855/hw2.1", + .board_size = 256 * 1024, + .cal_offset = 128 * 1024, + }, + .max_radios = 3, + .bdf_addr = 0x4B0C0000, + .hw_ops = &wcn6855_ops, + .ring_mask = &ath11k_hw_ring_mask_qca6390, + .internal_sleep_clock = true, + .regs = &wcn6855_regs, + .qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390, + .host_ce_config = ath11k_host_ce_config_qca6390, + .ce_count = 9, + .target_ce_config = ath11k_target_ce_config_wlan_qca6390, + .target_ce_count = 9, + .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390, + .svc_to_ce_map_len = 14, + .single_pdev_only = true, + .rxdma1_enable = false, + .num_rxmda_per_pdev = 2, + .rx_mac_buf_ring = true, + .vdev_start_delay = true, + .htt_peer_map_v2 = false, + + .spectral = { + .fft_sz = 0, + .fft_pad_sz = 0, + .summary_pad_sz = 0, + .fft_hdr_len = 0, + .max_fft_bins = 0, + }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP), + .supports_monitor = false, + .supports_shadow_regs = true, + .idle_ps = true, + .supports_sta_ps = true, + .cold_boot_calib = false, + .fw_mem_mode = 0, + .num_vdevs = 16 + 1, + .num_peers = 512, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), + .fix_l1ss = false, + .credit_flow = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, + .hal_params = &ath11k_hw_hal_params_qca6390, + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = false, + .wakeup_mhi = true, }, }; @@ -392,11 +493,26 @@ static int ath11k_core_create_board_name(struct ath11k_base *ab, char *name, scnprintf(variant, sizeof(variant), ",variant=%s", ab->qmi.target.bdf_ext); - scnprintf(name, name_len, - "bus=%s,qmi-chip-id=%d,qmi-board-id=%d%s", - ath11k_bus_str(ab->hif.bus), - ab->qmi.target.chip_id, - ab->qmi.target.board_id, variant); + switch (ab->id.bdf_search) { + case ATH11K_BDF_SEARCH_BUS_AND_BOARD: + scnprintf(name, name_len, + "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x,qmi-chip-id=%d,qmi-board-id=%d%s", + ath11k_bus_str(ab->hif.bus), + ab->id.vendor, ab->id.device, + ab->id.subsystem_vendor, + ab->id.subsystem_device, + ab->qmi.target.chip_id, + ab->qmi.target.board_id, + variant); + break; + default: + scnprintf(name, name_len, + "bus=%s,qmi-chip-id=%d,qmi-board-id=%d%s", + ath11k_bus_str(ab->hif.bus), + ab->qmi.target.chip_id, + ab->qmi.target.board_id, variant); + break; + } ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot using board name '%s'\n", name); @@ -633,7 +749,7 @@ static int ath11k_core_fetch_board_data_api_1(struct ath11k_base *ab, return 0; } -#define BOARD_NAME_SIZE 100 +#define BOARD_NAME_SIZE 200 int ath11k_core_fetch_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd) { char boardname[BOARD_NAME_SIZE]; @@ -969,7 +1085,7 @@ static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab) ath11k_dp_free(ab); ath11k_hal_srng_deinit(ab); - ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1; + ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS(ab))) - 1; ret = ath11k_hal_srng_init(ab); if (ret) @@ -1003,6 +1119,7 @@ void ath11k_core_halt(struct ath11k *ar) ath11k_mac_peer_cleanup_all(ar); cancel_delayed_work_sync(&ar->scan.timeout); cancel_work_sync(&ar->regd_update_work); + cancel_work_sync(&ab->update_11d_work); rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL); synchronize_rcu(); @@ -1010,6 +1127,34 @@ void ath11k_core_halt(struct ath11k *ar) idr_init(&ar->txmgmt_idr); } +static void ath11k_update_11d(struct work_struct *work) +{ + struct ath11k_base *ab = container_of(work, struct ath11k_base, update_11d_work); + struct ath11k *ar; + struct ath11k_pdev *pdev; + struct wmi_set_current_country_params set_current_param = {}; + int ret, i; + + spin_lock_bh(&ab->base_lock); + memcpy(&set_current_param.alpha2, &ab->new_alpha2, 2); + spin_unlock_bh(&ab->base_lock); + + ath11k_dbg(ab, ATH11K_DBG_WMI, "update 11d new cc %c%c\n", + set_current_param.alpha2[0], + set_current_param.alpha2[1]); + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + ar = pdev->ar; + + ret = ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); + if (ret) + ath11k_warn(ar->ab, + "pdev id %d failed set current country code: %d\n", + i, ret); + } +} + static void ath11k_core_restart(struct work_struct *work) { struct ath11k_base *ab = container_of(work, struct ath11k_base, restart_work); @@ -1043,6 +1188,7 @@ static void ath11k_core_restart(struct work_struct *work) idr_for_each(&ar->txmgmt_idr, ath11k_mac_tx_mgmt_pending_free, ar); idr_destroy(&ar->txmgmt_idr); + wake_up(&ar->txmgmt_empty_waitq); } wake_up(&ab->wmi_ab.tx_credits_wq); @@ -1179,12 +1325,14 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size, mutex_init(&ab->core_lock); spin_lock_init(&ab->base_lock); + mutex_init(&ab->vdev_id_11d_lock); INIT_LIST_HEAD(&ab->peers); init_waitqueue_head(&ab->peer_mapping_wq); init_waitqueue_head(&ab->wmi_ab.tx_credits_wq); init_waitqueue_head(&ab->qmi.cold_boot_waitq); INIT_WORK(&ab->restart_work, ath11k_core_restart); + INIT_WORK(&ab->update_11d_work, ath11k_update_11d); timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0); init_completion(&ab->htc_suspend); init_completion(&ab->wow.wakeup_completed); diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 31d234a51c79..bab3878a41a7 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -47,6 +47,11 @@ enum ath11k_supported_bw { ATH11K_BW_160 = 3, }; +enum ath11k_bdf_search { + ATH11K_BDF_SEARCH_DEFAULT, + ATH11K_BDF_SEARCH_BUS_AND_BOARD, +}; + enum wme_ac { WME_AC_BE, WME_AC_BK, @@ -112,6 +117,7 @@ enum ath11k_hw_rev { ATH11K_HW_IPQ6018_HW10, ATH11K_HW_QCN9074_HW10, ATH11K_HW_WCN6855_HW20, + ATH11K_HW_WCN6855_HW21, }; enum ath11k_firmware_mode { @@ -194,6 +200,9 @@ enum ath11k_dev_flags { ATH11K_FLAG_REGISTERED, ATH11K_FLAG_QMI_FAIL, ATH11K_FLAG_HTC_SUSPEND_COMPLETE, + ATH11K_FLAG_CE_IRQ_ENABLED, + ATH11K_FLAG_EXT_IRQ_ENABLED, + ATH11K_FLAG_FIXED_MEM_RGN, }; enum ath11k_monitor_flags { @@ -240,6 +249,7 @@ struct ath11k_vif { bool is_started; bool is_up; bool spectral_enabled; + bool ps; u32 aid; u8 bssid[ETH_ALEN]; struct cfg80211_bitrate_mask bitrate_mask; @@ -249,6 +259,8 @@ struct ath11k_vif { int txpower; bool rsnie_present; bool wpaie_present; + bool bcca_zero_sent; + bool do_not_send_tmpl; struct ieee80211_chanctx_conf chanctx; }; @@ -539,6 +551,7 @@ struct ath11k { /* protects txmgmt_idr data */ spinlock_t txmgmt_idr_lock; atomic_t num_pending_mgmt_tx; + wait_queue_head_t txmgmt_empty_waitq; /* cycle count is reported twice for each visited channel during scan. * access protected by data_lock @@ -577,6 +590,11 @@ struct ath11k { #endif bool dfs_block_radar_events; struct ath11k_thermal thermal; + u32 vdev_id_11d_scan; + struct completion finish_11d_scan; + struct completion finish_11d_ch_list; + bool pending_11d; + bool regdom_set_by_user; }; struct ath11k_band_cap { @@ -703,6 +721,11 @@ struct ath11k_base { /* Protects data like peers */ spinlock_t base_lock; struct ath11k_pdev pdevs[MAX_RADIOS]; + struct { + enum WMI_HOST_WLAN_BAND supported_bands; + u32 pdev_id; + } target_pdev_ids[MAX_RADIOS]; + u8 target_pdev_count; struct ath11k_pdev __rcu *pdevs_active[MAX_RADIOS]; struct ath11k_hal_reg_capabilities_ext hal_reg_cap[MAX_RADIOS]; unsigned long long free_vdev_map; @@ -746,6 +769,8 @@ struct ath11k_base { struct completion driver_recovery; struct workqueue_struct *workqueue; struct work_struct restart_work; + struct work_struct update_11d_work; + u8 new_alpha2[3]; struct { /* protected by data_lock */ u32 fw_crash_counter; @@ -755,10 +780,20 @@ struct ath11k_base { struct ath11k_dbring_cap *db_caps; u32 num_db_cap; + /* To synchronize 11d scan vdev id */ + struct mutex vdev_id_11d_lock; struct timer_list mon_reap_timer; struct completion htc_suspend; + struct { + enum ath11k_bdf_search bdf_search; + u32 vendor; + u32 device; + u32 subsystem_vendor; + u32 subsystem_device; + } id; + /* must be last */ u8 drv_priv[0] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath11k/dbring.c b/drivers/net/wireless/ath/ath11k/dbring.c index fd98ba5b1130..eda67ebfc4c2 100644 --- a/drivers/net/wireless/ath/ath11k/dbring.c +++ b/drivers/net/wireless/ath/ath11k/dbring.c @@ -6,6 +6,35 @@ #include "core.h" #include "debug.h" +#define ATH11K_DB_MAGIC_VALUE 0xdeadbeaf + +int ath11k_dbring_validate_buffer(struct ath11k *ar, void *buffer, u32 size) +{ + u32 *temp; + int idx; + + size = size >> 2; + + for (idx = 0, temp = buffer; idx < size; idx++, temp++) { + if (*temp == ATH11K_DB_MAGIC_VALUE) + return -EINVAL; + } + + return 0; +} + +static void ath11k_dbring_fill_magic_value(struct ath11k *ar, + void *buffer, u32 size) +{ + u32 *temp; + int idx; + + size = size >> 2; + + for (idx = 0, temp = buffer; idx < size; idx++, temp++) + *temp++ = ATH11K_DB_MAGIC_VALUE; +} + static int ath11k_dbring_bufs_replenish(struct ath11k *ar, struct ath11k_dbring *ring, struct ath11k_dbring_element *buff) @@ -26,6 +55,7 @@ static int ath11k_dbring_bufs_replenish(struct ath11k *ar, ptr_unaligned = buff->payload; ptr_aligned = PTR_ALIGN(ptr_unaligned, ring->buf_align); + ath11k_dbring_fill_magic_value(ar, ptr_aligned, ring->buf_sz); paddr = dma_map_single(ab->dev, ptr_aligned, ring->buf_sz, DMA_FROM_DEVICE); @@ -87,17 +117,23 @@ static int ath11k_dbring_fill_bufs(struct ath11k *ar, req_entries = min(num_free, ring->bufs_max); num_remain = req_entries; align = ring->buf_align; - size = sizeof(*buff) + ring->buf_sz + align - 1; + size = ring->buf_sz + align - 1; while (num_remain > 0) { - buff = kzalloc(size, GFP_ATOMIC); + buff = kzalloc(sizeof(*buff), GFP_ATOMIC); if (!buff) break; + buff->payload = kzalloc(size, GFP_ATOMIC); + if (!buff->payload) { + kfree(buff); + break; + } ret = ath11k_dbring_bufs_replenish(ar, ring, buff); if (ret) { ath11k_warn(ar->ab, "failed to replenish db ring num_remain %d req_ent %d\n", num_remain, req_entries); + kfree(buff->payload); kfree(buff); break; } @@ -282,7 +318,7 @@ int ath11k_dbring_buffer_release_event(struct ath11k_base *ab, srng = &ab->hal.srng_list[ring->refill_srng.ring_id]; num_entry = ev->fixed.num_buf_release_entry; - size = sizeof(*buff) + ring->buf_sz + ring->buf_align - 1; + size = ring->buf_sz + ring->buf_align - 1; num_buff_reaped = 0; spin_lock_bh(&srng->lock); @@ -319,7 +355,8 @@ int ath11k_dbring_buffer_release_event(struct ath11k_base *ab, ring->handler(ar, &handler_data); } - memset(buff, 0, size); + buff->paddr = 0; + memset(buff->payload, 0, size); ath11k_dbring_bufs_replenish(ar, ring, buff); } @@ -346,6 +383,7 @@ void ath11k_dbring_buf_cleanup(struct ath11k *ar, struct ath11k_dbring *ring) idr_remove(&ring->bufs_idr, buf_id); dma_unmap_single(ar->ab->dev, buff->paddr, ring->buf_sz, DMA_FROM_DEVICE); + kfree(buff->payload); kfree(buff); } diff --git a/drivers/net/wireless/ath/ath11k/dbring.h b/drivers/net/wireless/ath/ath11k/dbring.h index f7fce9ef9c36..ef906c687b8c 100644 --- a/drivers/net/wireless/ath/ath11k/dbring.h +++ b/drivers/net/wireless/ath/ath11k/dbring.h @@ -13,7 +13,7 @@ struct ath11k_dbring_element { dma_addr_t paddr; - u8 payload[0]; + u8 *payload; }; struct ath11k_dbring_data { @@ -76,4 +76,6 @@ int ath11k_dbring_get_cap(struct ath11k_base *ab, struct ath11k_dbring_cap *db_cap); void ath11k_dbring_srng_cleanup(struct ath11k *ar, struct ath11k_dbring *ring); void ath11k_dbring_buf_cleanup(struct ath11k *ar, struct ath11k_dbring *ring); +int ath11k_dbring_validate_buffer(struct ath11k *ar, void *data, u32 size); + #endif /* ATH11K_DBRING_H */ diff --git a/drivers/net/wireless/ath/ath11k/debug.c b/drivers/net/wireless/ath/ath11k/debug.c index c86de95fbdc5..958d87429062 100644 --- a/drivers/net/wireless/ath/ath11k/debug.c +++ b/drivers/net/wireless/ath/ath11k/debug.c @@ -17,7 +17,7 @@ void ath11k_info(struct ath11k_base *ab, const char *fmt, ...) va_start(args, fmt); vaf.va = &args; dev_info(ab->dev, "%pV", &vaf); - /* TODO: Trace the log */ + trace_ath11k_log_info(ab, &vaf); va_end(args); } EXPORT_SYMBOL(ath11k_info); @@ -32,7 +32,7 @@ void ath11k_err(struct ath11k_base *ab, const char *fmt, ...) va_start(args, fmt); vaf.va = &args; dev_err(ab->dev, "%pV", &vaf); - /* TODO: Trace the log */ + trace_ath11k_log_err(ab, &vaf); va_end(args); } EXPORT_SYMBOL(ath11k_err); @@ -47,7 +47,7 @@ void ath11k_warn(struct ath11k_base *ab, const char *fmt, ...) va_start(args, fmt); vaf.va = &args; dev_warn_ratelimited(ab->dev, "%pV", &vaf); - /* TODO: Trace the log */ + trace_ath11k_log_warn(ab, &vaf); va_end(args); } EXPORT_SYMBOL(ath11k_warn); @@ -68,7 +68,7 @@ void __ath11k_dbg(struct ath11k_base *ab, enum ath11k_debug_mask mask, if (ath11k_debug_mask & mask) dev_printk(KERN_DEBUG, ab->dev, "%pV", &vaf); - /* TODO: trace log */ + trace_ath11k_log_dbg(ab, mask, &vaf); va_end(args); } @@ -100,6 +100,10 @@ void ath11k_dbg_dump(struct ath11k_base *ab, dev_printk(KERN_DEBUG, ab->dev, "%s\n", linebuf); } } + + /* tracing code doesn't like null strings */ + trace_ath11k_log_dbg_dump(ab, msg ? msg : "", prefix ? prefix : "", + buf, len); } EXPORT_SYMBOL(ath11k_dbg_dump); diff --git a/drivers/net/wireless/ath/ath11k/debug.h b/drivers/net/wireless/ath/ath11k/debug.h index 659a275e2eb3..fbbd5fe02aa8 100644 --- a/drivers/net/wireless/ath/ath11k/debug.h +++ b/drivers/net/wireless/ath/ath11k/debug.h @@ -60,7 +60,8 @@ static inline void ath11k_dbg_dump(struct ath11k_base *ab, #define ath11k_dbg(ar, dbg_mask, fmt, ...) \ do { \ - if (ath11k_debug_mask & dbg_mask) \ + if ((ath11k_debug_mask & dbg_mask) || \ + trace_ath11k_log_dbg_enabled()) \ __ath11k_dbg(ar, dbg_mask, fmt, ##__VA_ARGS__); \ } while (0) diff --git a/drivers/net/wireless/ath/ath11k/debugfs.c b/drivers/net/wireless/ath/ath11k/debugfs.c index 80afd35337a1..dba055d085be 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs.c +++ b/drivers/net/wireless/ath/ath11k/debugfs.c @@ -195,7 +195,7 @@ static int ath11k_debugfs_fw_stats_request(struct ath11k *ar, * received 'update stats' event, we keep a 3 seconds timeout in case, * fw_stats_done is not marked yet */ - timeout = jiffies + msecs_to_jiffies(3 * HZ); + timeout = jiffies + msecs_to_jiffies(3 * 1000); ath11k_debugfs_fw_stats_reset(ar); diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index 8baaeeb8cf82..8b790ce72e5d 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -101,8 +101,11 @@ void ath11k_dp_srng_cleanup(struct ath11k_base *ab, struct dp_srng *ring) if (!ring->vaddr_unaligned) return; - dma_free_coherent(ab->dev, ring->size, ring->vaddr_unaligned, - ring->paddr_unaligned); + if (ring->cached) + kfree(ring->vaddr_unaligned); + else + dma_free_coherent(ab->dev, ring->size, ring->vaddr_unaligned, + ring->paddr_unaligned); ring->vaddr_unaligned = NULL; } @@ -222,6 +225,7 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, int entry_sz = ath11k_hal_srng_get_entrysize(ab, type); int max_entries = ath11k_hal_srng_get_max_entries(ab, type); int ret; + bool cached = false; if (max_entries < 0 || entry_sz < 0) return -EINVAL; @@ -230,9 +234,29 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, num_entries = max_entries; ring->size = (num_entries * entry_sz) + HAL_RING_BASE_ALIGN - 1; - ring->vaddr_unaligned = dma_alloc_coherent(ab->dev, ring->size, - &ring->paddr_unaligned, - GFP_KERNEL); + + if (ab->hw_params.alloc_cacheable_memory) { + /* Allocate the reo dst and tx completion rings from cacheable memory */ + switch (type) { + case HAL_REO_DST: + case HAL_WBM2SW_RELEASE: + cached = true; + break; + default: + cached = false; + } + + if (cached) { + ring->vaddr_unaligned = kzalloc(ring->size, GFP_KERNEL); + ring->paddr_unaligned = virt_to_phys(ring->vaddr_unaligned); + } + } + + if (!cached) + ring->vaddr_unaligned = dma_alloc_coherent(ab->dev, ring->size, + &ring->paddr_unaligned, + GFP_KERNEL); + if (!ring->vaddr_unaligned) return -ENOMEM; @@ -292,6 +316,11 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, return -EINVAL; } + if (cached) { + params.flags |= HAL_SRNG_FLAGS_CACHED; + ring->cached = 1; + } + ret = ath11k_hal_srng_setup(ab, type, ring_num, mac_id, ¶ms); if (ret < 0) { ath11k_warn(ab, "failed to setup srng: %d ring_id %d\n", @@ -742,13 +771,12 @@ int ath11k_dp_service_srng(struct ath11k_base *ab, const struct ath11k_hw_hal_params *hal_params; int grp_id = irq_grp->grp_id; int work_done = 0; - int i = 0, j; + int i, j; int tot_work_done = 0; - while (ab->hw_params.ring_mask->tx[grp_id] >> i) { - if (ab->hw_params.ring_mask->tx[grp_id] & BIT(i)) - ath11k_dp_tx_completion_handler(ab, i); - i++; + if (ab->hw_params.ring_mask->tx[grp_id]) { + i = __fls(ab->hw_params.ring_mask->tx[grp_id]); + ath11k_dp_tx_completion_handler(ab, i); } if (ab->hw_params.ring_mask->rx_err[grp_id]) { @@ -1023,6 +1051,7 @@ int ath11k_dp_alloc(struct ath11k_base *ab) INIT_LIST_HEAD(&dp->reo_cmd_list); INIT_LIST_HEAD(&dp->reo_cmd_cache_flush_list); + INIT_LIST_HEAD(&dp->dp_full_mon_mpdu_list); spin_lock_init(&dp->reo_cmd_lock); dp->reo_cmd_cache_flush_count = 0; diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h index 4794ca04f213..409d6cc5a1d5 100644 --- a/drivers/net/wireless/ath/ath11k/dp.h +++ b/drivers/net/wireless/ath/ath11k/dp.h @@ -64,6 +64,7 @@ struct dp_srng { dma_addr_t paddr; int size; u32 ring_id; + u8 cached; }; struct dp_rxdma_ring { @@ -88,6 +89,19 @@ struct dp_tx_ring { int tx_status_tail; }; +enum dp_mon_status_buf_state { + /* PPDU id matches in dst ring and status ring */ + DP_MON_STATUS_MATCH, + /* status ring dma is not done */ + DP_MON_STATUS_NO_DMA, + /* status ring is lagging, reap status ring */ + DP_MON_STATUS_LAG, + /* status ring is leading, reap dst ring and drop */ + DP_MON_STATUS_LEAD, + /* replinish monitor status ring */ + DP_MON_STATUS_REPLINISH, +}; + struct ath11k_pdev_mon_stats { u32 status_ppdu_state; u32 status_ppdu_start; @@ -103,6 +117,12 @@ struct ath11k_pdev_mon_stats { u32 dup_mon_buf_cnt; }; +struct dp_full_mon_mpdu { + struct list_head list; + struct sk_buff *head; + struct sk_buff *tail; +}; + struct dp_link_desc_bank { void *vaddr_unaligned; void *vaddr; @@ -134,7 +154,11 @@ struct ath11k_mon_data { u32 mon_last_buf_cookie; u64 mon_last_linkdesc_paddr; u16 chan_noise_floor; - + bool hold_mon_dst_ring; + enum dp_mon_status_buf_state buf_state; + dma_addr_t mon_status_paddr; + struct dp_full_mon_mpdu *mon_mpdu; + struct hal_sw_mon_ring_entries sw_mon_entries; struct ath11k_pdev_mon_stats rx_mon_stats; /* lock for monitor data */ spinlock_t mon_lock; @@ -244,6 +268,7 @@ struct ath11k_dp { struct hal_wbm_idle_scatter_list scatter_list[DP_IDLE_SCATTER_BUFS_MAX]; struct list_head reo_cmd_list; struct list_head reo_cmd_cache_flush_list; + struct list_head dp_full_mon_mpdu_list; u32 reo_cmd_cache_flush_count; /** * protects access to below fields, @@ -291,6 +316,7 @@ enum htt_h2t_msg_type { HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG = 0xc, HTT_H2T_MSG_TYPE_EXT_STATS_CFG = 0x10, HTT_H2T_MSG_TYPE_PPDU_STATS_CFG = 0x11, + HTT_H2T_MSG_TYPE_RX_FULL_MONITOR_MODE = 0x17, }; #define HTT_VER_REQ_INFO_MSG_ID GENMASK(7, 0) @@ -517,7 +543,8 @@ struct htt_ppdu_stats_cfg_cmd { } __packed; #define HTT_PPDU_STATS_CFG_MSG_TYPE GENMASK(7, 0) -#define HTT_PPDU_STATS_CFG_PDEV_ID GENMASK(15, 8) +#define HTT_PPDU_STATS_CFG_SOC_STATS BIT(8) +#define HTT_PPDU_STATS_CFG_PDEV_ID GENMASK(15, 9) #define HTT_PPDU_STATS_CFG_TLV_TYPE_BITMASK GENMASK(31, 16) enum htt_ppdu_stats_tag_type { @@ -955,6 +982,33 @@ struct htt_rx_ring_tlv_filter { u32 pkt_filter_flags3; /* DATA */ }; +#define HTT_RX_FULL_MON_MODE_CFG_CMD_INFO0_MSG_TYPE GENMASK(7, 0) +#define HTT_RX_FULL_MON_MODE_CFG_CMD_INFO0_PDEV_ID GENMASK(15, 8) + +#define HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_ENABLE BIT(0) +#define HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_ZERO_MPDUS_END BIT(1) +#define HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_NON_ZERO_MPDUS_END BIT(2) +#define HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_RELEASE_RING GENMASK(10, 3) + +/** + * Enumeration for full monitor mode destination ring select + * 0 - REO destination ring select + * 1 - FW destination ring select + * 2 - SW destination ring select + * 3 - Release destination ring select + */ +enum htt_rx_full_mon_release_ring { + HTT_RX_MON_RING_REO, + HTT_RX_MON_RING_FW, + HTT_RX_MON_RING_SW, + HTT_RX_MON_RING_RELEASE, +}; + +struct htt_rx_full_monitor_mode_cfg_cmd { + u32 info0; + u32 cfg; +} __packed; + /* HTT message target->host */ enum htt_t2h_msg_type { diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index c5320847b80a..38eeb6e7c6b6 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -20,13 +20,15 @@ #define ATH11K_DP_RX_FRAGMENT_TIMEOUT_MS (2 * HZ) -static u8 *ath11k_dp_rx_h_80211_hdr(struct ath11k_base *ab, struct hal_rx_desc *desc) +static inline +u8 *ath11k_dp_rx_h_80211_hdr(struct ath11k_base *ab, struct hal_rx_desc *desc) { return ab->hw_params.hw_ops->rx_desc_get_hdr_status(desc); } -static enum hal_encrypt_type ath11k_dp_rx_h_mpdu_start_enctype(struct ath11k_base *ab, - struct hal_rx_desc *desc) +static inline +enum hal_encrypt_type ath11k_dp_rx_h_mpdu_start_enctype(struct ath11k_base *ab, + struct hal_rx_desc *desc) { if (!ab->hw_params.hw_ops->rx_desc_encrypt_valid(desc)) return HAL_ENCRYPT_TYPE_OPEN; @@ -34,32 +36,34 @@ static enum hal_encrypt_type ath11k_dp_rx_h_mpdu_start_enctype(struct ath11k_bas return ab->hw_params.hw_ops->rx_desc_get_encrypt_type(desc); } -static u8 ath11k_dp_rx_h_msdu_start_decap_type(struct ath11k_base *ab, - struct hal_rx_desc *desc) +static inline u8 ath11k_dp_rx_h_msdu_start_decap_type(struct ath11k_base *ab, + struct hal_rx_desc *desc) { return ab->hw_params.hw_ops->rx_desc_get_decap_type(desc); } -static u8 ath11k_dp_rx_h_msdu_start_mesh_ctl_present(struct ath11k_base *ab, - struct hal_rx_desc *desc) +static inline +u8 ath11k_dp_rx_h_msdu_start_mesh_ctl_present(struct ath11k_base *ab, + struct hal_rx_desc *desc) { return ab->hw_params.hw_ops->rx_desc_get_mesh_ctl(desc); } -static bool ath11k_dp_rx_h_mpdu_start_seq_ctrl_valid(struct ath11k_base *ab, - struct hal_rx_desc *desc) +static inline +bool ath11k_dp_rx_h_mpdu_start_seq_ctrl_valid(struct ath11k_base *ab, + struct hal_rx_desc *desc) { return ab->hw_params.hw_ops->rx_desc_get_mpdu_seq_ctl_vld(desc); } -static bool ath11k_dp_rx_h_mpdu_start_fc_valid(struct ath11k_base *ab, - struct hal_rx_desc *desc) +static inline bool ath11k_dp_rx_h_mpdu_start_fc_valid(struct ath11k_base *ab, + struct hal_rx_desc *desc) { return ab->hw_params.hw_ops->rx_desc_get_mpdu_fc_valid(desc); } -static bool ath11k_dp_rx_h_mpdu_start_more_frags(struct ath11k_base *ab, - struct sk_buff *skb) +static inline bool ath11k_dp_rx_h_mpdu_start_more_frags(struct ath11k_base *ab, + struct sk_buff *skb) { struct ieee80211_hdr *hdr; @@ -67,8 +71,8 @@ static bool ath11k_dp_rx_h_mpdu_start_more_frags(struct ath11k_base *ab, return ieee80211_has_morefrags(hdr->frame_control); } -static u16 ath11k_dp_rx_h_mpdu_start_frag_no(struct ath11k_base *ab, - struct sk_buff *skb) +static inline u16 ath11k_dp_rx_h_mpdu_start_frag_no(struct ath11k_base *ab, + struct sk_buff *skb) { struct ieee80211_hdr *hdr; @@ -76,37 +80,37 @@ static u16 ath11k_dp_rx_h_mpdu_start_frag_no(struct ath11k_base *ab, return le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; } -static u16 ath11k_dp_rx_h_mpdu_start_seq_no(struct ath11k_base *ab, - struct hal_rx_desc *desc) +static inline u16 ath11k_dp_rx_h_mpdu_start_seq_no(struct ath11k_base *ab, + struct hal_rx_desc *desc) { return ab->hw_params.hw_ops->rx_desc_get_mpdu_start_seq_no(desc); } -static void *ath11k_dp_rx_get_attention(struct ath11k_base *ab, - struct hal_rx_desc *desc) +static inline void *ath11k_dp_rx_get_attention(struct ath11k_base *ab, + struct hal_rx_desc *desc) { return ab->hw_params.hw_ops->rx_desc_get_attention(desc); } -static bool ath11k_dp_rx_h_attn_msdu_done(struct rx_attention *attn) +static inline bool ath11k_dp_rx_h_attn_msdu_done(struct rx_attention *attn) { return !!FIELD_GET(RX_ATTENTION_INFO2_MSDU_DONE, __le32_to_cpu(attn->info2)); } -static bool ath11k_dp_rx_h_attn_l4_cksum_fail(struct rx_attention *attn) +static inline bool ath11k_dp_rx_h_attn_l4_cksum_fail(struct rx_attention *attn) { return !!FIELD_GET(RX_ATTENTION_INFO1_TCP_UDP_CKSUM_FAIL, __le32_to_cpu(attn->info1)); } -static bool ath11k_dp_rx_h_attn_ip_cksum_fail(struct rx_attention *attn) +static inline bool ath11k_dp_rx_h_attn_ip_cksum_fail(struct rx_attention *attn) { return !!FIELD_GET(RX_ATTENTION_INFO1_IP_CKSUM_FAIL, __le32_to_cpu(attn->info1)); } -static bool ath11k_dp_rx_h_attn_is_decrypted(struct rx_attention *attn) +static inline bool ath11k_dp_rx_h_attn_is_decrypted(struct rx_attention *attn) { return (FIELD_GET(RX_ATTENTION_INFO2_DCRYPT_STATUS_CODE, __le32_to_cpu(attn->info2)) == @@ -154,68 +158,68 @@ static bool ath11k_dp_rx_h_attn_msdu_len_err(struct ath11k_base *ab, return errmap & DP_RX_MPDU_ERR_MSDU_LEN; } -static u16 ath11k_dp_rx_h_msdu_start_msdu_len(struct ath11k_base *ab, - struct hal_rx_desc *desc) +static inline u16 ath11k_dp_rx_h_msdu_start_msdu_len(struct ath11k_base *ab, + struct hal_rx_desc *desc) { return ab->hw_params.hw_ops->rx_desc_get_msdu_len(desc); } -static u8 ath11k_dp_rx_h_msdu_start_sgi(struct ath11k_base *ab, - struct hal_rx_desc *desc) +static inline u8 ath11k_dp_rx_h_msdu_start_sgi(struct ath11k_base *ab, + struct hal_rx_desc *desc) { return ab->hw_params.hw_ops->rx_desc_get_msdu_sgi(desc); } -static u8 ath11k_dp_rx_h_msdu_start_rate_mcs(struct ath11k_base *ab, - struct hal_rx_desc *desc) +static inline u8 ath11k_dp_rx_h_msdu_start_rate_mcs(struct ath11k_base *ab, + struct hal_rx_desc *desc) { return ab->hw_params.hw_ops->rx_desc_get_msdu_rate_mcs(desc); } -static u8 ath11k_dp_rx_h_msdu_start_rx_bw(struct ath11k_base *ab, - struct hal_rx_desc *desc) +static inline u8 ath11k_dp_rx_h_msdu_start_rx_bw(struct ath11k_base *ab, + struct hal_rx_desc *desc) { return ab->hw_params.hw_ops->rx_desc_get_msdu_rx_bw(desc); } -static u32 ath11k_dp_rx_h_msdu_start_freq(struct ath11k_base *ab, - struct hal_rx_desc *desc) +static inline u32 ath11k_dp_rx_h_msdu_start_freq(struct ath11k_base *ab, + struct hal_rx_desc *desc) { return ab->hw_params.hw_ops->rx_desc_get_msdu_freq(desc); } -static u8 ath11k_dp_rx_h_msdu_start_pkt_type(struct ath11k_base *ab, - struct hal_rx_desc *desc) +static inline u8 ath11k_dp_rx_h_msdu_start_pkt_type(struct ath11k_base *ab, + struct hal_rx_desc *desc) { return ab->hw_params.hw_ops->rx_desc_get_msdu_pkt_type(desc); } -static u8 ath11k_dp_rx_h_msdu_start_nss(struct ath11k_base *ab, - struct hal_rx_desc *desc) +static inline u8 ath11k_dp_rx_h_msdu_start_nss(struct ath11k_base *ab, + struct hal_rx_desc *desc) { return hweight8(ab->hw_params.hw_ops->rx_desc_get_msdu_nss(desc)); } -static u8 ath11k_dp_rx_h_mpdu_start_tid(struct ath11k_base *ab, - struct hal_rx_desc *desc) +static inline u8 ath11k_dp_rx_h_mpdu_start_tid(struct ath11k_base *ab, + struct hal_rx_desc *desc) { return ab->hw_params.hw_ops->rx_desc_get_mpdu_tid(desc); } -static u16 ath11k_dp_rx_h_mpdu_start_peer_id(struct ath11k_base *ab, - struct hal_rx_desc *desc) +static inline u16 ath11k_dp_rx_h_mpdu_start_peer_id(struct ath11k_base *ab, + struct hal_rx_desc *desc) { return ab->hw_params.hw_ops->rx_desc_get_mpdu_peer_id(desc); } -static u8 ath11k_dp_rx_h_msdu_end_l3pad(struct ath11k_base *ab, - struct hal_rx_desc *desc) +static inline u8 ath11k_dp_rx_h_msdu_end_l3pad(struct ath11k_base *ab, + struct hal_rx_desc *desc) { return ab->hw_params.hw_ops->rx_desc_get_l3_pad_bytes(desc); } -static bool ath11k_dp_rx_h_msdu_end_first_msdu(struct ath11k_base *ab, - struct hal_rx_desc *desc) +static inline bool ath11k_dp_rx_h_msdu_end_first_msdu(struct ath11k_base *ab, + struct hal_rx_desc *desc) { return ab->hw_params.hw_ops->rx_desc_get_first_msdu(desc); } @@ -233,14 +237,14 @@ static void ath11k_dp_rx_desc_end_tlv_copy(struct ath11k_base *ab, ab->hw_params.hw_ops->rx_desc_copy_attn_end_tlv(fdesc, ldesc); } -static u32 ath11k_dp_rxdesc_get_mpdulen_err(struct rx_attention *attn) +static inline u32 ath11k_dp_rxdesc_get_mpdulen_err(struct rx_attention *attn) { return FIELD_GET(RX_ATTENTION_INFO1_MPDU_LEN_ERR, __le32_to_cpu(attn->info1)); } -static u8 *ath11k_dp_rxdesc_get_80211hdr(struct ath11k_base *ab, - struct hal_rx_desc *rx_desc) +static inline u8 *ath11k_dp_rxdesc_get_80211hdr(struct ath11k_base *ab, + struct hal_rx_desc *rx_desc) { u8 *rx_pkt_hdr; @@ -249,8 +253,8 @@ static u8 *ath11k_dp_rxdesc_get_80211hdr(struct ath11k_base *ab, return rx_pkt_hdr; } -static bool ath11k_dp_rxdesc_mpdu_valid(struct ath11k_base *ab, - struct hal_rx_desc *rx_desc) +static inline bool ath11k_dp_rxdesc_mpdu_valid(struct ath11k_base *ab, + struct hal_rx_desc *rx_desc) { u32 tlv_tag; @@ -259,15 +263,15 @@ static bool ath11k_dp_rxdesc_mpdu_valid(struct ath11k_base *ab, return tlv_tag == HAL_RX_MPDU_START; } -static u32 ath11k_dp_rxdesc_get_ppduid(struct ath11k_base *ab, - struct hal_rx_desc *rx_desc) +static inline u32 ath11k_dp_rxdesc_get_ppduid(struct ath11k_base *ab, + struct hal_rx_desc *rx_desc) { return ab->hw_params.hw_ops->rx_desc_get_mpdu_ppdu_id(rx_desc); } -static void ath11k_dp_rxdesc_set_msdu_len(struct ath11k_base *ab, - struct hal_rx_desc *desc, - u16 len) +static inline void ath11k_dp_rxdesc_set_msdu_len(struct ath11k_base *ab, + struct hal_rx_desc *desc, + u16 len) { ab->hw_params.hw_ops->rx_desc_set_msdu_len(desc, len); } @@ -2596,36 +2600,30 @@ free_out: static void ath11k_dp_rx_process_received_packets(struct ath11k_base *ab, struct napi_struct *napi, struct sk_buff_head *msdu_list, - int *quota, int ring_id) + int mac_id) { - struct ath11k_skb_rxcb *rxcb; struct sk_buff *msdu; struct ath11k *ar; struct ieee80211_rx_status rx_status = {0}; - u8 mac_id; int ret; if (skb_queue_empty(msdu_list)) return; - rcu_read_lock(); - - while (*quota && (msdu = __skb_dequeue(msdu_list))) { - rxcb = ATH11K_SKB_RXCB(msdu); - mac_id = rxcb->mac_id; - ar = ab->pdevs[mac_id].ar; - if (!rcu_dereference(ab->pdevs_active[mac_id])) { - dev_kfree_skb_any(msdu); - continue; - } + if (unlikely(!rcu_access_pointer(ab->pdevs_active[mac_id]))) { + __skb_queue_purge(msdu_list); + return; + } - if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) { - dev_kfree_skb_any(msdu); - continue; - } + ar = ab->pdevs[mac_id].ar; + if (unlikely(test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags))) { + __skb_queue_purge(msdu_list); + return; + } + while ((msdu = __skb_dequeue(msdu_list))) { ret = ath11k_dp_rx_process_msdu(ar, msdu, msdu_list, &rx_status); - if (ret) { + if (unlikely(ret)) { ath11k_dbg(ab, ATH11K_DBG_DATA, "Unable to process msdu %d", ret); dev_kfree_skb_any(msdu); @@ -2633,10 +2631,7 @@ static void ath11k_dp_rx_process_received_packets(struct ath11k_base *ab, } ath11k_dp_rx_deliver_msdu(ar, napi, msdu, &rx_status); - (*quota)--; } - - rcu_read_unlock(); } int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id, @@ -2645,19 +2640,21 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id, struct ath11k_dp *dp = &ab->dp; struct dp_rxdma_ring *rx_ring; int num_buffs_reaped[MAX_RADIOS] = {0}; - struct sk_buff_head msdu_list; + struct sk_buff_head msdu_list[MAX_RADIOS]; struct ath11k_skb_rxcb *rxcb; int total_msdu_reaped = 0; struct hal_srng *srng; struct sk_buff *msdu; - int quota = budget; bool done = false; int buf_id, mac_id; struct ath11k *ar; - u32 *rx_desc; + struct hal_reo_dest_ring *desc; + enum hal_reo_dest_ring_push_reason push_reason; + u32 cookie; int i; - __skb_queue_head_init(&msdu_list); + for (i = 0; i < MAX_RADIOS; i++) + __skb_queue_head_init(&msdu_list[i]); srng = &ab->hal.srng_list[dp->reo_dst_ring[ring_id].ring_id]; @@ -2666,13 +2663,11 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id, ath11k_hal_srng_access_begin(ab, srng); try_again: - while ((rx_desc = ath11k_hal_srng_dst_get_next_entry(ab, srng))) { - struct hal_reo_dest_ring desc = *(struct hal_reo_dest_ring *)rx_desc; - enum hal_reo_dest_ring_push_reason push_reason; - u32 cookie; - + while (likely(desc = + (struct hal_reo_dest_ring *)ath11k_hal_srng_dst_get_next_entry(ab, + srng))) { cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, - desc.buf_addr_info.info1); + desc->buf_addr_info.info1); buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, cookie); mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID, cookie); @@ -2681,7 +2676,7 @@ try_again: rx_ring = &ar->dp.rx_refill_buf_ring; spin_lock_bh(&rx_ring->idr_lock); msdu = idr_find(&rx_ring->bufs_idr, buf_id); - if (!msdu) { + if (unlikely(!msdu)) { ath11k_warn(ab, "frame rx with invalid buf_id %d\n", buf_id); spin_unlock_bh(&rx_ring->idr_lock); @@ -2697,37 +2692,41 @@ try_again: DMA_FROM_DEVICE); num_buffs_reaped[mac_id]++; - total_msdu_reaped++; push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON, - desc.info0); - if (push_reason != - HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION) { + desc->info0); + if (unlikely(push_reason != + HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION)) { dev_kfree_skb_any(msdu); ab->soc_stats.hal_reo_error[dp->reo_dst_ring[ring_id].ring_id]++; continue; } - rxcb->is_first_msdu = !!(desc.rx_msdu_info.info0 & + rxcb->is_first_msdu = !!(desc->rx_msdu_info.info0 & RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU); - rxcb->is_last_msdu = !!(desc.rx_msdu_info.info0 & + rxcb->is_last_msdu = !!(desc->rx_msdu_info.info0 & RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU); - rxcb->is_continuation = !!(desc.rx_msdu_info.info0 & + rxcb->is_continuation = !!(desc->rx_msdu_info.info0 & RX_MSDU_DESC_INFO0_MSDU_CONTINUATION); rxcb->peer_id = FIELD_GET(RX_MPDU_DESC_META_DATA_PEER_ID, - desc.rx_mpdu_info.meta_data); + desc->rx_mpdu_info.meta_data); rxcb->seq_no = FIELD_GET(RX_MPDU_DESC_INFO0_SEQ_NUM, - desc.rx_mpdu_info.info0); + desc->rx_mpdu_info.info0); rxcb->tid = FIELD_GET(HAL_REO_DEST_RING_INFO0_RX_QUEUE_NUM, - desc.info0); + desc->info0); rxcb->mac_id = mac_id; - __skb_queue_tail(&msdu_list, msdu); + __skb_queue_tail(&msdu_list[mac_id], msdu); - if (total_msdu_reaped >= quota && !rxcb->is_continuation) { + if (rxcb->is_continuation) { + done = false; + } else { + total_msdu_reaped++; done = true; - break; } + + if (total_msdu_reaped >= budget) + break; } /* Hw might have updated the head pointer after we cached it. @@ -2736,7 +2735,7 @@ try_again: * head pointer so that we can reap complete MPDU in the current * rx processing. */ - if (!done && ath11k_hal_srng_dst_num_free(ab, srng, true)) { + if (unlikely(!done && ath11k_hal_srng_dst_num_free(ab, srng, true))) { ath11k_hal_srng_access_end(ab, srng); goto try_again; } @@ -2745,25 +2744,23 @@ try_again: spin_unlock_bh(&srng->lock); - if (!total_msdu_reaped) + if (unlikely(!total_msdu_reaped)) goto exit; for (i = 0; i < ab->num_radios; i++) { if (!num_buffs_reaped[i]) continue; + ath11k_dp_rx_process_received_packets(ab, napi, &msdu_list[i], i); + ar = ab->pdevs[i].ar; rx_ring = &ar->dp.rx_refill_buf_ring; ath11k_dp_rxbufs_replenish(ab, i, rx_ring, num_buffs_reaped[i], ab->hw_params.hal_params->rx_buf_rbm); } - - ath11k_dp_rx_process_received_packets(ab, napi, &msdu_list, - "a, ring_id); - exit: - return budget - quota; + return total_msdu_reaped; } static void ath11k_dp_rx_update_peer_stats(struct ath11k_sta *arsta, @@ -2945,6 +2942,43 @@ fail_desc_get: return req_entries - num_remain; } +#define ATH11K_DP_RX_FULL_MON_PPDU_ID_WRAP 32535 + +static void +ath11k_dp_rx_mon_update_status_buf_state(struct ath11k_mon_data *pmon, + struct hal_tlv_hdr *tlv) +{ + struct hal_rx_ppdu_start *ppdu_start; + u16 ppdu_id_diff, ppdu_id, tlv_len; + u8 *ptr; + + /* PPDU id is part of second tlv, move ptr to second tlv */ + tlv_len = FIELD_GET(HAL_TLV_HDR_LEN, tlv->tl); + ptr = (u8 *)tlv; + ptr += sizeof(*tlv) + tlv_len; + tlv = (struct hal_tlv_hdr *)ptr; + + if (FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl) != HAL_RX_PPDU_START) + return; + + ptr += sizeof(*tlv); + ppdu_start = (struct hal_rx_ppdu_start *)ptr; + ppdu_id = FIELD_GET(HAL_RX_PPDU_START_INFO0_PPDU_ID, + __le32_to_cpu(ppdu_start->info0)); + + if (pmon->sw_mon_entries.ppdu_id < ppdu_id) { + pmon->buf_state = DP_MON_STATUS_LEAD; + ppdu_id_diff = ppdu_id - pmon->sw_mon_entries.ppdu_id; + if (ppdu_id_diff > ATH11K_DP_RX_FULL_MON_PPDU_ID_WRAP) + pmon->buf_state = DP_MON_STATUS_LAG; + } else if (pmon->sw_mon_entries.ppdu_id > ppdu_id) { + pmon->buf_state = DP_MON_STATUS_LAG; + ppdu_id_diff = pmon->sw_mon_entries.ppdu_id - ppdu_id; + if (ppdu_id_diff > ATH11K_DP_RX_FULL_MON_PPDU_ID_WRAP) + pmon->buf_state = DP_MON_STATUS_LEAD; + } +} + static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, int *budget, struct sk_buff_head *skb_list) { @@ -2952,6 +2986,7 @@ static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, const struct ath11k_hw_hal_params *hal_params; struct ath11k_pdev_dp *dp; struct dp_rxdma_ring *rx_ring; + struct ath11k_mon_data *pmon; struct hal_srng *srng; void *rx_mon_status_desc; struct sk_buff *skb; @@ -2965,6 +3000,7 @@ static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, ar = ab->pdevs[ath11k_hw_mac_id_to_pdev_id(&ab->hw_params, mac_id)].ar; dp = &ar->dp; + pmon = &dp->mon_data; srng_id = ath11k_hw_mac_id_to_srng_id(&ab->hw_params, mac_id); rx_ring = &dp->rx_mon_status_refill_ring[srng_id]; @@ -2977,8 +3013,10 @@ static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, *budget -= 1; rx_mon_status_desc = ath11k_hal_srng_src_peek(ab, srng); - if (!rx_mon_status_desc) + if (!rx_mon_status_desc) { + pmon->buf_state = DP_MON_STATUS_REPLINISH; break; + } ath11k_hal_rx_buf_addr_info_get(rx_mon_status_desc, &paddr, &cookie, &rbm); @@ -2991,6 +3029,7 @@ static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, ath11k_warn(ab, "rx monitor status with invalid buf_id %d\n", buf_id); spin_unlock_bh(&rx_ring->idr_lock); + pmon->buf_state = DP_MON_STATUS_REPLINISH; goto move_next; } @@ -3010,10 +3049,18 @@ static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl)); dev_kfree_skb_any(skb); + pmon->buf_state = DP_MON_STATUS_NO_DMA; goto move_next; } + if (ab->hw_params.full_monitor_mode) { + ath11k_dp_rx_mon_update_status_buf_state(pmon, tlv); + if (paddr == pmon->mon_status_paddr) + pmon->buf_state = DP_MON_STATUS_MATCH; + } __skb_queue_tail(skb_list, skb); + } else { + pmon->buf_state = DP_MON_STATUS_REPLINISH; } move_next: skb = ath11k_dp_rx_alloc_mon_status_buf(ab, rx_ring, @@ -3064,10 +3111,10 @@ int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id, if (!num_buffs_reaped) goto exit; - while ((skb = __skb_dequeue(&skb_list))) { - memset(&ppdu_info, 0, sizeof(ppdu_info)); - ppdu_info.peer_id = HAL_INVALID_PEERID; + memset(&ppdu_info, 0, sizeof(ppdu_info)); + ppdu_info.peer_id = HAL_INVALID_PEERID; + while ((skb = __skb_dequeue(&skb_list))) { if (ath11k_debugfs_is_pktlog_lite_mode_enabled(ar)) { log_type = ATH11K_PKTLOG_TYPE_LITE_RX; rx_buf_sz = DP_RX_BUFFER_SIZE_LITE; @@ -3095,10 +3142,7 @@ int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id, ath11k_dbg(ab, ATH11K_DBG_DATA, "failed to find the peer with peer_id %d\n", ppdu_info.peer_id); - spin_unlock_bh(&ab->base_lock); - rcu_read_unlock(); - dev_kfree_skb_any(skb); - continue; + goto next_skb; } arsta = (struct ath11k_sta *)peer->sta->drv_priv; @@ -3107,10 +3151,13 @@ int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id, if (ath11k_debugfs_is_pktlog_peer_valid(ar, peer->addr)) trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); +next_skb: spin_unlock_bh(&ab->base_lock); rcu_read_unlock(); dev_kfree_skb_any(skb); + memset(&ppdu_info, 0, sizeof(ppdu_info)); + ppdu_info.peer_id = HAL_INVALID_PEERID; } exit: return num_buffs_reaped; @@ -4829,7 +4876,7 @@ static struct sk_buff * ath11k_dp_rx_mon_merg_msdus(struct ath11k *ar, u32 mac_id, struct sk_buff *head_msdu, struct sk_buff *last_msdu, - struct ieee80211_rx_status *rxs) + struct ieee80211_rx_status *rxs, bool *fcs_err) { struct ath11k_base *ab = ar->ab; struct sk_buff *msdu, *prev_buf; @@ -4839,12 +4886,17 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11k *ar, u8 *dest, decap_format; struct ieee80211_hdr_3addr *wh; struct rx_attention *rx_attention; + u32 err_bitmap; if (!head_msdu) goto err_merge_fail; rx_desc = (struct hal_rx_desc *)head_msdu->data; rx_attention = ath11k_dp_rx_get_attention(ab, rx_desc); + err_bitmap = ath11k_dp_rx_h_attn_mpdu_err(rx_attention); + + if (err_bitmap & DP_RX_MPDU_ERR_FCS) + *fcs_err = true; if (ath11k_dp_rxdesc_get_mpdulen_err(rx_attention)) return NULL; @@ -4933,9 +4985,10 @@ static int ath11k_dp_rx_mon_deliver(struct ath11k *ar, u32 mac_id, struct ath11k_pdev_dp *dp = &ar->dp; struct sk_buff *mon_skb, *skb_next, *header; struct ieee80211_rx_status *rxs = &dp->rx_status; + bool fcs_err = false; mon_skb = ath11k_dp_rx_mon_merg_msdus(ar, mac_id, head_msdu, - tail_msdu, rxs); + tail_msdu, rxs, &fcs_err); if (!mon_skb) goto mon_deliver_fail; @@ -4943,6 +4996,10 @@ static int ath11k_dp_rx_mon_deliver(struct ath11k *ar, u32 mac_id, header = mon_skb; rxs->flag = 0; + + if (fcs_err) + rxs->flag = RX_FLAG_FAILED_FCS_CRC; + do { skb_next = mon_skb->next; if (!skb_next) @@ -5091,6 +5148,357 @@ static void ath11k_dp_rx_mon_status_process_tlv(struct ath11k *ar, } } +static u32 +ath11k_dp_rx_full_mon_mpdu_pop(struct ath11k *ar, + void *ring_entry, struct sk_buff **head_msdu, + struct sk_buff **tail_msdu, + struct hal_sw_mon_ring_entries *sw_mon_entries) +{ + struct ath11k_pdev_dp *dp = &ar->dp; + struct ath11k_mon_data *pmon = &dp->mon_data; + struct dp_rxdma_ring *rx_ring = &dp->rxdma_mon_buf_ring; + struct sk_buff *msdu = NULL, *last = NULL; + struct hal_sw_monitor_ring *sw_desc = ring_entry; + struct hal_rx_msdu_list msdu_list; + struct hal_rx_desc *rx_desc; + struct ath11k_skb_rxcb *rxcb; + void *rx_msdu_link_desc; + void *p_buf_addr_info, *p_last_buf_addr_info; + int buf_id, i = 0; + u32 rx_buf_size, rx_pkt_offset, l2_hdr_offset; + u32 rx_bufs_used = 0, msdu_cnt = 0; + u32 total_len = 0, frag_len = 0, sw_cookie; + u16 num_msdus = 0; + u8 rxdma_err, rbm; + bool is_frag, is_first_msdu; + bool drop_mpdu = false; + + ath11k_hal_rx_sw_mon_ring_buf_paddr_get(ring_entry, sw_mon_entries); + + sw_cookie = sw_mon_entries->mon_dst_sw_cookie; + sw_mon_entries->end_of_ppdu = false; + sw_mon_entries->drop_ppdu = false; + p_last_buf_addr_info = sw_mon_entries->dst_buf_addr_info; + msdu_cnt = sw_mon_entries->msdu_cnt; + + sw_mon_entries->end_of_ppdu = + FIELD_GET(HAL_SW_MON_RING_INFO0_END_OF_PPDU, sw_desc->info0); + if (sw_mon_entries->end_of_ppdu) + return rx_bufs_used; + + if (FIELD_GET(HAL_SW_MON_RING_INFO0_RXDMA_PUSH_REASON, + sw_desc->info0) == + HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED) { + rxdma_err = + FIELD_GET(HAL_SW_MON_RING_INFO0_RXDMA_ERROR_CODE, + sw_desc->info0); + if (rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_FLUSH_REQUEST_ERR || + rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_MPDU_LEN_ERR || + rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_OVERFLOW_ERR) { + pmon->rx_mon_stats.dest_mpdu_drop++; + drop_mpdu = true; + } + } + + is_frag = false; + is_first_msdu = true; + + do { + rx_msdu_link_desc = + (u8 *)pmon->link_desc_banks[sw_cookie].vaddr + + (sw_mon_entries->mon_dst_paddr - + pmon->link_desc_banks[sw_cookie].paddr); + + ath11k_hal_rx_msdu_list_get(ar, rx_msdu_link_desc, &msdu_list, + &num_msdus); + + for (i = 0; i < num_msdus; i++) { + buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, + msdu_list.sw_cookie[i]); + + spin_lock_bh(&rx_ring->idr_lock); + msdu = idr_find(&rx_ring->bufs_idr, buf_id); + if (!msdu) { + ath11k_dbg(ar->ab, ATH11K_DBG_DATA, + "full mon msdu_pop: invalid buf_id %d\n", + buf_id); + spin_unlock_bh(&rx_ring->idr_lock); + break; + } + idr_remove(&rx_ring->bufs_idr, buf_id); + spin_unlock_bh(&rx_ring->idr_lock); + + rxcb = ATH11K_SKB_RXCB(msdu); + if (!rxcb->unmapped) { + dma_unmap_single(ar->ab->dev, rxcb->paddr, + msdu->len + + skb_tailroom(msdu), + DMA_FROM_DEVICE); + rxcb->unmapped = 1; + } + if (drop_mpdu) { + ath11k_dbg(ar->ab, ATH11K_DBG_DATA, + "full mon: i %d drop msdu %p *ppdu_id %x\n", + i, msdu, sw_mon_entries->ppdu_id); + dev_kfree_skb_any(msdu); + msdu_cnt--; + goto next_msdu; + } + + rx_desc = (struct hal_rx_desc *)msdu->data; + + rx_pkt_offset = sizeof(struct hal_rx_desc); + l2_hdr_offset = ath11k_dp_rx_h_msdu_end_l3pad(ar->ab, rx_desc); + + if (is_first_msdu) { + if (!ath11k_dp_rxdesc_mpdu_valid(ar->ab, rx_desc)) { + drop_mpdu = true; + dev_kfree_skb_any(msdu); + msdu = NULL; + goto next_msdu; + } + is_first_msdu = false; + } + + ath11k_dp_mon_get_buf_len(&msdu_list.msdu_info[i], + &is_frag, &total_len, + &frag_len, &msdu_cnt); + + rx_buf_size = rx_pkt_offset + l2_hdr_offset + frag_len; + + ath11k_dp_pkt_set_pktlen(msdu, rx_buf_size); + + if (!(*head_msdu)) + *head_msdu = msdu; + else if (last) + last->next = msdu; + + last = msdu; +next_msdu: + rx_bufs_used++; + } + + ath11k_dp_rx_mon_next_link_desc_get(rx_msdu_link_desc, + &sw_mon_entries->mon_dst_paddr, + &sw_mon_entries->mon_dst_sw_cookie, + &rbm, + &p_buf_addr_info); + + if (ath11k_dp_rx_monitor_link_desc_return(ar, + p_last_buf_addr_info, + dp->mac_id)) + ath11k_dbg(ar->ab, ATH11K_DBG_DATA, + "full mon: dp_rx_monitor_link_desc_return failed\n"); + + p_last_buf_addr_info = p_buf_addr_info; + + } while (sw_mon_entries->mon_dst_paddr && msdu_cnt); + + if (last) + last->next = NULL; + + *tail_msdu = msdu; + + return rx_bufs_used; +} + +static int ath11k_dp_rx_full_mon_prepare_mpdu(struct ath11k_dp *dp, + struct dp_full_mon_mpdu *mon_mpdu, + struct sk_buff *head, + struct sk_buff *tail) +{ + mon_mpdu = kzalloc(sizeof(*mon_mpdu), GFP_ATOMIC); + if (!mon_mpdu) + return -ENOMEM; + + list_add_tail(&mon_mpdu->list, &dp->dp_full_mon_mpdu_list); + mon_mpdu->head = head; + mon_mpdu->tail = tail; + + return 0; +} + +static void ath11k_dp_rx_full_mon_drop_ppdu(struct ath11k_dp *dp, + struct dp_full_mon_mpdu *mon_mpdu) +{ + struct dp_full_mon_mpdu *tmp; + struct sk_buff *tmp_msdu, *skb_next; + + if (list_empty(&dp->dp_full_mon_mpdu_list)) + return; + + list_for_each_entry_safe(mon_mpdu, tmp, &dp->dp_full_mon_mpdu_list, list) { + list_del(&mon_mpdu->list); + + tmp_msdu = mon_mpdu->head; + while (tmp_msdu) { + skb_next = tmp_msdu->next; + dev_kfree_skb_any(tmp_msdu); + tmp_msdu = skb_next; + } + + kfree(mon_mpdu); + } +} + +static int ath11k_dp_rx_full_mon_deliver_ppdu(struct ath11k *ar, + int mac_id, + struct ath11k_mon_data *pmon, + struct napi_struct *napi) +{ + struct ath11k_pdev_mon_stats *rx_mon_stats; + struct dp_full_mon_mpdu *tmp; + struct dp_full_mon_mpdu *mon_mpdu = pmon->mon_mpdu; + struct sk_buff *head_msdu, *tail_msdu; + struct ath11k_base *ab = ar->ab; + struct ath11k_dp *dp = &ab->dp; + int ret; + + rx_mon_stats = &pmon->rx_mon_stats; + + list_for_each_entry_safe(mon_mpdu, tmp, &dp->dp_full_mon_mpdu_list, list) { + list_del(&mon_mpdu->list); + head_msdu = mon_mpdu->head; + tail_msdu = mon_mpdu->tail; + if (head_msdu && tail_msdu) { + ret = ath11k_dp_rx_mon_deliver(ar, mac_id, head_msdu, + tail_msdu, napi); + rx_mon_stats->dest_mpdu_done++; + ath11k_dbg(ar->ab, ATH11K_DBG_DATA, "full mon: deliver ppdu\n"); + } + kfree(mon_mpdu); + } + + return ret; +} + +static int +ath11k_dp_rx_process_full_mon_status_ring(struct ath11k_base *ab, int mac_id, + struct napi_struct *napi, int budget) +{ + struct ath11k *ar = ab->pdevs[mac_id].ar; + struct ath11k_pdev_dp *dp = &ar->dp; + struct ath11k_mon_data *pmon = &dp->mon_data; + struct hal_sw_mon_ring_entries *sw_mon_entries; + int quota = 0, work = 0, count; + + sw_mon_entries = &pmon->sw_mon_entries; + + while (pmon->hold_mon_dst_ring) { + quota = ath11k_dp_rx_process_mon_status(ab, mac_id, + napi, 1); + if (pmon->buf_state == DP_MON_STATUS_MATCH) { + count = sw_mon_entries->status_buf_count; + if (count > 1) { + quota += ath11k_dp_rx_process_mon_status(ab, mac_id, + napi, count); + } + + ath11k_dp_rx_full_mon_deliver_ppdu(ar, dp->mac_id, + pmon, napi); + pmon->hold_mon_dst_ring = false; + } else if (!pmon->mon_status_paddr || + pmon->buf_state == DP_MON_STATUS_LEAD) { + sw_mon_entries->drop_ppdu = true; + pmon->hold_mon_dst_ring = false; + } + + if (!quota) + break; + + work += quota; + } + + if (sw_mon_entries->drop_ppdu) + ath11k_dp_rx_full_mon_drop_ppdu(&ab->dp, pmon->mon_mpdu); + + return work; +} + +static int ath11k_dp_full_mon_process_rx(struct ath11k_base *ab, int mac_id, + struct napi_struct *napi, int budget) +{ + struct ath11k *ar = ab->pdevs[mac_id].ar; + struct ath11k_pdev_dp *dp = &ar->dp; + struct ath11k_mon_data *pmon = &dp->mon_data; + struct hal_sw_mon_ring_entries *sw_mon_entries; + struct ath11k_pdev_mon_stats *rx_mon_stats; + struct sk_buff *head_msdu, *tail_msdu; + void *mon_dst_srng = &ar->ab->hal.srng_list[dp->rxdma_mon_dst_ring.ring_id]; + void *ring_entry; + u32 rx_bufs_used = 0, mpdu_rx_bufs_used; + int quota = 0, ret; + bool break_dst_ring = false; + + spin_lock_bh(&pmon->mon_lock); + + sw_mon_entries = &pmon->sw_mon_entries; + rx_mon_stats = &pmon->rx_mon_stats; + + if (pmon->hold_mon_dst_ring) { + spin_unlock_bh(&pmon->mon_lock); + goto reap_status_ring; + } + + ath11k_hal_srng_access_begin(ar->ab, mon_dst_srng); + while ((ring_entry = ath11k_hal_srng_dst_peek(ar->ab, mon_dst_srng))) { + head_msdu = NULL; + tail_msdu = NULL; + + mpdu_rx_bufs_used = ath11k_dp_rx_full_mon_mpdu_pop(ar, ring_entry, + &head_msdu, + &tail_msdu, + sw_mon_entries); + rx_bufs_used += mpdu_rx_bufs_used; + + if (!sw_mon_entries->end_of_ppdu) { + if (head_msdu) { + ret = ath11k_dp_rx_full_mon_prepare_mpdu(&ab->dp, + pmon->mon_mpdu, + head_msdu, + tail_msdu); + if (ret) + break_dst_ring = true; + } + + goto next_entry; + } else { + if (!sw_mon_entries->ppdu_id && + !sw_mon_entries->mon_status_paddr) { + break_dst_ring = true; + goto next_entry; + } + } + + rx_mon_stats->dest_ppdu_done++; + pmon->mon_ppdu_status = DP_PPDU_STATUS_START; + pmon->buf_state = DP_MON_STATUS_LAG; + pmon->mon_status_paddr = sw_mon_entries->mon_status_paddr; + pmon->hold_mon_dst_ring = true; +next_entry: + ring_entry = ath11k_hal_srng_dst_get_next_entry(ar->ab, + mon_dst_srng); + if (break_dst_ring) + break; + } + + ath11k_hal_srng_access_end(ar->ab, mon_dst_srng); + spin_unlock_bh(&pmon->mon_lock); + + if (rx_bufs_used) { + ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id, + &dp->rxdma_mon_buf_ring, + rx_bufs_used, + HAL_RX_BUF_RBM_SW3_BM); + } + +reap_status_ring: + quota = ath11k_dp_rx_process_full_mon_status_ring(ab, mac_id, + napi, budget); + + return quota; +} + static int ath11k_dp_mon_process_rx(struct ath11k_base *ab, int mac_id, struct napi_struct *napi, int budget) { @@ -5113,10 +5521,14 @@ int ath11k_dp_rx_process_mon_rings(struct ath11k_base *ab, int mac_id, struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); int ret = 0; - if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) + if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags) && + ab->hw_params.full_monitor_mode) + ret = ath11k_dp_full_mon_process_rx(ab, mac_id, napi, budget); + else if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) ret = ath11k_dp_mon_process_rx(ab, mac_id, napi, budget); else ret = ath11k_dp_rx_process_mon_status(ab, mac_id, napi, budget); + return ret; } diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c index 879fb2a9dc0c..8560f3b33812 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c @@ -9,6 +9,7 @@ #include "debugfs_sta.h" #include "hw.h" #include "peer.h" +#include "mac.h" static enum hal_tcl_encap_type ath11k_dp_tx_get_encap_type(struct ath11k_vif *arvif, struct sk_buff *skb) @@ -95,11 +96,11 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, u8 ring_selector = 0, ring_map = 0; bool tcl_ring_retry; - if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) + if (unlikely(test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))) return -ESHUTDOWN; - if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && - !ieee80211_is_data(hdr->frame_control)) + if (unlikely(!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && + !ieee80211_is_data(hdr->frame_control))) return -ENOTSUPP; pool_id = skb_get_queue_mapping(skb) & (ATH11K_HW_MAX_QUEUES - 1); @@ -127,7 +128,7 @@ tcl_ring_sel: DP_TX_IDR_SIZE - 1, GFP_ATOMIC); spin_unlock_bh(&tx_ring->tx_idr_lock); - if (ret < 0) { + if (unlikely(ret < 0)) { if (ring_map == (BIT(ab->hw_params.max_tx_ring) - 1)) { atomic_inc(&ab->soc_stats.tx_err.misc_fail); return -ENOSPC; @@ -152,7 +153,7 @@ tcl_ring_sel: ti.meta_data_flags = arvif->tcl_metadata; } - if (ti.encap_type == HAL_TCL_ENCAP_TYPE_RAW) { + if (unlikely(ti.encap_type == HAL_TCL_ENCAP_TYPE_RAW)) { if (skb_cb->flags & ATH11K_SKB_CIPHER_SET) { ti.encrypt_type = ath11k_dp_tx_get_encrypt_type(skb_cb->cipher); @@ -173,8 +174,8 @@ tcl_ring_sel: ti.bss_ast_idx = arvif->ast_idx; ti.dscp_tid_tbl_idx = 0; - if (skb->ip_summed == CHECKSUM_PARTIAL && - ti.encap_type != HAL_TCL_ENCAP_TYPE_RAW) { + if (likely(skb->ip_summed == CHECKSUM_PARTIAL && + ti.encap_type != HAL_TCL_ENCAP_TYPE_RAW)) { ti.flags0 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_IP4_CKSUM_EN, 1) | FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_UDP4_CKSUM_EN, 1) | FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_UDP6_CKSUM_EN, 1) | @@ -211,7 +212,7 @@ tcl_ring_sel: } ti.paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE); - if (dma_mapping_error(ab->dev, ti.paddr)) { + if (unlikely(dma_mapping_error(ab->dev, ti.paddr))) { atomic_inc(&ab->soc_stats.tx_err.misc_fail); ath11k_warn(ab, "failed to DMA map data Tx buffer\n"); ret = -ENOMEM; @@ -231,7 +232,7 @@ tcl_ring_sel: ath11k_hal_srng_access_begin(ab, tcl_ring); hal_tcl_desc = (void *)ath11k_hal_srng_src_get_next_entry(ab, tcl_ring); - if (!hal_tcl_desc) { + if (unlikely(!hal_tcl_desc)) { /* NOTE: It is highly unlikely we'll be running out of tcl_ring * desc because the desc is directly enqueued onto hw queue. */ @@ -245,7 +246,7 @@ tcl_ring_sel: * checking this ring earlier for each pkt tx. * Restart ring selection if some rings are not checked yet. */ - if (ring_map != (BIT(ab->hw_params.max_tx_ring) - 1) && + if (unlikely(ring_map != (BIT(ab->hw_params.max_tx_ring)) - 1) && ab->hw_params.max_tx_ring > 1) { tcl_ring_retry = true; ring_selector++; @@ -293,20 +294,18 @@ static void ath11k_dp_tx_free_txbuf(struct ath11k_base *ab, u8 mac_id, struct sk_buff *msdu; struct ath11k_skb_cb *skb_cb; - spin_lock_bh(&tx_ring->tx_idr_lock); - msdu = idr_find(&tx_ring->txbuf_idr, msdu_id); - if (!msdu) { + spin_lock(&tx_ring->tx_idr_lock); + msdu = idr_remove(&tx_ring->txbuf_idr, msdu_id); + spin_unlock(&tx_ring->tx_idr_lock); + + if (unlikely(!msdu)) { ath11k_warn(ab, "tx completion for unknown msdu_id %d\n", msdu_id); - spin_unlock_bh(&tx_ring->tx_idr_lock); return; } skb_cb = ATH11K_SKB_CB(msdu); - idr_remove(&tx_ring->txbuf_idr, msdu_id); - spin_unlock_bh(&tx_ring->tx_idr_lock); - dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); dev_kfree_skb_any(msdu); @@ -325,12 +324,13 @@ ath11k_dp_tx_htt_tx_complete_buf(struct ath11k_base *ab, struct ath11k_skb_cb *skb_cb; struct ath11k *ar; - spin_lock_bh(&tx_ring->tx_idr_lock); - msdu = idr_find(&tx_ring->txbuf_idr, ts->msdu_id); - if (!msdu) { + spin_lock(&tx_ring->tx_idr_lock); + msdu = idr_remove(&tx_ring->txbuf_idr, ts->msdu_id); + spin_unlock(&tx_ring->tx_idr_lock); + + if (unlikely(!msdu)) { ath11k_warn(ab, "htt tx completion for unknown msdu_id %d\n", ts->msdu_id); - spin_unlock_bh(&tx_ring->tx_idr_lock); return; } @@ -339,9 +339,6 @@ ath11k_dp_tx_htt_tx_complete_buf(struct ath11k_base *ab, ar = skb_cb->ar; - idr_remove(&tx_ring->txbuf_idr, ts->msdu_id); - spin_unlock_bh(&tx_ring->tx_idr_lock); - if (atomic_dec_and_test(&ar->dp.num_tx_pending)) wake_up(&ar->dp.tx_empty_waitq); @@ -435,16 +432,14 @@ static void ath11k_dp_tx_complete_msdu(struct ath11k *ar, dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); - rcu_read_lock(); - - if (!rcu_dereference(ab->pdevs_active[ar->pdev_idx])) { + if (unlikely(!rcu_access_pointer(ab->pdevs_active[ar->pdev_idx]))) { dev_kfree_skb_any(msdu); - goto exit; + return; } - if (!skb_cb->vif) { + if (unlikely(!skb_cb->vif)) { dev_kfree_skb_any(msdu); - goto exit; + return; } info = IEEE80211_SKB_CB(msdu); @@ -465,7 +460,7 @@ static void ath11k_dp_tx_complete_msdu(struct ath11k *ar, (info->flags & IEEE80211_TX_CTL_NO_ACK)) info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; - if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) { + if (unlikely(ath11k_debugfs_is_extd_tx_stats_enabled(ar))) { if (ts->flags & HAL_TX_STATUS_FLAGS_FIRST_MSDU) { if (ar->last_ppdu_id == 0) { ar->last_ppdu_id = ts->ppdu_id; @@ -494,9 +489,6 @@ static void ath11k_dp_tx_complete_msdu(struct ath11k *ar, */ ieee80211_tx_status(ar->hw, msdu); - -exit: - rcu_read_unlock(); } static inline void ath11k_dp_tx_status_parse(struct ath11k_base *ab, @@ -505,11 +497,11 @@ static inline void ath11k_dp_tx_status_parse(struct ath11k_base *ab, { ts->buf_rel_source = FIELD_GET(HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE, desc->info0); - if (ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_FW && - ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM) + if (unlikely(ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_FW && + ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM)) return; - if (ts->buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW) + if (unlikely(ts->buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW)) return; ts->status = FIELD_GET(HAL_WBM_RELEASE_INFO0_TQM_RELEASE_REASON, @@ -556,8 +548,9 @@ void ath11k_dp_tx_completion_handler(struct ath11k_base *ab, int ring_id) ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head); } - if ((ath11k_hal_srng_dst_peek(ab, status_ring) != NULL) && - (ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head) == tx_ring->tx_status_tail)) { + if (unlikely((ath11k_hal_srng_dst_peek(ab, status_ring) != NULL) && + (ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head) == + tx_ring->tx_status_tail))) { /* TODO: Process pending tx_status messages when kfifo_is_full() */ ath11k_warn(ab, "Unable to process some of the tx_status ring desc because status_fifo is full\n"); } @@ -580,7 +573,7 @@ void ath11k_dp_tx_completion_handler(struct ath11k_base *ab, int ring_id) mac_id = FIELD_GET(DP_TX_DESC_ID_MAC_ID, desc_id); msdu_id = FIELD_GET(DP_TX_DESC_ID_MSDU_ID, desc_id); - if (ts.buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW) { + if (unlikely(ts.buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW)) { ath11k_dp_tx_process_htt_tx_complete(ab, (void *)tx_status, mac_id, msdu_id, @@ -588,16 +581,16 @@ void ath11k_dp_tx_completion_handler(struct ath11k_base *ab, int ring_id) continue; } - spin_lock_bh(&tx_ring->tx_idr_lock); - msdu = idr_find(&tx_ring->txbuf_idr, msdu_id); - if (!msdu) { + spin_lock(&tx_ring->tx_idr_lock); + msdu = idr_remove(&tx_ring->txbuf_idr, msdu_id); + if (unlikely(!msdu)) { ath11k_warn(ab, "tx completion for unknown msdu_id %d\n", msdu_id); - spin_unlock_bh(&tx_ring->tx_idr_lock); + spin_unlock(&tx_ring->tx_idr_lock); continue; } - idr_remove(&tx_ring->txbuf_idr, msdu_id); - spin_unlock_bh(&tx_ring->tx_idr_lock); + + spin_unlock(&tx_ring->tx_idr_lock); ar = ab->pdevs[mac_id].ar; @@ -903,7 +896,7 @@ int ath11k_dp_tx_htt_h2t_ppdu_stats_req(struct ath11k *ar, u32 mask) cmd->msg = FIELD_PREP(HTT_PPDU_STATS_CFG_MSG_TYPE, HTT_H2T_MSG_TYPE_PPDU_STATS_CFG); - pdev_mask = 1 << (i + 1); + pdev_mask = 1 << (ar->pdev_idx + i); cmd->msg |= FIELD_PREP(HTT_PPDU_STATS_CFG_PDEV_ID, pdev_mask); cmd->msg |= FIELD_PREP(HTT_PPDU_STATS_CFG_TLV_TYPE_BITMASK, mask); @@ -993,6 +986,7 @@ ath11k_dp_tx_htt_h2t_ext_stats_req(struct ath11k *ar, u8 type, struct ath11k_dp *dp = &ab->dp; struct sk_buff *skb; struct htt_ext_stats_cfg_cmd *cmd; + u32 pdev_id; int len = sizeof(*cmd); int ret; @@ -1006,7 +1000,12 @@ ath11k_dp_tx_htt_h2t_ext_stats_req(struct ath11k *ar, u8 type, memset(cmd, 0, sizeof(*cmd)); cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_EXT_STATS_CFG; - cmd->hdr.pdev_mask = 1 << ar->pdev->pdev_id; + if (ab->hw_params.single_pdev_only) + pdev_id = ath11k_mac_get_target_pdev_id(ar); + else + pdev_id = ar->pdev->pdev_id; + + cmd->hdr.pdev_mask = 1 << pdev_id; cmd->hdr.stats_type = type; cmd->cfg_param0 = cfg_params->cfg0; @@ -1034,6 +1033,15 @@ int ath11k_dp_tx_htt_monitor_mode_ring_config(struct ath11k *ar, bool reset) struct htt_rx_ring_tlv_filter tlv_filter = {0}; int ret = 0, ring_id = 0, i; + if (ab->hw_params.full_monitor_mode) { + ret = ath11k_dp_tx_htt_rx_full_mon_setup(ab, + dp->mac_id, !reset); + if (ret < 0) { + ath11k_err(ab, "failed to setup full monitor %d\n", ret); + return ret; + } + } + ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id; if (!reset) { @@ -1099,3 +1107,42 @@ int ath11k_dp_tx_htt_monitor_mode_ring_config(struct ath11k *ar, bool reset) return ret; } + +int ath11k_dp_tx_htt_rx_full_mon_setup(struct ath11k_base *ab, int mac_id, + bool config) +{ + struct htt_rx_full_monitor_mode_cfg_cmd *cmd; + struct sk_buff *skb; + int ret, len = sizeof(*cmd); + + skb = ath11k_htc_alloc_skb(ab, len); + if (!skb) + return -ENOMEM; + + skb_put(skb, len); + cmd = (struct htt_rx_full_monitor_mode_cfg_cmd *)skb->data; + memset(cmd, 0, sizeof(*cmd)); + cmd->info0 = FIELD_PREP(HTT_RX_FULL_MON_MODE_CFG_CMD_INFO0_MSG_TYPE, + HTT_H2T_MSG_TYPE_RX_FULL_MONITOR_MODE); + + cmd->info0 |= FIELD_PREP(HTT_RX_FULL_MON_MODE_CFG_CMD_INFO0_PDEV_ID, mac_id); + + cmd->cfg = HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_ENABLE | + FIELD_PREP(HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_RELEASE_RING, + HTT_RX_MON_RING_SW); + if (config) { + cmd->cfg |= HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_ZERO_MPDUS_END | + HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_NON_ZERO_MPDUS_END; + } + + ret = ath11k_htc_send(&ab->htc, ab->dp.eid, skb); + if (ret) + goto err_free; + + return 0; + +err_free: + dev_kfree_skb_any(skb); + + return ret; +} diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.h b/drivers/net/wireless/ath/ath11k/dp_tx.h index 698b907b878d..e373dbccf417 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.h +++ b/drivers/net/wireless/ath/ath11k/dp_tx.h @@ -37,4 +37,6 @@ int ath11k_dp_tx_htt_rx_filter_setup(struct ath11k_base *ab, u32 ring_id, int rx_buf_size, struct htt_rx_ring_tlv_filter *tlv_filter); +int ath11k_dp_tx_htt_rx_full_mon_setup(struct ath11k_base *ab, int mac_id, + bool config); #endif diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index eaa0edca5576..2ec09ae90080 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -627,6 +627,21 @@ u32 *ath11k_hal_srng_dst_peek(struct ath11k_base *ab, struct hal_srng *srng) return NULL; } +static void ath11k_hal_srng_prefetch_desc(struct ath11k_base *ab, + struct hal_srng *srng) +{ + u32 *desc; + + /* prefetch only if desc is available */ + desc = ath11k_hal_srng_dst_peek(ab, srng); + if (likely(desc)) { + dma_sync_single_for_cpu(ab->dev, virt_to_phys(desc), + (srng->entry_size * sizeof(u32)), + DMA_FROM_DEVICE); + prefetch(desc); + } +} + u32 *ath11k_hal_srng_dst_get_next_entry(struct ath11k_base *ab, struct hal_srng *srng) { @@ -639,8 +654,15 @@ u32 *ath11k_hal_srng_dst_get_next_entry(struct ath11k_base *ab, desc = srng->ring_base_vaddr + srng->u.dst_ring.tp; - srng->u.dst_ring.tp = (srng->u.dst_ring.tp + srng->entry_size) % - srng->ring_size; + srng->u.dst_ring.tp += srng->entry_size; + + /* wrap around to start of ring*/ + if (srng->u.dst_ring.tp == srng->ring_size) + srng->u.dst_ring.tp = 0; + + /* Try to prefetch the next descriptor in the ring */ + if (srng->flags & HAL_SRNG_FLAGS_CACHED) + ath11k_hal_srng_prefetch_desc(ab, srng); return desc; } @@ -775,11 +797,16 @@ void ath11k_hal_srng_access_begin(struct ath11k_base *ab, struct hal_srng *srng) { lockdep_assert_held(&srng->lock); - if (srng->ring_dir == HAL_SRNG_DIR_SRC) + if (srng->ring_dir == HAL_SRNG_DIR_SRC) { srng->u.src_ring.cached_tp = *(volatile u32 *)srng->u.src_ring.tp_addr; - else + } else { srng->u.dst_ring.cached_hp = *srng->u.dst_ring.hp_addr; + + /* Try to prefetch the next descriptor in the ring */ + if (srng->flags & HAL_SRNG_FLAGS_CACHED) + ath11k_hal_srng_prefetch_desc(ab, srng); + } } /* Update cached ring head/tail pointers to HW. ath11k_hal_srng_access_begin() @@ -947,6 +974,7 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type, srng->msi_data = params->msi_data; srng->initialized = 1; spin_lock_init(&srng->lock); + lockdep_set_class(&srng->lock, hal->srng_key + ring_id); for (i = 0; i < HAL_SRNG_NUM_REG_GRP; i++) { srng->hwreg_base[i] = srng_config->reg_start[i] + @@ -1233,6 +1261,24 @@ static int ath11k_hal_srng_create_config(struct ath11k_base *ab) return 0; } +static void ath11k_hal_register_srng_key(struct ath11k_base *ab) +{ + struct ath11k_hal *hal = &ab->hal; + u32 ring_id; + + for (ring_id = 0; ring_id < HAL_SRNG_RING_ID_MAX; ring_id++) + lockdep_register_key(hal->srng_key + ring_id); +} + +static void ath11k_hal_unregister_srng_key(struct ath11k_base *ab) +{ + struct ath11k_hal *hal = &ab->hal; + u32 ring_id; + + for (ring_id = 0; ring_id < HAL_SRNG_RING_ID_MAX; ring_id++) + lockdep_unregister_key(hal->srng_key + ring_id); +} + int ath11k_hal_srng_init(struct ath11k_base *ab) { struct ath11k_hal *hal = &ab->hal; @@ -1252,6 +1298,8 @@ int ath11k_hal_srng_init(struct ath11k_base *ab) if (ret) goto err_free_cont_rdp; + ath11k_hal_register_srng_key(ab); + return 0; err_free_cont_rdp: @@ -1266,6 +1314,7 @@ void ath11k_hal_srng_deinit(struct ath11k_base *ab) { struct ath11k_hal *hal = &ab->hal; + ath11k_hal_unregister_srng_key(ab); ath11k_hal_free_cont_rdp(ab); ath11k_hal_free_cont_wrp(ab); kfree(hal->srng_config); diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h index 35ed3a14e200..a7d9b4c551ad 100644 --- a/drivers/net/wireless/ath/ath11k/hal.h +++ b/drivers/net/wireless/ath/ath11k/hal.h @@ -513,6 +513,7 @@ enum hal_srng_dir { #define HAL_SRNG_FLAGS_DATA_TLV_SWAP 0x00000020 #define HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN 0x00010000 #define HAL_SRNG_FLAGS_MSI_INTR 0x00020000 +#define HAL_SRNG_FLAGS_CACHED 0x20000000 #define HAL_SRNG_FLAGS_LMAC_RING 0x80000000 #define HAL_SRNG_TLV_HDR_TAG GENMASK(9, 1) @@ -901,6 +902,8 @@ struct ath11k_hal { /* shadow register configuration */ u32 shadow_reg_addr[HAL_SHADOW_NUM_REGS]; int num_shadow_reg_configured; + + struct lock_class_key srng_key[HAL_SRNG_RING_ID_MAX]; }; u32 ath11k_hal_reo_qdesc_size(u32 ba_window_size, u8 tid); diff --git a/drivers/net/wireless/ath/ath11k/hal_desc.h b/drivers/net/wireless/ath/ath11k/hal_desc.h index 00b595b84939..406767672844 100644 --- a/drivers/net/wireless/ath/ath11k/hal_desc.h +++ b/drivers/net/wireless/ath/ath11k/hal_desc.h @@ -858,6 +858,25 @@ struct hal_reo_entrance_ring { * this ring has looped around the ring. */ +#define HAL_SW_MON_RING_INFO0_RXDMA_PUSH_REASON GENMASK(1, 0) +#define HAL_SW_MON_RING_INFO0_RXDMA_ERROR_CODE GENMASK(6, 2) +#define HAL_SW_MON_RING_INFO0_MPDU_FRAG_NUMBER GENMASK(10, 7) +#define HAL_SW_MON_RING_INFO0_FRAMELESS_BAR BIT(11) +#define HAL_SW_MON_RING_INFO0_STATUS_BUF_CNT GENMASK(15, 12) +#define HAL_SW_MON_RING_INFO0_END_OF_PPDU BIT(16) + +#define HAL_SW_MON_RING_INFO1_PHY_PPDU_ID GENMASK(15, 0) +#define HAL_SW_MON_RING_INFO1_RING_ID GENMASK(27, 20) +#define HAL_SW_MON_RING_INFO1_LOOPING_COUNT GENMASK(31, 28) + +struct hal_sw_monitor_ring { + struct ath11k_buffer_addr buf_addr_info; + struct rx_mpdu_desc rx_mpdu_info; + struct ath11k_buffer_addr status_buf_addr_info; + u32 info0; + u32 info1; +} __packed; + #define HAL_REO_CMD_HDR_INFO0_CMD_NUMBER GENMASK(15, 0) #define HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED BIT(16) diff --git a/drivers/net/wireless/ath/ath11k/hal_rx.c b/drivers/net/wireless/ath/ath11k/hal_rx.c index 329c404cfa80..1e279e99baa8 100644 --- a/drivers/net/wireless/ath/ath11k/hal_rx.c +++ b/drivers/net/wireless/ath/ath11k/hal_rx.c @@ -29,8 +29,7 @@ static int ath11k_hal_reo_cmd_queue_stats(struct hal_tlv_hdr *tlv, FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc)); desc = (struct hal_reo_get_queue_stats *)tlv->value; - memset(&desc->queue_addr_lo, 0, - (sizeof(*desc) - sizeof(struct hal_reo_cmd_hdr))); + memset_startat(desc, 0, queue_addr_lo); desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED; if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS) @@ -62,8 +61,7 @@ static int ath11k_hal_reo_cmd_flush_cache(struct ath11k_hal *hal, struct hal_tlv FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc)); desc = (struct hal_reo_flush_cache *)tlv->value; - memset(&desc->cache_addr_lo, 0, - (sizeof(*desc) - sizeof(struct hal_reo_cmd_hdr))); + memset_startat(desc, 0, cache_addr_lo); desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED; if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS) @@ -101,8 +99,7 @@ static int ath11k_hal_reo_cmd_update_rx_queue(struct hal_tlv_hdr *tlv, FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc)); desc = (struct hal_reo_update_rx_queue *)tlv->value; - memset(&desc->queue_addr_lo, 0, - (sizeof(*desc) - sizeof(struct hal_reo_cmd_hdr))); + memset_startat(desc, 0, queue_addr_lo); desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED; if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS) @@ -764,15 +761,17 @@ void ath11k_hal_reo_qdesc_setup(void *vaddr, int tid, u32 ba_window_size, * size changes and also send WMI message to FW to change the REO * queue descriptor in Rx peer entry as part of dp_rx_tid_update. */ - memset(ext_desc, 0, 3 * sizeof(*ext_desc)); + memset(ext_desc, 0, sizeof(*ext_desc)); ath11k_hal_reo_set_desc_hdr(&ext_desc->desc_hdr, HAL_DESC_REO_OWNED, HAL_DESC_REO_QUEUE_EXT_DESC, REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_1); ext_desc++; + memset(ext_desc, 0, sizeof(*ext_desc)); ath11k_hal_reo_set_desc_hdr(&ext_desc->desc_hdr, HAL_DESC_REO_OWNED, HAL_DESC_REO_QUEUE_EXT_DESC, REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_2); ext_desc++; + memset(ext_desc, 0, sizeof(*ext_desc)); ath11k_hal_reo_set_desc_hdr(&ext_desc->desc_hdr, HAL_DESC_REO_OWNED, HAL_DESC_REO_QUEUE_EXT_DESC, REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_3); @@ -1186,3 +1185,47 @@ void ath11k_hal_rx_reo_ent_buf_paddr_get(void *rx_desc, dma_addr_t *paddr, *pp_buf_addr = (void *)buf_addr_info; } + +void +ath11k_hal_rx_sw_mon_ring_buf_paddr_get(void *rx_desc, + struct hal_sw_mon_ring_entries *sw_mon_entries) +{ + struct hal_sw_monitor_ring *sw_mon_ring = rx_desc; + struct ath11k_buffer_addr *buf_addr_info; + struct ath11k_buffer_addr *status_buf_addr_info; + struct rx_mpdu_desc *rx_mpdu_desc_info_details; + + rx_mpdu_desc_info_details = &sw_mon_ring->rx_mpdu_info; + + sw_mon_entries->msdu_cnt = FIELD_GET(RX_MPDU_DESC_INFO0_MSDU_COUNT, + rx_mpdu_desc_info_details->info0); + + buf_addr_info = &sw_mon_ring->buf_addr_info; + status_buf_addr_info = &sw_mon_ring->status_buf_addr_info; + + sw_mon_entries->mon_dst_paddr = (((u64)FIELD_GET(BUFFER_ADDR_INFO1_ADDR, + buf_addr_info->info1)) << 32) | + FIELD_GET(BUFFER_ADDR_INFO0_ADDR, + buf_addr_info->info0); + + sw_mon_entries->mon_status_paddr = + (((u64)FIELD_GET(BUFFER_ADDR_INFO1_ADDR, + status_buf_addr_info->info1)) << 32) | + FIELD_GET(BUFFER_ADDR_INFO0_ADDR, + status_buf_addr_info->info0); + + sw_mon_entries->mon_dst_sw_cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, + buf_addr_info->info1); + + sw_mon_entries->mon_status_sw_cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, + status_buf_addr_info->info1); + + sw_mon_entries->status_buf_count = FIELD_GET(HAL_SW_MON_RING_INFO0_STATUS_BUF_CNT, + sw_mon_ring->info0); + + sw_mon_entries->dst_buf_addr_info = buf_addr_info; + sw_mon_entries->status_buf_addr_info = status_buf_addr_info; + + sw_mon_entries->ppdu_id = + FIELD_GET(HAL_SW_MON_RING_INFO1_PHY_PPDU_ID, sw_mon_ring->info1); +} diff --git a/drivers/net/wireless/ath/ath11k/hal_rx.h b/drivers/net/wireless/ath/ath11k/hal_rx.h index 0f1f04b812b9..8db420ef6351 100644 --- a/drivers/net/wireless/ath/ath11k/hal_rx.h +++ b/drivers/net/wireless/ath/ath11k/hal_rx.h @@ -77,6 +77,20 @@ enum hal_rx_mon_status { HAL_RX_MON_STATUS_BUF_DONE, }; +struct hal_sw_mon_ring_entries { + dma_addr_t mon_dst_paddr; + dma_addr_t mon_status_paddr; + u32 mon_dst_sw_cookie; + u32 mon_status_sw_cookie; + void *dst_buf_addr_info; + void *status_buf_addr_info; + u16 ppdu_id; + u8 status_buf_count; + u8 msdu_cnt; + bool end_of_ppdu; + bool drop_ppdu; +}; + struct hal_rx_mon_ppdu_info { u32 ppdu_id; u32 ppdu_ts; @@ -331,6 +345,9 @@ void ath11k_hal_rx_reo_ent_buf_paddr_get(void *rx_desc, dma_addr_t *paddr, u32 *sw_cookie, void **pp_buf_addr_info, u8 *rbm, u32 *msdu_cnt); +void +ath11k_hal_rx_sw_mon_ring_buf_paddr_get(void *rx_desc, + struct hal_sw_mon_ring_entries *sw_mon_ent); enum hal_rx_mon_status ath11k_hal_rx_parse_mon_status(struct ath11k_base *ab, struct hal_rx_mon_ppdu_info *ppdu_info, diff --git a/drivers/net/wireless/ath/ath11k/htc.c b/drivers/net/wireless/ath/ath11k/htc.c index 54b1d34724d7..6913b7494b9b 100644 --- a/drivers/net/wireless/ath/ath11k/htc.c +++ b/drivers/net/wireless/ath/ath11k/htc.c @@ -81,6 +81,8 @@ int ath11k_htc_send(struct ath11k_htc *htc, struct ath11k_base *ab = htc->ab; int credits = 0; int ret; + bool credit_flow_enabled = (ab->hw_params.credit_flow && + ep->tx_credit_flow_enabled); if (eid >= ATH11K_HTC_EP_COUNT) { ath11k_warn(ab, "Invalid endpoint id: %d\n", eid); @@ -89,7 +91,7 @@ int ath11k_htc_send(struct ath11k_htc *htc, skb_push(skb, sizeof(struct ath11k_htc_hdr)); - if (ep->tx_credit_flow_enabled) { + if (credit_flow_enabled) { credits = DIV_ROUND_UP(skb->len, htc->target_credit_size); spin_lock_bh(&htc->tx_lock); if (ep->tx_credits < credits) { @@ -126,7 +128,7 @@ int ath11k_htc_send(struct ath11k_htc *htc, err_unmap: dma_unmap_single(dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE); err_credits: - if (ep->tx_credit_flow_enabled) { + if (credit_flow_enabled) { spin_lock_bh(&htc->tx_lock); ep->tx_credits += credits; ath11k_dbg(ab, ATH11K_DBG_HTC, @@ -203,23 +205,25 @@ static int ath11k_htc_process_trailer(struct ath11k_htc *htc, break; } - switch (record->hdr.id) { - case ATH11K_HTC_RECORD_CREDITS: - len = sizeof(struct ath11k_htc_credit_report); - if (record->hdr.len < len) { - ath11k_warn(ab, "Credit report too long\n"); - status = -EINVAL; + if (ab->hw_params.credit_flow) { + switch (record->hdr.id) { + case ATH11K_HTC_RECORD_CREDITS: + len = sizeof(struct ath11k_htc_credit_report); + if (record->hdr.len < len) { + ath11k_warn(ab, "Credit report too long\n"); + status = -EINVAL; + break; + } + ath11k_htc_process_credit_report(htc, + record->credit_report, + record->hdr.len, + src_eid); + break; + default: + ath11k_warn(ab, "Unhandled record: id:%d length:%d\n", + record->hdr.id, record->hdr.len); break; } - ath11k_htc_process_credit_report(htc, - record->credit_report, - record->hdr.len, - src_eid); - break; - default: - ath11k_warn(ab, "Unhandled record: id:%d length:%d\n", - record->hdr.id, record->hdr.len); - break; } if (status) @@ -245,6 +249,29 @@ static void ath11k_htc_suspend_complete(struct ath11k_base *ab, bool ack) complete(&ab->htc_suspend); } +void ath11k_htc_tx_completion_handler(struct ath11k_base *ab, + struct sk_buff *skb) +{ + struct ath11k_htc *htc = &ab->htc; + struct ath11k_htc_ep *ep; + void (*ep_tx_complete)(struct ath11k_base *, struct sk_buff *); + u8 eid; + + eid = ATH11K_SKB_CB(skb)->eid; + if (eid >= ATH11K_HTC_EP_COUNT) + return; + + ep = &htc->endpoint[eid]; + spin_lock_bh(&htc->tx_lock); + ep_tx_complete = ep->ep_ops.ep_tx_complete; + spin_unlock_bh(&htc->tx_lock); + if (!ep_tx_complete) { + dev_kfree_skb_any(skb); + return; + } + ep_tx_complete(htc->ab, skb); +} + void ath11k_htc_rx_completion_handler(struct ath11k_base *ab, struct sk_buff *skb) { @@ -607,6 +634,11 @@ int ath11k_htc_connect_service(struct ath11k_htc *htc, disable_credit_flow_ctrl = true; } + if (!ab->hw_params.credit_flow) { + flags |= ATH11K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL; + disable_credit_flow_ctrl = true; + } + req_msg->flags_len = FIELD_PREP(HTC_SVC_MSG_CONNECTIONFLAGS, flags); req_msg->msg_svc_id |= FIELD_PREP(HTC_SVC_MSG_SERVICE_ID, conn_req->service_id); @@ -732,7 +764,10 @@ int ath11k_htc_start(struct ath11k_htc *htc) msg->msg_id = FIELD_PREP(HTC_MSG_MESSAGEID, ATH11K_HTC_MSG_SETUP_COMPLETE_EX_ID); - ath11k_dbg(ab, ATH11K_DBG_HTC, "HTC is using TX credit flow control\n"); + if (ab->hw_params.credit_flow) + ath11k_dbg(ab, ATH11K_DBG_HTC, "HTC is using TX credit flow control\n"); + else + msg->flags |= ATH11K_GLOBAL_DISABLE_CREDIT_FLOW; status = ath11k_htc_send(htc, ATH11K_HTC_EP_0, skb); if (status) { diff --git a/drivers/net/wireless/ath/ath11k/htc.h b/drivers/net/wireless/ath/ath11k/htc.h index 6c8a469d7f9d..f429b37cfdf7 100644 --- a/drivers/net/wireless/ath/ath11k/htc.h +++ b/drivers/net/wireless/ath/ath11k/htc.h @@ -83,8 +83,8 @@ enum ath11k_htc_conn_flags { ATH11K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_ONE_HALF = 0x1, ATH11K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_THREE_FOURTHS = 0x2, ATH11K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_UNITY = 0x3, - ATH11K_HTC_CONN_FLAGS_REDUCE_CREDIT_DRIBBLE = 1 << 2, - ATH11K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL = 1 << 3 + ATH11K_HTC_CONN_FLAGS_REDUCE_CREDIT_DRIBBLE = 0x4, + ATH11K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL = 0x8, }; enum ath11k_htc_conn_svc_status { @@ -116,6 +116,8 @@ struct ath11k_htc_conn_svc_resp { u32 svc_meta_pad; } __packed; +#define ATH11K_GLOBAL_DISABLE_CREDIT_FLOW BIT(1) + struct ath11k_htc_setup_complete_extended { u32 msg_id; u32 flags; @@ -305,5 +307,6 @@ int ath11k_htc_send(struct ath11k_htc *htc, enum ath11k_htc_ep_id eid, struct sk_buff *ath11k_htc_alloc_skb(struct ath11k_base *ar, int size); void ath11k_htc_rx_completion_handler(struct ath11k_base *ar, struct sk_buff *skb); - +void ath11k_htc_tx_completion_handler(struct ath11k_base *ab, + struct sk_buff *skb); #endif diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index da35fcf5bc56..3b0fdc1a6b3f 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -150,18 +150,18 @@ static void ath11k_hw_ipq8074_reo_setup(struct ath11k_base *ab) static void ath11k_init_wmi_config_ipq8074(struct ath11k_base *ab, struct target_resource_config *config) { - config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS; + config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS(ab); if (ab->num_radios == 2) { - config->num_peers = TARGET_NUM_PEERS(DBS); - config->num_tids = TARGET_NUM_TIDS(DBS); + config->num_peers = TARGET_NUM_PEERS(ab, DBS); + config->num_tids = TARGET_NUM_TIDS(ab, DBS); } else if (ab->num_radios == 3) { - config->num_peers = TARGET_NUM_PEERS(DBS_SBS); - config->num_tids = TARGET_NUM_TIDS(DBS_SBS); + config->num_peers = TARGET_NUM_PEERS(ab, DBS_SBS); + config->num_tids = TARGET_NUM_TIDS(ab, DBS_SBS); } else { /* Control should not reach here */ - config->num_peers = TARGET_NUM_PEERS(SINGLE); - config->num_tids = TARGET_NUM_TIDS(SINGLE); + config->num_peers = TARGET_NUM_PEERS(ab, SINGLE); + config->num_tids = TARGET_NUM_TIDS(ab, SINGLE); } config->num_offload_peers = TARGET_NUM_OFFLD_PEERS; config->num_offload_reorder_buffs = TARGET_NUM_OFFLD_REORDER_BUFFS; @@ -1061,8 +1061,6 @@ const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq8074 = { const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qca6390 = { .tx = { ATH11K_TX_RING_MASK_0, - ATH11K_TX_RING_MASK_1, - ATH11K_TX_RING_MASK_2, }, .rx_mon_status = { 0, 0, 0, 0, diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 19223d36846e..23f3ce741636 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -12,26 +12,26 @@ /* Target configuration defines */ /* Num VDEVS per radio */ -#define TARGET_NUM_VDEVS (16 + 1) +#define TARGET_NUM_VDEVS(ab) (ab->hw_params.num_vdevs) -#define TARGET_NUM_PEERS_PDEV (512 + TARGET_NUM_VDEVS) +#define TARGET_NUM_PEERS_PDEV(ab) (ab->hw_params.num_peers + TARGET_NUM_VDEVS(ab)) /* Num of peers for Single Radio mode */ -#define TARGET_NUM_PEERS_SINGLE (TARGET_NUM_PEERS_PDEV) +#define TARGET_NUM_PEERS_SINGLE(ab) (TARGET_NUM_PEERS_PDEV(ab)) /* Num of peers for DBS */ -#define TARGET_NUM_PEERS_DBS (2 * TARGET_NUM_PEERS_PDEV) +#define TARGET_NUM_PEERS_DBS(ab) (2 * TARGET_NUM_PEERS_PDEV(ab)) /* Num of peers for DBS_SBS */ -#define TARGET_NUM_PEERS_DBS_SBS (3 * TARGET_NUM_PEERS_PDEV) +#define TARGET_NUM_PEERS_DBS_SBS(ab) (3 * TARGET_NUM_PEERS_PDEV(ab)) /* Max num of stations (per radio) */ -#define TARGET_NUM_STATIONS 512 +#define TARGET_NUM_STATIONS(ab) (ab->hw_params.num_peers) -#define TARGET_NUM_PEERS(x) TARGET_NUM_PEERS_##x +#define TARGET_NUM_PEERS(ab, x) TARGET_NUM_PEERS_##x(ab) #define TARGET_NUM_PEER_KEYS 2 -#define TARGET_NUM_TIDS(x) (2 * TARGET_NUM_PEERS(x) + \ - 4 * TARGET_NUM_VDEVS + 8) +#define TARGET_NUM_TIDS(ab, x) (2 * TARGET_NUM_PEERS(ab, x) + \ + 4 * TARGET_NUM_VDEVS(ab) + 8) #define TARGET_AST_SKID_LIMIT 16 #define TARGET_NUM_OFFLD_PEERS 4 @@ -168,14 +168,23 @@ struct ath11k_hw_params { u16 interface_modes; bool supports_monitor; + bool full_monitor_mode; bool supports_shadow_regs; bool idle_ps; + bool supports_sta_ps; bool cold_boot_calib; + int fw_mem_mode; + u32 num_vdevs; + u32 num_peers; bool supports_suspend; u32 hal_desc_sz; bool fix_l1ss; + bool credit_flow; u8 max_tx_ring; const struct ath11k_hw_hal_params *hal_params; + bool supports_dynamic_smps_6ghz; + bool alloc_cacheable_memory; + bool wakeup_mhi; }; struct ath11k_hw_ops { diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 1cc55602787b..2bc93456b34e 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <net/mac80211.h> @@ -553,6 +554,67 @@ struct ath11k *ath11k_mac_get_ar_by_pdev_id(struct ath11k_base *ab, u32 pdev_id) return NULL; } +struct ath11k_vif *ath11k_mac_get_vif_up(struct ath11k_base *ab) +{ + struct ath11k *ar; + struct ath11k_pdev *pdev; + struct ath11k_vif *arvif; + int i; + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + ar = pdev->ar; + list_for_each_entry(arvif, &ar->arvifs, list) { + if (arvif->is_up) + return arvif; + } + } + + return NULL; +} + +static bool ath11k_mac_band_match(enum nl80211_band band1, enum WMI_HOST_WLAN_BAND band2) +{ + return (((band1 == NL80211_BAND_2GHZ) && (band2 & WMI_HOST_WLAN_2G_CAP)) || + (((band1 == NL80211_BAND_5GHZ) || (band1 == NL80211_BAND_6GHZ)) && + (band2 & WMI_HOST_WLAN_5G_CAP))); +} + +u8 ath11k_mac_get_target_pdev_id_from_vif(struct ath11k_vif *arvif) +{ + struct ath11k *ar = arvif->ar; + struct ath11k_base *ab = ar->ab; + struct ieee80211_vif *vif = arvif->vif; + struct cfg80211_chan_def def; + enum nl80211_band band; + u8 pdev_id = ab->target_pdev_ids[0].pdev_id; + int i; + + if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) + return pdev_id; + + band = def.chan->band; + + for (i = 0; i < ab->target_pdev_count; i++) { + if (ath11k_mac_band_match(band, ab->target_pdev_ids[i].supported_bands)) + return ab->target_pdev_ids[i].pdev_id; + } + + return pdev_id; +} + +u8 ath11k_mac_get_target_pdev_id(struct ath11k *ar) +{ + struct ath11k_vif *arvif; + + arvif = ath11k_mac_get_vif_up(ar->ab); + + if (arvif) + return ath11k_mac_get_target_pdev_id_from_vif(arvif); + else + return ar->ab->target_pdev_ids[0].pdev_id; +} + static void ath11k_pdev_caps_update(struct ath11k *ar) { struct ath11k_base *ab = ar->ab; @@ -775,9 +837,9 @@ static int ath11k_mac_monitor_vdev_start(struct ath11k *ar, int vdev_id, arg.channel.chan_radar = !!(channel->flags & IEEE80211_CHAN_RADAR); arg.channel.min_power = 0; - arg.channel.max_power = channel->max_power * 2; - arg.channel.max_reg_power = channel->max_reg_power * 2; - arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; + arg.channel.max_power = channel->max_power; + arg.channel.max_reg_power = channel->max_reg_power; + arg.channel.max_antenna_gain = channel->max_antenna_gain; arg.pref_tx_streams = ar->num_tx_chains; arg.pref_rx_streams = ar->num_rx_chains; @@ -1049,6 +1111,83 @@ static int ath11k_mac_monitor_stop(struct ath11k *ar) return 0; } +static int ath11k_mac_vif_setup_ps(struct ath11k_vif *arvif) +{ + struct ath11k *ar = arvif->ar; + struct ieee80211_vif *vif = arvif->vif; + struct ieee80211_conf *conf = &ar->hw->conf; + enum wmi_sta_powersave_param param; + enum wmi_sta_ps_mode psmode; + int ret; + int timeout; + bool enable_ps; + + lockdep_assert_held(&arvif->ar->conf_mutex); + + if (arvif->vif->type != NL80211_IFTYPE_STATION) + return 0; + + enable_ps = arvif->ps; + + if (!arvif->is_started) { + /* mac80211 can update vif powersave state while disconnected. + * Firmware doesn't behave nicely and consumes more power than + * necessary if PS is disabled on a non-started vdev. Hence + * force-enable PS for non-running vdevs. + */ + psmode = WMI_STA_PS_MODE_ENABLED; + } else if (enable_ps) { + psmode = WMI_STA_PS_MODE_ENABLED; + param = WMI_STA_PS_PARAM_INACTIVITY_TIME; + + timeout = conf->dynamic_ps_timeout; + if (timeout == 0) { + /* firmware doesn't like 0 */ + timeout = ieee80211_tu_to_usec(vif->bss_conf.beacon_int) / 1000; + } + + ret = ath11k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, + timeout); + if (ret) { + ath11k_warn(ar->ab, "failed to set inactivity time for vdev %d: %i\n", + arvif->vdev_id, ret); + return ret; + } + } else { + psmode = WMI_STA_PS_MODE_DISABLED; + } + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev %d psmode %s\n", + arvif->vdev_id, psmode ? "enable" : "disable"); + + ret = ath11k_wmi_pdev_set_ps_mode(ar, arvif->vdev_id, psmode); + if (ret) { + ath11k_warn(ar->ab, "failed to set sta power save mode %d for vdev %d: %d\n", + psmode, arvif->vdev_id, ret); + return ret; + } + + return 0; +} + +static int ath11k_mac_config_ps(struct ath11k *ar) +{ + struct ath11k_vif *arvif; + int ret = 0; + + lockdep_assert_held(&ar->conf_mutex); + + list_for_each_entry(arvif, &ar->arvifs, list) { + ret = ath11k_mac_vif_setup_ps(arvif); + if (ret) { + ath11k_warn(ar->ab, "failed to setup powersave: %d\n", ret); + break; + } + } + + return ret; +} + static int ath11k_mac_op_config(struct ieee80211_hw *hw, u32 changed) { struct ath11k *ar = hw->priv; @@ -1137,11 +1276,15 @@ static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) if (cfg80211_find_ie(WLAN_EID_RSN, ies, (skb_tail_pointer(bcn) - ies))) arvif->rsnie_present = true; + else + arvif->rsnie_present = false; if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, WLAN_OUI_TYPE_MICROSOFT_WPA, ies, (skb_tail_pointer(bcn) - ies))) arvif->wpaie_present = true; + else + arvif->wpaie_present = false; ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn); @@ -1154,6 +1297,26 @@ static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) return ret; } +void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif) +{ + struct ieee80211_vif *vif = arvif->vif; + + if (!vif->color_change_active && !arvif->bcca_zero_sent) + return; + + if (vif->color_change_active && ieee80211_beacon_cntdwn_is_complete(vif)) { + arvif->bcca_zero_sent = true; + ieee80211_color_change_finish(vif); + return; + } + + arvif->bcca_zero_sent = false; + + if (vif->color_change_active) + ieee80211_beacon_update_cntdwn(vif); + ath11k_mac_setup_bcn_tmpl(arvif); +} + static void ath11k_control_beaconing(struct ath11k_vif *arvif, struct ieee80211_bss_conf *info) { @@ -1819,7 +1982,6 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, struct ath11k_vif *arvif = (void *)vif->drv_priv; struct cfg80211_chan_def def; const struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; - u8 ampdu_factor; enum nl80211_band band; u16 *he_mcs_mask; u8 max_nss, he_mcs; @@ -1827,6 +1989,9 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, int i, he_nss, nss_idx; bool user_rate_valid = true; u32 rx_nss, tx_nss, nss_160; + u8 ampdu_factor, rx_mcs_80, rx_mcs_160; + u16 mcs_160_map, mcs_80_map; + bool support_160; if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) return; @@ -1841,6 +2006,39 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, return; arg->he_flag = true; + support_160 = !!(he_cap->he_cap_elem.phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G); + + /* Supported HE-MCS and NSS Set of peer he_cap is intersection with self he_cp */ + mcs_160_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); + mcs_80_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80); + + if (support_160) { + for (i = 7; i >= 0; i--) { + u8 mcs_160 = (mcs_160_map >> (2 * i)) & 3; + + if (mcs_160 != IEEE80211_VHT_MCS_NOT_SUPPORTED) { + rx_mcs_160 = i + 1; + break; + } + } + } + + for (i = 7; i >= 0; i--) { + u8 mcs_80 = (mcs_80_map >> (2 * i)) & 3; + + if (mcs_80 != IEEE80211_VHT_MCS_NOT_SUPPORTED) { + rx_mcs_80 = i + 1; + break; + } + } + + if (support_160) + max_nss = min(rx_mcs_80, rx_mcs_160); + else + max_nss = rx_mcs_80; + + arg->peer_nss = min(sta->rx_nss, max_nss); memcpy_and_pad(&arg->peer_he_cap_macinfo, sizeof(arg->peer_he_cap_macinfo), @@ -2397,6 +2595,8 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, struct ath11k_vif *arvif = (void *)vif->drv_priv; struct peer_assoc_params peer_arg; struct ieee80211_sta *ap_sta; + struct ath11k_peer *peer; + bool is_auth = false; int ret; lockdep_assert_held(&ar->conf_mutex); @@ -2418,6 +2618,7 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, rcu_read_unlock(); + peer_arg.is_assoc = true; ret = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg); if (ret) { ath11k_warn(ar->ab, "failed to run peer assoc for %pM vdev %i: %d\n", @@ -2458,19 +2659,37 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, "mac vdev %d up (associated) bssid %pM aid %d\n", arvif->vdev_id, bss_conf->bssid, bss_conf->aid); - /* Authorize BSS Peer */ - ret = ath11k_wmi_set_peer_param(ar, arvif->bssid, - arvif->vdev_id, - WMI_PEER_AUTHORIZE, - 1); - if (ret) - ath11k_warn(ar->ab, "Unable to authorize BSS peer: %d\n", ret); + spin_lock_bh(&ar->ab->base_lock); + + peer = ath11k_peer_find(ar->ab, arvif->vdev_id, arvif->bssid); + if (peer && peer->is_authorized) + is_auth = true; + + spin_unlock_bh(&ar->ab->base_lock); + + if (is_auth) { + ret = ath11k_wmi_set_peer_param(ar, arvif->bssid, + arvif->vdev_id, + WMI_PEER_AUTHORIZE, + 1); + if (ret) + ath11k_warn(ar->ab, "Unable to authorize BSS peer: %d\n", ret); + } ret = ath11k_wmi_send_obss_spr_cmd(ar, arvif->vdev_id, &bss_conf->he_obss_pd); if (ret) ath11k_warn(ar->ab, "failed to set vdev %i OBSS PD parameters: %d\n", arvif->vdev_id, ret); + + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + WMI_VDEV_PARAM_DTIM_POLICY, + WMI_DTIM_POLICY_STICK); + if (ret) + ath11k_warn(ar->ab, "failed to set vdev %d dtim policy: %d\n", + arvif->vdev_id, ret); + + ath11k_mac_11d_scan_stop_all(ar->ab); } static void ath11k_bss_disassoc(struct ieee80211_hw *hw, @@ -2805,10 +3024,17 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, "Set staggered beacon mode for VDEV: %d\n", arvif->vdev_id); - ret = ath11k_mac_setup_bcn_tmpl(arvif); - if (ret) - ath11k_warn(ar->ab, "failed to update bcn template: %d\n", - ret); + if (!arvif->do_not_send_tmpl || !arvif->bcca_zero_sent) { + ret = ath11k_mac_setup_bcn_tmpl(arvif); + if (ret) + ath11k_warn(ar->ab, "failed to update bcn template: %d\n", + ret); + } + + if (arvif->bcca_zero_sent) + arvif->do_not_send_tmpl = true; + else + arvif->do_not_send_tmpl = false; } if (changed & (BSS_CHANGED_BEACON_INFO | BSS_CHANGED_BEACON)) { @@ -2942,6 +3168,16 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, ath11k_mac_txpower_recalc(ar); } + if (changed & BSS_CHANGED_PS && + ar->ab->hw_params.supports_sta_ps) { + arvif->ps = vif->bss_conf.ps; + + ret = ath11k_mac_config_ps(ar); + if (ret) + ath11k_warn(ar->ab, "failed to setup ps on vdev %i: %d\n", + arvif->vdev_id, ret); + } + if (changed & BSS_CHANGED_MCAST_RATE && !ath11k_mac_vif_chan(arvif->vif, &def)) { band = def.chan->band; @@ -3009,6 +3245,25 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, if (ret) ath11k_warn(ar->ab, "failed to set bss color collision on vdev %i: %d\n", arvif->vdev_id, ret); + + param_id = WMI_VDEV_PARAM_BSS_COLOR; + if (info->he_bss_color.enabled) + param_value = info->he_bss_color.color << + IEEE80211_HE_OPERATION_BSS_COLOR_OFFSET; + else + param_value = IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED; + + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + param_id, + param_value); + if (ret) + ath11k_warn(ar->ab, + "failed to set bss color param on vdev %i: %d\n", + arvif->vdev_id, ret); + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "bss color param 0x%x set on vdev %i\n", + param_value, arvif->vdev_id); } else if (vif->type == NL80211_IFTYPE_STATION) { ret = ath11k_wmi_send_bss_color_change_enable_cmd(ar, arvif->vdev_id, @@ -3164,6 +3419,7 @@ static int ath11k_start_scan(struct ath11k *ar, struct scan_req_params *arg) { int ret; + unsigned long timeout = 1 * HZ; lockdep_assert_held(&ar->conf_mutex); @@ -3174,7 +3430,14 @@ static int ath11k_start_scan(struct ath11k *ar, if (ret) return ret; - ret = wait_for_completion_timeout(&ar->scan.started, 1 * HZ); + if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map)) { + timeout = 5 * HZ; + + if (ar->supports_6ghz) + timeout += 5 * HZ; + } + + ret = wait_for_completion_timeout(&ar->scan.started, timeout); if (ret == 0) { ret = ath11k_scan_stop(ar); if (ret) @@ -3231,15 +3494,38 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw, if (ret) goto exit; + /* Currently the pending_11d=true only happened 1 time while + * wlan interface up in ath11k_mac_11d_scan_start(), it is called by + * ath11k_mac_op_add_interface(), after wlan interface up, + * pending_11d=false always. + * If remove below wait, it always happened scan fail and lead connect + * fail while wlan interface up, because it has a 11d scan which is running + * in firmware, and lead this scan failed. + */ + if (ar->pending_11d) { + long time_left; + unsigned long timeout = 5 * HZ; + + if (ar->supports_6ghz) + timeout += 5 * HZ; + + time_left = wait_for_completion_timeout(&ar->finish_11d_ch_list, timeout); + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "mac wait 11d channel list time left %ld\n", time_left); + } + memset(&arg, 0, sizeof(arg)); ath11k_wmi_start_scan_init(ar, &arg); arg.vdev_id = arvif->vdev_id; arg.scan_id = ATH11K_SCAN_ID; if (req->ie_len) { + arg.extraie.ptr = kmemdup(req->ie, req->ie_len, GFP_KERNEL); + if (!arg.extraie.ptr) { + ret = -ENOMEM; + goto exit; + } arg.extraie.len = req->ie_len; - arg.extraie.ptr = kzalloc(req->ie_len, GFP_KERNEL); - memcpy(arg.extraie.ptr, req->ie, req->ie_len); } if (req->n_ssids) { @@ -3255,10 +3541,24 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw, if (req->n_channels) { arg.num_chan = req->n_channels; + arg.chan_list = kcalloc(arg.num_chan, sizeof(*arg.chan_list), + GFP_KERNEL); + + if (!arg.chan_list) { + ret = -ENOMEM; + goto exit; + } + for (i = 0; i < arg.num_chan; i++) arg.chan_list[i] = req->channels[i]->center_freq; } + if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { + arg.scan_f_add_spoofed_mac_in_probe = 1; + ether_addr_copy(arg.mac_addr.addr, req->mac_addr); + ether_addr_copy(arg.mac_mask.addr, req->mac_addr_mask); + } + ret = ath11k_start_scan(ar, &arg); if (ret) { ath11k_warn(ar->ab, "failed to start hw scan: %d\n", ret); @@ -3273,6 +3573,8 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw, ATH11K_MAC_SCAN_TIMEOUT_MSECS)); exit: + kfree(arg.chan_list); + if (req->ie_len) kfree(arg.extraie.ptr); @@ -3316,9 +3618,7 @@ static int ath11k_install_key(struct ath11k_vif *arvif, return 0; if (cmd == DISABLE_KEY) { - /* TODO: Check if FW expects value other than NONE for del */ - /* arg.key_cipher = WMI_CIPHER_NONE; */ - arg.key_len = 0; + arg.key_cipher = WMI_CIPHER_NONE; arg.key_data = NULL; goto install; } @@ -3450,7 +3750,7 @@ static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, /* flush the fragments cache during key (re)install to * ensure all frags in the new frag list belong to the same key. */ - if (peer && cmd == SET_KEY) + if (peer && sta && cmd == SET_KEY) ath11k_peer_frags_flush(ar, peer); spin_unlock_bh(&ab->base_lock); @@ -3685,6 +3985,7 @@ static int ath11k_station_assoc(struct ath11k *ar, ath11k_peer_assoc_prepare(ar, vif, sta, &peer_arg, reassoc); + peer_arg.is_assoc = true; ret = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg); if (ret) { ath11k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n", @@ -3824,11 +4125,27 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) ath11k_mac_max_he_nss(he_mcs_mask))); if (changed & IEEE80211_RC_BW_CHANGED) { - err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, - WMI_PEER_CHWIDTH, bw); - if (err) - ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n", - sta->addr, bw, err); + /* Send peer assoc command before set peer bandwidth param to + * avoid the mismatch between the peer phymode and the peer + * bandwidth. + */ + ath11k_peer_assoc_prepare(ar, arvif->vif, sta, &peer_arg, true); + + peer_arg.is_assoc = false; + err = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg); + if (err) { + ath11k_warn(ar->ab, "failed to send peer assoc for STA %pM vdev %i: %d\n", + sta->addr, arvif->vdev_id, err); + } else if (wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ)) { + err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, + WMI_PEER_CHWIDTH, bw); + if (err) + ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n", + sta->addr, bw, err); + } else { + ath11k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n", + sta->addr, arvif->vdev_id); + } } if (changed & IEEE80211_RC_NSS_CHANGED) { @@ -3896,6 +4213,7 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) ath11k_peer_assoc_prepare(ar, arvif->vif, sta, &peer_arg, true); + peer_arg.is_assoc = false; err = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg); if (err) ath11k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n", @@ -4095,6 +4413,10 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, new_state == IEEE80211_STA_NOTEXIST)) { ath11k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr); + if (ar->ab->hw_params.vdev_start_delay && + vif->type == NL80211_IFTYPE_STATION) + goto free; + ret = ath11k_peer_delete(ar, arvif->vdev_id, sta->addr); if (ret) ath11k_warn(ar->ab, "Failed to delete peer: %pM for VDEV: %d\n", @@ -4116,6 +4438,7 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, } spin_unlock_bh(&ar->ab->base_lock); +free: kfree(arsta->tx_stats); arsta->tx_stats = NULL; @@ -4131,6 +4454,34 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, ath11k_warn(ar->ab, "Failed to associate station: %pM\n", sta->addr); } else if (old_state == IEEE80211_STA_ASSOC && + new_state == IEEE80211_STA_AUTHORIZED) { + spin_lock_bh(&ar->ab->base_lock); + + peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr); + if (peer) + peer->is_authorized = true; + + spin_unlock_bh(&ar->ab->base_lock); + + if (vif->type == NL80211_IFTYPE_STATION && arvif->is_up) { + ret = ath11k_wmi_set_peer_param(ar, sta->addr, + arvif->vdev_id, + WMI_PEER_AUTHORIZE, + 1); + if (ret) + ath11k_warn(ar->ab, "Unable to authorize peer %pM vdev %d: %d\n", + sta->addr, arvif->vdev_id, ret); + } + } else if (old_state == IEEE80211_STA_AUTHORIZED && + new_state == IEEE80211_STA_ASSOC) { + spin_lock_bh(&ar->ab->base_lock); + + peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr); + if (peer) + peer->is_authorized = false; + + spin_unlock_bh(&ar->ab->base_lock); + } else if (old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTH && (vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_MESH_POINT || @@ -4561,6 +4912,10 @@ ath11k_create_vht_cap(struct ath11k *ar, u32 rate_cap_tx_chainmask, vht_cap.vht_supported = 1; vht_cap.cap = ar->pdev->cap.vht_cap; + if (ar->pdev->cap.nss_ratio_enabled) + vht_cap.vht_mcs.tx_highest |= + cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); + ath11k_set_vht_txbf_cap(ar, &vht_cap.cap); rxmcs_map = 0; @@ -4926,23 +5281,47 @@ static int __ath11k_set_antenna(struct ath11k *ar, u32 tx_ant, u32 rx_ant) return 0; } -int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx) +static void ath11k_mgmt_over_wmi_tx_drop(struct ath11k *ar, struct sk_buff *skb) { - struct sk_buff *msdu = skb; + int num_mgmt; + + ieee80211_free_txskb(ar->hw, skb); + + num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx); + + if (num_mgmt < 0) + WARN_ON_ONCE(1); + + if (!num_mgmt) + wake_up(&ar->txmgmt_empty_waitq); +} + +static void ath11k_mac_tx_mgmt_free(struct ath11k *ar, int buf_id) +{ + struct sk_buff *msdu; struct ieee80211_tx_info *info; - struct ath11k *ar = ctx; - struct ath11k_base *ab = ar->ab; spin_lock_bh(&ar->txmgmt_idr_lock); - idr_remove(&ar->txmgmt_idr, buf_id); + msdu = idr_remove(&ar->txmgmt_idr, buf_id); spin_unlock_bh(&ar->txmgmt_idr_lock); - dma_unmap_single(ab->dev, ATH11K_SKB_CB(msdu)->paddr, msdu->len, + + if (!msdu) + return; + + dma_unmap_single(ar->ab->dev, ATH11K_SKB_CB(msdu)->paddr, msdu->len, DMA_TO_DEVICE); info = IEEE80211_SKB_CB(msdu); memset(&info->status, 0, sizeof(info->status)); - ieee80211_free_txskb(ar->hw, msdu); + ath11k_mgmt_over_wmi_tx_drop(ar, msdu); +} + +int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx) +{ + struct ath11k *ar = ctx; + + ath11k_mac_tx_mgmt_free(ar, buf_id); return 0; } @@ -4951,17 +5330,10 @@ static int ath11k_mac_vif_txmgmt_idr_remove(int buf_id, void *skb, void *ctx) { struct ieee80211_vif *vif = ctx; struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB((struct sk_buff *)skb); - struct sk_buff *msdu = skb; struct ath11k *ar = skb_cb->ar; - struct ath11k_base *ab = ar->ab; - if (skb_cb->vif == vif) { - spin_lock_bh(&ar->txmgmt_idr_lock); - idr_remove(&ar->txmgmt_idr, buf_id); - spin_unlock_bh(&ar->txmgmt_idr_lock); - dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, - DMA_TO_DEVICE); - } + if (skb_cb->vif == vif) + ath11k_mac_tx_mgmt_free(ar, buf_id); return 0; } @@ -4976,10 +5348,16 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif, int buf_id; int ret; + ATH11K_SKB_CB(skb)->ar = ar; + spin_lock_bh(&ar->txmgmt_idr_lock); buf_id = idr_alloc(&ar->txmgmt_idr, skb, 0, ATH11K_TX_MGMT_NUM_PENDING_MAX, GFP_ATOMIC); spin_unlock_bh(&ar->txmgmt_idr_lock); + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "mac tx mgmt frame, buf id %d\n", buf_id); + if (buf_id < 0) return -ENOSPC; @@ -5026,7 +5404,7 @@ static void ath11k_mgmt_over_wmi_tx_purge(struct ath11k *ar) struct sk_buff *skb; while ((skb = skb_dequeue(&ar->wmi_mgmt_tx_queue)) != NULL) - ieee80211_free_txskb(ar->hw, skb); + ath11k_mgmt_over_wmi_tx_drop(ar, skb); } static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work) @@ -5041,7 +5419,7 @@ static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work) skb_cb = ATH11K_SKB_CB(skb); if (!skb_cb->vif) { ath11k_warn(ar->ab, "no vif found for mgmt frame\n"); - ieee80211_free_txskb(ar->hw, skb); + ath11k_mgmt_over_wmi_tx_drop(ar, skb); continue; } @@ -5052,16 +5430,18 @@ static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work) if (ret) { ath11k_warn(ar->ab, "failed to tx mgmt frame, vdev_id %d :%d\n", arvif->vdev_id, ret); - ieee80211_free_txskb(ar->hw, skb); + ath11k_mgmt_over_wmi_tx_drop(ar, skb); } else { - atomic_inc(&ar->num_pending_mgmt_tx); + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "mac tx mgmt frame, vdev_id %d\n", + arvif->vdev_id); } } else { ath11k_warn(ar->ab, "dropping mgmt frame for vdev %d, is_started %d\n", arvif->vdev_id, arvif->is_started); - ieee80211_free_txskb(ar->hw, skb); + ath11k_mgmt_over_wmi_tx_drop(ar, skb); } } } @@ -5092,6 +5472,7 @@ static int ath11k_mac_mgmt_tx(struct ath11k *ar, struct sk_buff *skb, } skb_queue_tail(q, skb); + atomic_inc(&ar->num_pending_mgmt_tx); ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work); return 0; @@ -5138,7 +5519,7 @@ static void ath11k_mac_op_tx(struct ieee80211_hw *hw, arsta = (struct ath11k_sta *)control->sta->drv_priv; ret = ath11k_dp_tx(ar, arvif, arsta, skb); - if (ret) { + if (unlikely(ret)) { ath11k_warn(ar->ab, "failed to transmit frame %d\n", ret); ieee80211_free_txskb(ar->hw, skb); } @@ -5222,6 +5603,14 @@ static int ath11k_mac_op_start(struct ieee80211_hw *hw) goto err; } + if (test_bit(WMI_TLV_SERVICE_SPOOF_MAC_SUPPORT, ar->wmi->wmi_ab->svc_map)) { + ret = ath11k_wmi_scan_prob_req_oui(ar, ar->mac_addr); + if (ret) { + ath11k_err(ab, "failed to set prob req oui: %i\n", ret); + goto err; + } + } + ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_ARP_AC_OVERRIDE, 0, pdev->pdev_id); if (ret) { @@ -5320,6 +5709,7 @@ static void ath11k_mac_op_stop(struct ieee80211_hw *hw) cancel_delayed_work_sync(&ar->scan.timeout); cancel_work_sync(&ar->regd_update_work); + cancel_work_sync(&ar->ab->update_11d_work); spin_lock_bh(&ar->data_lock); list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) { @@ -5473,6 +5863,122 @@ static void ath11k_mac_op_update_vif_offload(struct ieee80211_hw *hw, } } +static bool ath11k_mac_vif_ap_active_any(struct ath11k_base *ab) +{ + struct ath11k *ar; + struct ath11k_pdev *pdev; + struct ath11k_vif *arvif; + int i; + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + ar = pdev->ar; + list_for_each_entry(arvif, &ar->arvifs, list) { + if (arvif->is_up && arvif->vdev_type == WMI_VDEV_TYPE_AP) + return true; + } + } + return false; +} + +void ath11k_mac_11d_scan_start(struct ath11k *ar, u32 vdev_id, bool wait) +{ + struct wmi_11d_scan_start_params param; + int ret; + + mutex_lock(&ar->ab->vdev_id_11d_lock); + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev id for 11d scan %d\n", + ar->vdev_id_11d_scan); + + if (ar->regdom_set_by_user) + goto fin; + + if (ar->vdev_id_11d_scan != ATH11K_11D_INVALID_VDEV_ID) + goto fin; + + if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map)) + goto fin; + + if (ath11k_mac_vif_ap_active_any(ar->ab)) + goto fin; + + param.vdev_id = vdev_id; + param.start_interval_msec = 0; + param.scan_period_msec = ATH11K_SCAN_11D_INTERVAL; + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac start 11d scan\n"); + + if (wait) + reinit_completion(&ar->finish_11d_scan); + + ret = ath11k_wmi_send_11d_scan_start_cmd(ar, ¶m); + if (ret) { + ath11k_warn(ar->ab, "failed to start 11d scan vdev %d ret: %d\n", + vdev_id, ret); + } else { + ar->vdev_id_11d_scan = vdev_id; + if (wait) { + ar->pending_11d = true; + ret = wait_for_completion_timeout(&ar->finish_11d_scan, + 5 * HZ); + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "mac 11d scan left time %d\n", ret); + + if (!ret) + ar->pending_11d = false; + } + } + +fin: + mutex_unlock(&ar->ab->vdev_id_11d_lock); +} + +void ath11k_mac_11d_scan_stop(struct ath11k *ar) +{ + int ret; + u32 vdev_id; + + if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map)) + return; + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac stop 11d scan\n"); + + mutex_lock(&ar->ab->vdev_id_11d_lock); + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac stop 11d vdev id %d\n", + ar->vdev_id_11d_scan); + + if (ar->vdev_id_11d_scan != ATH11K_11D_INVALID_VDEV_ID) { + vdev_id = ar->vdev_id_11d_scan; + + ret = ath11k_wmi_send_11d_scan_stop_cmd(ar, vdev_id); + if (ret) + ath11k_warn(ar->ab, + "failed to stopt 11d scan vdev %d ret: %d\n", + vdev_id, ret); + else + ar->vdev_id_11d_scan = ATH11K_11D_INVALID_VDEV_ID; + } + mutex_unlock(&ar->ab->vdev_id_11d_lock); +} + +void ath11k_mac_11d_scan_stop_all(struct ath11k_base *ab) +{ + struct ath11k *ar; + struct ath11k_pdev *pdev; + int i; + + ath11k_dbg(ab, ATH11K_DBG_MAC, "mac stop soc 11d scan\n"); + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + ar = pdev->ar; + + ath11k_mac_11d_scan_stop(ar); + } +} + static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -5484,7 +5990,7 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, u32 param_id, param_value; u16 nss; int i; - int ret; + int ret, fbret; int bit; vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; @@ -5498,9 +6004,9 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, goto err; } - if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) { + if (ar->num_created_vdevs > (TARGET_NUM_VDEVS(ab) - 1)) { ath11k_warn(ab, "failed to create vdev %u, reached max vdev limit %d\n", - ar->num_created_vdevs, TARGET_NUM_VDEVS); + ar->num_created_vdevs, TARGET_NUM_VDEVS(ab)); ret = -EBUSY; goto err; } @@ -5606,6 +6112,8 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, arvif->vdev_id, ret); goto err_peer_del; } + + ath11k_mac_11d_scan_stop_all(ar->ab); break; case WMI_VDEV_TYPE_STA: param_id = WMI_STA_PS_PARAM_RX_WAKE_POLICY; @@ -5638,12 +6146,16 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, goto err_peer_del; } - ret = ath11k_wmi_pdev_set_ps_mode(ar, arvif->vdev_id, false); + ret = ath11k_wmi_pdev_set_ps_mode(ar, arvif->vdev_id, + WMI_STA_PS_MODE_DISABLED); if (ret) { ath11k_warn(ar->ab, "failed to disable vdev %d ps mode: %d\n", arvif->vdev_id, ret); goto err_peer_del; } + + ath11k_mac_11d_scan_start(ar, arvif->vdev_id, true); + break; case WMI_VDEV_TYPE_MONITOR: set_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); @@ -5686,17 +6198,17 @@ err_peer_del: if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { reinit_completion(&ar->peer_delete_done); - ret = ath11k_wmi_send_peer_delete_cmd(ar, vif->addr, - arvif->vdev_id); - if (ret) { + fbret = ath11k_wmi_send_peer_delete_cmd(ar, vif->addr, + arvif->vdev_id); + if (fbret) { ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n", arvif->vdev_id, vif->addr); goto err; } - ret = ath11k_wait_for_peer_delete_done(ar, arvif->vdev_id, - vif->addr); - if (ret) + fbret = ath11k_wait_for_peer_delete_done(ar, arvif->vdev_id, + vif->addr); + if (fbret) goto err; ar->num_peers--; @@ -5745,6 +6257,9 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw, ath11k_dbg(ab, ATH11K_DBG_MAC, "mac remove interface (vdev %d)\n", arvif->vdev_id); + if (arvif->vdev_type == WMI_VDEV_TYPE_STA) + ath11k_mac_11d_scan_stop(ar); + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { ret = ath11k_peer_delete(ar, arvif->vdev_id, vif->addr); if (ret) @@ -5831,7 +6346,6 @@ static void ath11k_mac_op_configure_filter(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); - changed_flags &= SUPPORTED_FILTERS; *total_flags &= SUPPORTED_FILTERS; ar->filter_flags = *total_flags; @@ -5969,9 +6483,9 @@ ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif, ath11k_phymodes[chandef->chan->band][chandef->width]; arg.channel.min_power = 0; - arg.channel.max_power = chandef->chan->max_power * 2; - arg.channel.max_reg_power = chandef->chan->max_reg_power * 2; - arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2; + arg.channel.max_power = chandef->chan->max_power; + arg.channel.max_reg_power = chandef->chan->max_reg_power; + arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain; arg.pref_tx_streams = ar->num_tx_chains; arg.pref_rx_streams = ar->num_rx_chains; @@ -6159,37 +6673,7 @@ ath11k_mac_update_vif_chan(struct ath11k *ar, lockdep_assert_held(&ar->conf_mutex); - for (i = 0; i < n_vifs; i++) { - arvif = (void *)vifs[i].vif->drv_priv; - - if (vifs[i].vif->type == NL80211_IFTYPE_MONITOR) - monitor_vif = true; - - ath11k_dbg(ab, ATH11K_DBG_MAC, - "mac chanctx switch vdev_id %i freq %u->%u width %d->%d\n", - arvif->vdev_id, - vifs[i].old_ctx->def.chan->center_freq, - vifs[i].new_ctx->def.chan->center_freq, - vifs[i].old_ctx->def.width, - vifs[i].new_ctx->def.width); - - if (WARN_ON(!arvif->is_started)) - continue; - - if (WARN_ON(!arvif->is_up)) - continue; - - ret = ath11k_wmi_vdev_down(ar, arvif->vdev_id); - if (ret) { - ath11k_warn(ab, "failed to down vdev %d: %d\n", - arvif->vdev_id, ret); - continue; - } - - ar->num_started_vdevs--; - } - - /* All relevant vdevs are downed and associated channel resources + /* Associated channel resources of all relevant vdevs * should be available for the channel switch now. */ @@ -6468,6 +6952,19 @@ ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, arvif->is_started = false; if (ab->hw_params.vdev_start_delay && + arvif->vdev_type == WMI_VDEV_TYPE_STA) { + ret = ath11k_peer_delete(ar, arvif->vdev_id, arvif->bssid); + if (ret) + ath11k_warn(ar->ab, + "failed to delete peer %pM for vdev %d: %d\n", + arvif->bssid, arvif->vdev_id, ret); + else + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "mac removed peer %pM vdev %d after vdev stop\n", + arvif->bssid, arvif->vdev_id); + } + + if (ab->hw_params.vdev_start_delay && arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) ath11k_wmi_vdev_down(ar, arvif->vdev_id); @@ -6481,6 +6978,9 @@ ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, ret); } + if (arvif->vdev_type == WMI_VDEV_TYPE_STA) + ath11k_mac_11d_scan_start(ar, arvif->vdev_id, false); + mutex_unlock(&ar->conf_mutex); } @@ -6567,6 +7067,17 @@ static void ath11k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *v ATH11K_FLUSH_TIMEOUT); if (time_left == 0) ath11k_warn(ar->ab, "failed to flush transmit queue %ld\n", time_left); + + time_left = wait_event_timeout(ar->txmgmt_empty_waitq, + (atomic_read(&ar->num_pending_mgmt_tx) == 0), + ATH11K_FLUSH_TIMEOUT); + if (time_left == 0) + ath11k_warn(ar->ab, "failed to flush mgmt transmit queue %ld\n", + time_left); + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "mac mgmt tx flush mgmt pending %d\n", + atomic_read(&ar->num_pending_mgmt_tx)); } static int @@ -7277,21 +7788,20 @@ static void ath11k_mac_op_sta_statistics(struct ieee80211_hw *hw, sinfo->tx_duration = arsta->tx_duration; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_DURATION); - if (!arsta->txrate.legacy && !arsta->txrate.nss) - return; - - if (arsta->txrate.legacy) { - sinfo->txrate.legacy = arsta->txrate.legacy; - } else { - sinfo->txrate.mcs = arsta->txrate.mcs; - sinfo->txrate.nss = arsta->txrate.nss; - sinfo->txrate.bw = arsta->txrate.bw; - sinfo->txrate.he_gi = arsta->txrate.he_gi; - sinfo->txrate.he_dcm = arsta->txrate.he_dcm; - sinfo->txrate.he_ru_alloc = arsta->txrate.he_ru_alloc; + if (arsta->txrate.legacy || arsta->txrate.nss) { + if (arsta->txrate.legacy) { + sinfo->txrate.legacy = arsta->txrate.legacy; + } else { + sinfo->txrate.mcs = arsta->txrate.mcs; + sinfo->txrate.nss = arsta->txrate.nss; + sinfo->txrate.bw = arsta->txrate.bw; + sinfo->txrate.he_gi = arsta->txrate.he_gi; + sinfo->txrate.he_dcm = arsta->txrate.he_dcm; + sinfo->txrate.he_ru_alloc = arsta->txrate.he_ru_alloc; + } + sinfo->txrate.flags = arsta->txrate.flags; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); } - sinfo->txrate.flags = arsta->txrate.flags; - sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); /* TODO: Use real NF instead of default one. */ sinfo->signal = arsta->rssi_comb + ATH11K_DEFAULT_NOISE_FLOOR; @@ -7633,6 +8143,9 @@ static int __ath11k_mac_register(struct ath11k *ar) ar->hw->wiphy->interface_modes = ab->hw_params.interface_modes; + if (ab->hw_params.single_pdev_only && ar->supports_6ghz) + ieee80211_hw_set(ar->hw, SINGLE_SCAN_ON_ALL_BANDS); + ieee80211_hw_set(ar->hw, SIGNAL_DBM); ieee80211_hw_set(ar->hw, SUPPORTS_PS); ieee80211_hw_set(ar->hw, SUPPORTS_DYNAMIC_PS); @@ -7672,7 +8185,8 @@ static int __ath11k_mac_register(struct ath11k *ar) * for each band for a dual band capable radio. It will be tricky to * handle it when the ht capability different for each band. */ - if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS || ar->supports_6ghz) + if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS || + (ar->supports_6ghz && ab->hw_params.supports_dynamic_smps_6ghz)) ar->hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS; ar->hw->wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID; @@ -7688,11 +8202,16 @@ static int __ath11k_mac_register(struct ath11k *ar) ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | NL80211_FEATURE_AP_SCAN; - ar->max_num_stations = TARGET_NUM_STATIONS; - ar->max_num_peers = TARGET_NUM_PEERS_PDEV; + ar->max_num_stations = TARGET_NUM_STATIONS(ab); + ar->max_num_peers = TARGET_NUM_PEERS_PDEV(ab); ar->hw->wiphy->max_ap_assoc_sta = ar->max_num_stations; + if (test_bit(WMI_TLV_SERVICE_SPOOF_MAC_SUPPORT, ar->wmi->wmi_ab->svc_map)) { + ar->hw->wiphy->features |= + NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; + } + ar->hw->queues = ATH11K_HW_MAX_QUEUES; ar->hw->wiphy->tx_queue_len = ATH11K_QUEUE_LEN; ar->hw->offchannel_tx_hw_queue = ATH11K_HW_MAX_QUEUES - 1; @@ -7703,6 +8222,9 @@ static int __ath11k_mac_register(struct ath11k *ar) wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_STA_TX_PWR); + if (test_bit(WMI_TLV_SERVICE_BSS_COLOR_OFFLOAD, ar->ab->wmi_ab.svc_map)) + wiphy_ext_feature_set(ar->hw->wiphy, + NL80211_EXT_FEATURE_BSS_COLOR); ar->hw->wiphy->cipher_suites = cipher_suites; ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); @@ -7784,7 +8306,7 @@ int ath11k_mac_register(struct ath11k_base *ab) /* Initialize channel counters frequency value in hertz */ ab->cc_freq_hz = IPQ8074_CC_FREQ_HERTZ; - ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1; + ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS(ab))) - 1; for (i = 0; i < ab->num_radios; i++) { pdev = &ab->pdevs[i]; @@ -7802,6 +8324,8 @@ int ath11k_mac_register(struct ath11k_base *ab) ret = __ath11k_mac_register(ar); if (ret) goto err_cleanup; + + init_waitqueue_head(&ar->txmgmt_empty_waitq); } return 0; @@ -7879,6 +8403,9 @@ int ath11k_mac_allocate(struct ath11k_base *ab) ar->monitor_vdev_id = -1; clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); + ar->vdev_id_11d_scan = ATH11K_11D_INVALID_VDEV_ID; + init_completion(&ar->finish_11d_scan); + init_completion(&ar->finish_11d_ch_list); } return 0; diff --git a/drivers/net/wireless/ath/ath11k/mac.h b/drivers/net/wireless/ath/ath11k/mac.h index 254ca4acc8e8..035d6738c20b 100644 --- a/drivers/net/wireless/ath/ath11k/mac.h +++ b/drivers/net/wireless/ath/ath11k/mac.h @@ -127,6 +127,13 @@ struct ath11k_generic_iter { extern const struct htt_rx_ring_tlv_filter ath11k_mac_mon_status_filter_default; +#define ATH11K_SCAN_11D_INTERVAL 600000 +#define ATH11K_11D_INVALID_VDEV_ID 0xFFFF + +void ath11k_mac_11d_scan_start(struct ath11k *ar, u32 vdev_id, bool wait); +void ath11k_mac_11d_scan_stop(struct ath11k *ar); +void ath11k_mac_11d_scan_stop_all(struct ath11k_base *ab); + void ath11k_mac_destroy(struct ath11k_base *ab); void ath11k_mac_unregister(struct ath11k_base *ab); int ath11k_mac_register(struct ath11k_base *ab); @@ -144,6 +151,10 @@ void ath11k_mac_scan_finish(struct ath11k *ar); struct ath11k_vif *ath11k_mac_get_arvif(struct ath11k *ar, u32 vdev_id); struct ath11k_vif *ath11k_mac_get_arvif_by_vdev_id(struct ath11k_base *ab, u32 vdev_id); +u8 ath11k_mac_get_target_pdev_id(struct ath11k *ar); +u8 ath11k_mac_get_target_pdev_id_from_vif(struct ath11k_vif *arvif); +struct ath11k_vif *ath11k_mac_get_vif_up(struct ath11k_base *ab); + struct ath11k *ath11k_mac_get_ar_by_vdev_id(struct ath11k_base *ab, u32 vdev_id); struct ath11k *ath11k_mac_get_ar_by_pdev_id(struct ath11k_base *ab, u32 pdev_id); @@ -155,4 +166,5 @@ enum ath11k_supported_bw ath11k_mac_mac80211_bw_to_ath11k_bw(enum rate_info_bw b enum hal_encrypt_type ath11k_dp_tx_get_encrypt_type(u32 cipher); void ath11k_mac_handle_beacon(struct ath11k *ar, struct sk_buff *skb); void ath11k_mac_handle_beacon_miss(struct ath11k *ar, u32 vdev_id); +void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif); #endif diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index 26c7ae242db6..e4250ba8dfee 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -3,6 +3,9 @@ #include <linux/msi.h> #include <linux/pci.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/ioport.h> #include "core.h" #include "debug.h" @@ -248,6 +251,7 @@ static int ath11k_mhi_get_msi(struct ath11k_pci *ab_pci) u32 user_base_data, base_vector; int ret, num_vectors, i; int *irq; + unsigned int msi_data; ret = ath11k_pci_get_user_msi_assignment(ab_pci, "MHI", &num_vectors, @@ -262,9 +266,15 @@ static int ath11k_mhi_get_msi(struct ath11k_pci *ab_pci) if (!irq) return -ENOMEM; - for (i = 0; i < num_vectors; i++) + for (i = 0; i < num_vectors; i++) { + msi_data = base_vector; + + if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + msi_data += i; + irq[i] = ath11k_pci_get_msi_irq(ab->dev, - base_vector + i); + msi_data); + } ab_pci->mhi_ctrl->irq = irq; ab_pci->mhi_ctrl->nr_irqs = num_vectors; @@ -311,6 +321,26 @@ static void ath11k_mhi_op_write_reg(struct mhi_controller *mhi_cntrl, writel(val, addr); } +static int ath11k_mhi_read_addr_from_dt(struct mhi_controller *mhi_ctrl) +{ + struct device_node *np; + struct resource res; + int ret; + + np = of_find_node_by_type(NULL, "memory"); + if (!np) + return -ENOENT; + + ret = of_address_to_resource(np, 0, &res); + if (ret) + return ret; + + mhi_ctrl->iova_start = res.start + 0x1000000; + mhi_ctrl->iova_stop = res.end; + + return 0; +} + int ath11k_mhi_register(struct ath11k_pci *ab_pci) { struct ath11k_base *ab = ab_pci->ab; @@ -339,8 +369,18 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci) return ret; } - mhi_ctrl->iova_start = 0; - mhi_ctrl->iova_stop = 0xffffffff; + if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + mhi_ctrl->irq_flags = IRQF_SHARED | IRQF_NOBALANCING; + + if (test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) { + ret = ath11k_mhi_read_addr_from_dt(mhi_ctrl); + if (ret < 0) + return ret; + } else { + mhi_ctrl->iova_start = 0; + mhi_ctrl->iova_stop = 0xFFFFFFFF; + } + mhi_ctrl->sbl_size = SZ_512K; mhi_ctrl->seg_len = SZ_512K; mhi_ctrl->fbc_download = true; @@ -356,6 +396,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci) break; case ATH11K_HW_QCA6390_HW20: case ATH11K_HW_WCN6855_HW20: + case ATH11K_HW_WCN6855_HW21: ath11k_mhi_config = &ath11k_mhi_config_qca6390; break; default: @@ -533,7 +574,11 @@ static int ath11k_mhi_set_state(struct ath11k_pci *ab_pci, ret = mhi_pm_suspend(ab_pci->mhi_ctrl); break; case ATH11K_MHI_RESUME: - ret = mhi_pm_resume(ab_pci->mhi_ctrl); + /* Do force MHI resume as some devices like QCA6390, WCN6855 + * are not in M3 state but they are functional. So just ignore + * the MHI state while resuming. + */ + ret = mhi_pm_resume_force(ab_pci->mhi_ctrl); break; case ATH11K_MHI_TRIGGER_RDDM: ret = mhi_force_rddm_mode(ab_pci->mhi_ctrl); diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 3d353e7c9d5c..8c09d61138a1 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -6,6 +6,7 @@ #include <linux/module.h> #include <linux/msi.h> #include <linux/pci.h> +#include <linux/of.h> #include "pci.h" #include "core.h" @@ -16,7 +17,8 @@ #define ATH11K_PCI_BAR_NUM 0 #define ATH11K_PCI_DMA_MASK 32 -#define ATH11K_PCI_IRQ_CE0_OFFSET 3 +#define ATH11K_PCI_IRQ_CE0_OFFSET 3 +#define ATH11K_PCI_IRQ_DP_OFFSET 14 #define WINDOW_ENABLE_BIT 0x40000000 #define WINDOW_REG_ADDRESS 0x310c @@ -25,7 +27,7 @@ #define WINDOW_RANGE_MASK GENMASK(18, 0) #define TCSR_SOC_HW_VERSION 0x0224 -#define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(16, 8) +#define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(11, 8) #define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 0) /* BAR0 + 4k is always accessible, and no @@ -76,6 +78,17 @@ static const struct ath11k_msi_config ath11k_msi_config[] = { }, }; +static const struct ath11k_msi_config msi_config_one_msi = { + .total_vectors = 1, + .total_users = 4, + .users = (struct ath11k_msi_user[]) { + { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, + { .name = "CE", .num_vectors = 1, .base_vector = 0 }, + { .name = "WAKE", .num_vectors = 1, .base_vector = 0 }, + { .name = "DP", .num_vectors = 1, .base_vector = 0 }, + }, +}; + static const char *irq_name[ATH11K_IRQ_NUM_MAX] = { "bhi", "mhi-er0", @@ -182,7 +195,8 @@ void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value) /* for offset beyond BAR + 4K - 32, may * need to wakeup MHI to access. */ - if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && + if (ab->hw_params.wakeup_mhi && + test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && offset >= ACCESS_ALWAYS_OFF) mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); @@ -206,7 +220,8 @@ void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value) } } - if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && + if (ab->hw_params.wakeup_mhi && + test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && offset >= ACCESS_ALWAYS_OFF) mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); } @@ -219,7 +234,8 @@ u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset) /* for offset beyond BAR + 4K - 32, may * need to wakeup MHI to access. */ - if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && + if (ab->hw_params.wakeup_mhi && + test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && offset >= ACCESS_ALWAYS_OFF) mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); @@ -243,7 +259,8 @@ u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset) } } - if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && + if (ab->hw_params.wakeup_mhi && + test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && offset >= ACCESS_ALWAYS_OFF) mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); @@ -481,11 +498,11 @@ int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_nam for (idx = 0; idx < msi_config->total_users; idx++) { if (strcmp(user_name, msi_config->users[idx].name) == 0) { *num_vectors = msi_config->users[idx].num_vectors; - *user_base_data = msi_config->users[idx].base_vector - + ab_pci->msi_ep_base_data; - *base_vector = msi_config->users[idx].base_vector; + *base_vector = msi_config->users[idx].base_vector; + *user_base_data = *base_vector + ab_pci->msi_ep_base_data; - ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", + ath11k_dbg(ab, ATH11K_DBG_PCI, + "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", user_name, *num_vectors, *user_base_data, *base_vector); @@ -556,16 +573,30 @@ static void ath11k_pci_free_irq(struct ath11k_base *ab) static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) { + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); u32 irq_idx; + /* In case of one MSI vector, we handle irq enable/disable in a + * uniform way since we only have one irq + */ + if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + return; + irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; enable_irq(ab->irq_num[irq_idx]); } static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) { + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); u32 irq_idx; + /* In case of one MSI vector, we handle irq enable/disable in a + * uniform way since we only have one irq + */ + if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + return; + irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; disable_irq_nosync(ab->irq_num[irq_idx]); } @@ -574,6 +605,8 @@ static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab) { int i; + clear_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); + for (i = 0; i < ab->hw_params.ce_count; i++) { if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; @@ -598,20 +631,27 @@ static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab) static void ath11k_pci_ce_tasklet(struct tasklet_struct *t) { struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); + int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); - ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num); + enable_irq(ce_pipe->ab->irq_num[irq_idx]); } static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) { struct ath11k_ce_pipe *ce_pipe = arg; + struct ath11k_base *ab = ce_pipe->ab; + int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; + + if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags)) + return IRQ_HANDLED; /* last interrupt received for this CE */ ce_pipe->timestamp = jiffies; - ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num); + disable_irq_nosync(ab->irq_num[irq_idx]); + tasklet_schedule(&ce_pipe->intr_tq); return IRQ_HANDLED; @@ -619,8 +659,15 @@ static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp) { + struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab); int i; + /* In case of one MSI vector, we handle irq enable/disable + * in a uniform way since we only have one irq + */ + if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + return; + for (i = 0; i < irq_grp->num_irq; i++) disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); } @@ -629,6 +676,8 @@ static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc) { int i; + clear_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &sc->dev_flags); + for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i]; @@ -641,8 +690,15 @@ static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc) static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp) { + struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab); int i; + /* In case of one MSI vector, we handle irq enable/disable in a + * uniform way since we only have one irq + */ + if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + return; + for (i = 0; i < irq_grp->num_irq; i++) enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); } @@ -651,6 +707,8 @@ static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab) { int i; + set_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags); + for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; @@ -686,11 +744,13 @@ static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget) napi); struct ath11k_base *ab = irq_grp->ab; int work_done; + int i; work_done = ath11k_dp_service_srng(ab, irq_grp, budget); if (work_done < budget) { napi_complete_done(napi, work_done); - ath11k_pci_ext_grp_enable(irq_grp); + for (i = 0; i < irq_grp->num_irq; i++) + enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); } if (work_done > budget) @@ -702,13 +762,19 @@ static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget) static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg) { struct ath11k_ext_irq_grp *irq_grp = arg; + struct ath11k_base *ab = irq_grp->ab; + int i; + + if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags)) + return IRQ_HANDLED; ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq); /* last interrupt received for this group */ irq_grp->timestamp = jiffies; - ath11k_pci_ext_grp_disable(irq_grp); + for (i = 0; i < irq_grp->num_irq; i++) + disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); napi_schedule(&irq_grp->napi); @@ -717,10 +783,10 @@ static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg) static int ath11k_pci_ext_irq_config(struct ath11k_base *ab) { + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); int i, j, ret, num_vectors = 0; - u32 user_base_data = 0, base_vector = 0, base_idx; + u32 user_base_data = 0, base_vector = 0; - base_idx = ATH11K_PCI_IRQ_CE0_OFFSET + CE_COUNT_MAX; ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP", &num_vectors, &user_base_data, @@ -750,7 +816,7 @@ static int ath11k_pci_ext_irq_config(struct ath11k_base *ab) } irq_grp->num_irq = num_irq; - irq_grp->irqs[0] = base_idx + i; + irq_grp->irqs[0] = ATH11K_PCI_IRQ_DP_OFFSET + i; for (j = 0; j < irq_grp->num_irq; j++) { int irq_idx = irq_grp->irqs[j]; @@ -764,23 +830,32 @@ static int ath11k_pci_ext_irq_config(struct ath11k_base *ab) irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); ret = request_irq(irq, ath11k_pci_ext_interrupt_handler, - IRQF_SHARED, + ab_pci->irq_flags, "DP_EXT_IRQ", irq_grp); if (ret) { ath11k_err(ab, "failed request irq %d: %d\n", vector, ret); return ret; } - - disable_irq_nosync(ab->irq_num[irq_idx]); } + ath11k_pci_ext_grp_disable(irq_grp); } return 0; } +static int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci, + const struct cpumask *m) +{ + if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + return 0; + + return irq_set_affinity_hint(ab_pci->pdev->irq, m); +} + static int ath11k_pci_config_irq(struct ath11k_base *ab) { + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); struct ath11k_ce_pipe *ce_pipe; u32 msi_data_start; u32 msi_data_count, msi_data_idx; @@ -794,6 +869,12 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab) if (ret) return ret; + ret = ath11k_pci_set_irq_affinity_hint(ab_pci, cpumask_of(0)); + if (ret) { + ath11k_err(ab, "failed to set irq affinity %d\n", ret); + return ret; + } + /* Configure CE irqs */ for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) @@ -808,12 +889,12 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab) tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet); ret = request_irq(irq, ath11k_pci_ce_interrupt_handler, - IRQF_SHARED, irq_name[irq_idx], + ab_pci->irq_flags, irq_name[irq_idx], ce_pipe); if (ret) { ath11k_err(ab, "failed to request irq %d: %d\n", irq_idx, ret); - return ret; + goto err_irq_affinity_cleanup; } ab->irq_num[irq_idx] = irq; @@ -824,9 +905,13 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab) ret = ath11k_pci_ext_irq_config(ab); if (ret) - return ret; + goto err_irq_affinity_cleanup; return 0; + +err_irq_affinity_cleanup: + ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); + return ret; } static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) @@ -848,6 +933,8 @@ static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab) { int i; + set_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); + for (i = 0; i < ab->hw_params.ce_count; i++) { if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; @@ -892,15 +979,25 @@ static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci) msi_config->total_vectors, msi_config->total_vectors, PCI_IRQ_MSI); - if (num_vectors != msi_config->total_vectors) { - ath11k_err(ab, "failed to get %d MSI vectors, only %d available", - msi_config->total_vectors, num_vectors); - - if (num_vectors >= 0) - return -EINVAL; - else - return num_vectors; + if (num_vectors == msi_config->total_vectors) { + set_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); + ab_pci->irq_flags = IRQF_SHARED; + } else { + num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, + 1, + 1, + PCI_IRQ_MSI); + if (num_vectors < 0) { + ret = -EINVAL; + goto reset_msi_config; + } + clear_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); + ab_pci->msi_config = &msi_config_one_msi; + ab_pci->irq_flags = IRQF_SHARED | IRQF_NOBALANCING; + ath11k_dbg(ab, ATH11K_DBG_PCI, "request MSI one vector\n"); } + ath11k_info(ab, "MSI vectors: %d\n", num_vectors); + ath11k_pci_msi_disable(ab_pci); msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); @@ -921,6 +1018,7 @@ static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci) free_msi_vector: pci_free_irq_vectors(ab_pci->pdev); +reset_msi_config: return ret; } @@ -929,6 +1027,25 @@ static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci) pci_free_irq_vectors(ab_pci->pdev); } +static int ath11k_pci_config_msi_data(struct ath11k_pci *ab_pci) +{ + struct msi_desc *msi_desc; + + msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); + if (!msi_desc) { + ath11k_err(ab_pci->ab, "msi_desc is NULL!\n"); + pci_free_irq_vectors(ab_pci->pdev); + return -EINVAL; + } + + ab_pci->msi_ep_base_data = msi_desc->msg.data; + + ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n", + ab_pci->msi_ep_base_data); + + return 0; +} + static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) { struct ath11k_base *ab = ab_pci->ab; @@ -1126,7 +1243,13 @@ static int ath11k_pci_start(struct ath11k_base *ab) set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); - ath11k_pci_aspm_restore(ab_pci); + /* TODO: for now don't restore ASPM in case of single MSI + * vector as MHI register reading in M2 causes system hang. + */ + if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + ath11k_pci_aspm_restore(ab_pci); + else + ath11k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n"); ath11k_pci_ce_irqs_enable(ab); ath11k_ce_rx_post_buf(ab); @@ -1225,7 +1348,7 @@ static int ath11k_pci_probe(struct pci_dev *pdev, { struct ath11k_base *ab; struct ath11k_pci *ab_pci; - u32 soc_hw_version_major, soc_hw_version_minor; + u32 soc_hw_version_major, soc_hw_version_minor, addr; int ret; ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI, @@ -1245,12 +1368,29 @@ static int ath11k_pci_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, ab); spin_lock_init(&ab_pci->window_lock); + /* Set fixed_mem_region to true for platforms support reserved memory + * from DT. If memory is reserved from DT for FW, ath11k driver need not + * allocate memory. + */ + ret = of_property_read_u32(ab->dev->of_node, "memory-region", &addr); + if (!ret) + set_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags); + ret = ath11k_pci_claim(ab_pci, pdev); if (ret) { ath11k_err(ab, "failed to claim device: %d\n", ret); goto err_free_core; } + ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n", + pdev->vendor, pdev->device, + pdev->subsystem_vendor, pdev->subsystem_device); + + ab->id.vendor = pdev->vendor; + ab->id.device = pdev->device; + ab->id.subsystem_vendor = pdev->subsystem_vendor; + ab->id.subsystem_device = pdev->subsystem_device; + switch (pci_dev->device) { case QCA6390_DEVICE_ID: ath11k_pci_read_hw_version(ab, &soc_hw_version_major, @@ -1273,13 +1413,26 @@ static int ath11k_pci_probe(struct pci_dev *pdev, ab->hw_rev = ATH11K_HW_QCN9074_HW10; break; case WCN6855_DEVICE_ID: + ab->id.bdf_search = ATH11K_BDF_SEARCH_BUS_AND_BOARD; ath11k_pci_read_hw_version(ab, &soc_hw_version_major, &soc_hw_version_minor); switch (soc_hw_version_major) { case 2: - ab->hw_rev = ATH11K_HW_WCN6855_HW20; + switch (soc_hw_version_minor) { + case 0x00: + case 0x01: + ab->hw_rev = ATH11K_HW_WCN6855_HW20; + break; + case 0x10: + case 0x11: + ab->hw_rev = ATH11K_HW_WCN6855_HW21; + break; + default: + goto unsupported_wcn6855_soc; + } break; default: +unsupported_wcn6855_soc: dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n", soc_hw_version_major, soc_hw_version_minor); ret = -EOPNOTSUPP; @@ -1328,6 +1481,17 @@ static int ath11k_pci_probe(struct pci_dev *pdev, goto err_ce_free; } + /* kernel may allocate a dummy vector before request_irq and + * then allocate a real vector when request_irq is called. + * So get msi_data here again to avoid spurious interrupt + * as msi_data will configured to srngs. + */ + ret = ath11k_pci_config_msi_data(ab_pci); + if (ret) { + ath11k_err(ab, "failed to config msi_data: %d\n", ret); + goto err_free_irq; + } + ret = ath11k_core_init(ab); if (ret) { ath11k_err(ab, "failed to init core: %d\n", ret); @@ -1364,6 +1528,8 @@ static void ath11k_pci_remove(struct pci_dev *pdev) struct ath11k_base *ab = pci_get_drvdata(pdev); struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); + if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { ath11k_pci_power_down(ab); ath11k_debugfs_soc_destroy(ab); diff --git a/drivers/net/wireless/ath/ath11k/pci.h b/drivers/net/wireless/ath/ath11k/pci.h index f3e645891d19..61d67b20a0eb 100644 --- a/drivers/net/wireless/ath/ath11k/pci.h +++ b/drivers/net/wireless/ath/ath11k/pci.h @@ -68,6 +68,7 @@ enum ath11k_pci_flags { ATH11K_PCI_FLAG_INIT_DONE, ATH11K_PCI_FLAG_IS_MSI_64, ATH11K_PCI_ASPM_RESTORE, + ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, }; struct ath11k_pci { @@ -87,6 +88,8 @@ struct ath11k_pci { /* enum ath11k_pci_flags */ unsigned long flags; u16 link_ctl; + + unsigned long irq_flags; }; static inline struct ath11k_pci *ath11k_pci_priv(struct ath11k_base *ab) diff --git a/drivers/net/wireless/ath/ath11k/peer.h b/drivers/net/wireless/ath/ath11k/peer.h index 619db001be8e..63fe5665badf 100644 --- a/drivers/net/wireless/ath/ath11k/peer.h +++ b/drivers/net/wireless/ath/ath11k/peer.h @@ -28,6 +28,7 @@ struct ath11k_peer { u8 ucast_keyidx; u16 sec_type; u16 sec_type_grp; + bool is_authorized; }; void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id); diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index fa73118de6db..3b9ba0e03a66 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -9,6 +9,8 @@ #include "core.h" #include "debug.h" #include <linux/of.h> +#include <linux/of_address.h> +#include <linux/ioport.h> #include <linux/firmware.h> #define SLEEP_CLOCK_SELECT_INTERNAL_BIT 0x02 @@ -1586,7 +1588,7 @@ static int ath11k_qmi_host_cap_send(struct ath11k_base *ab) { struct qmi_wlanfw_host_cap_req_msg_v01 req; struct qmi_wlanfw_host_cap_resp_msg_v01 resp; - struct qmi_txn txn = {}; + struct qmi_txn txn; int ret = 0; memset(&req, 0, sizeof(req)); @@ -1640,6 +1642,7 @@ static int ath11k_qmi_host_cap_send(struct ath11k_base *ab) QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN, qmi_wlanfw_host_cap_req_msg_v01_ei, &req); if (ret < 0) { + qmi_txn_cancel(&txn); ath11k_warn(ab, "failed to send host capability request: %d\n", ret); goto out; } @@ -1705,6 +1708,7 @@ static int ath11k_qmi_fw_ind_register_send(struct ath11k_base *ab) QMI_WLANFW_IND_REGISTER_REQ_MSG_V01_MAX_LEN, qmi_wlanfw_ind_register_req_msg_v01_ei, req); if (ret < 0) { + qmi_txn_cancel(&txn); ath11k_warn(ab, "failed to send indication register request: %d\n", ret); goto out; @@ -1734,7 +1738,7 @@ static int ath11k_qmi_respond_fw_mem_request(struct ath11k_base *ab) { struct qmi_wlanfw_respond_mem_req_msg_v01 *req; struct qmi_wlanfw_respond_mem_resp_msg_v01 resp; - struct qmi_txn txn = {}; + struct qmi_txn txn; int ret = 0, i; bool delayed; @@ -1749,7 +1753,9 @@ static int ath11k_qmi_respond_fw_mem_request(struct ath11k_base *ab) * failure to FW and FW will then request mulitple blocks of small * chunk size memory. */ - if (!ab->bus_params.fixed_mem_region && ab->qmi.target_mem_delayed) { + if (!(ab->bus_params.fixed_mem_region || + test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) && + ab->qmi.target_mem_delayed) { delayed = true; ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi delays mem_request %d\n", ab->qmi.mem_seg_count); @@ -1783,6 +1789,7 @@ static int ath11k_qmi_respond_fw_mem_request(struct ath11k_base *ab) QMI_WLANFW_RESPOND_MEM_REQ_MSG_V01_MAX_LEN, qmi_wlanfw_respond_mem_req_msg_v01_ei, req); if (ret < 0) { + qmi_txn_cancel(&txn); ath11k_warn(ab, "failed to respond qmi memory request: %d\n", ret); goto out; @@ -1815,10 +1822,12 @@ static void ath11k_qmi_free_target_mem_chunk(struct ath11k_base *ab) { int i; - if (ab->bus_params.fixed_mem_region) - return; - for (i = 0; i < ab->qmi.mem_seg_count; i++) { + if ((ab->bus_params.fixed_mem_region || + test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) && + ab->qmi.target_mem[i].iaddr) + iounmap(ab->qmi.target_mem[i].iaddr); + if (!ab->qmi.target_mem[i].vaddr) continue; @@ -1866,10 +1875,44 @@ static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab) static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab) { - int i, idx; + struct device *dev = ab->dev; + struct device_node *hremote_node = NULL; + struct resource res; + u32 host_ddr_sz; + int i, idx, ret; for (i = 0, idx = 0; i < ab->qmi.mem_seg_count; i++) { switch (ab->qmi.target_mem[i].type) { + case HOST_DDR_REGION_TYPE: + hremote_node = of_parse_phandle(dev->of_node, "memory-region", 0); + if (!hremote_node) { + ath11k_dbg(ab, ATH11K_DBG_QMI, + "qmi fail to get hremote_node\n"); + return ret; + } + + ret = of_address_to_resource(hremote_node, 0, &res); + if (ret) { + ath11k_dbg(ab, ATH11K_DBG_QMI, + "qmi fail to get reg from hremote\n"); + return ret; + } + + if (res.end - res.start + 1 < ab->qmi.target_mem[i].size) { + ath11k_dbg(ab, ATH11K_DBG_QMI, + "qmi fail to assign memory of sz\n"); + return -EINVAL; + } + + ab->qmi.target_mem[idx].paddr = res.start; + ab->qmi.target_mem[idx].iaddr = + ioremap(ab->qmi.target_mem[idx].paddr, + ab->qmi.target_mem[i].size); + ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size; + host_ddr_sz = ab->qmi.target_mem[i].size; + ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type; + idx++; + break; case BDF_MEM_REGION_TYPE: ab->qmi.target_mem[idx].paddr = ab->hw_params.bdf_addr; ab->qmi.target_mem[idx].vaddr = NULL; @@ -1884,10 +1927,16 @@ static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab) } if (ath11k_cold_boot_cal && ab->hw_params.cold_boot_calib) { - ab->qmi.target_mem[idx].paddr = - ATH11K_QMI_CALDB_ADDRESS; - ab->qmi.target_mem[idx].vaddr = - (void *)ATH11K_QMI_CALDB_ADDRESS; + if (hremote_node) { + ab->qmi.target_mem[idx].paddr = + res.start + host_ddr_sz; + ab->qmi.target_mem[idx].iaddr = + ioremap(ab->qmi.target_mem[idx].paddr, + ab->qmi.target_mem[i].size); + } else { + ab->qmi.target_mem[idx].paddr = + ATH11K_QMI_CALDB_ADDRESS; + } } else { ab->qmi.target_mem[idx].paddr = 0; ab->qmi.target_mem[idx].vaddr = NULL; @@ -1911,7 +1960,7 @@ static int ath11k_qmi_request_target_cap(struct ath11k_base *ab) { struct qmi_wlanfw_cap_req_msg_v01 req; struct qmi_wlanfw_cap_resp_msg_v01 resp; - struct qmi_txn txn = {}; + struct qmi_txn txn; int ret = 0; int r; @@ -1930,6 +1979,7 @@ static int ath11k_qmi_request_target_cap(struct ath11k_base *ab) QMI_WLANFW_CAP_REQ_MSG_V01_MAX_LEN, qmi_wlanfw_cap_req_msg_v01_ei, &req); if (ret < 0) { + qmi_txn_cancel(&txn); ath11k_warn(ab, "failed to send qmi cap request: %d\n", ret); goto out; @@ -2000,7 +2050,7 @@ static int ath11k_qmi_load_file_target_mem(struct ath11k_base *ab, { struct qmi_wlanfw_bdf_download_req_msg_v01 *req; struct qmi_wlanfw_bdf_download_resp_msg_v01 resp; - struct qmi_txn txn = {}; + struct qmi_txn txn; const u8 *temp = data; void __iomem *bdf_addr = NULL; int ret; @@ -2245,7 +2295,7 @@ static int ath11k_qmi_wlanfw_m3_info_send(struct ath11k_base *ab) struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; struct qmi_wlanfw_m3_info_req_msg_v01 req; struct qmi_wlanfw_m3_info_resp_msg_v01 resp; - struct qmi_txn txn = {}; + struct qmi_txn txn; int ret = 0; memset(&req, 0, sizeof(req)); @@ -2277,6 +2327,7 @@ static int ath11k_qmi_wlanfw_m3_info_send(struct ath11k_base *ab) QMI_WLANFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN, qmi_wlanfw_m3_info_req_msg_v01_ei, &req); if (ret < 0) { + qmi_txn_cancel(&txn); ath11k_warn(ab, "failed to send m3 information request: %d\n", ret); goto out; @@ -2303,7 +2354,7 @@ static int ath11k_qmi_wlanfw_mode_send(struct ath11k_base *ab, { struct qmi_wlanfw_wlan_mode_req_msg_v01 req; struct qmi_wlanfw_wlan_mode_resp_msg_v01 resp; - struct qmi_txn txn = {}; + struct qmi_txn txn; int ret = 0; memset(&req, 0, sizeof(req)); @@ -2325,6 +2376,7 @@ static int ath11k_qmi_wlanfw_mode_send(struct ath11k_base *ab, QMI_WLANFW_WLAN_MODE_REQ_MSG_V01_MAX_LEN, qmi_wlanfw_wlan_mode_req_msg_v01_ei, &req); if (ret < 0) { + qmi_txn_cancel(&txn); ath11k_warn(ab, "failed to send wlan mode request (mode %d): %d\n", mode, ret); goto out; @@ -2358,7 +2410,7 @@ static int ath11k_qmi_wlanfw_wlan_cfg_send(struct ath11k_base *ab) struct qmi_wlanfw_wlan_cfg_resp_msg_v01 resp; struct ce_pipe_config *ce_cfg; struct service_to_pipe *svc_cfg; - struct qmi_txn txn = {}; + struct qmi_txn txn; int ret = 0, pipe_num; ce_cfg = (struct ce_pipe_config *)ab->qmi.ce_cfg.tgt_ce; @@ -2419,6 +2471,7 @@ static int ath11k_qmi_wlanfw_wlan_cfg_send(struct ath11k_base *ab) QMI_WLANFW_WLAN_CFG_REQ_MSG_V01_MAX_LEN, qmi_wlanfw_wlan_cfg_req_msg_v01_ei, req); if (ret < 0) { + qmi_txn_cancel(&txn); ath11k_warn(ab, "failed to send wlan config request: %d\n", ret); goto out; @@ -2614,7 +2667,8 @@ static void ath11k_qmi_msg_mem_request_cb(struct qmi_handle *qmi_hdl, msg->mem_seg[i].type, msg->mem_seg[i].size); } - if (ab->bus_params.fixed_mem_region) { + if (ab->bus_params.fixed_mem_region || + test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) { ret = ath11k_qmi_assign_target_mem_chunk(ab); if (ret) { ath11k_warn(ab, "failed to assign qmi target memory: %d\n", @@ -2823,7 +2877,7 @@ int ath11k_qmi_init_service(struct ath11k_base *ab) memset(&ab->qmi.target_mem, 0, sizeof(struct target_mem_chunk)); ab->qmi.ab = ab; - ab->qmi.target_mem_mode = ATH11K_QMI_TARGET_MEM_MODE_DEFAULT; + ab->qmi.target_mem_mode = ab->hw_params.fw_mem_mode; ret = qmi_handle_init(&ab->qmi.handle, ATH11K_QMI_RESP_LEN_MAX, &ath11k_qmi_ops, ath11k_qmi_msg_handlers); if (ret < 0) { diff --git a/drivers/net/wireless/ath/ath11k/qmi.h b/drivers/net/wireless/ath/ath11k/qmi.h index 3bb0f9ef7996..a6fb7d47ee82 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.h +++ b/drivers/net/wireless/ath/ath11k/qmi.h @@ -34,14 +34,13 @@ #define QMI_WLANFW_MAX_DATA_SIZE_V01 6144 #define ATH11K_FIRMWARE_MODE_OFF 4 -#define ATH11K_QMI_TARGET_MEM_MODE_DEFAULT 0 #define ATH11K_COLD_BOOT_FW_RESET_DELAY (40 * HZ) struct ath11k_base; enum ath11k_qmi_file_type { ATH11K_QMI_FILE_TYPE_BDF_GOLDEN, - ATH11K_QMI_FILE_TYPE_CALDATA, + ATH11K_QMI_FILE_TYPE_CALDATA = 2, ATH11K_QMI_FILE_TYPE_EEPROM, ATH11K_QMI_MAX_FILE_TYPE, }; @@ -95,6 +94,7 @@ struct target_mem_chunk { u32 type; dma_addr_t paddr; u32 *vaddr; + void __iomem *iaddr; }; struct target_info { diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index a66b5bdd2167..1f8a81987187 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -86,6 +86,9 @@ ath11k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) if (ret) ath11k_warn(ar->ab, "INIT Country code set to fw failed : %d\n", ret); + + ath11k_mac_11d_scan_stop(ar); + ar->regdom_set_by_user = true; } int ath11k_reg_update_chan_list(struct ath11k *ar) @@ -179,6 +182,11 @@ int ath11k_reg_update_chan_list(struct ath11k *ar) ret = ath11k_wmi_send_scan_chan_list_cmd(ar, params); kfree(params); + if (ar->pending_11d) { + complete(&ar->finish_11d_ch_list); + ar->pending_11d = false; + } + return ret; } @@ -244,8 +252,15 @@ int ath11k_regd_update(struct ath11k *ar) goto err; } + if (ar->pending_11d) + complete(&ar->finish_11d_scan); + rtnl_lock(); wiphy_lock(ar->hw->wiphy); + + if (ar->pending_11d) + reinit_completion(&ar->finish_11d_ch_list); + ret = regulatory_set_wiphy_regd_sync(ar->hw->wiphy, regd_copy); wiphy_unlock(ar->hw->wiphy); rtnl_unlock(); @@ -456,6 +471,9 @@ ath11k_reg_adjust_bw(u16 start_freq, u16 end_freq, u16 max_bw) { u16 bw; + if (end_freq <= start_freq) + return 0; + bw = end_freq - start_freq; bw = min_t(u16, bw, max_bw); @@ -463,8 +481,10 @@ ath11k_reg_adjust_bw(u16 start_freq, u16 end_freq, u16 max_bw) bw = 80; else if (bw >= 40 && bw < 80) bw = 40; - else if (bw < 40) + else if (bw >= 20 && bw < 40) bw = 20; + else + bw = 0; return bw; } @@ -488,73 +508,77 @@ ath11k_reg_update_weather_radar_band(struct ath11k_base *ab, struct cur_reg_rule *reg_rule, u8 *rule_idx, u32 flags, u16 max_bw) { + u32 start_freq; u32 end_freq; u16 bw; u8 i; i = *rule_idx; + /* there might be situations when even the input rule must be dropped */ + i--; + + /* frequencies below weather radar */ bw = ath11k_reg_adjust_bw(reg_rule->start_freq, ETSI_WEATHER_RADAR_BAND_LOW, max_bw); + if (bw > 0) { + i++; - ath11k_reg_update_rule(regd->reg_rules + i, reg_rule->start_freq, - ETSI_WEATHER_RADAR_BAND_LOW, bw, - reg_rule->ant_gain, reg_rule->reg_power, - flags); + ath11k_reg_update_rule(regd->reg_rules + i, + reg_rule->start_freq, + ETSI_WEATHER_RADAR_BAND_LOW, bw, + reg_rule->ant_gain, reg_rule->reg_power, + flags); - ath11k_dbg(ab, ATH11K_DBG_REG, - "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", - i + 1, reg_rule->start_freq, ETSI_WEATHER_RADAR_BAND_LOW, - bw, reg_rule->ant_gain, reg_rule->reg_power, - regd->reg_rules[i].dfs_cac_ms, - flags); - - if (reg_rule->end_freq > ETSI_WEATHER_RADAR_BAND_HIGH) - end_freq = ETSI_WEATHER_RADAR_BAND_HIGH; - else - end_freq = reg_rule->end_freq; + ath11k_dbg(ab, ATH11K_DBG_REG, + "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", + i + 1, reg_rule->start_freq, + ETSI_WEATHER_RADAR_BAND_LOW, bw, reg_rule->ant_gain, + reg_rule->reg_power, regd->reg_rules[i].dfs_cac_ms, + flags); + } - bw = ath11k_reg_adjust_bw(ETSI_WEATHER_RADAR_BAND_LOW, end_freq, - max_bw); + /* weather radar frequencies */ + start_freq = max_t(u32, reg_rule->start_freq, + ETSI_WEATHER_RADAR_BAND_LOW); + end_freq = min_t(u32, reg_rule->end_freq, ETSI_WEATHER_RADAR_BAND_HIGH); - i++; + bw = ath11k_reg_adjust_bw(start_freq, end_freq, max_bw); + if (bw > 0) { + i++; - ath11k_reg_update_rule(regd->reg_rules + i, - ETSI_WEATHER_RADAR_BAND_LOW, end_freq, bw, - reg_rule->ant_gain, reg_rule->reg_power, - flags); + ath11k_reg_update_rule(regd->reg_rules + i, start_freq, + end_freq, bw, reg_rule->ant_gain, + reg_rule->reg_power, flags); - regd->reg_rules[i].dfs_cac_ms = ETSI_WEATHER_RADAR_BAND_CAC_TIMEOUT; + regd->reg_rules[i].dfs_cac_ms = ETSI_WEATHER_RADAR_BAND_CAC_TIMEOUT; - ath11k_dbg(ab, ATH11K_DBG_REG, - "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", - i + 1, ETSI_WEATHER_RADAR_BAND_LOW, end_freq, - bw, reg_rule->ant_gain, reg_rule->reg_power, - regd->reg_rules[i].dfs_cac_ms, - flags); - - if (end_freq == reg_rule->end_freq) { - regd->n_reg_rules--; - *rule_idx = i; - return; + ath11k_dbg(ab, ATH11K_DBG_REG, + "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", + i + 1, start_freq, end_freq, bw, + reg_rule->ant_gain, reg_rule->reg_power, + regd->reg_rules[i].dfs_cac_ms, flags); } + /* frequencies above weather radar */ bw = ath11k_reg_adjust_bw(ETSI_WEATHER_RADAR_BAND_HIGH, reg_rule->end_freq, max_bw); + if (bw > 0) { + i++; - i++; - - ath11k_reg_update_rule(regd->reg_rules + i, ETSI_WEATHER_RADAR_BAND_HIGH, - reg_rule->end_freq, bw, - reg_rule->ant_gain, reg_rule->reg_power, - flags); + ath11k_reg_update_rule(regd->reg_rules + i, + ETSI_WEATHER_RADAR_BAND_HIGH, + reg_rule->end_freq, bw, + reg_rule->ant_gain, reg_rule->reg_power, + flags); - ath11k_dbg(ab, ATH11K_DBG_REG, - "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", - i + 1, ETSI_WEATHER_RADAR_BAND_HIGH, reg_rule->end_freq, - bw, reg_rule->ant_gain, reg_rule->reg_power, - regd->reg_rules[i].dfs_cac_ms, - flags); + ath11k_dbg(ab, ATH11K_DBG_REG, + "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", + i + 1, ETSI_WEATHER_RADAR_BAND_HIGH, + reg_rule->end_freq, bw, reg_rule->ant_gain, + reg_rule->reg_power, regd->reg_rules[i].dfs_cac_ms, + flags); + } *rule_idx = i; } diff --git a/drivers/net/wireless/ath/ath11k/spectral.c b/drivers/net/wireless/ath/ath11k/spectral.c index ac4da99b5577..4100cc1449a2 100644 --- a/drivers/net/wireless/ath/ath11k/spectral.c +++ b/drivers/net/wireless/ath/ath11k/spectral.c @@ -581,6 +581,7 @@ int ath11k_spectral_process_fft(struct ath11k *ar, u16 length, freq; u8 chan_width_mhz, bin_sz; int ret; + u32 check_length; lockdep_assert_held(&ar->spectral.lock); @@ -614,6 +615,13 @@ int ath11k_spectral_process_fft(struct ath11k *ar, return -EINVAL; } + check_length = sizeof(*fft_report) + (num_bins * ab->hw_params.spectral.fft_sz); + ret = ath11k_dbring_validate_buffer(ar, data, check_length); + if (ret) { + ath11k_warn(ar->ab, "found magic value in fft data, dropping\n"); + return ret; + } + ret = ath11k_spectral_pull_search(ar, data, &search); if (ret) { ath11k_warn(ab, "failed to pull search report %d\n", ret); @@ -747,6 +755,12 @@ static int ath11k_spectral_process_data(struct ath11k *ar, goto err; } + ret = ath11k_dbring_validate_buffer(ar, data, tlv_len); + if (ret) { + ath11k_warn(ar->ab, "found magic value in spectral summary, dropping\n"); + goto err; + } + summary = (struct spectral_summary_fft_report *)tlv; ath11k_spectral_pull_summary(ar, ¶m->meta, summary, &summ_rpt); diff --git a/drivers/net/wireless/ath/ath11k/trace.c b/drivers/net/wireless/ath/ath11k/trace.c index f0cc49ba0387..6620650d7845 100644 --- a/drivers/net/wireless/ath/ath11k/trace.c +++ b/drivers/net/wireless/ath/ath11k/trace.c @@ -7,3 +7,4 @@ #define CREATE_TRACE_POINTS #include "trace.h" +EXPORT_SYMBOL(__tracepoint_ath11k_log_dbg); diff --git a/drivers/net/wireless/ath/ath11k/trace.h b/drivers/net/wireless/ath/ath11k/trace.h index 25d18e9d5b0b..02003dc4207d 100644 --- a/drivers/net/wireless/ath/ath11k/trace.h +++ b/drivers/net/wireless/ath/ath11k/trace.h @@ -14,12 +14,24 @@ #if !defined(CONFIG_ATH11K_TRACING) #undef TRACE_EVENT #define TRACE_EVENT(name, proto, ...) \ +static inline void trace_ ## name(proto) {} \ +static inline bool trace_##name##_enabled(void) \ +{ \ + return false; \ +} + +#undef DECLARE_EVENT_CLASS +#define DECLARE_EVENT_CLASS(...) +#undef DEFINE_EVENT +#define DEFINE_EVENT(evt_class, name, proto, ...) \ static inline void trace_ ## name(proto) {} #endif /* !CONFIG_ATH11K_TRACING || __CHECKER__ */ #undef TRACE_SYSTEM #define TRACE_SYSTEM ath11k +#define ATH11K_MSG_MAX 400 + TRACE_EVENT(ath11k_htt_pktlog, TP_PROTO(struct ath11k *ar, const void *buf, u16 buf_len, u32 pktlog_checksum), @@ -108,6 +120,166 @@ TRACE_EVENT(ath11k_htt_rxdesc, ) ); +DECLARE_EVENT_CLASS(ath11k_log_event, + TP_PROTO(struct ath11k_base *ab, struct va_format *vaf), + TP_ARGS(ab, vaf), + TP_STRUCT__entry( + __string(device, dev_name(ab->dev)) + __string(driver, dev_driver_string(ab->dev)) + __dynamic_array(char, msg, ATH11K_MSG_MAX) + ), + TP_fast_assign( + __assign_str(device, dev_name(ab->dev)); + __assign_str(driver, dev_driver_string(ab->dev)); + WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), + ATH11K_MSG_MAX, + vaf->fmt, + *vaf->va) >= ATH11K_MSG_MAX); + ), + TP_printk( + "%s %s %s", + __get_str(driver), + __get_str(device), + __get_str(msg) + ) +); + +DEFINE_EVENT(ath11k_log_event, ath11k_log_err, + TP_PROTO(struct ath11k_base *ab, struct va_format *vaf), + TP_ARGS(ab, vaf) +); + +DEFINE_EVENT(ath11k_log_event, ath11k_log_warn, + TP_PROTO(struct ath11k_base *ab, struct va_format *vaf), + TP_ARGS(ab, vaf) +); + +DEFINE_EVENT(ath11k_log_event, ath11k_log_info, + TP_PROTO(struct ath11k_base *ab, struct va_format *vaf), + TP_ARGS(ab, vaf) +); + +TRACE_EVENT(ath11k_wmi_cmd, + TP_PROTO(struct ath11k_base *ab, int id, const void *buf, size_t buf_len), + + TP_ARGS(ab, id, buf, buf_len), + + TP_STRUCT__entry( + __string(device, dev_name(ab->dev)) + __string(driver, dev_driver_string(ab->dev)) + __field(unsigned int, id) + __field(size_t, buf_len) + __dynamic_array(u8, buf, buf_len) + ), + + TP_fast_assign( + __assign_str(device, dev_name(ab->dev)); + __assign_str(driver, dev_driver_string(ab->dev)); + __entry->id = id; + __entry->buf_len = buf_len; + memcpy(__get_dynamic_array(buf), buf, buf_len); + ), + + TP_printk( + "%s %s id %d len %zu", + __get_str(driver), + __get_str(device), + __entry->id, + __entry->buf_len + ) +); + +TRACE_EVENT(ath11k_wmi_event, + TP_PROTO(struct ath11k_base *ab, int id, const void *buf, size_t buf_len), + + TP_ARGS(ab, id, buf, buf_len), + + TP_STRUCT__entry( + __string(device, dev_name(ab->dev)) + __string(driver, dev_driver_string(ab->dev)) + __field(unsigned int, id) + __field(size_t, buf_len) + __dynamic_array(u8, buf, buf_len) + ), + + TP_fast_assign( + __assign_str(device, dev_name(ab->dev)); + __assign_str(driver, dev_driver_string(ab->dev)); + __entry->id = id; + __entry->buf_len = buf_len; + memcpy(__get_dynamic_array(buf), buf, buf_len); + ), + + TP_printk( + "%s %s id %d len %zu", + __get_str(driver), + __get_str(device), + __entry->id, + __entry->buf_len + ) +); + +TRACE_EVENT(ath11k_log_dbg, + TP_PROTO(struct ath11k_base *ab, unsigned int level, struct va_format *vaf), + + TP_ARGS(ab, level, vaf), + + TP_STRUCT__entry( + __string(device, dev_name(ab->dev)) + __string(driver, dev_driver_string(ab->dev)) + __field(unsigned int, level) + __dynamic_array(char, msg, ATH11K_MSG_MAX) + ), + + TP_fast_assign( + __assign_str(device, dev_name(ab->dev)); + __assign_str(driver, dev_driver_string(ab->dev)); + __entry->level = level; + WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), + ATH11K_MSG_MAX, vaf->fmt, + *vaf->va) >= ATH11K_MSG_MAX); + ), + + TP_printk( + "%s %s %s", + __get_str(driver), + __get_str(device), + __get_str(msg) + ) +); + +TRACE_EVENT(ath11k_log_dbg_dump, + TP_PROTO(struct ath11k_base *ab, const char *msg, const char *prefix, + const void *buf, size_t buf_len), + + TP_ARGS(ab, msg, prefix, buf, buf_len), + + TP_STRUCT__entry( + __string(device, dev_name(ab->dev)) + __string(driver, dev_driver_string(ab->dev)) + __string(msg, msg) + __string(prefix, prefix) + __field(size_t, buf_len) + __dynamic_array(u8, buf, buf_len) + ), + + TP_fast_assign( + __assign_str(device, dev_name(ab->dev)); + __assign_str(driver, dev_driver_string(ab->dev)); + __assign_str(msg, msg); + __assign_str(prefix, prefix); + __entry->buf_len = buf_len; + memcpy(__get_dynamic_array(buf), buf, buf_len); + ), + + TP_printk( + "%s %s %s/%s\n", + __get_str(driver), + __get_str(device), + __get_str(prefix), + __get_str(msg) + ) +); #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/ /* we don't want to use include/trace/events */ diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 5ae2ef4680d6..2b4d27d807ab 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -128,6 +128,10 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = { .min_len = sizeof(struct wmi_probe_resp_tx_status_event) }, [WMI_TAG_VDEV_DELETE_RESP_EVENT] = { .min_len = sizeof(struct wmi_vdev_delete_resp_event) }, + [WMI_TAG_OBSS_COLOR_COLLISION_EVT] = { + .min_len = sizeof(struct wmi_obss_color_collision_event) }, + [WMI_TAG_11D_NEW_COUNTRY_EVENT] = { + .min_len = sizeof(struct wmi_11d_new_cc_ev) }, }; #define PRIMAP(_hw_mode_) \ @@ -249,6 +253,8 @@ static int ath11k_wmi_cmd_send_nowait(struct ath11k_pdev_wmi *wmi, struct sk_buf cmd_hdr = (struct wmi_cmd_hdr *)skb->data; cmd_hdr->cmd_id = cmd; + trace_ath11k_wmi_cmd(ab, cmd_id, skb->data, skb->len); + memset(skb_cb, 0, sizeof(*skb_cb)); ret = ath11k_htc_send(&ab->htc, wmi->eid, skb); @@ -267,21 +273,39 @@ int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb, { struct ath11k_wmi_base *wmi_sc = wmi->wmi_ab; int ret = -EOPNOTSUPP; + struct ath11k_base *ab = wmi_sc->ab; might_sleep(); - wait_event_timeout(wmi_sc->tx_credits_wq, ({ - ret = ath11k_wmi_cmd_send_nowait(wmi, skb, cmd_id); + if (ab->hw_params.credit_flow) { + wait_event_timeout(wmi_sc->tx_credits_wq, ({ + ret = ath11k_wmi_cmd_send_nowait(wmi, skb, cmd_id); - if (ret && test_bit(ATH11K_FLAG_CRASH_FLUSH, &wmi_sc->ab->dev_flags)) - ret = -ESHUTDOWN; + if (ret && test_bit(ATH11K_FLAG_CRASH_FLUSH, + &wmi_sc->ab->dev_flags)) + ret = -ESHUTDOWN; + + (ret != -EAGAIN); + }), WMI_SEND_TIMEOUT_HZ); + } else { + wait_event_timeout(wmi->tx_ce_desc_wq, ({ + ret = ath11k_wmi_cmd_send_nowait(wmi, skb, cmd_id); - (ret != -EAGAIN); - }), WMI_SEND_TIMEOUT_HZ); + if (ret && test_bit(ATH11K_FLAG_CRASH_FLUSH, + &wmi_sc->ab->dev_flags)) + ret = -ESHUTDOWN; + + (ret != -ENOBUFS); + }), WMI_SEND_TIMEOUT_HZ); + } if (ret == -EAGAIN) ath11k_warn(wmi_sc->ab, "wmi command %d timeout\n", cmd_id); + if (ret == -ENOBUFS) + ath11k_warn(wmi_sc->ab, "ce desc not available for wmi command %d\n", + cmd_id); + return ret; } @@ -315,6 +339,7 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(struct ath11k_pdev_wmi *wmi_handle, struct ath11k_pdev *pdev) { struct wmi_mac_phy_capabilities *mac_phy_caps; + struct ath11k_base *ab = wmi_handle->wmi_ab->ab; struct ath11k_band_cap *cap_band; struct ath11k_pdev_cap *pdev_cap = &pdev->cap; u32 phy_map; @@ -346,6 +371,10 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(struct ath11k_pdev_wmi *wmi_handle, pdev->pdev_id = mac_phy_caps->pdev_id; pdev_cap->supported_bands |= mac_phy_caps->supported_bands; pdev_cap->ampdu_density = mac_phy_caps->ampdu_density; + ab->target_pdev_ids[ab->target_pdev_count].supported_bands = + mac_phy_caps->supported_bands; + ab->target_pdev_ids[ab->target_pdev_count].pdev_id = mac_phy_caps->pdev_id; + ab->target_pdev_count++; /* Take non-zero tx/rx chainmask. If tx/rx chainmask differs from * band to band for a single radio, need to see how this should be @@ -1244,7 +1273,8 @@ int ath11k_wmi_pdev_set_param(struct ath11k *ar, u32 param_id, return ret; } -int ath11k_wmi_pdev_set_ps_mode(struct ath11k *ar, int vdev_id, u32 enable) +int ath11k_wmi_pdev_set_ps_mode(struct ath11k *ar, int vdev_id, + enum wmi_sta_ps_mode psmode) { struct ath11k_pdev_wmi *wmi = ar->wmi; struct wmi_pdev_set_ps_mode_cmd *cmd; @@ -1259,7 +1289,7 @@ int ath11k_wmi_pdev_set_ps_mode(struct ath11k *ar, int vdev_id, u32 enable) cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_STA_POWERSAVE_MODE_CMD) | FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); cmd->vdev_id = vdev_id; - cmd->sta_ps_mode = enable; + cmd->sta_ps_mode = psmode; ret = ath11k_wmi_cmd_send(wmi, skb, WMI_STA_POWERSAVE_MODE_CMDID); if (ret) { @@ -1269,7 +1299,7 @@ int ath11k_wmi_pdev_set_ps_mode(struct ath11k *ar, int vdev_id, u32 enable) ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "WMI vdev set psmode %d vdev id %d\n", - enable, vdev_id); + psmode, vdev_id); return ret; } @@ -1612,6 +1642,15 @@ int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id, void *ptr; int ret, len; size_t aligned_len = roundup(bcn->len, 4); + struct ieee80211_vif *vif; + struct ath11k_vif *arvif = ath11k_mac_get_arvif(ar, vdev_id); + + if (!arvif) { + ath11k_warn(ar->ab, "failed to find arvif with vdev id %d\n", vdev_id); + return -EINVAL; + } + + vif = arvif->vif; len = sizeof(*cmd) + sizeof(*bcn_prb_info) + TLV_HDR_SIZE + aligned_len; @@ -1624,8 +1663,12 @@ int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id, FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); cmd->vdev_id = vdev_id; cmd->tim_ie_offset = offs->tim_offset; - cmd->csa_switch_count_offset = offs->cntdwn_counter_offs[0]; - cmd->ext_csa_switch_count_offset = offs->cntdwn_counter_offs[1]; + + if (vif->csa_active) { + cmd->csa_switch_count_offset = offs->cntdwn_counter_offs[0]; + cmd->ext_csa_switch_count_offset = offs->cntdwn_counter_offs[1]; + } + cmd->buf_len = bcn->len; ptr = skb->data + sizeof(*cmd); @@ -1689,7 +1732,8 @@ int ath11k_wmi_vdev_install_key(struct ath11k *ar, tlv = (struct wmi_tlv *)(skb->data + sizeof(*cmd)); tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) | FIELD_PREP(WMI_TLV_LEN, key_len_aligned); - memcpy(tlv->value, (u8 *)arg->key_data, key_len_aligned); + if (arg->key_data) + memcpy(tlv->value, (u8 *)arg->key_data, key_len_aligned); ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_INSTALL_KEY_CMDID); if (ret) { @@ -1762,7 +1806,7 @@ ath11k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd, cmd->peer_flags |= WMI_PEER_AUTH; if (param->need_ptk_4_way) { cmd->peer_flags |= WMI_PEER_NEED_PTK_4_WAY; - if (!hw_crypto_disabled) + if (!hw_crypto_disabled && param->is_assoc) cmd->peer_flags &= ~WMI_PEER_AUTH; } if (param->need_gtk_2_way) @@ -2069,7 +2113,7 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar, void *ptr; int i, ret, len; u32 *tmp_ptr; - u8 extraie_len_with_pad = 0; + u16 extraie_len_with_pad = 0; struct hint_short_ssid *s_ssid = NULL; struct hint_bssid *hint_bssid = NULL; @@ -2088,7 +2132,7 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar, len += sizeof(*bssid) * params->num_bssid; len += TLV_HDR_SIZE; - if (params->extraie.len) + if (params->extraie.len && params->extraie.len <= 0xFFFF) extraie_len_with_pad = roundup(params->extraie.len, sizeof(u32)); len += extraie_len_with_pad; @@ -2137,6 +2181,8 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar, cmd->num_ssids = params->num_ssids; cmd->ie_len = params->extraie.len; cmd->n_probes = params->n_probes; + ether_addr_copy(cmd->mac_addr.addr, params->mac_addr.addr); + ether_addr_copy(cmd->mac_mask.addr, params->mac_mask.addr); ptr += sizeof(*cmd); @@ -2195,7 +2241,7 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar, FIELD_PREP(WMI_TLV_LEN, len); ptr += TLV_HDR_SIZE; - if (params->extraie.len) + if (extraie_len_with_pad) memcpy(ptr, params->extraie.ptr, params->extraie.len); @@ -2386,6 +2432,8 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar, tchan_info->reg_class_id); *reg2 |= FIELD_PREP(WMI_CHAN_REG_INFO2_ANT_MAX, tchan_info->antennamax); + *reg2 |= FIELD_PREP(WMI_CHAN_REG_INFO2_MAX_TX_PWR, + tchan_info->maxregpower); ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "WMI chan scan list chan[%d] = %u, chan_info->info %8x\n", @@ -2754,6 +2802,42 @@ out: return ret; } +int ath11k_wmi_send_set_current_country_cmd(struct ath11k *ar, + struct wmi_set_current_country_params *param) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct wmi_set_current_country_cmd *cmd; + struct sk_buff *skb; + int ret; + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_current_country_cmd *)skb->data; + cmd->tlv_header = + FIELD_PREP(WMI_TLV_TAG, WMI_TAG_SET_CURRENT_COUNTRY_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + + cmd->pdev_id = ar->pdev->pdev_id; + memcpy(&cmd->new_alpha2, ¶m->alpha2, 3); + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_SET_CURRENT_COUNTRY_CMDID); + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "set current country pdev id %d alpha2 %c%c\n", + ar->pdev->pdev_id, + param->alpha2[0], + param->alpha2[1]); + + if (ret) { + ath11k_warn(ar->ab, + "failed to send WMI_SET_CURRENT_COUNTRY_CMDID: %d\n", ret); + dev_kfree_skb(skb); + } + + return ret; +} + int ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar, struct thermal_mitigation_params *param) @@ -2818,6 +2902,75 @@ ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar, return ret; } +int ath11k_wmi_send_11d_scan_start_cmd(struct ath11k *ar, + struct wmi_11d_scan_start_params *param) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct wmi_11d_scan_start_cmd *cmd; + struct sk_buff *skb; + int ret; + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_11d_scan_start_cmd *)skb->data; + cmd->tlv_header = + FIELD_PREP(WMI_TLV_TAG, WMI_TAG_11D_SCAN_START_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + + cmd->vdev_id = param->vdev_id; + cmd->scan_period_msec = param->scan_period_msec; + cmd->start_interval_msec = param->start_interval_msec; + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_START_CMDID); + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "send 11d scan start vdev id %d period %d ms internal %d ms\n", + cmd->vdev_id, + cmd->scan_period_msec, + cmd->start_interval_msec); + + if (ret) { + ath11k_warn(ar->ab, + "failed to send WMI_11D_SCAN_START_CMDID: %d\n", ret); + dev_kfree_skb(skb); + } + + return ret; +} + +int ath11k_wmi_send_11d_scan_stop_cmd(struct ath11k *ar, u32 vdev_id) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct wmi_11d_scan_stop_cmd *cmd; + struct sk_buff *skb; + int ret; + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_11d_scan_stop_cmd *)skb->data; + cmd->tlv_header = + FIELD_PREP(WMI_TLV_TAG, WMI_TAG_11D_SCAN_STOP_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + + cmd->vdev_id = vdev_id; + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_STOP_CMDID); + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "send 11d scan stop vdev id %d\n", + cmd->vdev_id); + + if (ret) { + ath11k_warn(ar->ab, + "failed to send WMI_11D_SCAN_STOP_CMDID: %d\n", ret); + dev_kfree_skb(skb); + } + + return ret; +} + int ath11k_wmi_pdev_pktlog_enable(struct ath11k *ar, u32 pktlog_filter) { struct ath11k_pdev_wmi *wmi = ar->wmi; @@ -3428,6 +3581,53 @@ int ath11k_wmi_fils_discovery(struct ath11k *ar, u32 vdev_id, u32 interval, } static void +ath11k_wmi_obss_color_collision_event(struct ath11k_base *ab, struct sk_buff *skb) +{ + const void **tb; + const struct wmi_obss_color_collision_event *ev; + struct ath11k_vif *arvif; + int ret; + + tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath11k_warn(ab, "failed to parse tlv: %d\n", ret); + return; + } + + ev = tb[WMI_TAG_OBSS_COLOR_COLLISION_EVT]; + if (!ev) { + ath11k_warn(ab, "failed to fetch obss color collision ev"); + goto exit; + } + + arvif = ath11k_mac_get_arvif_by_vdev_id(ab, ev->vdev_id); + if (!arvif) { + ath11k_warn(ab, "failed to find arvif with vedv id %d in obss_color_collision_event\n", + ev->vdev_id); + goto exit; + } + + switch (ev->evt_type) { + case WMI_BSS_COLOR_COLLISION_DETECTION: + ieeee80211_obss_color_collision_notify(arvif->vif, ev->obss_color_bitmap); + ath11k_dbg(ab, ATH11K_DBG_WMI, + "OBSS color collision detected vdev:%d, event:%d, bitmap:%08llx\n", + ev->vdev_id, ev->evt_type, ev->obss_color_bitmap); + break; + case WMI_BSS_COLOR_COLLISION_DISABLE: + case WMI_BSS_COLOR_FREE_SLOT_TIMER_EXPIRY: + case WMI_BSS_COLOR_FREE_SLOT_AVAILABLE: + break; + default: + ath11k_warn(ab, "received unknown obss color collision detection event\n"); + } + +exit: + kfree(tb); +} + +static void ath11k_fill_band_to_mac_param(struct ath11k_base *soc, struct wmi_host_pdev_band_to_mac *band_to_mac) { @@ -4144,6 +4344,7 @@ static int ath11k_wmi_tlv_ext_soc_hal_reg_caps_parse(struct ath11k_base *soc, svc_rdy_ext->param.num_phy = svc_rdy_ext->soc_hal_reg_caps->num_phy; soc->num_radios = 0; + soc->target_pdev_count = 0; phy_id_map = svc_rdy_ext->pref_hw_mode_caps.phy_id_map; while (phy_id_map && soc->num_radios < MAX_RADIOS) { @@ -4781,6 +4982,7 @@ static int wmi_process_mgmt_tx_comp(struct ath11k *ar, u32 desc_id, struct sk_buff *msdu; struct ieee80211_tx_info *info; struct ath11k_skb_cb *skb_cb; + int num_mgmt; spin_lock_bh(&ar->txmgmt_idr_lock); msdu = idr_find(&ar->txmgmt_idr, desc_id); @@ -4804,10 +5006,19 @@ static int wmi_process_mgmt_tx_comp(struct ath11k *ar, u32 desc_id, ieee80211_tx_status_irqsafe(ar->hw, msdu); + num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx); + /* WARN when we received this event without doing any mgmt tx */ - if (atomic_dec_if_positive(&ar->num_pending_mgmt_tx) < 0) + if (num_mgmt < 0) WARN_ON_ONCE(1); + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "wmi mgmt tx comp pending %d desc id %d\n", + num_mgmt, desc_id); + + if (!num_mgmt) + wake_up(&ar->txmgmt_empty_waitq); + return 0; } @@ -5810,15 +6021,79 @@ static void ath11k_wmi_op_ep_tx_credits(struct ath11k_base *ab) wake_up(&ab->wmi_ab.tx_credits_wq); } +static int ath11k_reg_11d_new_cc_event(struct ath11k_base *ab, struct sk_buff *skb) +{ + const struct wmi_11d_new_cc_ev *ev; + const void **tb; + int ret; + + tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath11k_warn(ab, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TAG_11D_NEW_COUNTRY_EVENT]; + if (!ev) { + kfree(tb); + ath11k_warn(ab, "failed to fetch 11d new cc ev"); + return -EPROTO; + } + + spin_lock_bh(&ab->base_lock); + memcpy(&ab->new_alpha2, &ev->new_alpha2, 2); + spin_unlock_bh(&ab->base_lock); + + ath11k_dbg(ab, ATH11K_DBG_WMI, "wmi 11d new cc %c%c\n", + ab->new_alpha2[0], + ab->new_alpha2[1]); + + kfree(tb); + + queue_work(ab->workqueue, &ab->update_11d_work); + + return 0; +} + static void ath11k_wmi_htc_tx_complete(struct ath11k_base *ab, struct sk_buff *skb) { + struct ath11k_pdev_wmi *wmi = NULL; + u32 i; + u8 wmi_ep_count; + u8 eid; + + eid = ATH11K_SKB_CB(skb)->eid; dev_kfree_skb(skb); + + if (eid >= ATH11K_HTC_EP_COUNT) + return; + + wmi_ep_count = ab->htc.wmi_ep_count; + if (wmi_ep_count > ab->hw_params.max_radios) + return; + + for (i = 0; i < ab->htc.wmi_ep_count; i++) { + if (ab->wmi_ab.wmi[i].eid == eid) { + wmi = &ab->wmi_ab.wmi[i]; + break; + } + } + + if (wmi) + wake_up(&wmi->tx_ce_desc_wq); } static bool ath11k_reg_is_world_alpha(char *alpha) { - return alpha[0] == '0' && alpha[1] == '0'; + if (alpha[0] == '0' && alpha[1] == '0') + return true; + + if (alpha[0] == 'n' && alpha[1] == 'a') + return true; + + return false; } static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *skb) @@ -5911,7 +6186,7 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *sk ar = ab->pdevs[pdev_idx].ar; kfree(ab->new_regd[pdev_idx]); ab->new_regd[pdev_idx] = regd; - ieee80211_queue_work(ar->hw, &ar->regd_update_work); + queue_work(ab->workqueue, &ar->regd_update_work); } else { /* This regd would be applied during mac registration and is * held constant throughout for regd intersection purpose @@ -6111,6 +6386,7 @@ static void ath11k_vdev_start_resp_event(struct ath11k_base *ab, struct sk_buff static void ath11k_bcn_tx_status_event(struct ath11k_base *ab, struct sk_buff *skb) { + struct ath11k_vif *arvif; u32 vdev_id, tx_status; if (ath11k_pull_bcn_tx_status_ev(ab, skb->data, skb->len, @@ -6118,6 +6394,14 @@ static void ath11k_bcn_tx_status_event(struct ath11k_base *ab, struct sk_buff *s ath11k_warn(ab, "failed to extract bcn tx status"); return; } + + arvif = ath11k_mac_get_arvif_by_vdev_id(ab, vdev_id); + if (!arvif) { + ath11k_warn(ab, "invalid vdev id %d in bcn_tx_status", + vdev_id); + return; + } + ath11k_mac_bcn_tx_event(arvif); } static void ath11k_vdev_stopped_event(struct ath11k_base *ab, struct sk_buff *skb) @@ -6398,6 +6682,7 @@ static void ath11k_peer_sta_kickout_event(struct ath11k_base *ab, struct sk_buff struct ieee80211_sta *sta; struct ath11k_peer *peer; struct ath11k *ar; + u32 vdev_id; if (ath11k_pull_peer_sta_kickout_ev(ab, skb, &arg) != 0) { ath11k_warn(ab, "failed to extract peer sta kickout event"); @@ -6413,10 +6698,15 @@ static void ath11k_peer_sta_kickout_event(struct ath11k_base *ab, struct sk_buff if (!peer) { ath11k_warn(ab, "peer not found %pM\n", arg.mac_addr); + spin_unlock_bh(&ab->base_lock); goto exit; } - ar = ath11k_mac_get_ar_by_vdev_id(ab, peer->vdev_id); + vdev_id = peer->vdev_id; + + spin_unlock_bh(&ab->base_lock); + + ar = ath11k_mac_get_ar_by_vdev_id(ab, vdev_id); if (!ar) { ath11k_warn(ab, "invalid vdev id in peer sta kickout ev %d", peer->vdev_id); @@ -6437,7 +6727,6 @@ static void ath11k_peer_sta_kickout_event(struct ath11k_base *ab, struct sk_buff ieee80211_report_low_ack(sta, 10); exit: - spin_unlock_bh(&ab->base_lock); rcu_read_unlock(); } @@ -7054,6 +7343,8 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) cmd_hdr = (struct wmi_cmd_hdr *)skb->data; id = FIELD_GET(WMI_CMD_HDR_CMD_ID, (cmd_hdr->cmd_id)); + trace_ath11k_wmi_event(ab, id, skb->data, skb->len); + if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) goto out; @@ -7138,6 +7429,9 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) case WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID: ath11k_probe_resp_tx_status_event(ab, skb); break; + case WMI_OBSS_COLOR_COLLISION_DETECTION_EVENTID: + ath11k_wmi_obss_color_collision_event(ab, skb); + break; /* add Unsupported events here */ case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: case WMI_PEER_OPER_MODE_CHANGE_EVENTID: @@ -7157,6 +7451,9 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) case WMI_WOW_WAKEUP_HOST_EVENTID: ath11k_wmi_event_wow_wakeup_host(ab, skb); break; + case WMI_11D_NEW_COUNTRY_EVENTID: + ath11k_reg_11d_new_cc_event(ab, skb); + break; /* TODO: Add remaining events */ default: ath11k_dbg(ab, ATH11K_DBG_WMI, "Unknown eventid: 0x%x\n", id); @@ -7199,6 +7496,7 @@ static int ath11k_connect_pdev_htc_service(struct ath11k_base *ab, ab->wmi_ab.wmi_endpoint_id[pdev_idx] = conn_resp.eid; ab->wmi_ab.wmi[pdev_idx].eid = conn_resp.eid; ab->wmi_ab.max_msg_len[pdev_idx] = conn_resp.max_msg_len; + init_waitqueue_head(&ab->wmi_ab.wmi[pdev_idx].tx_ce_desc_wq); return 0; } @@ -7414,3 +7712,31 @@ int ath11k_wmi_wow_enable(struct ath11k *ar) return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ENABLE_CMDID); } + +int ath11k_wmi_scan_prob_req_oui(struct ath11k *ar, + const u8 mac_addr[ETH_ALEN]) +{ + struct sk_buff *skb; + struct wmi_scan_prob_req_oui_cmd *cmd; + u32 prob_req_oui; + int len; + + prob_req_oui = (((u32)mac_addr[0]) << 16) | + (((u32)mac_addr[1]) << 8) | mac_addr[2]; + + len = sizeof(*cmd); + skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_scan_prob_req_oui_cmd *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, + WMI_TAG_SCAN_PROB_REQ_OUI_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + cmd->prob_req_oui = prob_req_oui; + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi scan prob req oui %d\n", + prob_req_oui); + + return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_SCAN_PROB_REQ_OUI_CMDID); +} diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 0584e68e7593..d79eb1b7d9c2 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -113,10 +113,10 @@ enum wmi_host_hw_mode_priority { WMI_HOST_HW_MODE_MAX_PRI }; -enum { +enum WMI_HOST_WLAN_BAND { WMI_HOST_WLAN_2G_CAP = 0x1, WMI_HOST_WLAN_5G_CAP = 0x2, - WMI_HOST_WLAN_2G_5G_CAP = 0x3, + WMI_HOST_WLAN_2G_5G_CAP = WMI_HOST_WLAN_2G_CAP | WMI_HOST_WLAN_5G_CAP, }; /* Parameters used for WMI_VDEV_PARAM_AUTORATE_MISC_CFG command. @@ -774,6 +774,8 @@ enum wmi_tlv_event_id { WMI_MDNS_STATS_EVENTID = WMI_TLV_CMD(WMI_GRP_MDNS_OFL), WMI_SAP_OFL_ADD_STA_EVENTID = WMI_TLV_CMD(WMI_GRP_SAP_OFL), WMI_SAP_OFL_DEL_STA_EVENTID, + WMI_OBSS_COLOR_COLLISION_DETECTION_EVENTID = + WMI_EVT_GRP_START_ID(WMI_GRP_OBSS_OFL), WMI_OCB_SET_CONFIG_RESP_EVENTID = WMI_TLV_CMD(WMI_GRP_OCB), WMI_OCB_GET_TSF_TIMER_RESP_EVENTID, WMI_DCC_GET_STATS_RESP_EVENTID, @@ -2167,6 +2169,13 @@ enum wmi_nss_ratio { WMI_NSS_RATIO_2_NSS = 0x3, }; +enum wmi_dtim_policy { + WMI_DTIM_POLICY_IGNORE = 1, + WMI_DTIM_POLICY_NORMAL = 2, + WMI_DTIM_POLICY_STICK = 3, + WMI_DTIM_POLICY_AUTO = 4, +}; + struct wmi_host_pdev_band_to_mac { u32 pdev_id; u32 start_freq; @@ -2522,6 +2531,7 @@ struct ath11k_pdev_wmi { enum ath11k_htc_ep_id eid; const struct wmi_peer_flags_map *peer_flags; u32 rx_decap_mode; + wait_queue_head_t tx_ce_desc_wq; }; struct vdev_create_params { @@ -3079,7 +3089,6 @@ enum scan_dwelltime_adaptive_mode { #define WLAN_SCAN_MAX_NUM_SSID 10 #define WLAN_SCAN_MAX_NUM_BSSID 10 -#define WLAN_SCAN_MAX_NUM_CHANNELS 40 #define WLAN_SSID_MAX_LEN 32 @@ -3300,7 +3309,7 @@ struct scan_req_params { u32 num_bssid; u32 num_ssids; u32 n_probes; - u32 chan_list[WLAN_SCAN_MAX_NUM_CHANNELS]; + u32 *chan_list; u32 notify_scan_events; struct wlan_ssid ssid[WLAN_SCAN_MAX_NUM_SSID]; struct wmi_mac_addr bssid_list[WLAN_SCAN_MAX_NUM_BSSID]; @@ -3311,6 +3320,8 @@ struct scan_req_params { u32 num_hint_bssid; struct hint_short_ssid hint_s_ssid[WLAN_SCAN_MAX_HINT_S_SSID]; struct hint_bssid hint_bssid[WLAN_SCAN_MAX_HINT_BSSID]; + struct wmi_mac_addr mac_addr; + struct wmi_mac_addr mac_mask; }; struct wmi_ssid_arg { @@ -3617,6 +3628,7 @@ struct peer_assoc_params { u32 peer_he_tx_mcs_set[WMI_HOST_MAX_HE_RATE_SET]; bool twt_responder; bool twt_requester; + bool is_assoc; struct ath11k_ppe_threshold peer_ppet; }; @@ -3673,6 +3685,11 @@ struct wmi_scan_chan_list_cmd { u32 pdev_id; } __packed; +struct wmi_scan_prob_req_oui_cmd { + u32 tlv_header; + u32 prob_req_oui; +} __packed; + #define WMI_MGMT_SEND_DOWNLD_LEN 64 #define WMI_TX_PARAMS_DWORD0_POWER GENMASK(7, 0) @@ -3766,6 +3783,16 @@ struct stats_request_params { u32 pdev_id; }; +struct wmi_set_current_country_params { + u8 alpha2[3]; +}; + +struct wmi_set_current_country_cmd { + u32 tlv_header; + u32 pdev_id; + u32 new_alpha2; +} __packed; + enum set_init_cc_type { WMI_COUNTRY_INFO_TYPE_ALPHA, WMI_COUNTRY_INFO_TYPE_COUNTRY_CODE, @@ -3799,6 +3826,28 @@ struct wmi_init_country_cmd { } cc_info; } __packed; +struct wmi_11d_scan_start_params { + u32 vdev_id; + u32 scan_period_msec; + u32 start_interval_msec; +}; + +struct wmi_11d_scan_start_cmd { + u32 tlv_header; + u32 vdev_id; + u32 scan_period_msec; + u32 start_interval_msec; +} __packed; + +struct wmi_11d_scan_stop_cmd { + u32 tlv_header; + u32 vdev_id; +} __packed; + +struct wmi_11d_new_cc_ev { + u32 new_alpha2; +} __packed; + #define THERMAL_LEVELS 1 struct tt_level_config { u32 tmplwm; @@ -4914,6 +4963,13 @@ struct wmi_pdev_obss_pd_bitmap_cmd { #define ATH11K_BSS_COLOR_COLLISION_DETECTION_STA_PERIOD_MS 10000 #define ATH11K_BSS_COLOR_COLLISION_DETECTION_AP_PERIOD_MS 5000 +enum wmi_bss_color_collision { + WMI_BSS_COLOR_COLLISION_DISABLE = 0, + WMI_BSS_COLOR_COLLISION_DETECTION, + WMI_BSS_COLOR_FREE_SLOT_TIMER_EXPIRY, + WMI_BSS_COLOR_FREE_SLOT_AVAILABLE, +}; + struct wmi_obss_color_collision_cfg_params_cmd { u32 tlv_header; u32 vdev_id; @@ -4931,6 +4987,12 @@ struct wmi_bss_color_change_enable_params_cmd { u32 enable; } __packed; +struct wmi_obss_color_collision_event { + u32 vdev_id; + u32 evt_type; + u64 obss_color_bitmap; +} __packed; + #define ATH11K_IPV4_TH_SEED_SIZE 5 #define ATH11K_IPV6_TH_SEED_SIZE 11 @@ -5351,7 +5413,8 @@ int ath11k_wmi_set_peer_param(struct ath11k *ar, const u8 *peer_addr, u32 vdev_id, u32 param_id, u32 param_val); int ath11k_wmi_pdev_set_param(struct ath11k *ar, u32 param_id, u32 param_value, u8 pdev_id); -int ath11k_wmi_pdev_set_ps_mode(struct ath11k *ar, int vdev_id, u32 enable); +int ath11k_wmi_pdev_set_ps_mode(struct ath11k *ar, int vdev_id, + enum wmi_sta_ps_mode psmode); int ath11k_wmi_wait_for_unified_ready(struct ath11k_base *ab); int ath11k_wmi_cmd_init(struct ath11k_base *ab); int ath11k_wmi_wait_for_service_ready(struct ath11k_base *ab); @@ -5415,9 +5478,16 @@ int ath11k_wmi_delba_send(struct ath11k *ar, u32 vdev_id, const u8 *mac, u32 tid, u32 initiator, u32 reason); int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar, u32 vdev_id, u32 bcn_ctrl_op); +int ath11k_wmi_send_set_current_country_cmd(struct ath11k *ar, + struct wmi_set_current_country_params *param); int ath11k_wmi_send_init_country_cmd(struct ath11k *ar, struct wmi_init_country_params init_cc_param); + +int ath11k_wmi_send_11d_scan_start_cmd(struct ath11k *ar, + struct wmi_11d_scan_start_params *param); +int ath11k_wmi_send_11d_scan_stop_cmd(struct ath11k *ar, u32 vdev_id); + int ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar, struct thermal_mitigation_params *param); @@ -5474,5 +5544,6 @@ int ath11k_wmi_set_hw_mode(struct ath11k_base *ab, enum wmi_host_hw_mode_config_type mode); int ath11k_wmi_wow_host_wakeup_ind(struct ath11k *ar); int ath11k_wmi_wow_enable(struct ath11k *ar); - +int ath11k_wmi_scan_prob_req_oui(struct ath11k *ar, + const u8 mac_addr[ETH_ALEN]); #endif diff --git a/drivers/net/wireless/ath/ath6kl/htc.h b/drivers/net/wireless/ath/ath6kl/htc.h index 112d8a9b8d43..d3534a29c4f0 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.h +++ b/drivers/net/wireless/ath/ath6kl/htc.h @@ -153,12 +153,19 @@ * implementations. */ struct htc_frame_hdr { - u8 eid; - u8 flags; - - /* length of data (including trailer) that follows the header */ - __le16 payld_len; - + struct_group_tagged(htc_frame_look_ahead, header, + union { + struct { + u8 eid; + u8 flags; + + /* length of data (including trailer) that follows the header */ + __le16 payld_len; + + }; + u32 word; + }; + ); /* end of 4-byte lookahead */ u8 ctrl[2]; diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c index 998947ef63b6..e3874421c4c0 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c +++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c @@ -2260,19 +2260,16 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target, static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target) { struct htc_packet *packet = NULL; - struct htc_frame_hdr *htc_hdr; - u32 look_ahead; + struct htc_frame_look_ahead look_ahead; - if (ath6kl_hif_poll_mboxmsg_rx(target->dev, &look_ahead, + if (ath6kl_hif_poll_mboxmsg_rx(target->dev, &look_ahead.word, HTC_TARGET_RESPONSE_TIMEOUT)) return NULL; ath6kl_dbg(ATH6KL_DBG_HTC, - "htc rx wait ctrl look_ahead 0x%X\n", look_ahead); - - htc_hdr = (struct htc_frame_hdr *)&look_ahead; + "htc rx wait ctrl look_ahead 0x%X\n", look_ahead.word); - if (htc_hdr->eid != ENDPOINT_0) + if (look_ahead.eid != ENDPOINT_0) return NULL; packet = htc_get_control_buf(target, false); @@ -2281,8 +2278,8 @@ static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target) return NULL; packet->info.rx.rx_flags = 0; - packet->info.rx.exp_hdr = look_ahead; - packet->act_len = le16_to_cpu(htc_hdr->payld_len) + HTC_HDR_LENGTH; + packet->info.rx.exp_hdr = look_ahead.word; + packet->act_len = le16_to_cpu(look_ahead.payld_len) + HTC_HDR_LENGTH; if (packet->act_len > packet->buf_len) goto fail_ctrl_rx; diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index ce9a0a53771e..fba5a847c3bb 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -120,7 +120,7 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked, AR_ISR_TXEOL); } - ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK); + ah->intr_txqs = MS(s0_s, AR_ISR_S0_QCU_TXOK); ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC); ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR); ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 7e27a06e5df1..dc24da1ff00b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -1005,24 +1005,20 @@ static void __ar955x_tx_iq_cal_sort(struct ath_hw *ah, int i, int nmeasurement) { struct ath_common *common = ath9k_hw_common(ah); - int im, ix, iy, temp; + int im, ix, iy; for (im = 0; im < nmeasurement; im++) { for (ix = 0; ix < MAXIQCAL - 1; ix++) { for (iy = ix + 1; iy <= MAXIQCAL - 1; iy++) { if (coeff->mag_coeff[i][im][iy] < coeff->mag_coeff[i][im][ix]) { - temp = coeff->mag_coeff[i][im][ix]; - coeff->mag_coeff[i][im][ix] = - coeff->mag_coeff[i][im][iy]; - coeff->mag_coeff[i][im][iy] = temp; + swap(coeff->mag_coeff[i][im][ix], + coeff->mag_coeff[i][im][iy]); } if (coeff->phs_coeff[i][im][iy] < coeff->phs_coeff[i][im][ix]) { - temp = coeff->phs_coeff[i][im][ix]; - coeff->phs_coeff[i][im][ix] = - coeff->phs_coeff[i][im][iy]; - coeff->phs_coeff[i][im][iy] = temp; + swap(coeff->phs_coeff[i][im][ix], + coeff->phs_coeff[i][im][iy]); } } } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 5691bd6eb82c..d0caf1de2bde 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -154,11 +154,52 @@ static void ath_send_bar(struct ath_atx_tid *tid, u16 seqno) seqno << IEEE80211_SEQ_SEQ_SHIFT); } +static bool ath_merge_ratetbl(struct ieee80211_sta *sta, struct ath_buf *bf, + struct ieee80211_tx_info *tx_info) +{ + struct ieee80211_sta_rates *ratetbl; + u8 i; + + if (!sta) + return false; + + ratetbl = rcu_dereference(sta->rates); + if (!ratetbl) + return false; + + if (tx_info->control.rates[0].idx < 0 || + tx_info->control.rates[0].count == 0) + { + i = 0; + } else { + bf->rates[0] = tx_info->control.rates[0]; + i = 1; + } + + for ( ; i < IEEE80211_TX_MAX_RATES; i++) { + bf->rates[i].idx = ratetbl->rate[i].idx; + bf->rates[i].flags = ratetbl->rate[i].flags; + if (tx_info->control.use_rts) + bf->rates[i].count = ratetbl->rate[i].count_rts; + else if (tx_info->control.use_cts_prot) + bf->rates[i].count = ratetbl->rate[i].count_cts; + else + bf->rates[i].count = ratetbl->rate[i].count; + } + + return true; +} + static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ath_buf *bf) { - ieee80211_get_tx_rates(vif, sta, bf->bf_mpdu, bf->rates, - ARRAY_SIZE(bf->rates)); + struct ieee80211_tx_info *tx_info; + + tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); + + if (!ath_merge_ratetbl(sta, bf, tx_info)) + ieee80211_get_tx_rates(vif, sta, bf->bf_mpdu, bf->rates, + ARRAY_SIZE(bf->rates)); } static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index cca3b086aa70..49f7ee1c912b 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -307,8 +307,7 @@ static void carl9170_zap_queues(struct ar9170 *ar) for (i = 0; i < ar->hw->queues; i++) ar->tx_stats[i].limit = CARL9170_NUM_TX_LIMIT_HARD; - for (i = 0; i < DIV_ROUND_UP(ar->fw.mem_blocks, BITS_PER_LONG); i++) - ar->mem_bitmap[i] = 0; + bitmap_zero(ar->mem_bitmap, ar->fw.mem_blocks); rcu_read_lock(); list_for_each_entry_rcu(cvif, &ar->vif_list, list) { @@ -1968,9 +1967,7 @@ int carl9170_register(struct ar9170 *ar) if (WARN_ON(ar->mem_bitmap)) return -EINVAL; - ar->mem_bitmap = kcalloc(roundup(ar->fw.mem_blocks, BITS_PER_LONG), - sizeof(unsigned long), - GFP_KERNEL); + ar->mem_bitmap = bitmap_zalloc(ar->fw.mem_blocks, GFP_KERNEL); if (!ar->mem_bitmap) return -ENOMEM; @@ -2085,7 +2082,7 @@ void carl9170_free(struct ar9170 *ar) kfree_skb(ar->rx_failover); ar->rx_failover = NULL; - kfree(ar->mem_bitmap); + bitmap_free(ar->mem_bitmap); ar->mem_bitmap = NULL; kfree(ar->survey); diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 8d5a16b558e6..774419c7f442 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -126,6 +126,7 @@ enum CountryCode { CTRY_KOREA_ROC = 410, CTRY_KOREA_ROC2 = 411, CTRY_KOREA_ROC3 = 412, + CTRY_KOREA_ROC4 = 413, CTRY_KUWAIT = 414, CTRY_LATVIA = 428, CTRY_LEBANON = 422, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index c4bd26e65949..cdb1e9a23734 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -76,6 +76,7 @@ enum EnumRd { APL7_FCCA = 0x5C, APL8_WORLD = 0x5D, APL9_WORLD = 0x5E, + APL10_WORLD = 0x5F, WOR0_WORLD = 0x60, WOR1_WORLD = 0x61, @@ -204,6 +205,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {APL6_WORLD, CTL_ETSI, CTL_ETSI}, {APL8_WORLD, CTL_ETSI, CTL_ETSI}, {APL9_WORLD, CTL_ETSI, CTL_ETSI}, + {APL10_WORLD, CTL_ETSI, CTL_ETSI}, {APL3_FCCA, CTL_FCC, CTL_FCC}, {APL7_FCCA, CTL_FCC, CTL_FCC}, @@ -426,6 +428,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_KOREA_ROC, APL9_WORLD, "KR"}, {CTRY_KOREA_ROC2, APL2_WORLD, "K2"}, {CTRY_KOREA_ROC3, APL9_WORLD, "K3"}, + {CTRY_KOREA_ROC4, APL10_WORLD, "K4"}, {CTRY_KUWAIT, ETSI3_WORLD, "KW"}, {CTRY_LATVIA, ETSI1_WORLD, "LV"}, {CTRY_LEBANON, NULL1_WORLD, "LB"}, diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index aff04ef66266..4e9e13941c8f 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -272,6 +272,21 @@ static int wcn36xx_dxe_enable_ch_int(struct wcn36xx *wcn, u16 wcn_ch) return 0; } +static void wcn36xx_dxe_disable_ch_int(struct wcn36xx *wcn, u16 wcn_ch) +{ + int reg_data = 0; + + wcn36xx_dxe_read_register(wcn, + WCN36XX_DXE_INT_MASK_REG, + ®_data); + + reg_data &= ~wcn_ch; + + wcn36xx_dxe_write_register(wcn, + WCN36XX_DXE_INT_MASK_REG, + (int)reg_data); +} + static int wcn36xx_dxe_fill_skb(struct device *dev, struct wcn36xx_dxe_ctl *ctl, gfp_t gfp) @@ -834,6 +849,53 @@ unlock: return ret; } +static bool _wcn36xx_dxe_tx_channel_is_empty(struct wcn36xx_dxe_ch *ch) +{ + unsigned long flags; + struct wcn36xx_dxe_ctl *ctl_bd_start, *ctl_skb_start; + struct wcn36xx_dxe_ctl *ctl_bd, *ctl_skb; + bool ret = true; + + spin_lock_irqsave(&ch->lock, flags); + + /* Loop through ring buffer looking for nonempty entries. */ + ctl_bd_start = ch->head_blk_ctl; + ctl_bd = ctl_bd_start; + ctl_skb_start = ctl_bd_start->next; + ctl_skb = ctl_skb_start; + do { + if (ctl_skb->skb) { + ret = false; + goto unlock; + } + ctl_bd = ctl_skb->next; + ctl_skb = ctl_bd->next; + } while (ctl_skb != ctl_skb_start); + +unlock: + spin_unlock_irqrestore(&ch->lock, flags); + return ret; +} + +int wcn36xx_dxe_tx_flush(struct wcn36xx *wcn) +{ + int i = 0; + + /* Called with mac80211 queues stopped. Wait for empty HW queues. */ + do { + if (_wcn36xx_dxe_tx_channel_is_empty(&wcn->dxe_tx_l_ch) && + _wcn36xx_dxe_tx_channel_is_empty(&wcn->dxe_tx_h_ch)) { + return 0; + } + /* This ieee80211_ops callback is specifically allowed to + * sleep. + */ + usleep_range(1000, 1100); + } while (++i < 100); + + return -EBUSY; +} + int wcn36xx_dxe_init(struct wcn36xx *wcn) { int reg_data = 0, ret; @@ -869,7 +931,6 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) WCN36XX_DXE_WQ_TX_L); wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_REG_CH_EN, ®_data); - wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_TX_L); /***************************************/ /* Init descriptors for TX HIGH channel */ @@ -893,9 +954,6 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_REG_CH_EN, ®_data); - /* Enable channel interrupts */ - wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_TX_H); - /***************************************/ /* Init descriptors for RX LOW channel */ /***************************************/ @@ -905,7 +963,6 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) goto out_err_rxl_ch; } - /* For RX we need to preallocated buffers */ wcn36xx_dxe_ch_alloc_skb(wcn, &wcn->dxe_rx_l_ch); @@ -928,9 +985,6 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) WCN36XX_DXE_REG_CTL_RX_L, WCN36XX_DXE_CH_DEFAULT_CTL_RX_L); - /* Enable channel interrupts */ - wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_RX_L); - /***************************************/ /* Init descriptors for RX HIGH channel */ /***************************************/ @@ -962,15 +1016,18 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) WCN36XX_DXE_REG_CTL_RX_H, WCN36XX_DXE_CH_DEFAULT_CTL_RX_H); - /* Enable channel interrupts */ - wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_RX_H); - ret = wcn36xx_dxe_request_irqs(wcn); if (ret < 0) goto out_err_irq; timer_setup(&wcn->tx_ack_timer, wcn36xx_dxe_tx_timer, 0); + /* Enable channel interrupts */ + wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_TX_L); + wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_TX_H); + wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_RX_L); + wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_RX_H); + return 0; out_err_irq: @@ -987,6 +1044,14 @@ out_err_txh_ch: void wcn36xx_dxe_deinit(struct wcn36xx *wcn) { + int reg_data = 0; + + /* Disable channel interrupts */ + wcn36xx_dxe_disable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_RX_H); + wcn36xx_dxe_disable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_RX_L); + wcn36xx_dxe_disable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_TX_H); + wcn36xx_dxe_disable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_TX_L); + free_irq(wcn->tx_irq, wcn); free_irq(wcn->rx_irq, wcn); del_timer(&wcn->tx_ack_timer); @@ -996,6 +1061,15 @@ void wcn36xx_dxe_deinit(struct wcn36xx *wcn) wcn->tx_ack_skb = NULL; } + /* Put the DXE block into reset before freeing memory */ + reg_data = WCN36XX_DXE_REG_RESET; + wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_REG_CSR_RESET, reg_data); + wcn36xx_dxe_ch_free_skbs(wcn, &wcn->dxe_rx_l_ch); wcn36xx_dxe_ch_free_skbs(wcn, &wcn->dxe_rx_h_ch); + + wcn36xx_dxe_deinit_descs(wcn->dev, &wcn->dxe_tx_l_ch); + wcn36xx_dxe_deinit_descs(wcn->dev, &wcn->dxe_tx_h_ch); + wcn36xx_dxe_deinit_descs(wcn->dev, &wcn->dxe_rx_l_ch); + wcn36xx_dxe_deinit_descs(wcn->dev, &wcn->dxe_rx_h_ch); } diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.h b/drivers/net/wireless/ath/wcn36xx/dxe.h index 31b81b7547a3..26a31edf52e9 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.h +++ b/drivers/net/wireless/ath/wcn36xx/dxe.h @@ -466,5 +466,6 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, struct wcn36xx_tx_bd *bd, struct sk_buff *skb, bool is_low); +int wcn36xx_dxe_tx_flush(struct wcn36xx *wcn); void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status); #endif /* _DXE_H_ */ diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h index 9bea2b01f9aa..2a1db9756fd5 100644 --- a/drivers/net/wireless/ath/wcn36xx/hal.h +++ b/drivers/net/wireless/ath/wcn36xx/hal.h @@ -3459,9 +3459,6 @@ struct wcn36xx_hal_missed_beacon_ind_msg { /* Beacon Filtering data structures */ -/* The above structure would be followed by multiple of below mentioned - * structure - */ struct beacon_filter_ie { u8 element_id; u8 check_ie_presence; @@ -3469,7 +3466,27 @@ struct beacon_filter_ie { u8 value; u8 bitmask; u8 ref; -}; +} __packed; + +#define WCN36XX_FILTER_CAPABILITY_MASK 0x73cf +#define WCN36XX_FILTER_IE_DS_CHANNEL_MASK 0x00 +#define WCN36XX_FILTER_IE_ERP_FILTER_MASK 0xF8 +#define WCN36XX_FILTER_IE_EDCA_FILTER_MASK 0xF0 +#define WCN36XX_FILTER_IE_QOS_FILTER_MASK 0xF0 +#define WCN36XX_FILTER_IE_CHANNEL_SWITCH_MASK 0x00 +#define WCN36XX_FILTER_IE_HT_BYTE0_FILTER_MASK 0x00 +#define WCN36XX_FILTER_IE_HT_BYTE1_FILTER_MASK 0xF8 +#define WCN36XX_FILTER_IE_HT_BYTE2_FILTER_MASK 0xEB +#define WCN36XX_FILTER_IE_HT_BYTE5_FILTER_MASK 0xFD +#define WCN36XX_FILTER_IE_PWR_CONSTRAINT_MASK 0x00 +#define WCN36XX_FILTER_IE_OPMODE_NOTIF_MASK 0x00 +#define WCN36XX_FILTER_IE_VHTOP_CHWIDTH_MASK 0xFC +#define WCN36XX_FILTER_IE_RSN_MASK 0x00 +#define WCN36XX_FILTER_IE_VENDOR_MASK 0x00 + +/* The above structure would be followed by multiple of below mentioned + * structure + */ struct wcn36xx_hal_add_bcn_filter_req_msg { struct wcn36xx_hal_msg_header header; @@ -3480,14 +3497,14 @@ struct wcn36xx_hal_add_bcn_filter_req_msg { u16 ie_num; u8 bss_index; u8 reserved; -}; +} __packed; struct wcn36xx_hal_rem_bcn_filter_req { struct wcn36xx_hal_msg_header header; u8 ie_Count; u8 rem_ie_id[1]; -}; +} __packed; #define WCN36XX_HAL_IPV4_ARP_REPLY_OFFLOAD 0 #define WCN36XX_HAL_IPV6_NEIGHBOR_DISCOVERY_OFFLOAD 1 diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index b04533bbc3a4..9575d7373bf2 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -402,6 +402,7 @@ static void wcn36xx_change_opchannel(struct wcn36xx *wcn, int ch) static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed) { struct wcn36xx *wcn = hw->priv; + int ret; wcn36xx_dbg(WCN36XX_DBG_MAC, "mac config changed 0x%08x\n", changed); @@ -417,17 +418,31 @@ static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed) * want to receive/transmit regular data packets, then * simply stop the scan session and exit PS mode. */ - wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN, - wcn->sw_scan_vif); - wcn->sw_scan_channel = 0; + if (wcn->sw_scan_channel) + wcn36xx_smd_end_scan(wcn, wcn->sw_scan_channel); + if (wcn->sw_scan_init) { + wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN, + wcn->sw_scan_vif); + } } else if (wcn->sw_scan) { /* A scan is ongoing, do not change the operating * channel, but start a scan session on the channel. */ - wcn36xx_smd_init_scan(wcn, HAL_SYS_MODE_SCAN, - wcn->sw_scan_vif); + if (wcn->sw_scan_channel) + wcn36xx_smd_end_scan(wcn, wcn->sw_scan_channel); + if (!wcn->sw_scan_init) { + /* This can fail if we are unable to notify the + * operating channel. + */ + ret = wcn36xx_smd_init_scan(wcn, + HAL_SYS_MODE_SCAN, + wcn->sw_scan_vif); + if (ret) { + mutex_unlock(&wcn->conf_mutex); + return -EIO; + } + } wcn36xx_smd_start_scan(wcn, ch); - wcn->sw_scan_channel = ch; } else { wcn36xx_change_opchannel(wcn, ch); } @@ -707,6 +722,8 @@ static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw, struct wcn36xx *wcn = hw->priv; struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); + wcn36xx_dbg(WCN36XX_DBG_MAC, "sw_scan_start"); + wcn->sw_scan = true; wcn->sw_scan_vif = vif; wcn->sw_scan_channel = 0; @@ -721,8 +738,15 @@ static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw, { struct wcn36xx *wcn = hw->priv; + wcn36xx_dbg(WCN36XX_DBG_MAC, "sw_scan_complete"); + /* ensure that any scan session is finished */ - wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN, wcn->sw_scan_vif); + if (wcn->sw_scan_channel) + wcn36xx_smd_end_scan(wcn, wcn->sw_scan_channel); + if (wcn->sw_scan_init) { + wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN, + wcn->sw_scan_vif); + } wcn->sw_scan = false; wcn->sw_scan_opchannel = 0; } @@ -910,6 +934,8 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, * place where AID is available. */ wcn36xx_smd_config_sta(wcn, vif, sta); + if (vif->type == NL80211_IFTYPE_STATION) + wcn36xx_smd_add_beacon_filter(wcn, vif); wcn36xx_enable_keep_alive_null_packet(wcn, vif); } else { wcn36xx_dbg(WCN36XX_DBG_MAC, @@ -1196,7 +1222,7 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, u16 tid = params->tid; u16 *ssn = ¶ms->ssn; int ret = 0; - u8 session; + int session; wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n", action, tid); @@ -1208,9 +1234,11 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, sta_priv->tid = tid; session = wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 0, get_sta_index(vif, sta_priv)); + if (session < 0) { + ret = session; + goto out; + } wcn36xx_smd_add_ba(wcn, session); - wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv), tid, - session); break; case IEEE80211_AMPDU_RX_STOP: wcn36xx_smd_del_ba(wcn, tid, 0, get_sta_index(vif, sta_priv)); @@ -1220,6 +1248,18 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START; spin_unlock_bh(&sta_priv->ampdu_lock); + /* Replace the mac80211 ssn with the firmware one */ + wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu ssn = %u\n", *ssn); + wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv), tid, ssn); + wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu fw-ssn = %u\n", *ssn); + + /* Start BA session */ + session = wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1, + get_sta_index(vif, sta_priv)); + if (session < 0) { + ret = session; + goto out; + } ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_OPERATIONAL: @@ -1227,8 +1267,6 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_OPERATIONAL; spin_unlock_bh(&sta_priv->ampdu_lock); - wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1, - get_sta_index(vif, sta_priv)); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: @@ -1244,6 +1282,7 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, wcn36xx_err("Unknown AMPDU action\n"); } +out: mutex_unlock(&wcn->conf_mutex); return ret; @@ -1277,6 +1316,16 @@ static void wcn36xx_ipv6_addr_change(struct ieee80211_hw *hw, } #endif +static void wcn36xx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) +{ + struct wcn36xx *wcn = hw->priv; + + if (wcn36xx_dxe_tx_flush(wcn)) { + wcn36xx_err("Failed to flush hardware tx queues\n"); + } +} + static const struct ieee80211_ops wcn36xx_ops = { .start = wcn36xx_start, .stop = wcn36xx_stop, @@ -1304,6 +1353,7 @@ static const struct ieee80211_ops wcn36xx_ops = { #if IS_ENABLED(CONFIG_IPV6) .ipv6_addr_change = wcn36xx_ipv6_addr_change, #endif + .flush = wcn36xx_flush, CFG80211_TESTMODE_CMD(wcn36xx_tm_cmd) }; diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index ed45e2cf039b..caeb68901326 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -722,6 +722,7 @@ int wcn36xx_smd_init_scan(struct wcn36xx *wcn, enum wcn36xx_hal_sys_mode mode, wcn36xx_err("hal_init_scan response failed err=%d\n", ret); goto out; } + wcn->sw_scan_init = true; out: mutex_unlock(&wcn->hal_mutex); return ret; @@ -752,6 +753,7 @@ int wcn36xx_smd_start_scan(struct wcn36xx *wcn, u8 scan_channel) wcn36xx_err("hal_start_scan response failed err=%d\n", ret); goto out; } + wcn->sw_scan_channel = scan_channel; out: mutex_unlock(&wcn->hal_mutex); return ret; @@ -782,6 +784,7 @@ int wcn36xx_smd_end_scan(struct wcn36xx *wcn, u8 scan_channel) wcn36xx_err("hal_end_scan response failed err=%d\n", ret); goto out; } + wcn->sw_scan_channel = 0; out: mutex_unlock(&wcn->hal_mutex); return ret; @@ -823,6 +826,7 @@ int wcn36xx_smd_finish_scan(struct wcn36xx *wcn, wcn36xx_err("hal_finish_scan response failed err=%d\n", ret); goto out; } + wcn->sw_scan_init = false; out: mutex_unlock(&wcn->hal_mutex); return ret; @@ -940,7 +944,7 @@ int wcn36xx_smd_update_channel_list(struct wcn36xx *wcn, struct cfg80211_scan_re INIT_HAL_MSG((*msg_body), WCN36XX_HAL_UPDATE_CHANNEL_LIST_REQ); - msg_body->num_channel = min_t(u8, req->n_channels, sizeof(msg_body->channels)); + msg_body->num_channel = min_t(u8, req->n_channels, ARRAY_SIZE(msg_body->channels)); for (i = 0; i < msg_body->num_channel; i++) { struct wcn36xx_hal_channel_param *param = &msg_body->channels[i]; u32 min_power = WCN36XX_HAL_DEFAULT_MIN_POWER; @@ -2557,6 +2561,7 @@ int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn, &session_id); if (ret) { wcn36xx_err("hal_add_ba_session response failed err=%d\n", ret); + ret = -EINVAL; goto out; } @@ -2622,27 +2627,43 @@ out: return ret; } -static int wcn36xx_smd_trigger_ba_rsp(void *buf, int len) +static int wcn36xx_smd_trigger_ba_rsp(void *buf, int len, struct add_ba_info *ba_info) { + struct wcn36xx_hal_trigger_ba_rsp_candidate *candidate; struct wcn36xx_hal_trigger_ba_rsp_msg *rsp; + int i; if (len < sizeof(*rsp)) return -EINVAL; rsp = (struct wcn36xx_hal_trigger_ba_rsp_msg *) buf; + + if (rsp->candidate_cnt < 1) + return rsp->status ? rsp->status : -EINVAL; + + candidate = (struct wcn36xx_hal_trigger_ba_rsp_candidate *)(buf + sizeof(*rsp)); + + for (i = 0; i < STACFG_MAX_TC; i++) { + ba_info[i] = candidate->ba_info[i]; + } + return rsp->status; } -int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u8 session_id) +int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u16 *ssn) { struct wcn36xx_hal_trigger_ba_req_msg msg_body; struct wcn36xx_hal_trigger_ba_req_candidate *candidate; + struct add_ba_info ba_info[STACFG_MAX_TC]; int ret; + if (tid >= STACFG_MAX_TC) + return -EINVAL; + mutex_lock(&wcn->hal_mutex); INIT_HAL_MSG(msg_body, WCN36XX_HAL_TRIGGER_BA_REQ); - msg_body.session_id = session_id; + msg_body.session_id = 0; /* not really used */ msg_body.candidate_cnt = 1; msg_body.header.len += sizeof(*candidate); PREPARE_HAL_BUF(wcn->hal_buf, msg_body); @@ -2657,13 +2678,17 @@ int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u8 sessio wcn36xx_err("Sending hal_trigger_ba failed\n"); goto out; } - ret = wcn36xx_smd_trigger_ba_rsp(wcn->hal_buf, wcn->hal_rsp_len); + ret = wcn36xx_smd_trigger_ba_rsp(wcn->hal_buf, wcn->hal_rsp_len, ba_info); if (ret) { wcn36xx_err("hal_trigger_ba response failed err=%d\n", ret); goto out; } out: mutex_unlock(&wcn->hal_mutex); + + if (ssn) + *ssn = ba_info[tid].starting_seq_num; + return ret; } @@ -2732,7 +2757,7 @@ static int wcn36xx_smd_missed_beacon_ind(struct wcn36xx *wcn, wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n", tmp->bss_index); vif = wcn36xx_priv_to_vif(tmp); - ieee80211_connection_loss(vif); + ieee80211_beacon_loss(vif); } return 0; } @@ -2747,7 +2772,7 @@ static int wcn36xx_smd_missed_beacon_ind(struct wcn36xx *wcn, wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n", rsp->bss_index); vif = wcn36xx_priv_to_vif(tmp); - ieee80211_connection_loss(vif); + ieee80211_beacon_loss(vif); return 0; } } @@ -3168,6 +3193,91 @@ out: return ret; } +#define BEACON_FILTER(eid, presence, offs, val, mask, ref_val) \ + { \ + .element_id = eid, \ + .check_ie_presence = presence, \ + .offset = offs, \ + .value = val, \ + .bitmask = mask, \ + .ref = ref_val, \ + } + +static const struct beacon_filter_ie bcn_filter_ies[] = { + BEACON_FILTER(WLAN_EID_DS_PARAMS, 0, 0, 0, + WCN36XX_FILTER_IE_DS_CHANNEL_MASK, 0), + BEACON_FILTER(WLAN_EID_ERP_INFO, 0, 0, 0, + WCN36XX_FILTER_IE_ERP_FILTER_MASK, 0), + BEACON_FILTER(WLAN_EID_EDCA_PARAM_SET, 0, 0, 0, + WCN36XX_FILTER_IE_EDCA_FILTER_MASK, 0), + BEACON_FILTER(WLAN_EID_QOS_CAPA, 0, 0, 0, + WCN36XX_FILTER_IE_QOS_FILTER_MASK, 0), + BEACON_FILTER(WLAN_EID_CHANNEL_SWITCH, 1, 0, 0, + WCN36XX_FILTER_IE_CHANNEL_SWITCH_MASK, 0), + BEACON_FILTER(WLAN_EID_HT_OPERATION, 0, 0, 0, + WCN36XX_FILTER_IE_HT_BYTE0_FILTER_MASK, 0), + BEACON_FILTER(WLAN_EID_HT_OPERATION, 0, 2, 0, + WCN36XX_FILTER_IE_HT_BYTE2_FILTER_MASK, 0), + BEACON_FILTER(WLAN_EID_HT_OPERATION, 0, 5, 0, + WCN36XX_FILTER_IE_HT_BYTE5_FILTER_MASK, 0), + BEACON_FILTER(WLAN_EID_PWR_CONSTRAINT, 0, 0, 0, + WCN36XX_FILTER_IE_PWR_CONSTRAINT_MASK, 0), + BEACON_FILTER(WLAN_EID_OPMODE_NOTIF, 0, 0, 0, + WCN36XX_FILTER_IE_OPMODE_NOTIF_MASK, 0), + BEACON_FILTER(WLAN_EID_VHT_OPERATION, 0, 0, 0, + WCN36XX_FILTER_IE_VHTOP_CHWIDTH_MASK, 0), + BEACON_FILTER(WLAN_EID_RSN, 1, 0, 0, + WCN36XX_FILTER_IE_RSN_MASK, 0), + BEACON_FILTER(WLAN_EID_VENDOR_SPECIFIC, 1, 0, 0, + WCN36XX_FILTER_IE_VENDOR_MASK, 0), +}; + +int wcn36xx_smd_add_beacon_filter(struct wcn36xx *wcn, + struct ieee80211_vif *vif) +{ + struct wcn36xx_hal_add_bcn_filter_req_msg msg_body, *body; + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); + u8 *payload; + size_t payload_size; + int ret; + + if (!get_feat_caps(wcn->fw_feat_caps, BCN_FILTER)) + return -EOPNOTSUPP; + + mutex_lock(&wcn->hal_mutex); + INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_BCN_FILTER_REQ); + + PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + + body = (struct wcn36xx_hal_add_bcn_filter_req_msg *)wcn->hal_buf; + body->capability_info = vif->bss_conf.assoc_capability; + body->capability_mask = WCN36XX_FILTER_CAPABILITY_MASK; + body->beacon_interval = vif->bss_conf.beacon_int; + body->ie_num = ARRAY_SIZE(bcn_filter_ies); + body->bss_index = vif_priv->bss_index; + + payload = ((u8 *)body) + body->header.len; + payload_size = sizeof(bcn_filter_ies); + memcpy(payload, &bcn_filter_ies, payload_size); + + body->header.len += payload_size; + + ret = wcn36xx_smd_send_and_wait(wcn, body->header.len); + if (ret) { + wcn36xx_err("Sending add bcn_filter failed\n"); + goto out; + } + + ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); + if (ret) { + wcn36xx_err("add bcn filter response failed err=%d\n", ret); + goto out; + } +out: + mutex_unlock(&wcn->hal_mutex); + return ret; +} + int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev, void *buf, int len, void *priv, u32 addr) { @@ -3223,6 +3333,7 @@ int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev, case WCN36XX_HAL_ENTER_IMPS_RSP: case WCN36XX_HAL_EXIT_IMPS_RSP: case WCN36XX_HAL_UPDATE_CHANNEL_LIST_RSP: + case WCN36XX_HAL_ADD_BCN_FILTER_RSP: memcpy(wcn->hal_buf, buf, len); wcn->hal_rsp_len = len; complete(&wcn->hal_rsp_compl); diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h index 88e045dad8f3..957cfa87fbde 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.h +++ b/drivers/net/wireless/ath/wcn36xx/smd.h @@ -137,7 +137,7 @@ int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn, u8 sta_index); int wcn36xx_smd_add_ba(struct wcn36xx *wcn, u8 session_id); int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 direction, u8 sta_index); -int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u8 session_id); +int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u16 *ssn); int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value); @@ -167,4 +167,7 @@ int wcn36xx_smd_host_resume(struct wcn36xx *wcn); int wcn36xx_smd_enter_imps(struct wcn36xx *wcn); int wcn36xx_smd_exit_imps(struct wcn36xx *wcn); +int wcn36xx_smd_add_beacon_filter(struct wcn36xx *wcn, + struct ieee80211_vif *vif); + #endif /* _SMD_H_ */ diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index 75951ccbc840..dd58dde8c836 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -272,7 +272,6 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) const struct wcn36xx_rate *rate; struct ieee80211_hdr *hdr; struct wcn36xx_rx_bd *bd; - struct ieee80211_supported_band *sband; u16 fc, sn; /* @@ -314,8 +313,6 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) fc = __le16_to_cpu(hdr->frame_control); sn = IEEE80211_SEQ_TO_SN(__le16_to_cpu(hdr->seq_ctrl)); - status.freq = WCN36XX_CENTER_FREQ(wcn); - status.band = WCN36XX_BAND(wcn); status.mactime = 10; status.signal = -get_rssi0(bd); status.antenna = 1; @@ -327,18 +324,36 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x\n", status.flag); + if (bd->scan_learn) { + /* If packet originate from hardware scanning, extract the + * band/channel from bd descriptor. + */ + u8 hwch = (bd->reserved0 << 4) + bd->rx_ch; + + if (bd->rf_band != 1 && hwch <= sizeof(ab_rx_ch_map) && hwch >= 1) { + status.band = NL80211_BAND_5GHZ; + status.freq = ieee80211_channel_to_frequency(ab_rx_ch_map[hwch - 1], + status.band); + } else { + status.band = NL80211_BAND_2GHZ; + status.freq = ieee80211_channel_to_frequency(hwch, status.band); + } + } else { + status.band = WCN36XX_BAND(wcn); + status.freq = WCN36XX_CENTER_FREQ(wcn); + } + if (bd->rate_id < ARRAY_SIZE(wcn36xx_rate_table)) { rate = &wcn36xx_rate_table[bd->rate_id]; status.encoding = rate->encoding; status.enc_flags = rate->encoding_flags; status.bw = rate->bw; status.rate_idx = rate->mcs_or_legacy_index; - sband = wcn->hw->wiphy->bands[status.band]; status.nss = 1; if (status.band == NL80211_BAND_5GHZ && status.encoding == RX_ENC_LEGACY && - status.rate_idx >= sband->n_bitrates) { + status.rate_idx >= 4) { /* no dsss rates in 5Ghz rates table */ status.rate_idx -= 4; } @@ -353,22 +368,6 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) ieee80211_is_probe_resp(hdr->frame_control)) status.boottime_ns = ktime_get_boottime_ns(); - if (bd->scan_learn) { - /* If packet originates from hardware scanning, extract the - * band/channel from bd descriptor. - */ - u8 hwch = (bd->reserved0 << 4) + bd->rx_ch; - - if (bd->rf_band != 1 && hwch <= sizeof(ab_rx_ch_map) && hwch >= 1) { - status.band = NL80211_BAND_5GHZ; - status.freq = ieee80211_channel_to_frequency(ab_rx_ch_map[hwch - 1], - status.band); - } else { - status.band = NL80211_BAND_2GHZ; - status.freq = ieee80211_channel_to_frequency(hwch, status.band); - } - } - memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); if (ieee80211_is_beacon(hdr->frame_control)) { diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index 1c8d918137da..fbd0558c2c19 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -248,6 +248,7 @@ struct wcn36xx { struct cfg80211_scan_request *scan_req; bool sw_scan; u8 sw_scan_opchannel; + bool sw_scan_init; u8 sw_scan_channel; struct ieee80211_vif *sw_scan_vif; struct mutex scan_lock; diff --git a/drivers/net/wireless/broadcom/brcm80211/Kconfig b/drivers/net/wireless/broadcom/brcm80211/Kconfig index 5bf2318763c5..3a1a35b5672f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/Kconfig +++ b/drivers/net/wireless/broadcom/brcm80211/Kconfig @@ -7,16 +7,20 @@ config BRCMSMAC depends on MAC80211 depends on BCMA_POSSIBLE select BCMA - select NEW_LEDS if BCMA_DRIVER_GPIO - select LEDS_CLASS if BCMA_DRIVER_GPIO select BRCMUTIL select FW_LOADER select CORDIC help This module adds support for PCIe wireless adapters based on Broadcom - IEEE802.11n SoftMAC chipsets. It also has WLAN led support, which will - be available if you select BCMA_DRIVER_GPIO. If you choose to build a - module, the driver will be called brcmsmac.ko. + IEEE802.11n SoftMAC chipsets. If you choose to build a module, the + driver will be called brcmsmac.ko. + +config BRCMSMAC_LEDS + def_bool BRCMSMAC && BCMA_DRIVER_GPIO && MAC80211_LEDS + help + The brcmsmac LED support depends on the presence of the + BCMA_DRIVER_GPIO driver, and it only works if LED support + is enabled and reachable from the driver module. source "drivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig" diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index fb727778312c..ba52318615ae 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -3901,6 +3901,24 @@ static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg, cfg->wowl.active = true; } +static int brcmf_keepalive_start(struct brcmf_if *ifp, unsigned int interval) +{ + struct brcmf_mkeep_alive_pkt_le kalive = {0}; + int ret = 0; + + /* Configure Null function/data keepalive */ + kalive.version = cpu_to_le16(1); + kalive.period_msec = cpu_to_le32(interval * MSEC_PER_SEC); + kalive.len_bytes = cpu_to_le16(0); + kalive.keep_alive_id = 0; + + ret = brcmf_fil_iovar_data_set(ifp, "mkeep_alive", &kalive, sizeof(kalive)); + if (ret) + brcmf_err("keep-alive packet config failed, ret=%d\n", ret); + + return ret; +} + static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wowl) { @@ -3947,6 +3965,9 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, } else { /* Configure WOWL paramaters */ brcmf_configure_wowl(cfg, ifp, wowl); + + /* Prevent disassociation due to inactivity with keep-alive */ + brcmf_keepalive_start(ifp, 30); } exit: diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index ff2ef557f0ea..e69d1e56996f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -1052,4 +1052,23 @@ struct brcmf_gscan_config { struct brcmf_gscan_bucket_config bucket[1]; }; +/** + * struct brcmf_mkeep_alive_pkt_le - configuration data for keep-alive frame. + * + * @version: version for mkeep_alive + * @length: length of fixed parameters in the structure. + * @period_msec: keep-alive period in milliseconds. + * @len_bytes: size of the data. + * @keep_alive_id: ID (0 - 3). + * @data: keep-alive frame data. + */ +struct brcmf_mkeep_alive_pkt_le { + __le16 version; + __le16 length; + __le32 period_msec; + __le16 len_bytes; + u8 keep_alive_id; + u8 data[0]; +} __packed; + #endif /* FWIL_TYPES_H_ */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile index 482d7737764d..090757730ba6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile @@ -42,6 +42,6 @@ brcmsmac-y := \ brcms_trace_events.o \ debug.o -brcmsmac-$(CONFIG_BCMA_DRIVER_GPIO) += led.o +brcmsmac-$(CONFIG_BRCMSMAC_LEDS) += led.o obj-$(CONFIG_BRCMSMAC) += brcmsmac.o diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h index d65f5c268fd7..2a5cbeb9e783 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h @@ -24,7 +24,7 @@ struct brcms_led { struct gpio_desc *gpiod; }; -#ifdef CONFIG_BCMA_DRIVER_GPIO +#ifdef CONFIG_BRCMSMAC_LEDS void brcms_led_unregister(struct brcms_info *wl); int brcms_led_register(struct brcms_info *wl); #else diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index 23037bfc9e4c..5727c7c00a28 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -2303,7 +2303,7 @@ static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len) ssid); } -static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac) +static int ipw_send_adapter_address(struct ipw_priv *priv, const u8 * mac) { if (!priv || !mac) { IPW_ERROR("Invalid args\n"); diff --git a/drivers/net/wireless/intel/iwlegacy/Kconfig b/drivers/net/wireless/intel/iwlegacy/Kconfig index 24fe3f63c321..7eacc8e58ee1 100644 --- a/drivers/net/wireless/intel/iwlegacy/Kconfig +++ b/drivers/net/wireless/intel/iwlegacy/Kconfig @@ -2,14 +2,13 @@ config IWLEGACY tristate select FW_LOADER - select NEW_LEDS - select LEDS_CLASS select LEDS_TRIGGERS select MAC80211_LEDS config IWL4965 tristate "Intel Wireless WiFi 4965AGN (iwl4965)" depends on PCI && MAC80211 + depends on LEDS_CLASS=y || LEDS_CLASS=MAC80211 select IWLEGACY help This option enables support for @@ -38,6 +37,7 @@ config IWL4965 config IWL3945 tristate "Intel PRO/Wireless 3945ABG/BG Network Connection (iwl3945)" depends on PCI && MAC80211 + depends on LEDS_CLASS=y || LEDS_CLASS=MAC80211 select IWLEGACY help Select to build the driver supporting the: diff --git a/drivers/net/wireless/intel/iwlwifi/Kconfig b/drivers/net/wireless/intel/iwlwifi/Kconfig index 1085afbefba8..c21c0c68849a 100644 --- a/drivers/net/wireless/intel/iwlwifi/Kconfig +++ b/drivers/net/wireless/intel/iwlwifi/Kconfig @@ -2,6 +2,7 @@ config IWLWIFI tristate "Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlwifi) " depends on PCI && HAS_IOMEM && CFG80211 + depends on IWLMEI || !IWLMEI select FW_LOADER help Select to build the driver supporting the: @@ -47,7 +48,7 @@ if IWLWIFI config IWLWIFI_LEDS bool - depends on LEDS_CLASS=y || LEDS_CLASS=IWLWIFI + depends on LEDS_CLASS=y || LEDS_CLASS=MAC80211 depends on IWLMVM || IWLDVM select LEDS_TRIGGERS select MAC80211_LEDS @@ -146,3 +147,28 @@ config IWLWIFI_DEVICE_TRACING endmenu endif + +config IWLMEI + tristate "Intel Management Engine communication over WLAN" + depends on INTEL_MEI + depends on PM + help + Enables the iwlmei kernel module. + + CSME stands for Converged Security and Management Engine. It is a CPU + on the chipset and runs a dedicated firmware. AMT (Active Management + Technology) is one of the applications that run on that CPU. AMT + allows to control the platform remotely. + + This kernel module allows to communicate with the Intel Management + Engine over Wifi. This is supported starting from Tiger Lake + platforms and has been tested on 9260 devices only. + If AMT is configured not to use the wireless device, this module is + harmless (and useless). + Enabling this option on a platform that has a different device and + has Wireless enabled on AMT can prevent WiFi from working correctly. + + For more information see + <https://software.intel.com/en-us/manageability/> + + If unsure, say N. diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index 0d4656efe908..75a703eb1bdf 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -30,5 +30,6 @@ ccflags-y += -I$(src) obj-$(CONFIG_IWLDVM) += dvm/ obj-$(CONFIG_IWLMVM) += mvm/ +obj-$(CONFIG_IWLMEI) += mei/ CFLAGS_iwl-devtrace.o := -I$(src) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 1572097bccf1..b1ad0e1c472a 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -9,7 +9,7 @@ #include "iwl-prph.h" /* Highest firmware API version supported */ -#define IWL_22000_UCODE_API_MAX 67 +#define IWL_22000_UCODE_API_MAX 68 /* Lowest firmware API version supported */ #define IWL_22000_UCODE_API_MIN 39 @@ -54,7 +54,8 @@ #define IWL_BZ_A_GF4_A_FW_PRE "iwlwifi-bz-a0-gf4-a0-" #define IWL_BZ_A_MR_A_FW_PRE "iwlwifi-bz-a0-mr-a0-" #define IWL_BZ_A_FM_A_FW_PRE "iwlwifi-bz-a0-fm-a0-" -#define IWL_GL_A_FM_A_FW_PRE "iwlwifi-gl-a0-fm7-a0-" +#define IWL_GL_A_FM_A_FW_PRE "iwlwifi-gl-a0-fm-a0-" +#define IWL_BZ_Z_GF_A_FW_PRE "iwlwifi-bz-z0-gf-a0-" #define IWL_QU_B_HR_B_MODULE_FIRMWARE(api) \ @@ -113,6 +114,8 @@ IWL_BZ_A_FM_A_FW_PRE __stringify(api) ".ucode" #define IWL_GL_A_FM_A_MODULE_FIRMWARE(api) \ IWL_GL_A_FM_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BZ_Z_GF_A_MODULE_FIRMWARE(api) \ + IWL_BZ_Z_GF_A_FW_PRE __stringify(api) ".ucode" static const struct iwl_base_params iwl_22000_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, @@ -626,7 +629,7 @@ const struct iwl_cfg iwl_ax200_cfg_cc = { }; const struct iwl_cfg killer1650s_2ax_cfg_qu_b0_hr_b0 = { - .name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW)", + .name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201NGW)", .fw_name_pre = IWL_QU_B_HR_B_FW_PRE, IWL_DEVICE_22500, /* @@ -639,7 +642,7 @@ const struct iwl_cfg killer1650s_2ax_cfg_qu_b0_hr_b0 = { }; const struct iwl_cfg killer1650i_2ax_cfg_qu_b0_hr_b0 = { - .name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201D2W)", + .name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201D2W)", .fw_name_pre = IWL_QU_B_HR_B_FW_PRE, IWL_DEVICE_22500, /* @@ -652,7 +655,7 @@ const struct iwl_cfg killer1650i_2ax_cfg_qu_b0_hr_b0 = { }; const struct iwl_cfg killer1650s_2ax_cfg_qu_c0_hr_b0 = { - .name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW)", + .name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201NGW)", .fw_name_pre = IWL_QU_C_HR_B_FW_PRE, IWL_DEVICE_22500, /* @@ -665,7 +668,7 @@ const struct iwl_cfg killer1650s_2ax_cfg_qu_c0_hr_b0 = { }; const struct iwl_cfg killer1650i_2ax_cfg_qu_c0_hr_b0 = { - .name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201D2W)", + .name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201D2W)", .fw_name_pre = IWL_QU_C_HR_B_FW_PRE, IWL_DEVICE_22500, /* @@ -696,13 +699,6 @@ const struct iwl_cfg iwlax210_2ax_cfg_so_jf_b0 = { .num_rbds = IWL_NUM_RBDS_NON_HE, }; -const struct iwl_cfg iwlax210_2ax_cfg_so_hr_a0 = { - .name = "Intel(R) Wi-Fi 6 AX210 160MHz", - .fw_name_pre = IWL_SO_A_HR_B_FW_PRE, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0 = { .name = iwl_ax211_name, .fw_name_pre = IWL_SO_A_GF_A_FW_PRE, @@ -879,6 +875,13 @@ const struct iwl_cfg iwl_cfg_gl_a0_fm_a0 = { .num_rbds = IWL_NUM_RBDS_AX210_HE, }; +const struct iwl_cfg iwl_cfg_bz_z0_gf_a0 = { + .fw_name_pre = IWL_BZ_Z_GF_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + MODULE_FIRMWARE(IWL_QU_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_QNJ_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_QU_C_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index fbd57a2b2bd5..90b9becd1673 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -1974,12 +1974,8 @@ static void iwl_nic_config(struct iwl_op_mode *op_mode) /* SKU Control */ iwl_trans_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | - CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP, - (CSR_HW_REV_STEP(priv->trans->hw_rev) << - CSR_HW_IF_CONFIG_REG_POS_MAC_STEP) | - (CSR_HW_REV_DASH(priv->trans->hw_rev) << - CSR_HW_IF_CONFIG_REG_POS_MAC_DASH)); + CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP_DASH, + CSR_HW_REV_STEP_DASH(priv->trans->hw_rev)); /* write radio config values to register */ if (priv->nvm_data->radio_cfg_type <= EEPROM_RF_CONFIG_TYPE_MAX) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index bf431fa4fe81..0495316d1fc1 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -789,7 +789,7 @@ int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) * looking up in ACPI */ if (wifi_pkg->package.count != - min_size + profile_size * num_profiles) { + hdr_size + profile_size * num_profiles) { ret = -EINVAL; goto out_free; } @@ -852,6 +852,8 @@ read_table: } } + fwrt->geo_num_profiles = num_profiles; + fwrt->geo_enabled = true; ret = 0; out_free: kfree(data); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h b/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h index c840a97e6a62..7dd984fbe0f8 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018, 2020 Intel Corporation + * Copyright (C) 2012-2014, 2018, 2020-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -97,6 +97,21 @@ struct iwl_alive_ntf_v5 { struct iwl_sku_id sku_id; } __packed; /* UCODE_ALIVE_NTFY_API_S_VER_5 */ +struct iwl_imr_alive_info { + __le64 base_addr; + __le32 size; + __le32 enabled; +} __packed; /* IMR_ALIVE_INFO_API_S_VER_1 */ + +struct iwl_alive_ntf_v6 { + __le16 status; + __le16 flags; + struct iwl_lmac_alive lmac_data[2]; + struct iwl_umac_alive umac_data; + struct iwl_sku_id sku_id; + struct iwl_imr_alive_info imr; +} __packed; /* UCODE_ALIVE_NTFY_API_S_VER_6 */ + /** * enum iwl_extended_cfg_flag - commands driver may send before * finishing init flow diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index ee6b5844a871..dab02a6a2622 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -51,7 +51,7 @@ enum iwl_legacy_cmds { * @UCODE_ALIVE_NTFY: * Alive data from the firmware, as described in * &struct iwl_alive_ntf_v3 or &struct iwl_alive_ntf_v4 or - * &struct iwl_alive_ntf_v5. + * &struct iwl_alive_ntf_v5 or &struct iwl_alive_ntf_v6. */ UCODE_ALIVE_NTFY = 0x1, @@ -72,7 +72,8 @@ enum iwl_legacy_cmds { /** * @PHY_CONTEXT_CMD: - * Add/modify/remove a PHY context, using &struct iwl_phy_context_cmd. + * Add/modify/remove a PHY context, using &struct iwl_phy_context_cmd + * or &struct iwl_phy_context_cmd_v1. */ PHY_CONTEXT_CMD = 0x8, @@ -356,7 +357,7 @@ enum iwl_legacy_cmds { * &struct iwl_notif_statistics_v11, * &struct iwl_notif_statistics_v10, * &struct iwl_notif_statistics, - * &struct iwl_statistics_operational_ntfy + * &struct iwl_statistics_operational_ntfy_ver_14 */ STATISTICS_CMD = 0x9c, @@ -365,6 +366,7 @@ enum iwl_legacy_cmds { * one of &struct iwl_notif_statistics_v10, * &struct iwl_notif_statistics_v11, * &struct iwl_notif_statistic, + * &struct iwl_statistics_operational_ntfy_ver_14 * &struct iwl_statistics_operational_ntfy */ STATISTICS_NOTIFICATION = 0x9d, @@ -612,6 +614,11 @@ enum iwl_system_subcmd_ids { * @RFI_GET_FREQ_TABLE_CMD: &struct iwl_rfi_config_cmd */ RFI_GET_FREQ_TABLE_CMD = 0xc, + + /** + * @SYSTEM_FEATURES_CONTROL_CMD: &struct iwl_system_features_control_cmd + */ + SYSTEM_FEATURES_CONTROL_CMD = 0xd, }; #endif /* __iwl_fw_api_commands_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index 1503119ea910..4cd9ab23954e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -554,7 +554,7 @@ struct iwl_wowlan_gtk_status_v1 { } __packed; /* WOWLAN_GTK_MATERIAL_VER_1 */ /** - * struct iwl_wowlan_gtk_status - GTK status + * struct iwl_wowlan_gtk_status_v2 - GTK status * @key: GTK material * @key_len: GTK legth, if set to 0, the key is not available * @key_flags: information about the key: @@ -565,7 +565,7 @@ struct iwl_wowlan_gtk_status_v1 { * @tkip_mic_key: TKIP RX MIC key * @rsc: TSC RSC counters */ -struct iwl_wowlan_gtk_status { +struct iwl_wowlan_gtk_status_v2 { u8 key[WOWLAN_KEY_MAX_SIZE]; u8 key_len; u8 key_flags; @@ -574,6 +574,41 @@ struct iwl_wowlan_gtk_status { struct iwl_wowlan_rsc_tsc_params_cmd_ver_2 rsc; } __packed; /* WOWLAN_GTK_MATERIAL_VER_2 */ +/** + * struct iwl_wowlan_all_rsc_tsc_v5 - key counters + * @ucast_rsc: unicast RSC values + * @mcast_rsc: multicast RSC values (per key map value) + * @sta_id: station ID + * @mcast_key_id_map: map of key id to @mcast_rsc entry + */ +struct iwl_wowlan_all_rsc_tsc_v5 { + __le64 ucast_rsc[IWL_MAX_TID_COUNT]; + __le64 mcast_rsc[2][IWL_MAX_TID_COUNT]; + __le32 sta_id; + u8 mcast_key_id_map[4]; +} __packed; /* ALL_TSC_RSC_API_S_VER_5 */ + +/** + * struct iwl_wowlan_gtk_status_v3 - GTK status + * @key: GTK material + * @key_len: GTK length, if set to 0, the key is not available + * @key_flags: information about the key: + * bits[0:1]: key index assigned by the AP + * bits[2:6]: GTK index of the key in the internal DB + * bit[7]: Set iff this is the currently used GTK + * @reserved: padding + * @tkip_mic_key: TKIP RX MIC key + * @sc: RSC/TSC counters + */ +struct iwl_wowlan_gtk_status_v3 { + u8 key[WOWLAN_KEY_MAX_SIZE]; + u8 key_len; + u8 key_flags; + u8 reserved[2]; + u8 tkip_mic_key[IWL_MIC_KEY_SIZE]; + struct iwl_wowlan_all_rsc_tsc_v5 sc; +} __packed; /* WOWLAN_GTK_MATERIAL_VER_3 */ + #define IWL_WOWLAN_GTK_IDX_MASK (BIT(0) | BIT(1)) /** @@ -640,7 +675,7 @@ struct iwl_wowlan_status_v6 { * @wake_packet: wakeup packet */ struct iwl_wowlan_status_v7 { - struct iwl_wowlan_gtk_status gtk[WOWLAN_GTK_KEYS_NUM]; + struct iwl_wowlan_gtk_status_v2 gtk[WOWLAN_GTK_KEYS_NUM]; struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; __le64 replay_ctr; __le16 pattern_number; @@ -676,7 +711,7 @@ struct iwl_wowlan_status_v7 { * @wake_packet: wakeup packet */ struct iwl_wowlan_status_v9 { - struct iwl_wowlan_gtk_status gtk[WOWLAN_GTK_KEYS_NUM]; + struct iwl_wowlan_gtk_status_v2 gtk[WOWLAN_GTK_KEYS_NUM]; struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; __le64 replay_ctr; __le16 pattern_number; @@ -693,6 +728,44 @@ struct iwl_wowlan_status_v9 { u8 wake_packet[]; /* can be truncated from _length to _bufsize */ } __packed; /* WOWLAN_STATUSES_RSP_API_S_VER_9 */ +/** + * struct iwl_wowlan_status_v12 - WoWLAN status + * @gtk: GTK data + * @igtk: IGTK data + * @replay_ctr: GTK rekey replay counter + * @pattern_number: number of the matched pattern + * @non_qos_seq_ctr: non-QoS sequence counter to use next. + * Reserved if the struct has version >= 10. + * @qos_seq_ctr: QoS sequence counters to use next + * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason + * @num_of_gtk_rekeys: number of GTK rekeys + * @transmitted_ndps: number of transmitted neighbor discovery packets + * @received_beacons: number of received beacons + * @wake_packet_length: wakeup packet length + * @wake_packet_bufsize: wakeup packet buffer size + * @tid_tear_down: bit mask of tids whose BA sessions were closed + * in suspend state + * @reserved: unused + * @wake_packet: wakeup packet + */ +struct iwl_wowlan_status_v12 { + struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; + __le64 replay_ctr; + __le16 pattern_number; + __le16 non_qos_seq_ctr; + __le16 qos_seq_ctr[8]; + __le32 wakeup_reasons; + __le32 num_of_gtk_rekeys; + __le32 transmitted_ndps; + __le32 received_beacons; + __le32 wake_packet_length; + __le32 wake_packet_bufsize; + u8 tid_tear_down; + u8 reserved[3]; + u8 wake_packet[]; /* can be truncated from _length to _bufsize */ +} __packed; /* WOWLAN_STATUSES_RSP_API_S_VER_12 */ + /* TODO: NetDetect API */ #endif /* __iwl_fw_api_d3_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h index 985b0dc5b52a..89236f42c5a4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h @@ -32,6 +32,11 @@ enum iwl_data_path_subcmd_ids { STA_HE_CTXT_CMD = 0x7, /** + * @RLC_CONFIG_CMD: &struct iwl_rlc_config_cmd + */ + RLC_CONFIG_CMD = 0x8, + + /** * @RFH_QUEUE_CONFIG_CMD: &struct iwl_rfh_queue_config */ RFH_QUEUE_CONFIG_CMD = 0xD, @@ -195,4 +200,61 @@ struct iwl_thermal_dual_chain_request { __le32 event; } __packed; /* THERMAL_DUAL_CHAIN_DISABLE_REQ_NTFY_API_S_VER_1 */ +enum iwl_rlc_chain_info { + IWL_RLC_CHAIN_INFO_DRIVER_FORCE = BIT(0), + IWL_RLC_CHAIN_INFO_VALID = 0x000e, + IWL_RLC_CHAIN_INFO_FORCE = 0x0070, + IWL_RLC_CHAIN_INFO_FORCE_MIMO = 0x0380, + IWL_RLC_CHAIN_INFO_COUNT = 0x0c00, + IWL_RLC_CHAIN_INFO_MIMO_COUNT = 0x3000, +}; + +/** + * struct iwl_rlc_properties - RLC properties + * @rx_chain_info: RX chain info, &enum iwl_rlc_chain_info + * @reserved: reserved + */ +struct iwl_rlc_properties { + __le32 rx_chain_info; + __le32 reserved; +} __packed; /* RLC_PROPERTIES_S_VER_1 */ + +enum iwl_sad_mode { + IWL_SAD_MODE_ENABLED = BIT(0), + IWL_SAD_MODE_DEFAULT_ANT_MSK = 0x6, + IWL_SAD_MODE_DEFAULT_ANT_FW = 0x0, + IWL_SAD_MODE_DEFAULT_ANT_A = 0x2, + IWL_SAD_MODE_DEFAULT_ANT_B = 0x4, +}; + +/** + * struct iwl_sad_properties - SAD properties + * @chain_a_sad_mode: chain A SAD mode, &enum iwl_sad_mode + * @chain_b_sad_mode: chain B SAD mode, &enum iwl_sad_mode + * @mac_id: MAC index + * @reserved: reserved + */ +struct iwl_sad_properties { + __le32 chain_a_sad_mode; + __le32 chain_b_sad_mode; + __le32 mac_id; + __le32 reserved; +} __packed; + +/** + * struct iwl_rlc_config_cmd - RLC configuration + * @phy_id: PHY index + * @rlc: RLC properties, &struct iwl_rlc_properties + * @sad: SAD (single antenna diversity) options, &struct iwl_sad_properties + * @flags: flags, &enum iwl_rlc_flags + * @reserved: reserved + */ +struct iwl_rlc_config_cmd { + __le32 phy_id; + struct iwl_rlc_properties rlc; + struct iwl_sad_properties sad; + u8 flags; + u8 reserved[3]; +} __packed; /* RLC_CONFIG_CMD_API_S_VER_2 */ + #endif /* __iwl_fw_api_datapath_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h index 3988f5fea33a..224525417424 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -7,7 +7,6 @@ #include <linux/bitops.h> -#define IWL_FW_INI_HW_SMEM_REGION_ID 15 #define IWL_FW_INI_MAX_REGION_ID 64 #define IWL_FW_INI_MAX_NAME 32 #define IWL_FW_INI_MAX_CFG_NAME 64 @@ -124,6 +123,9 @@ struct iwl_fw_ini_region_internal_buffer { * @hdr: debug header * @id: region id. Max id is &IWL_FW_INI_MAX_REGION_ID * @type: region type. One of &enum iwl_fw_ini_region_type + * @sub_type: region sub type + * @sub_type_ver: region sub type + * @reserved: not in use * @name: region name * @dev_addr: device address configuration. Used by * &IWL_FW_INI_REGION_DEVICE_MEMORY, &IWL_FW_INI_REGION_PERIPHERY_MAC, @@ -146,7 +148,10 @@ struct iwl_fw_ini_region_internal_buffer { struct iwl_fw_ini_region_tlv { struct iwl_fw_ini_header hdr; __le32 id; - __le32 type; + u8 type; + u8 sub_type; + u8 sub_type_ver; + u8 reserved; u8 name[IWL_FW_INI_MAX_NAME]; union { struct iwl_fw_ini_region_dev_addr dev_addr; @@ -306,6 +311,7 @@ enum iwl_fw_ini_config_set_type { * @IWL_FW_INI_ALLOCATION_ID_DBGC1: allocation meant for DBGC1 configuration * @IWL_FW_INI_ALLOCATION_ID_DBGC2: allocation meant for DBGC2 configuration * @IWL_FW_INI_ALLOCATION_ID_DBGC3: allocation meant for DBGC3 configuration + * @IWL_FW_INI_ALLOCATION_ID_DBGC4: allocation meant for DBGC4 configuration * @IWL_FW_INI_ALLOCATION_NUM: number of allocation ids */ enum iwl_fw_ini_allocation_id { @@ -313,6 +319,7 @@ enum iwl_fw_ini_allocation_id { IWL_FW_INI_ALLOCATION_ID_DBGC1, IWL_FW_INI_ALLOCATION_ID_DBGC2, IWL_FW_INI_ALLOCATION_ID_DBGC3, + IWL_FW_INI_ALLOCATION_ID_DBGC4, IWL_FW_INI_ALLOCATION_NUM, }; /* FW_DEBUG_TLV_ALLOCATION_ID_E_VER_1 */ @@ -379,6 +386,8 @@ enum iwl_fw_ini_region_type { IWL_FW_INI_REGION_NUM }; /* FW_TLV_DEBUG_REGION_TYPE_API_E */ +#define IWL_FW_INI_REGION_DEVICE_MEMORY_SUBTYPE_HW_SMEM 1 + /** * enum iwl_fw_ini_time_point * diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index 3551a3f1c1aa..186199100929 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -34,6 +34,11 @@ enum iwl_regulatory_and_nvm_subcmd_ids { TAS_CONFIG = 0x3, /** + * @SAR_OFFSET_MAPPING_TABLE_CMD: &iwl_sar_offset_mapping_cmd + */ + SAR_OFFSET_MAPPING_TABLE_CMD = 0x4, + + /** * @PNVM_INIT_COMPLETE_NTFY: &struct iwl_pnvm_init_complete_ntfy */ PNVM_INIT_COMPLETE_NTFY = 0xFE, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h index 68b788b92b7a..e66f77924f83 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018, 2020 Intel Corporation + * Copyright (C) 2012-2014, 2018, 2020-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -150,11 +150,12 @@ struct iwl_phy_context_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ __le32 id_and_color; __le32 action; - /* PHY_CONTEXT_DATA_API_S_VER_3 */ + /* PHY_CONTEXT_DATA_API_S_VER_3, PHY_CONTEXT_DATA_API_S_VER_4 */ struct iwl_fw_channel_info ci; __le32 lmac_id; - __le32 rxchain_info; + __le32 rxchain_info; /* reserved in _VER_4 */ __le32 dsp_cfg_flags; __le32 reserved; -} __packed; /* PHY_CONTEXT_CMD_API_VER_3 */ +} __packed; /* PHY_CONTEXT_CMD_API_VER_3, PHY_CONTEXT_CMD_API_VER_4 */ + #endif /* __iwl_fw_api_phy_ctxt_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h index 4d671c878bb7..631b96cc8ee9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h @@ -503,6 +503,20 @@ union iwl_ppag_table_cmd { } v2; } __packed; +#define MCC_TO_SAR_OFFSET_TABLE_ROW_SIZE 26 +#define MCC_TO_SAR_OFFSET_TABLE_COL_SIZE 13 + +/** + * struct iwl_sar_offset_mapping_cmd - struct for SAR_OFFSET_MAPPING_TABLE_CMD + * @offset_map: mapping a mcc to a geo sar group + * @reserved: reserved + */ +struct iwl_sar_offset_mapping_cmd { + u8 offset_map[MCC_TO_SAR_OFFSET_TABLE_ROW_SIZE] + [MCC_TO_SAR_OFFSET_TABLE_COL_SIZE]; + u16 reserved; +} __packed; /*SAR_OFFSET_MAPPING_TABLE_CMD_API_S*/ + /** * struct iwl_beacon_filter_cmd * REPLY_BEACON_FILTERING_CMD = 0xd2 (command) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h index 8b200379f7c2..9aa7d0bbd64e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h @@ -660,6 +660,19 @@ enum iwl_umac_scan_general_flags_v2 { }; /** + * enum iwl_umac_scan_general_params_flags2 - UMAC scan general flags2 + * + * @IWL_UMAC_SCAN_GEN_PARAMS_FLAGS2_RESPECT_P2P_GO_LB: scan event scheduling + * should be aware of a P2P GO operation on the 2GHz band. + * @IWL_UMAC_SCAN_GEN_PARAMS_FLAGS2_RESPECT_P2P_GO_HB: scan event scheduling + * should be aware of a P2P GO operation on the 5GHz or 6GHz band. + */ +enum iwl_umac_scan_general_params_flags2 { + IWL_UMAC_SCAN_GEN_PARAMS_FLAGS2_RESPECT_P2P_GO_LB = BIT(0), + IWL_UMAC_SCAN_GEN_PARAMS_FLAGS2_RESPECT_P2P_GO_HB = BIT(1), +}; + +/** * struct iwl_scan_channel_cfg_umac * @flags: bitmap - 0-19: directed scan to i'th ssid. * @channel_num: channel number 1-13 etc. @@ -941,8 +954,8 @@ struct iwl_scan_channel_params_v6 { } __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_6 */ /** - * struct iwl_scan_general_params_v10 - * @flags: &enum iwl_umac_scan_flags + * struct iwl_scan_general_params_v11 + * @flags: &enum iwl_umac_scan_general_flags_v2 * @reserved: reserved for future * @scan_start_mac_id: report the scan start TSF time according to this mac TSF * @active_dwell: dwell time for active scan per LMAC @@ -952,7 +965,8 @@ struct iwl_scan_channel_params_v6 { * for 5GHz channels * @adwell_default_social_chn: adaptive dwell default number of * APs per social channel - * @reserved1: reserved for future + * @flags2: for version 11 see &enum iwl_umac_scan_general_params_flags2. + * Otherwise reserved. * @adwell_max_budget: the maximal number of TUs that adaptive dwell * can add to the total scan time * @max_out_of_time: max out of serving channel time, per LMAC @@ -963,7 +977,7 @@ struct iwl_scan_channel_params_v6 { * @num_of_fragments: number of fragments needed for full fragmented * scan coverage. */ -struct iwl_scan_general_params_v10 { +struct iwl_scan_general_params_v11 { __le16 flags; u8 reserved; u8 scan_start_mac_id; @@ -971,14 +985,14 @@ struct iwl_scan_general_params_v10 { u8 adwell_default_2g; u8 adwell_default_5g; u8 adwell_default_social_chn; - u8 reserved1; + u8 flags2; __le16 adwell_max_budget; __le32 max_out_of_time[SCAN_TWO_LMACS]; __le32 suspend_time[SCAN_TWO_LMACS]; __le32 scan_priority; u8 passive_dwell[SCAN_TWO_LMACS]; u8 num_of_fragments[SCAN_TWO_LMACS]; -} __packed; /* SCAN_GENERAL_PARAMS_API_S_VER_10 */ +} __packed; /* SCAN_GENERAL_PARAMS_API_S_VER_11 and *_VER_10 */ /** * struct iwl_scan_periodic_parms_v1 @@ -994,31 +1008,31 @@ struct iwl_scan_periodic_parms_v1 { /** * struct iwl_scan_req_params_v12 - * @general_params: &struct iwl_scan_general_params_v10 + * @general_params: &struct iwl_scan_general_params_v11 * @channel_params: &struct iwl_scan_channel_params_v4 * @periodic_params: &struct iwl_scan_periodic_parms_v1 * @probe_params: &struct iwl_scan_probe_params_v3 */ struct iwl_scan_req_params_v12 { - struct iwl_scan_general_params_v10 general_params; + struct iwl_scan_general_params_v11 general_params; struct iwl_scan_channel_params_v4 channel_params; struct iwl_scan_periodic_parms_v1 periodic_params; struct iwl_scan_probe_params_v3 probe_params; } __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_12 */ /** - * struct iwl_scan_req_params_v14 - * @general_params: &struct iwl_scan_general_params_v10 + * struct iwl_scan_req_params_v15 + * @general_params: &struct iwl_scan_general_params_v11 * @channel_params: &struct iwl_scan_channel_params_v6 * @periodic_params: &struct iwl_scan_periodic_parms_v1 * @probe_params: &struct iwl_scan_probe_params_v4 */ -struct iwl_scan_req_params_v14 { - struct iwl_scan_general_params_v10 general_params; +struct iwl_scan_req_params_v15 { + struct iwl_scan_general_params_v11 general_params; struct iwl_scan_channel_params_v6 channel_params; struct iwl_scan_periodic_parms_v1 periodic_params; struct iwl_scan_probe_params_v4 probe_params; -} __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_14 */ +} __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_15 and *_VER_14 */ /** * struct iwl_scan_req_umac_v12 @@ -1033,16 +1047,16 @@ struct iwl_scan_req_umac_v12 { } __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_12 */ /** - * struct iwl_scan_req_umac_v14 + * struct iwl_scan_req_umac_v15 * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @ooc_priority: out of channel priority - &enum iwl_scan_priority * @scan_params: scan parameters */ -struct iwl_scan_req_umac_v14 { +struct iwl_scan_req_umac_v15 { __le32 uid; __le32 ooc_priority; - struct iwl_scan_req_params_v14 scan_params; -} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_14 */ + struct iwl_scan_req_params_v15 scan_params; +} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_15 and *_VER_14 */ /** * struct iwl_umac_scan_abort diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h b/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h index 18cca15caa3a..898e62326e6c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018, 2020 Intel Corporation + * Copyright (C) 2012-2014, 2018, 2020 - 2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -432,6 +432,7 @@ enum iwl_fw_statistics_type { FW_STATISTICS_HE, }; /* FW_STATISTICS_TYPE_API_E_VER_1 */ +#define IWL_STATISTICS_TYPE_MSK 0x7f /** * struct iwl_statistics_ntfy_hdr * @@ -446,10 +447,97 @@ struct iwl_statistics_ntfy_hdr { }; /* STATISTICS_NTFY_HDR_API_S_VER_1 */ /** + * struct iwl_statistics_ntfy_per_mac + * + * @beacon_filter_average_energy: Average energy [-dBm] of the 2 + * antennas. + * @air_time: air time + * @beacon_counter: all beacons (both filtered and not filtered) + * @beacon_average_energy: all beacons (both filtered and not + * filtered) + * @beacon_rssi_a: beacon RSSI on antenna A + * @beacon_rssi_b: beacon RSSI on antenna B + * @rx_bytes: RX byte count + */ +struct iwl_statistics_ntfy_per_mac { + __le32 beacon_filter_average_energy; + __le32 air_time; + __le32 beacon_counter; + __le32 beacon_average_energy; + __le32 beacon_rssi_a; + __le32 beacon_rssi_b; + __le32 rx_bytes; +} __packed; /* STATISTICS_NTFY_PER_MAC_API_S_VER_1 */ + +#define IWL_STATS_MAX_BW_INDEX 5 +/** struct iwl_statistics_ntfy_per_phy + * @channel_load: channel load + * @channel_load_by_us: device contribution to MCLM + * @channel_load_not_by_us: other devices' contribution to MCLM + * @clt: CLT HW timer (TIM_CH_LOAD2) + * @act: active accumulator SW + * @elp: elapsed time accumulator SW + * @rx_detected_per_ch_width: number of deferred TX per channel width, + * 0 - 20, 1/2/3 - 40/80/160 + * @success_per_ch_width: number of frames that got ACK/BACK/CTS + * per channel BW. note, BACK counted as 1 + * @fail_per_ch_width: number of frames that didn't get ACK/BACK/CTS + * per channel BW. note BACK counted as 1 + * @last_tx_ch_width_indx: last txed frame channel width index + */ +struct iwl_statistics_ntfy_per_phy { + __le32 channel_load; + __le32 channel_load_by_us; + __le32 channel_load_not_by_us; + __le32 clt; + __le32 act; + __le32 elp; + __le32 rx_detected_per_ch_width[IWL_STATS_MAX_BW_INDEX]; + __le32 success_per_ch_width[IWL_STATS_MAX_BW_INDEX]; + __le32 fail_per_ch_width[IWL_STATS_MAX_BW_INDEX]; + __le32 last_tx_ch_width_indx; +} __packed; /* STATISTICS_NTFY_PER_PHY_API_S_VER_1 */ + +/** + * struct iwl_statistics_ntfy_per_sta + * + * @average_energy: in fact it is minus the energy.. + */ +struct iwl_statistics_ntfy_per_sta { + __le32 average_energy; +} __packed; /* STATISTICS_NTFY_PER_STA_API_S_VER_1 */ + +#define IWL_STATS_MAX_PHY_OPERTINAL 3 +/** * struct iwl_statistics_operational_ntfy * * @hdr: general statistics header * @flags: bitmap of possible notification structures + * @per_mac_stats: per mac statistics, &struct iwl_statistics_ntfy_per_mac + * @per_phy_stats: per phy statistics, &struct iwl_statistics_ntfy_per_phy + * @per_sta_stats: per sta statistics, &struct iwl_statistics_ntfy_per_sta + * @rx_time: rx time + * @tx_time: usec the radio is transmitting. + * @on_time_rf: The total time in usec the RF is awake. + * @on_time_scan: usec the radio is awake due to scan. + */ +struct iwl_statistics_operational_ntfy { + struct iwl_statistics_ntfy_hdr hdr; + __le32 flags; + struct iwl_statistics_ntfy_per_mac per_mac_stats[MAC_INDEX_AUX]; + struct iwl_statistics_ntfy_per_phy per_phy_stats[IWL_STATS_MAX_PHY_OPERTINAL]; + struct iwl_statistics_ntfy_per_sta per_sta_stats[IWL_MVM_STATION_COUNT_MAX]; + __le64 rx_time; + __le64 tx_time; + __le64 on_time_rf; + __le64 on_time_scan; +} __packed; /* STATISTICS_OPERATIONAL_NTFY_API_S_VER_15 */ + +/** + * struct iwl_statistics_operational_ntfy_ver_14 + * + * @hdr: general statistics header + * @flags: bitmap of possible notification structures * @mac_id: mac on which the beacon was received * @beacon_filter_average_energy: Average energy [-dBm] of the 2 * antennas. @@ -469,7 +557,7 @@ struct iwl_statistics_ntfy_hdr { * @average_energy: in fact it is minus the energy.. * @reserved: reserved */ -struct iwl_statistics_operational_ntfy { +struct iwl_statistics_operational_ntfy_ver_14 { struct iwl_statistics_ntfy_hdr hdr; __le32 flags; __le32 mac_id; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/soc.h b/drivers/net/wireless/intel/iwlwifi/fw/api/system.h index c5df1171462b..acf5d4b9a214 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/soc.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/system.h @@ -1,11 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2019-2020 Intel Corporation + * Copyright (C) 2012-2014, 2019-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ -#ifndef __iwl_fw_api_soc_h__ -#define __iwl_fw_api_soc_h__ +#ifndef __iwl_fw_api_system_h__ +#define __iwl_fw_api_system_h__ #define SOC_CONFIG_CMD_FLAGS_DISCRETE BIT(0) #define SOC_CONFIG_CMD_FLAGS_LOW_LATENCY BIT(1) @@ -32,4 +32,12 @@ struct iwl_soc_configuration_cmd { * SOC_CONFIGURATION_CMD_S_VER_2 */ -#endif /* __iwl_fw_api_soc_h__ */ +/** + * struct iwl_system_features_control_cmd - system features control command + * @features: bitmap of features to disable + */ +struct iwl_system_features_control_cmd { + __le32 features[4]; +} __packed; /* SYSTEM_FEATURES_CONTROL_CMD_API_S_VER_1 */ + +#endif /* __iwl_fw_api_system_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index a39013c401c9..a373a2bc964a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -880,7 +880,7 @@ iwl_fw_error_dump_file(struct iwl_fw_runtime *fwrt, dump_info->hw_type = cpu_to_le32(CSR_HW_REV_TYPE(fwrt->trans->hw_rev)); dump_info->hw_step = - cpu_to_le32(CSR_HW_REV_STEP(fwrt->trans->hw_rev)); + cpu_to_le32(fwrt->trans->hw_rev_step); memcpy(dump_info->fw_human_readable, fwrt->fw->human_readable, sizeof(dump_info->fw_human_readable)); strncpy(dump_info->dev_human_readable, fwrt->trans->name, @@ -1165,8 +1165,7 @@ static int iwl_dump_ini_dev_mem_iter(struct iwl_fw_runtime *fwrt, iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data, le32_to_cpu(reg->dev_addr.size)); - if ((le32_to_cpu(reg->id) & IWL_FW_INI_REGION_V2_MASK) == - IWL_FW_INI_HW_SMEM_REGION_ID && + if (reg->sub_type == IWL_FW_INI_REGION_DEVICE_MEMORY_SUBTYPE_HW_SMEM && fwrt->sanitize_ops && fwrt->sanitize_ops->frob_txf) fwrt->sanitize_ops->frob_txf(fwrt->sanitize_ctx, range->data, @@ -1988,17 +1987,18 @@ static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, struct list_head *list, { struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_fw_ini_dump_entry *entry; - struct iwl_fw_error_dump_data *tlv; + struct iwl_fw_ini_error_dump_data *tlv; struct iwl_fw_ini_error_dump_header *header; - u32 type = le32_to_cpu(reg->type), id = le32_to_cpu(reg->id); + u32 type = reg->type; + u32 id = le32_to_cpu(reg->id); u32 num_of_ranges, i, size; void *range; /* - * The higher part of the ID in version 2 is irrelevant for + * The higher part of the ID from 2 is irrelevant for * us, so mask it out. */ - if (le32_to_cpu(reg->hdr.version) == 2) + if (le32_to_cpu(reg->hdr.version) >= 2) id &= IWL_FW_INI_REGION_V2_MASK; if (!ops->get_num_of_ranges || !ops->get_size || !ops->fill_mem_hdr || @@ -2017,6 +2017,9 @@ static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, struct list_head *list, tlv = (void *)entry->data; tlv->type = reg->type; + tlv->sub_type = reg->sub_type; + tlv->sub_type_ver = reg->sub_type_ver; + tlv->reserved = reg->reserved; tlv->len = cpu_to_le32(size); IWL_DEBUG_FW(fwrt, "WRT: Collecting region: id=%d, type=%d\n", id, @@ -2099,7 +2102,7 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, dump->ver_type = cpu_to_le32(fwrt->dump.fw_ver.type); dump->ver_subtype = cpu_to_le32(fwrt->dump.fw_ver.subtype); - dump->hw_step = cpu_to_le32(CSR_HW_REV_STEP(fwrt->trans->hw_rev)); + dump->hw_step = cpu_to_le32(fwrt->trans->hw_rev_step); /* * Several HWs all have type == 0x42, so we'll override this value @@ -2291,7 +2294,7 @@ static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt, } reg = (void *)reg_data.reg_tlv->data; - reg_type = le32_to_cpu(reg->type); + reg_type = reg->type; if (reg_type >= ARRAY_SIZE(iwl_dump_ini_region_ops)) continue; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c index 016b3a4c5f51..358fc2d999d5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dump.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c @@ -212,7 +212,9 @@ static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_nu IWL_ERR(trans, "HW error, resetting before reading\n"); /* reset the device */ - iwl_trans_sw_reset(trans); + err = iwl_trans_sw_reset(trans, true); + if (err) + return; err = iwl_finish_nic_init(trans); if (err) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h index 9036b32ec765..079fa0023bd8 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h @@ -232,6 +232,24 @@ struct iwl_fw_error_dump_mem { #define IWL_INI_DUMP_INFO_TYPE BIT(31) /** + * struct iwl_fw_error_dump_data - data for one type + * @type: &enum iwl_fw_ini_region_type + * @sub_type: sub type id + * @sub_type_ver: sub type version + * @reserved: not in use + * @len: the length starting from %data + * @data: the data itself + */ +struct iwl_fw_ini_error_dump_data { + u8 type; + u8 sub_type; + u8 sub_type_ver; + u8 reserved; + __le32 len; + __u8 data[]; +} __packed; + +/** * struct iwl_fw_ini_dump_entry * @list: list of dump entries * @size: size of the data diff --git a/drivers/net/wireless/intel/iwlwifi/fw/init.c b/drivers/net/wireless/intel/iwlwifi/fw/init.c index 566957ac4539..139ece879fab 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/init.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/init.c @@ -8,7 +8,7 @@ #include "dbg.h" #include "debugfs.h" -#include "fw/api/soc.h" +#include "fw/api/system.h" #include "fw/api/commands.h" #include "fw/api/rx.h" #include "fw/api/datapath.h" diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 69799f1ed2c4..cd895b614ddb 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -156,8 +156,12 @@ struct iwl_fw_runtime { u8 sar_chain_b_profile; struct iwl_geo_profile geo_profiles[ACPI_NUM_GEO_PROFILES_REV3]; u32 geo_rev; + u32 geo_num_profiles; + bool geo_enabled; union iwl_ppag_table_cmd ppag_table; u32 ppag_ver; + struct iwl_sar_offset_mapping_cmd sgom_table; + bool sgom_enabled; #endif }; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index c875bf35533c..bd82c24811c8 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -11,6 +11,7 @@ #include "fw/uefi.h" #include "fw/api/alive.h" #include <linux/efi.h> +#include "fw/runtime.h" #define IWL_EFI_VAR_GUID EFI_GUID(0x92daaf2f, 0xc02b, 0x455b, \ 0xb2, 0xec, 0xf5, 0xa3, \ @@ -86,6 +87,7 @@ static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans, if (len < tlv_len) { IWL_ERR(trans, "invalid TLV len: %zd/%u\n", len, tlv_len); + kfree(reduce_power_data); reduce_power_data = ERR_PTR(-EINVAL); goto out; } @@ -105,6 +107,7 @@ static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans, IWL_DEBUG_FW(trans, "Couldn't allocate (more) reduce_power_data\n"); + kfree(reduce_power_data); reduce_power_data = ERR_PTR(-ENOMEM); goto out; } @@ -134,6 +137,10 @@ static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans, done: if (!size) { IWL_DEBUG_FW(trans, "Empty REDUCE_POWER, skipping.\n"); + /* Better safe than sorry, but 'reduce_power_data' should + * always be NULL if !size. + */ + kfree(reduce_power_data); reduce_power_data = ERR_PTR(-ENOENT); goto out; } @@ -260,3 +267,90 @@ out: return data; } + +#ifdef CONFIG_ACPI +static int iwl_uefi_sgom_parse(struct uefi_cnv_wlan_sgom_data *sgom_data, + struct iwl_fw_runtime *fwrt) +{ + int i, j; + + if (sgom_data->revision != 1) + return -EINVAL; + + memcpy(fwrt->sgom_table.offset_map, sgom_data->offset_map, + sizeof(fwrt->sgom_table.offset_map)); + + for (i = 0; i < MCC_TO_SAR_OFFSET_TABLE_ROW_SIZE; i++) { + for (j = 0; j < MCC_TO_SAR_OFFSET_TABLE_COL_SIZE; j++) { + /* since each byte is composed of to values, */ + /* one for each letter, */ + /* extract and check each of them separately */ + u8 value = fwrt->sgom_table.offset_map[i][j]; + u8 low = value & 0xF; + u8 high = (value & 0xF0) >> 4; + + if (high > fwrt->geo_num_profiles) + high = 0; + if (low > fwrt->geo_num_profiles) + low = 0; + fwrt->sgom_table.offset_map[i][j] = (high << 4) | low; + } + } + + fwrt->sgom_enabled = true; + return 0; +} + +void iwl_uefi_get_sgom_table(struct iwl_trans *trans, + struct iwl_fw_runtime *fwrt) +{ + struct efivar_entry *sgom_efivar; + struct uefi_cnv_wlan_sgom_data *data; + unsigned long package_size; + int err, ret; + + if (!fwrt->geo_enabled) + return; + + sgom_efivar = kzalloc(sizeof(*sgom_efivar), GFP_KERNEL); + if (!sgom_efivar) + return; + + memcpy(&sgom_efivar->var.VariableName, IWL_UEFI_SGOM_NAME, + sizeof(IWL_UEFI_SGOM_NAME)); + sgom_efivar->var.VendorGuid = IWL_EFI_VAR_GUID; + + /* TODO: we hardcode a maximum length here, because reading + * from the UEFI is not working. To implement this properly, + * we have to call efivar_entry_size(). + */ + package_size = IWL_HARDCODED_SGOM_SIZE; + + data = kmalloc(package_size, GFP_KERNEL); + if (!data) { + data = ERR_PTR(-ENOMEM); + goto out; + } + + err = efivar_entry_get(sgom_efivar, NULL, &package_size, data); + if (err) { + IWL_DEBUG_FW(trans, + "SGOM UEFI variable not found %d\n", err); + goto out_free; + } + + IWL_DEBUG_FW(trans, "Read SGOM from UEFI with size %lu\n", + package_size); + + ret = iwl_uefi_sgom_parse(data, fwrt); + if (ret < 0) + IWL_DEBUG_FW(trans, "Cannot read SGOM tables. rev is invalid\n"); + +out_free: + kfree(data); + +out: + kfree(sgom_efivar); +} +IWL_EXPORT_SYMBOL(iwl_uefi_get_sgom_table); +#endif /* CONFIG_ACPI */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index d552c656ac9f..09d2a971b3a0 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -7,6 +7,7 @@ #define IWL_UEFI_OEM_PNVM_NAME L"UefiCnvWlanOemSignedPnvm" #define IWL_UEFI_REDUCED_POWER_NAME L"UefiCnvWlanReducedPower" +#define IWL_UEFI_SGOM_NAME L"UefiCnvWlanSarGeoOffsetMapping" /* * TODO: we have these hardcoded values that the caller must pass, @@ -16,6 +17,7 @@ */ #define IWL_HARDCODED_PNVM_SIZE 4096 #define IWL_HARDCODED_REDUCE_POWER_SIZE 32768 +#define IWL_HARDCODED_SGOM_SIZE 339 struct pnvm_sku_package { u8 rev; @@ -25,6 +27,16 @@ struct pnvm_sku_package { u8 data[]; } __packed; +struct uefi_cnv_wlan_sgom_data { + u8 revision; + u8 offset_map[IWL_HARDCODED_SGOM_SIZE - 1]; +} __packed; + +/* + * This is known to be broken on v4.19 and to work on v5.4. Until we + * figure out why this is the case and how to make it work, simply + * disable the feature in old kernels. + */ #ifdef CONFIG_EFI void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len); void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len); @@ -42,4 +54,12 @@ void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) } #endif /* CONFIG_EFI */ +#if defined(CONFIG_EFI) && defined(CONFIG_ACPI) +void iwl_uefi_get_sgom_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt); +#else +static inline +void iwl_uefi_get_sgom_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt) +{ +} +#endif #endif /* __iwl_fw_uefi__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 665167a223f6..1ecde7c86368 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -610,7 +610,6 @@ extern const struct iwl_cfg killer1650x_2ax_cfg; extern const struct iwl_cfg killer1650w_2ax_cfg; extern const struct iwl_cfg iwl_qnj_b0_hr_b0_cfg; extern const struct iwl_cfg iwlax210_2ax_cfg_so_jf_b0; -extern const struct iwl_cfg iwlax210_2ax_cfg_so_hr_a0; extern const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0; extern const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0_long; extern const struct iwl_cfg iwlax210_2ax_cfg_ty_gf_a0; @@ -634,6 +633,7 @@ extern const struct iwl_cfg iwl_cfg_bz_a0_gf4_a0; extern const struct iwl_cfg iwl_cfg_bz_a0_mr_a0; extern const struct iwl_cfg iwl_cfg_bz_a0_fm_a0; extern const struct iwl_cfg iwl_cfg_gl_a0_fm_a0; +extern const struct iwl_cfg iwl_cfg_bz_z0_gf_a0; #endif /* CONFIG_IWLMVM */ #endif /* __IWL_CONFIG_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index ff79a2ecb242..21d8249980fa 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -105,6 +105,10 @@ /* GIO Chicken Bits (PCI Express bus link power management) */ #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) +#define CSR_IPC_SLEEP_CONTROL (CSR_BASE + 0x114) +#define CSR_IPC_SLEEP_CONTROL_SUSPEND 0x3 +#define CSR_IPC_SLEEP_CONTROL_RESUME 0 + /* Doorbell NMI (since Bz) */ #define CSR_DOORBELL_VECTOR (CSR_BASE + 0x130) #define CSR_DOORBELL_VECTOR_NMI BIT(1) @@ -143,8 +147,7 @@ #define CSR_FUNC_SCRATCH_INIT_VALUE (0x01010101) /* Bits for CSR_HW_IF_CONFIG_REG */ -#define CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH (0x00000003) -#define CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP (0x0000000C) +#define CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP_DASH (0x0000000F) #define CSR_HW_IF_CONFIG_REG_BIT_MONITOR_SRAM (0x00000080) #define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x000000C0) #define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) @@ -287,8 +290,7 @@ #define CSR_GP_CNTRL_REG_FLAG_SW_RESET BIT(31) /* HW REV */ -#define CSR_HW_REV_DASH(_val) (((_val) & 0x0000003) >> 0) -#define CSR_HW_REV_STEP(_val) (((_val) & 0x000000C) >> 2) +#define CSR_HW_REV_STEP_DASH(_val) ((_val) & CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP_DASH) #define CSR_HW_REV_TYPE(_val) (((_val) & 0x000FFF0) >> 4) /* HW RFID */ @@ -306,6 +308,7 @@ enum { SILICON_A_STEP = 0, SILICON_B_STEP, SILICON_C_STEP, + SILICON_Z_STEP = 0xf, }; @@ -328,10 +331,10 @@ enum { #define CSR_HW_REV_TYPE_7265D (0x0000210) #define CSR_HW_REV_TYPE_NONE (0x00001F0) #define CSR_HW_REV_TYPE_QNJ (0x0000360) -#define CSR_HW_REV_TYPE_QNJ_B0 (0x0000364) -#define CSR_HW_REV_TYPE_QU_B0 (0x0000334) -#define CSR_HW_REV_TYPE_QU_C0 (0x0000338) -#define CSR_HW_REV_TYPE_QUZ (0x0000354) +#define CSR_HW_REV_TYPE_QNJ_B0 (0x0000361) +#define CSR_HW_REV_TYPE_QU_B0 (0x0000331) +#define CSR_HW_REV_TYPE_QU_C0 (0x0000332) +#define CSR_HW_REV_TYPE_QUZ (0x0000351) #define CSR_HW_REV_TYPE_HR_CDB (0x0000340) #define CSR_HW_REV_TYPE_SO (0x0000370) #define CSR_HW_REV_TYPE_TY (0x0000420) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 7ab98b419cc1..a8ebc26d1da1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -59,7 +59,7 @@ dbg_ver_table[IWL_DBG_TLV_TYPE_NUM] = { [IWL_DBG_TLV_TYPE_DEBUG_INFO] = {.min_ver = 1, .max_ver = 1,}, [IWL_DBG_TLV_TYPE_BUF_ALLOC] = {.min_ver = 1, .max_ver = 1,}, [IWL_DBG_TLV_TYPE_HCMD] = {.min_ver = 1, .max_ver = 1,}, - [IWL_DBG_TLV_TYPE_REGION] = {.min_ver = 1, .max_ver = 2,}, + [IWL_DBG_TLV_TYPE_REGION] = {.min_ver = 1, .max_ver = 3,}, [IWL_DBG_TLV_TYPE_TRIGGER] = {.min_ver = 1, .max_ver = 1,}, [IWL_DBG_TLV_TYPE_CONF_SET] = {.min_ver = 1, .max_ver = 1,}, }; @@ -177,14 +177,14 @@ static int iwl_dbg_tlv_alloc_region(struct iwl_trans *trans, const struct iwl_fw_ini_region_tlv *reg = (const void *)tlv->data; struct iwl_ucode_tlv **active_reg; u32 id = le32_to_cpu(reg->id); - u32 type = le32_to_cpu(reg->type); + u8 type = reg->type; u32 tlv_len = sizeof(*tlv) + le32_to_cpu(tlv->length); /* - * The higher part of the ID in version 2 is irrelevant for + * The higher part of the ID in from version 2 is irrelevant for * us, so mask it out. */ - if (le32_to_cpu(reg->hdr.version) == 2) + if (le32_to_cpu(reg->hdr.version) >= 2) id &= IWL_FW_INI_REGION_V2_MASK; if (le32_to_cpu(tlv->length) < sizeof(*reg)) @@ -473,7 +473,7 @@ void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans) int res; if (!iwlwifi_mod_params.enable_ini || - trans->trans_cfg->device_family <= IWL_DEVICE_FAMILY_9000) + trans->trans_cfg->device_family <= IWL_DEVICE_FAMILY_8000) return; res = firmware_request_nowarn(&fw, yoyo_bin, dev); @@ -1244,7 +1244,7 @@ static void iwl_dbg_tlv_init_cfg(struct iwl_fw_runtime *fwrt) } reg = (void *)(*active_reg)->data; - reg_type = le32_to_cpu(reg->type); + reg_type = reg->type; if (reg_type != IWL_FW_INI_REGION_DRAM_BUFFER || !(BIT(le32_to_cpu(reg->dram_alloc_id)) & failed_alloc)) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 36196e07b1a0..40e8d7ed5615 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -163,8 +163,8 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) char tag[8]; if (drv->trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_9000 && - (CSR_HW_REV_STEP(drv->trans->hw_rev) != SILICON_B_STEP && - CSR_HW_REV_STEP(drv->trans->hw_rev) != SILICON_C_STEP)) { + (drv->trans->hw_rev_step != SILICON_B_STEP && + drv->trans->hw_rev_step != SILICON_C_STEP)) { IWL_ERR(drv, "Only HW steps B and C are currently supported (0x%0x)\n", drv->trans->hw_rev); @@ -1313,23 +1313,31 @@ _iwl_op_mode_start(struct iwl_drv *drv, struct iwlwifi_opmode_table *op) const struct iwl_op_mode_ops *ops = op->ops; struct dentry *dbgfs_dir = NULL; struct iwl_op_mode *op_mode = NULL; + int retry, max_retry = !!iwlwifi_mod_params.fw_restart * IWL_MAX_INIT_RETRY; + + for (retry = 0; retry <= max_retry; retry++) { #ifdef CONFIG_IWLWIFI_DEBUGFS - drv->dbgfs_op_mode = debugfs_create_dir(op->name, - drv->dbgfs_drv); - dbgfs_dir = drv->dbgfs_op_mode; + drv->dbgfs_op_mode = debugfs_create_dir(op->name, + drv->dbgfs_drv); + dbgfs_dir = drv->dbgfs_op_mode; #endif - op_mode = ops->start(drv->trans, drv->trans->cfg, &drv->fw, dbgfs_dir); + op_mode = ops->start(drv->trans, drv->trans->cfg, + &drv->fw, dbgfs_dir); + + if (op_mode) + return op_mode; + + IWL_ERR(drv, "retry init count %d\n", retry); #ifdef CONFIG_IWLWIFI_DEBUGFS - if (!op_mode) { debugfs_remove_recursive(drv->dbgfs_op_mode); drv->dbgfs_op_mode = NULL; - } #endif + } - return op_mode; + return NULL; } static void _iwl_op_mode_stop(struct iwl_drv *drv) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h index 2e2d60a58692..0fd009e6d685 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h @@ -89,4 +89,7 @@ void iwl_drv_stop(struct iwl_drv *drv); #define IWL_EXPORT_SYMBOL(sym) #endif +/* max retry for init flow */ +#define IWL_MAX_INIT_RETRY 2 + #endif /* __iwl_drv_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 881ede4a4aa2..dd58c8f9aa11 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -22,6 +22,7 @@ #include "fw/api/commands.h" #include "fw/api/cmdhdr.h" #include "fw/img.h" +#include "mei/iwl-mei.h" /* NVM offsets (in words) definitions */ enum nvm_offsets { @@ -1117,6 +1118,66 @@ iwl_nvm_no_wide_in_5ghz(struct iwl_trans *trans, const struct iwl_cfg *cfg, } struct iwl_nvm_data * +iwl_parse_mei_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, + const struct iwl_mei_nvm *mei_nvm, + const struct iwl_fw *fw) +{ + struct iwl_nvm_data *data; + u32 sbands_flags = 0; + u8 rx_chains = fw->valid_rx_ant; + u8 tx_chains = fw->valid_rx_ant; + + if (cfg->uhb_supported) + data = kzalloc(struct_size(data, channels, + IWL_NVM_NUM_CHANNELS_UHB), + GFP_KERNEL); + else + data = kzalloc(struct_size(data, channels, + IWL_NVM_NUM_CHANNELS_EXT), + GFP_KERNEL); + if (!data) + return NULL; + + BUILD_BUG_ON(ARRAY_SIZE(mei_nvm->channels) != + IWL_NVM_NUM_CHANNELS_UHB); + data->nvm_version = mei_nvm->nvm_version; + + iwl_set_radio_cfg(cfg, data, mei_nvm->radio_cfg); + if (data->valid_tx_ant) + tx_chains &= data->valid_tx_ant; + if (data->valid_rx_ant) + rx_chains &= data->valid_rx_ant; + + data->sku_cap_mimo_disabled = false; + data->sku_cap_band_24ghz_enable = true; + data->sku_cap_band_52ghz_enable = true; + data->sku_cap_11n_enable = + !(iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL); + data->sku_cap_11ac_enable = true; + data->sku_cap_11ax_enable = + mei_nvm->caps & MEI_NVM_CAPS_11AX_SUPPORT; + + data->lar_enabled = mei_nvm->caps & MEI_NVM_CAPS_LARI_SUPPORT; + + data->n_hw_addrs = mei_nvm->n_hw_addrs; + /* If no valid mac address was found - bail out */ + if (iwl_set_hw_address(trans, cfg, data, NULL, NULL)) { + kfree(data); + return NULL; + } + + if (data->lar_enabled && + fw_has_capa(&fw->ucode_capa, IWL_UCODE_TLV_CAPA_LAR_SUPPORT)) + sbands_flags |= IWL_NVM_SBANDS_FLAGS_LAR; + + iwl_init_sbands(trans, data, mei_nvm->channels, tx_chains, rx_chains, + sbands_flags, true, fw); + + return data; +} +IWL_EXPORT_SYMBOL(iwl_parse_mei_nvm_data); + +struct iwl_nvm_data * iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, const struct iwl_fw *fw, const __be16 *nvm_hw, const __le16 *nvm_sw, @@ -1550,7 +1611,7 @@ int iwl_read_external_nvm(struct iwl_trans *trans, /* nvm file validation, dword_buff[2] holds the file version */ if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_8000 && - CSR_HW_REV_STEP(trans->hw_rev) == SILICON_C_STEP && + trans->hw_rev_step == SILICON_C_STEP && le32_to_cpu(dword_buff[2]) < 0xE4A) { ret = -EFAULT; goto out; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h index e1f5a9741850..e01f7751cf11 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2015, 2018-2020 Intel Corporation + * Copyright (C) 2005-2015, 2018-2021 Intel Corporation * Copyright (C) 2016-2017 Intel Deutschland GmbH */ #ifndef __iwl_nvm_parse_h__ @@ -8,6 +8,7 @@ #include <net/cfg80211.h> #include "iwl-eeprom-parse.h" +#include "mei/iwl-mei.h" /** * enum iwl_nvm_sbands_flags - modification flags for the channel profiles @@ -81,4 +82,12 @@ void iwl_nvm_fixups(u32 hw_id, unsigned int section, u8 *data, struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, const struct iwl_fw *fw); +/** + * iwl_parse_mei_nvm_data - parse the mei_nvm_data and get an iwl_nvm_data + */ +struct iwl_nvm_data * +iwl_parse_mei_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, + const struct iwl_mei_nvm *mei_nvm, + const struct iwl_fw *fw); + #endif /* __iwl_nvm_parse_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index a84ab02cf9d7..2ca22e1b8bd9 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -455,6 +455,13 @@ enum { #define UREG_DOORBELL_TO_ISR6_RESUME BIT(19) #define UREG_DOORBELL_TO_ISR6_PNVM BIT(20) +/* + * From BZ family driver triggers this bit for suspend and resume + * The driver should update CSR_IPC_SLEEP_CONTROL before triggering + * this interrupt with suspend/resume value + */ +#define UREG_DOORBELL_TO_ISR6_SLEEP_CTRL BIT(31) + #define CNVI_MBOX_C 0xA3400C #define FSEQ_ERROR_CODE 0xA340C8 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 4ebb1871bd1f..e7c6e7bc5277 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -296,6 +296,8 @@ enum iwl_d3_status { * are sent * @STATUS_TRANS_IDLE: the trans is idle - general commands are not to be sent * @STATUS_TRANS_DEAD: trans is dead - avoid any read/write operation + * @STATUS_SUPPRESS_CMD_ERROR_ONCE: suppress "FW error in SYNC CMD" once, + * e.g. for testing */ enum iwl_trans_status { STATUS_SYNC_HCMD_ACTIVE, @@ -308,6 +310,7 @@ enum iwl_trans_status { STATUS_TRANS_GOING_IDLE, STATUS_TRANS_IDLE, STATUS_TRANS_DEAD, + STATUS_SUPPRESS_CMD_ERROR_ONCE, }; static inline int @@ -593,7 +596,7 @@ struct iwl_trans_ops { void (*configure)(struct iwl_trans *trans, const struct iwl_trans_config *trans_cfg); void (*set_pmi)(struct iwl_trans *trans, bool state); - void (*sw_reset)(struct iwl_trans *trans); + int (*sw_reset)(struct iwl_trans *trans, bool retake_ownership); bool (*grab_nic_access)(struct iwl_trans *trans); void (*release_nic_access)(struct iwl_trans *trans); void (*set_bits_mask)(struct iwl_trans *trans, u32 reg, u32 mask, @@ -924,6 +927,7 @@ struct iwl_trans_txqs { /** * struct iwl_trans - transport common data * + * @csme_own - true if we couldn't get ownership on the device * @ops - pointer to iwl_trans_ops * @op_mode - pointer to the op_mode * @trans_cfg: the trans-specific configuration part @@ -937,6 +941,7 @@ struct iwl_trans_txqs { * @hw_id: a u32 with the ID of the device / sub-device. * Set during transport allocation. * @hw_id_str: a string with info about HW ID. Set during transport allocation. + * @hw_rev_step: The mac step of the HW * @pm_support: set to true in start_hw if link pm is supported * @ltr_enabled: set to true if the LTR is enabled * @wide_cmd_header: true when ucode supports wide command header format @@ -958,6 +963,7 @@ struct iwl_trans_txqs { * @iwl_trans_txqs: transport tx queues data. */ struct iwl_trans { + bool csme_own; const struct iwl_trans_ops *ops; struct iwl_op_mode *op_mode; const struct iwl_cfg_trans_params *trans_cfg; @@ -969,6 +975,7 @@ struct iwl_trans { struct device *dev; u32 max_skb_frags; u32 hw_rev; + u32 hw_rev_step; u32 hw_rf_id; u32 hw_id; char hw_id_str[52]; @@ -1382,10 +1389,12 @@ static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state) trans->ops->set_pmi(trans, state); } -static inline void iwl_trans_sw_reset(struct iwl_trans *trans) +static inline int iwl_trans_sw_reset(struct iwl_trans *trans, + bool retake_ownership) { if (trans->ops->sw_reset) - trans->ops->sw_reset(trans); + return trans->ops->sw_reset(trans, retake_ownership); + return 0; } static inline void diff --git a/drivers/net/wireless/intel/iwlwifi/mei/Makefile b/drivers/net/wireless/intel/iwlwifi/mei/Makefile new file mode 100644 index 000000000000..8e3ef0347db7 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mei/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_IWLMEI) += iwlmei.o +iwlmei-y += main.o +iwlmei-y += net.o +iwlmei-$(CONFIG_IWLWIFI_DEVICE_TRACING) += trace.o +CFLAGS_trace.o := -I$(src) + +ccflags-y += -I $(srctree)/$(src)/../ diff --git a/drivers/net/wireless/intel/iwlwifi/mei/internal.h b/drivers/net/wireless/intel/iwlwifi/mei/internal.h new file mode 100644 index 000000000000..92fea7dd71e2 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mei/internal.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Intel Corporation + */ + +#ifndef __IWLMEI_INTERNAL_H_ +#define __IWLMEI_INTERNAL_H_ + +#include <uapi/linux/if_ether.h> +#include <linux/netdevice.h> + +#include "sap.h" + +rx_handler_result_t iwl_mei_rx_filter(struct sk_buff *skb, + const struct iwl_sap_oob_filters *filters, + bool *pass_to_csme); + +void iwl_mei_add_data_to_ring(struct sk_buff *skb, bool cb_tx); + +#endif /* __IWLMEI_INTERNAL_H_ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h b/drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h new file mode 100644 index 000000000000..67122cfa2292 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mei/iwl-mei.h @@ -0,0 +1,505 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Intel Corporation + */ + +#ifndef __iwl_mei_h__ +#define __iwl_mei_h__ + +#include <linux/if_ether.h> +#include <linux/skbuff.h> +#include <linux/ieee80211.h> + +/** + * DOC: Introduction + * + * iwlmei is the kernel module that is in charge of the commnunication between + * the iwlwifi driver and the CSME firmware's WLAN driver. This communication + * uses the SAP protocol defined in another file. + * iwlwifi can request or release ownership on the WiFi device through iwlmei. + * iwlmei may notify iwlwifi about certain events: what filter iwlwifi should + * use to passthrough inbound packets to the CSME firmware for example. iwlmei + * may also use iwlwifi to send traffic. This means that we need communication + * from iwlmei to iwlwifi and the other way around. + */ + +/** + * DOC: Life cycle + * + * iwlmei exports symbols that are needed by iwlwifi so that iwlmei will always + * be loaded when iwlwifi is alive. iwlwifi registers itself to iwlmei and + * provides the pointers to the functions that iwlmei calls whenever needed. + * iwlwifi calls iwlmei through direct and context-free function calls. + * It is assumed that only one device is accessible to the CSME firmware and + * under the scope of iwlmei so that it is valid not to have any context passed + * to iwlmei's functions. + * + * There are cases in which iwlmei can't access the CSME firmware, because the + * CSME firmware is undergoing a reset, or the mei bus decided to unbind the + * device. In those cases, iwlmei will need not to send requests over the mei + * bus. Instead, it needs to cache the requests from iwlwifi and fulfill them + * when the mei bus is available again. + * + * iwlmei can call iwlwifi as long as iwlwifi is registered to iwlmei. When + * iwlwifi goes down (the PCI device is unbound, or the iwlwifi is unloaded) + * iwlwifi needs to unregister from iwlmei. + */ + +/** + * DOC: Memory layout + * + * Since iwlwifi calls iwlmei without any context, iwlmei needs to hold a + * global pointer to its data (which is in the mei client device's private + * data area). If there was no bind on the mei bus, this pointer is NULL and + * iwlmei knows not access to the CSME firmware upon requests from iwlwifi. + * + * iwlmei needs to cache requests from iwlwifi when there is no mei client + * device available (when iwlmei has been removed from the mei bus). In this + * case, all iwlmei's data that resides in the mei client device's private data + * area is unavailable. For this specific case, a separate caching area is + * needed. + */ + +/** + * DOC: Concurrency + * + * iwlwifi can call iwlmei at any time. iwlmei will take care to synchronize + * the calls from iwlwifi with its internal flows. iwlwifi must not call iwlmei + * in flows that cannot sleep. Moreover, iwlwifi must not call iwlmei in flows + * that originated from iwlmei. + */ + +/** + * DOC: Probe and remove from mei bus driver + * + * When the mei bus driver enumerates its devices, it calls the iwlmei's probe + * function which will send the %SAP_ME_MSG_START message. The probe completes + * before the response (%SAP_ME_MSG_START_OK) is received. This response will + * be handle by the Rx path. Once it arrives, the connection to the CSME + * firmware is considered established and iwlwifi's requests can be treated + * against the CSME firmware. + * + * When the mei bus driver removes the device, iwlmei loses all the data that + * was attached to the mei client device. It clears the global pointer to the + * mei client device since it is not available anymore. This will cause all the + * requests coming from iwlwifi to be cached. This flow takes the global mutex + * to be synchronized with all the requests coming from iwlwifi. + */ + +/** + * DOC: Driver load when CSME owns the device + * + * When the driver (iwlwifi) is loaded while CSME owns the device, + * it'll ask CSME to release the device through HW registers. CSME + * will release the device only in the case that there is no connection + * through the mei bus. If there is a mei bus connection, CSME will refuse + * to release the ownership on the device through the HW registers. In that + * case, iwlwifi must first request ownership using the SAP protocol. + * + * Once iwlwifi will request ownership through the SAP protocol, CSME will + * grant the ownership on the device through the HW registers as well. + * In order to request ownership over SAP, we first need to have an interface + * which means that we need to register to mac80211. + * This can't happen before we get the NVM that contains all the capabilities + * of the device. Reading the NVM usually requires the load the firmware, but + * this is impossible as long as we don't have ownership on the device. + * In order to solve this chicken and egg problem, the host driver can get + * the NVM through CSME which owns the device. It can send + * %SAP_MSG_NOTIF_GET_NVM, which will be replied by %SAP_MSG_NOTIF_NVM with + * the NVM's content that the host driver needs. + */ + +/** + * DOC: CSME behavior regarding the ownership requests + * + * The ownership requests from the host can come in two different ways: + * - the HW registers in iwl_pcie_set_hw_ready + * - using the Software Arbitration Protocol (SAP) + * + * The host can ask CSME who owns the device with %SAP_MSG_NOTIF_WHO_OWNS_NIC, + * and it can request ownership with %SAP_MSG_NOTIF_HOST_ASKS_FOR_NIC_OWNERSHIP. + * The host will first use %SAP_MSG_NOTIF_WHO_OWNS_NIC to know what state + * CSME is in. In case CSME thinks it owns the device, the host can ask for + * ownership with %SAP_MSG_NOTIF_HOST_ASKS_FOR_NIC_OWNERSHIP. + * + * Here the table that describes CSME's behavior upon ownership request: + * + * +-------------------+------------+--------------+-----------------------------+------------+ + * | State | HW reg bit | Reply for | Event | HW reg bit | + * | | before | WHO_OWNS_NIC | | after | + * +===================+============+==============+=============================+============+ + * | WiAMT not | 0 | Host | HW register or | 0 | + * | operational | Host owner | | HOST_ASKS_FOR_NIC_OWNERSHIP | Host owner | + * +-------------------+------------+--------------+-----------------------------+------------+ + * | Operational & | 1 | N/A | HW register | 0 | + * | SAP down & | CSME owner | | | Host owner | + * | no session active | | | | | + * +-------------------+------------+--------------+-----------------------------+------------+ + * | Operational & | 1 | CSME | HW register | 1 | + * | SAP up | CSME owner | | | CSME owner | + * +-------------------+------------+--------------+-----------------------------+------------+ + * | Operational & | 1 | CSME | HOST_ASKS_FOR_NIC_OWNERSHIP | 0 | + * | SAP up | CSME owner | | | Host owner | + * +-------------------+------------+--------------+-----------------------------+------------+ + */ + +/** + * DOC: Driver load when CSME is associated and a session is active + * + * A "session" is active when CSME is associated to an access point and the + * link is used to attach a remote driver or to control the system remotely. + * When a session is active, we want to make sure it won't disconnect when we + * take ownership on the device. + * In this case, the driver can get the device, but it'll need to make + * sure that it'll connect to the exact same AP (same BSSID). + * In order to do so, CSME will send the connection parameters through + * SAP and then the host can check if it can connect to this same AP. + * If yes, it can request ownership through SAP and connect quickly without + * scanning all the channels, but just probing the AP on the channel that + * CSME was connected to. + * In order to signal this specific scenario to iwlwifi, iwlmei will + * immediately require iwlwifi to report RF-Kill to the network stack. This + * RF-Kill will prevent the stack from getting the device, and it has a reason + * that tells the userspace that the device is in RF-Kill because it is not + * owned by the host. Once the userspace has configured the right profile, + * it'll be able to let iwlmei know that it can request ownership over SAP + * which will remove the RF-Kill, and finally allow the host to connect. + * The host has then 3 seconds to connect (including DHCP). Had the host + * failed to connect within those 3 seconds, CSME will take the device back. + */ + +/** + * DOC: Datapath + * + * CSME can transmit packets, through the netdev that it gets from the wifi + * driver. It'll send packet in the 802.3 format and simply call + * dev_queue_xmit. + * + * For Rx, iwlmei registers a Rx handler that it attaches to the netdev. iwlmei + * may catch packets and send them to CSME, it can then either drop them so + * that they are invisible to user space, or let them go the user space. + * + * Packets transmitted by the user space do not need to be forwarded to CSME + * with the exception of the DHCP request. In order to know what IP is used + * by the user space, CSME needs to get the DHCP request. See + * iwl_mei_tx_copy_to_csme(). + */ + +/** + * enum iwl_mei_nvm_caps - capabilities for MEI NVM + * @MEI_NVM_CAPS_LARI_SUPPORT: Lari is supported + * @MEI_NVM_CAPS_11AX_SUPPORT: 11AX is supported + */ +enum iwl_mei_nvm_caps { + MEI_NVM_CAPS_LARI_SUPPORT = BIT(0), + MEI_NVM_CAPS_11AX_SUPPORT = BIT(1), +}; + +/** + * struct iwl_mei_nvm - used to pass the NVM from CSME + * @hw_addr: The MAC address + * @n_hw_addrs: The number of MAC addresses + * @reserved: For alignment. + * @radio_cfg: The radio configuration. + * @caps: See &enum iwl_mei_nvm_caps. + * @nvm_version: The version of the NVM. + * @channels: The data for each channel. + * + * If a field is added, it must correspond to the SAP structure. + */ +struct iwl_mei_nvm { + u8 hw_addr[ETH_ALEN]; + u8 n_hw_addrs; + u8 reserved; + u32 radio_cfg; + u32 caps; + u32 nvm_version; + u32 channels[110]; +}; + +/** + * enum iwl_mei_pairwise_cipher - cipher for UCAST key + * @IWL_MEI_CIPHER_NONE: none + * @IWL_MEI_CIPHER_CCMP: ccmp + * @IWL_MEI_CIPHER_GCMP: gcmp + * @IWL_MEI_CIPHER_GCMP_256: gcmp 256 + * + * Note that those values are dictated by the CSME firmware API (see sap.h) + */ +enum iwl_mei_pairwise_cipher { + IWL_MEI_CIPHER_NONE = 0, + IWL_MEI_CIPHER_CCMP = 4, + IWL_MEI_CIPHER_GCMP = 8, + IWL_MEI_CIPHER_GCMP_256 = 9, +}; + +/** + * enum iwl_mei_akm_auth - a combination of AKM and AUTH method + * @IWL_MEI_AKM_AUTH_OPEN: No encryption + * @IWL_MEI_AKM_AUTH_RSNA: 1X profile + * @IWL_MEI_AKM_AUTH_RSNA_PSK: PSK profile + * @IWL_MEI_AKM_AUTH_SAE: SAE profile + * + * Note that those values are dictated by the CSME firmware API (see sap.h) + */ +enum iwl_mei_akm_auth { + IWL_MEI_AKM_AUTH_OPEN = 0, + IWL_MEI_AKM_AUTH_RSNA = 6, + IWL_MEI_AKM_AUTH_RSNA_PSK = 7, + IWL_MEI_AKM_AUTH_SAE = 9, +}; + +/** + * struct iwl_mei_conn_info - connection info + * @lp_state: link protection state + * @auth_mode: authentication mode + * @ssid_len: the length of SSID + * @ssid: the SSID + * @pairwise_cipher: the cipher used for unicast packets + * @channel: the associated channel + * @band: the associated band + * @bssid: the BSSID + */ +struct iwl_mei_conn_info { + u8 lp_state; + u8 auth_mode; + u8 ssid_len; + u8 channel; + u8 band; + u8 pairwise_cipher; + u8 bssid[ETH_ALEN]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; +}; + +/** + * struct iwl_mei_colloc_info - collocated AP info + * @channel: the channel of the collocated AP + * @bssid: the BSSID of the collocated AP + */ +struct iwl_mei_colloc_info { + u8 channel; + u8 bssid[ETH_ALEN]; +}; + +/* + * struct iwl_mei_ops - driver's operations called by iwlmei + * Operations will not be called more than once concurrently. + * It's not allowed to call iwlmei functions from this context. + * + * @me_conn_status: provide information about CSME's current connection. + * @rfkill: called when the wifi driver should report a change in the rfkill + * status. + * @roaming_forbidden: indicates whether roaming is forbidden. + * @sap_connected: indicate that SAP is now connected. Will be called in case + * the wifi driver registered to iwlmei before SAP connection succeeded or + * when the SAP connection is re-established. + * @nic_stolen: this means that device is no longer available. The device can + * still be used until the callback returns. + */ +struct iwl_mei_ops { + void (*me_conn_status)(void *priv, + const struct iwl_mei_conn_info *conn_info); + void (*rfkill)(void *priv, bool blocked); + void (*roaming_forbidden)(void *priv, bool forbidden); + void (*sap_connected)(void *priv); + void (*nic_stolen)(void *priv); +}; + +#if IS_ENABLED(CONFIG_IWLMEI) + +/** + * iwl_mei_is_connected() - is the connection to the CSME firmware established? + * + * Return: true if we have a SAP connection + */ +bool iwl_mei_is_connected(void); + +/** + * iwl_mei_get_nvm() - returns the NVM for the device + * + * It is the caller's responsibility to free the memory returned + * by this function. + * This function blocks (sleeps) until the NVM is ready. + * + * Return: the NVM as received from CSME + */ +struct iwl_mei_nvm *iwl_mei_get_nvm(void); + +/** + * iwl_mei_get_ownership() - request ownership + * + * This function blocks until ownership is granted or timeout expired. + * + * Return: 0 in case we could get ownership on the device + */ +int iwl_mei_get_ownership(void); + +/** + * iwl_mei_set_rfkill_state() - set SW and HW RF kill states + * @hw_rfkill: HW RF kill state. + * @sw_rfkill: SW RF kill state. + * + * This function must be called when SW RF kill is issued by the user. + */ +void iwl_mei_set_rfkill_state(bool hw_rfkill, bool sw_rfkill); + +/** + * iwl_mei_set_nic_info() - set mac address + * @mac_address: mac address to set + * @nvm_address: NVM mac adsress to set + * + * This function must be called upon mac address change. + */ +void iwl_mei_set_nic_info(const u8 *mac_address, const u8 *nvm_address); + +/** + * iwl_mei_set_country_code() - set new country code + * @mcc: the new applied MCC + * + * This function must be called upon country code update + */ +void iwl_mei_set_country_code(u16 mcc); + +/** + * iwl_mei_set_power_limit() - set TX power limit + * @power_limit: pointer to an array of 10 elements (le16) represents the power + * restrictions per chain. + * + * This function must be called upon power restrictions change + */ +void iwl_mei_set_power_limit(const __le16 *power_limit); + +/** + * iwl_mei_register() - register the wifi driver to iwlmei + * @priv: a pointer to the wifi driver's context. Cannot be NULL. + * @ops: the ops structure. + * + * Return: 0 unless something went wrong. It is illegal to call any + * other API function before this function is called and succeeds. + * + * Only one wifi driver instance (wifi device instance really) + * can register at a time. + */ +int iwl_mei_register(void *priv, const struct iwl_mei_ops *ops); + +/** + * iwl_mei_start_unregister() - unregister the wifi driver from iwlmei + * + * From this point on, iwlmei will not used the callbacks provided by + * the driver, but the device is still usable. + */ +void iwl_mei_start_unregister(void); + +/** + * iwl_mei_unregister_complete() - complete the unregistration + * + * Must be called after iwl_mei_start_unregister. When this function returns, + * the device is owned by CSME. + */ +void iwl_mei_unregister_complete(void); + +/** + * iwl_mei_set_netdev() - sets the netdev for Tx / Rx. + * @netdev: the net_device + * + * The caller should set the netdev to a non-NULL value when the + * interface is added. Packets might be sent to the driver immediately + * afterwards. + * The caller should set the netdev to NULL when the interface is removed. + * This function will call synchronize_net() after setting the netdev to NULL. + * Only when this function returns, can the caller assume that iwlmei will + * no longer inject packets into the netdev's Tx path. + * + * Context: This function can sleep and assumes rtnl_lock is taken. + * The netdev must be set to NULL before iwl_mei_start_unregister() is called. + */ +void iwl_mei_set_netdev(struct net_device *netdev); + +/** + * iwl_mei_tx_copy_to_csme() - must be called for each packet sent by + * the wifi driver. + * @skb: the skb sent + * @ivlen: the size of the IV that needs to be skipped after the MAC and + * before the SNAP header. + * + * This function doesn't take any lock, it simply tries to catch DHCP + * packets sent by the wifi driver. If the packet is a DHCP packet, it + * will send it to CSME. This function must not be called for virtual + * interfaces that are not monitored by CSME, meaning it must be called + * only for packets transmitted by the netdevice that was registered + * with iwl_mei_set_netdev(). + */ +void iwl_mei_tx_copy_to_csme(struct sk_buff *skb, unsigned int ivlen); + +/** + * iwl_mei_host_associated() - must be called when iwlwifi associated. + * @conn_info: pointer to the connection info structure. + * @colloc_info: pointer to the collocated AP info. This is relevant only in + * case of UHB associated AP, otherwise set to NULL. + */ +void iwl_mei_host_associated(const struct iwl_mei_conn_info *conn_info, + const struct iwl_mei_colloc_info *colloc_info); + +/** + * iwl_mei_host_disassociated() - must be called when iwlwifi disassociated. + */ +void iwl_mei_host_disassociated(void); + +/** + * iwl_mei_device_down() - must be called when the device is down + */ +void iwl_mei_device_down(void); + +#else + +static inline bool iwl_mei_is_connected(void) +{ return false; } + +static inline struct iwl_mei_nvm *iwl_mei_get_nvm(void) +{ return NULL; } + +static inline int iwl_mei_get_ownership(void) +{ return 0; } + +static inline void iwl_mei_set_rfkill_state(bool hw_rfkill, bool sw_rfkill) +{} + +static inline void iwl_mei_set_nic_info(const u8 *mac_address, const u8 *nvm_address) +{} + +static inline void iwl_mei_set_country_code(u16 mcc) +{} + +static inline void iwl_mei_set_power_limit(__le16 *power_limit) +{} + +static inline int iwl_mei_register(void *priv, + const struct iwl_mei_ops *ops) +{ return 0; } + +static inline void iwl_mei_start_unregister(void) +{} + +static inline void iwl_mei_unregister_complete(void) +{} + +static inline void iwl_mei_set_netdev(struct net_device *netdev) +{} + +static inline void iwl_mei_tx_copy_to_csme(struct sk_buff *skb, + unsigned int ivlen) +{} + +static inline void iwl_mei_host_associated(const struct iwl_mei_conn_info *conn_info, + const struct iwl_mei_colloc_info *colloc_info) +{} + +static inline void iwl_mei_host_disassociated(void) +{} + +static inline void iwl_mei_device_down(void) +{} + +#endif /* CONFIG_IWLMEI */ + +#endif /* __iwl_mei_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mei/main.c b/drivers/net/wireless/intel/iwlwifi/mei/main.c new file mode 100644 index 000000000000..4453cd2571c2 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mei/main.c @@ -0,0 +1,1992 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Intel Corporation + */ + +#include <linux/etherdevice.h> +#include <linux/netdevice.h> +#include <linux/ieee80211.h> +#include <linux/rtnetlink.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/mei_cl_bus.h> +#include <linux/rcupdate.h> +#include <linux/debugfs.h> +#include <linux/skbuff.h> +#include <linux/wait.h> +#include <linux/slab.h> +#include <linux/mm.h> + +#include <net/cfg80211.h> + +#include "internal.h" +#include "iwl-mei.h" +#include "trace.h" +#include "trace-data.h" +#include "sap.h" + +MODULE_DESCRIPTION("The Intel(R) wireless / CSME firmware interface"); +MODULE_LICENSE("GPL"); + +#define MEI_WLAN_UUID UUID_LE(0x13280904, 0x7792, 0x4fcb, \ + 0xa1, 0xaa, 0x5e, 0x70, 0xcb, 0xb1, 0xe8, 0x65) + +/* + * Since iwlwifi calls iwlmei without any context, hold a pointer to the + * mei_cl_device structure here. + * Define a mutex that will synchronize all the flows between iwlwifi and + * iwlmei. + * Note that iwlmei can't have several instances, so it ok to have static + * variables here. + */ +static struct mei_cl_device *iwl_mei_global_cldev; +static DEFINE_MUTEX(iwl_mei_mutex); +static unsigned long iwl_mei_status; + +enum iwl_mei_status_bits { + IWL_MEI_STATUS_SAP_CONNECTED, +}; + +bool iwl_mei_is_connected(void) +{ + return test_bit(IWL_MEI_STATUS_SAP_CONNECTED, &iwl_mei_status); +} +EXPORT_SYMBOL_GPL(iwl_mei_is_connected); + +#define SAP_VERSION 3 +#define SAP_CONTROL_BLOCK_ID 0x21504153 /* SAP! in ASCII */ + +struct iwl_sap_q_ctrl_blk { + __le32 wr_ptr; + __le32 rd_ptr; + __le32 size; +}; + +enum iwl_sap_q_idx { + SAP_QUEUE_IDX_NOTIF = 0, + SAP_QUEUE_IDX_DATA, + SAP_QUEUE_IDX_MAX, +}; + +struct iwl_sap_dir { + __le32 reserved; + struct iwl_sap_q_ctrl_blk q_ctrl_blk[SAP_QUEUE_IDX_MAX]; +}; + +enum iwl_sap_dir_idx { + SAP_DIRECTION_HOST_TO_ME = 0, + SAP_DIRECTION_ME_TO_HOST, + SAP_DIRECTION_MAX, +}; + +struct iwl_sap_shared_mem_ctrl_blk { + __le32 sap_id; + __le32 size; + struct iwl_sap_dir dir[SAP_DIRECTION_MAX]; +}; + +/* + * The shared area has the following layout: + * + * +-----------------------------------+ + * |struct iwl_sap_shared_mem_ctrl_blk | + * +-----------------------------------+ + * |Host -> ME data queue | + * +-----------------------------------+ + * |Host -> ME notif queue | + * +-----------------------------------+ + * |ME -> Host data queue | + * +-----------------------------------+ + * |ME -> host notif queue | + * +-----------------------------------+ + * |SAP control block id (SAP!) | + * +-----------------------------------+ + */ + +#define SAP_H2M_DATA_Q_SZ 48256 +#define SAP_M2H_DATA_Q_SZ 24128 +#define SAP_H2M_NOTIF_Q_SZ 2240 +#define SAP_M2H_NOTIF_Q_SZ 62720 + +#define _IWL_MEI_SAP_SHARED_MEM_SZ \ + (sizeof(struct iwl_sap_shared_mem_ctrl_blk) + \ + SAP_H2M_DATA_Q_SZ + SAP_H2M_NOTIF_Q_SZ + \ + SAP_M2H_DATA_Q_SZ + SAP_M2H_NOTIF_Q_SZ + 4) + +#define IWL_MEI_SAP_SHARED_MEM_SZ \ + (roundup(_IWL_MEI_SAP_SHARED_MEM_SZ, PAGE_SIZE)) + +struct iwl_mei_shared_mem_ptrs { + struct iwl_sap_shared_mem_ctrl_blk *ctrl; + void *q_head[SAP_DIRECTION_MAX][SAP_QUEUE_IDX_MAX]; + size_t q_size[SAP_DIRECTION_MAX][SAP_QUEUE_IDX_MAX]; +}; + +struct iwl_mei_filters { + struct rcu_head rcu_head; + struct iwl_sap_oob_filters filters; +}; + +/** + * struct iwl_mei - holds the private date for iwl_mei + * + * @get_nvm_wq: the wait queue for the get_nvm flow + * @send_csa_msg_wk: used to defer the transmission of the CHECK_SHARED_AREA + * message. Used so that we can send CHECK_SHARED_AREA from atomic + * contexts. + * @get_ownership_wq: the wait queue for the get_ownership_flow + * @shared_mem: the memory that is shared between CSME and the host + * @cldev: the pointer to the MEI client device + * @nvm: the data returned by the CSME for the NVM + * @filters: the filters sent by CSME + * @got_ownership: true if we own the device + * @amt_enabled: true if CSME has wireless enabled + * @csa_throttled: when true, we can't send CHECK_SHARED_AREA over the MEI + * bus, but rather need to wait until send_csa_msg_wk runs + * @csme_taking_ownership: true when CSME is taking ownership. Used to remember + * to send CSME_OWNERSHIP_CONFIRMED when the driver completes its down + * flow. + * @csa_throttle_end_wk: used when &csa_throttled is true + * @data_q_lock: protects the access to the data queues which are + * accessed without the mutex. + * @sap_seq_no: the sequence number for the SAP messages + * @seq_no: the sequence number for the SAP messages + * @dbgfs_dir: the debugfs dir entry + */ +struct iwl_mei { + wait_queue_head_t get_nvm_wq; + struct work_struct send_csa_msg_wk; + wait_queue_head_t get_ownership_wq; + struct iwl_mei_shared_mem_ptrs shared_mem; + struct mei_cl_device *cldev; + struct iwl_mei_nvm *nvm; + struct iwl_mei_filters __rcu *filters; + bool got_ownership; + bool amt_enabled; + bool csa_throttled; + bool csme_taking_ownership; + struct delayed_work csa_throttle_end_wk; + spinlock_t data_q_lock; + + atomic_t sap_seq_no; + atomic_t seq_no; + + struct dentry *dbgfs_dir; +}; + +/** + * iwl_mei_cache - cache for the parameters from iwlwifi + * @ops: Callbacks to iwlwifi. + * @netdev: The netdev that will be used to transmit / receive packets. + * @conn_info: The connection info message triggered by iwlwifi's association. + * @power_limit: pointer to an array of 10 elements (le16) represents the power + * restrictions per chain. + * @rf_kill: rf kill state. + * @mcc: MCC info + * @mac_address: interface MAC address. + * @nvm_address: NVM MAC address. + * @priv: A pointer to iwlwifi. + * + * This used to cache the configurations coming from iwlwifi's way. The data + * is cached here so that we can buffer the configuration even if we don't have + * a bind from the mei bus and hence, on iwl_mei structure. + */ +static struct { + const struct iwl_mei_ops *ops; + struct net_device __rcu *netdev; + const struct iwl_sap_notif_connection_info *conn_info; + const __le16 *power_limit; + u32 rf_kill; + u16 mcc; + u8 mac_address[6]; + u8 nvm_address[6]; + void *priv; +} iwl_mei_cache = { + .rf_kill = SAP_HW_RFKILL_DEASSERTED | SAP_SW_RFKILL_DEASSERTED +}; + +static void iwl_mei_free_shared_mem(struct mei_cl_device *cldev) +{ + struct iwl_mei *mei = mei_cldev_get_drvdata(cldev); + + if (mei_cldev_dma_unmap(cldev)) + dev_err(&cldev->dev, "Couldn't unmap the shared mem properly\n"); + memset(&mei->shared_mem, 0, sizeof(mei->shared_mem)); +} + +#define HBM_DMA_BUF_ID_WLAN 1 + +static int iwl_mei_alloc_shared_mem(struct mei_cl_device *cldev) +{ + struct iwl_mei *mei = mei_cldev_get_drvdata(cldev); + struct iwl_mei_shared_mem_ptrs *mem = &mei->shared_mem; + + mem->ctrl = mei_cldev_dma_map(cldev, HBM_DMA_BUF_ID_WLAN, + IWL_MEI_SAP_SHARED_MEM_SZ); + + if (IS_ERR(mem->ctrl)) { + int ret = PTR_ERR(mem->ctrl); + + dev_err(&cldev->dev, "Couldn't allocate the shared memory: %d\n", + ret); + mem->ctrl = NULL; + + return ret; + } + + memset(mem->ctrl, 0, IWL_MEI_SAP_SHARED_MEM_SZ); + + return 0; +} + +static void iwl_mei_init_shared_mem(struct iwl_mei *mei) +{ + struct iwl_mei_shared_mem_ptrs *mem = &mei->shared_mem; + struct iwl_sap_dir *h2m; + struct iwl_sap_dir *m2h; + int dir, queue; + u8 *q_head; + + mem->ctrl->sap_id = cpu_to_le32(SAP_CONTROL_BLOCK_ID); + + mem->ctrl->size = cpu_to_le32(sizeof(*mem->ctrl)); + + h2m = &mem->ctrl->dir[SAP_DIRECTION_HOST_TO_ME]; + m2h = &mem->ctrl->dir[SAP_DIRECTION_ME_TO_HOST]; + + h2m->q_ctrl_blk[SAP_QUEUE_IDX_DATA].size = + cpu_to_le32(SAP_H2M_DATA_Q_SZ); + h2m->q_ctrl_blk[SAP_QUEUE_IDX_NOTIF].size = + cpu_to_le32(SAP_H2M_NOTIF_Q_SZ); + m2h->q_ctrl_blk[SAP_QUEUE_IDX_DATA].size = + cpu_to_le32(SAP_M2H_DATA_Q_SZ); + m2h->q_ctrl_blk[SAP_QUEUE_IDX_NOTIF].size = + cpu_to_le32(SAP_M2H_NOTIF_Q_SZ); + + /* q_head points to the start of the first queue */ + q_head = (void *)(mem->ctrl + 1); + + /* Initialize the queue heads */ + for (dir = 0; dir < SAP_DIRECTION_MAX; dir++) { + for (queue = 0; queue < SAP_QUEUE_IDX_MAX; queue++) { + mem->q_head[dir][queue] = q_head; + q_head += + le32_to_cpu(mem->ctrl->dir[dir].q_ctrl_blk[queue].size); + mem->q_size[dir][queue] = + le32_to_cpu(mem->ctrl->dir[dir].q_ctrl_blk[queue].size); + } + } + + *(__le32 *)q_head = cpu_to_le32(SAP_CONTROL_BLOCK_ID); +} + +static ssize_t iwl_mei_write_cyclic_buf(struct mei_cl_device *cldev, + struct iwl_sap_q_ctrl_blk *notif_q, + u8 *q_head, + const struct iwl_sap_hdr *hdr, + u32 q_sz) +{ + u32 rd = le32_to_cpu(READ_ONCE(notif_q->rd_ptr)); + u32 wr = le32_to_cpu(READ_ONCE(notif_q->wr_ptr)); + size_t room_in_buf; + size_t tx_sz = sizeof(*hdr) + le16_to_cpu(hdr->len); + + if (rd > q_sz || wr > q_sz) { + dev_err(&cldev->dev, + "Pointers are past the end of the buffer\n"); + return -EINVAL; + } + + room_in_buf = wr >= rd ? q_sz - wr + rd : rd - wr; + + /* we don't have enough room for the data to write */ + if (room_in_buf < tx_sz) { + dev_err(&cldev->dev, + "Not enough room in the buffer\n"); + return -ENOSPC; + } + + if (wr + tx_sz <= q_sz) { + memcpy(q_head + wr, hdr, tx_sz); + } else { + memcpy(q_head + wr, hdr, q_sz - wr); + memcpy(q_head, (u8 *)hdr + q_sz - wr, tx_sz - (q_sz - wr)); + } + + WRITE_ONCE(notif_q->wr_ptr, cpu_to_le32((wr + tx_sz) % q_sz)); + return 0; +} + +static bool iwl_mei_host_to_me_data_pending(const struct iwl_mei *mei) +{ + struct iwl_sap_q_ctrl_blk *notif_q; + struct iwl_sap_dir *dir; + + dir = &mei->shared_mem.ctrl->dir[SAP_DIRECTION_HOST_TO_ME]; + notif_q = &dir->q_ctrl_blk[SAP_QUEUE_IDX_DATA]; + + if (READ_ONCE(notif_q->wr_ptr) != READ_ONCE(notif_q->rd_ptr)) + return true; + + notif_q = &dir->q_ctrl_blk[SAP_QUEUE_IDX_NOTIF]; + return READ_ONCE(notif_q->wr_ptr) != READ_ONCE(notif_q->rd_ptr); +} + +static int iwl_mei_send_check_shared_area(struct mei_cl_device *cldev) +{ + struct iwl_mei *mei = mei_cldev_get_drvdata(cldev); + struct iwl_sap_me_msg_start msg = { + .hdr.type = cpu_to_le32(SAP_ME_MSG_CHECK_SHARED_AREA), + .hdr.seq_num = cpu_to_le32(atomic_inc_return(&mei->seq_no)), + }; + int ret; + + lockdep_assert_held(&iwl_mei_mutex); + + if (mei->csa_throttled) + return 0; + + trace_iwlmei_me_msg(&msg.hdr, true); + ret = mei_cldev_send(cldev, (void *)&msg, sizeof(msg)); + if (ret != sizeof(msg)) { + dev_err(&cldev->dev, + "failed to send the SAP_ME_MSG_CHECK_SHARED_AREA message %d\n", + ret); + return ret; + } + + mei->csa_throttled = true; + + schedule_delayed_work(&mei->csa_throttle_end_wk, + msecs_to_jiffies(100)); + + return 0; +} + +static void iwl_mei_csa_throttle_end_wk(struct work_struct *wk) +{ + struct iwl_mei *mei = + container_of(wk, struct iwl_mei, csa_throttle_end_wk.work); + + mutex_lock(&iwl_mei_mutex); + + mei->csa_throttled = false; + + if (iwl_mei_host_to_me_data_pending(mei)) + iwl_mei_send_check_shared_area(mei->cldev); + + mutex_unlock(&iwl_mei_mutex); +} + +static int iwl_mei_send_sap_msg_payload(struct mei_cl_device *cldev, + struct iwl_sap_hdr *hdr) +{ + struct iwl_mei *mei = mei_cldev_get_drvdata(cldev); + struct iwl_sap_q_ctrl_blk *notif_q; + struct iwl_sap_dir *dir; + void *q_head; + u32 q_sz; + int ret; + + lockdep_assert_held(&iwl_mei_mutex); + + if (!mei->shared_mem.ctrl) { + dev_err(&cldev->dev, + "No shared memory, can't send any SAP message\n"); + return -EINVAL; + } + + if (!iwl_mei_is_connected()) { + dev_err(&cldev->dev, + "Can't send a SAP message if we're not connected\n"); + return -ENODEV; + } + + hdr->seq_num = cpu_to_le32(atomic_inc_return(&mei->sap_seq_no)); + dev_dbg(&cldev->dev, "Sending %d\n", hdr->type); + + dir = &mei->shared_mem.ctrl->dir[SAP_DIRECTION_HOST_TO_ME]; + notif_q = &dir->q_ctrl_blk[SAP_QUEUE_IDX_NOTIF]; + q_head = mei->shared_mem.q_head[SAP_DIRECTION_HOST_TO_ME][SAP_QUEUE_IDX_NOTIF]; + q_sz = mei->shared_mem.q_size[SAP_DIRECTION_HOST_TO_ME][SAP_QUEUE_IDX_NOTIF]; + ret = iwl_mei_write_cyclic_buf(q_head, notif_q, q_head, hdr, q_sz); + + if (ret < 0) + return ret; + + trace_iwlmei_sap_cmd(hdr, true); + + return iwl_mei_send_check_shared_area(cldev); +} + +void iwl_mei_add_data_to_ring(struct sk_buff *skb, bool cb_tx) +{ + struct iwl_sap_q_ctrl_blk *notif_q; + struct iwl_sap_dir *dir; + struct iwl_mei *mei; + size_t room_in_buf; + size_t tx_sz; + size_t hdr_sz; + u32 q_sz; + u32 rd; + u32 wr; + void *q_head; + + if (!iwl_mei_global_cldev) + return; + + mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); + + /* + * We access this path for Rx packets (the more common case) + * and from Tx path when we send DHCP packets, the latter is + * very unlikely. + * Take the lock already here to make sure we see that remove() + * might have cleared the IWL_MEI_STATUS_SAP_CONNECTED bit. + */ + spin_lock_bh(&mei->data_q_lock); + + if (!iwl_mei_is_connected()) { + spin_unlock_bh(&mei->data_q_lock); + return; + } + + /* + * We are in a RCU critical section and the remove from the CSME bus + * which would free this memory waits for the readers to complete (this + * is done in netdev_rx_handler_unregister). + */ + dir = &mei->shared_mem.ctrl->dir[SAP_DIRECTION_HOST_TO_ME]; + notif_q = &dir->q_ctrl_blk[SAP_QUEUE_IDX_DATA]; + q_head = mei->shared_mem.q_head[SAP_DIRECTION_HOST_TO_ME][SAP_QUEUE_IDX_DATA]; + q_sz = mei->shared_mem.q_size[SAP_DIRECTION_HOST_TO_ME][SAP_QUEUE_IDX_DATA]; + + rd = le32_to_cpu(READ_ONCE(notif_q->rd_ptr)); + wr = le32_to_cpu(READ_ONCE(notif_q->wr_ptr)); + hdr_sz = cb_tx ? sizeof(struct iwl_sap_cb_data) : + sizeof(struct iwl_sap_hdr); + tx_sz = skb->len + hdr_sz; + + if (rd > q_sz || wr > q_sz) { + dev_err(&mei->cldev->dev, + "can't write the data: pointers are past the end of the buffer\n"); + goto out; + } + + room_in_buf = wr >= rd ? q_sz - wr + rd : rd - wr; + + /* we don't have enough room for the data to write */ + if (room_in_buf < tx_sz) { + dev_err(&mei->cldev->dev, + "Not enough room in the buffer for this data\n"); + goto out; + } + + if (skb_headroom(skb) < hdr_sz) { + dev_err(&mei->cldev->dev, + "Not enough headroom in the skb to write the SAP header\n"); + goto out; + } + + if (cb_tx) { + struct iwl_sap_cb_data *cb_hdr = skb_push(skb, sizeof(*cb_hdr)); + + cb_hdr->hdr.type = cpu_to_le16(SAP_MSG_CB_DATA_PACKET); + cb_hdr->hdr.len = cpu_to_le16(skb->len - sizeof(cb_hdr->hdr)); + cb_hdr->hdr.seq_num = cpu_to_le32(atomic_inc_return(&mei->sap_seq_no)); + cb_hdr->to_me_filt_status = cpu_to_le32(BIT(CB_TX_DHCP_FILT_IDX)); + cb_hdr->data_len = cpu_to_le32(skb->len - sizeof(*cb_hdr)); + trace_iwlmei_sap_data(skb, IWL_SAP_TX_DHCP); + } else { + struct iwl_sap_hdr *hdr = skb_push(skb, sizeof(*hdr)); + + hdr->type = cpu_to_le16(SAP_MSG_DATA_PACKET); + hdr->len = cpu_to_le16(skb->len - sizeof(*hdr)); + hdr->seq_num = cpu_to_le32(atomic_inc_return(&mei->sap_seq_no)); + trace_iwlmei_sap_data(skb, IWL_SAP_TX_DATA_FROM_AIR); + } + + if (wr + tx_sz <= q_sz) { + skb_copy_bits(skb, 0, q_head + wr, tx_sz); + } else { + skb_copy_bits(skb, 0, q_head + wr, q_sz - wr); + skb_copy_bits(skb, q_sz - wr, q_head, tx_sz - (q_sz - wr)); + } + + WRITE_ONCE(notif_q->wr_ptr, cpu_to_le32((wr + tx_sz) % q_sz)); + +out: + spin_unlock_bh(&mei->data_q_lock); +} + +static int +iwl_mei_send_sap_msg(struct mei_cl_device *cldev, u16 type) +{ + struct iwl_sap_hdr msg = { + .type = cpu_to_le16(type), + }; + + return iwl_mei_send_sap_msg_payload(cldev, &msg); +} + +static void iwl_mei_send_csa_msg_wk(struct work_struct *wk) +{ + struct iwl_mei *mei = + container_of(wk, struct iwl_mei, send_csa_msg_wk); + + if (!iwl_mei_is_connected()) + return; + + mutex_lock(&iwl_mei_mutex); + + iwl_mei_send_check_shared_area(mei->cldev); + + mutex_unlock(&iwl_mei_mutex); +} + +/* Called in a RCU read critical section from netif_receive_skb */ +static rx_handler_result_t iwl_mei_rx_handler(struct sk_buff **pskb) +{ + struct sk_buff *skb = *pskb; + struct iwl_mei *mei = + rcu_dereference(skb->dev->rx_handler_data); + struct iwl_mei_filters *filters = rcu_dereference(mei->filters); + bool rx_for_csme = false; + rx_handler_result_t res; + + /* + * remove() unregisters this handler and synchronize_net, so this + * should never happen. + */ + if (!iwl_mei_is_connected()) { + dev_err(&mei->cldev->dev, + "Got an Rx packet, but we're not connected to SAP?\n"); + return RX_HANDLER_PASS; + } + + if (filters) + res = iwl_mei_rx_filter(skb, &filters->filters, &rx_for_csme); + else + res = RX_HANDLER_PASS; + + /* + * The data is already on the ring of the shared area, all we + * need to do is to tell the CSME firmware to check what we have + * there. + */ + if (rx_for_csme) + schedule_work(&mei->send_csa_msg_wk); + + if (res != RX_HANDLER_PASS) { + trace_iwlmei_sap_data(skb, IWL_SAP_RX_DATA_DROPPED_FROM_AIR); + dev_kfree_skb(skb); + } + + return res; +} + +static void +iwl_mei_handle_rx_start_ok(struct mei_cl_device *cldev, + const struct iwl_sap_me_msg_start_ok *rsp, + ssize_t len) +{ + struct iwl_mei *mei = mei_cldev_get_drvdata(cldev); + + if (len != sizeof(*rsp)) { + dev_err(&cldev->dev, + "got invalid SAP_ME_MSG_START_OK from CSME firmware\n"); + dev_err(&cldev->dev, + "size is incorrect: %zd instead of %zu\n", + len, sizeof(*rsp)); + return; + } + + if (rsp->supported_version != SAP_VERSION) { + dev_err(&cldev->dev, + "didn't get the expected version: got %d\n", + rsp->supported_version); + return; + } + + mutex_lock(&iwl_mei_mutex); + set_bit(IWL_MEI_STATUS_SAP_CONNECTED, &iwl_mei_status); + /* wifi driver has registered already */ + if (iwl_mei_cache.ops) { + iwl_mei_send_sap_msg(mei->cldev, + SAP_MSG_NOTIF_WIFIDR_UP); + iwl_mei_cache.ops->sap_connected(iwl_mei_cache.priv); + } + + mutex_unlock(&iwl_mei_mutex); +} + +static void iwl_mei_handle_csme_filters(struct mei_cl_device *cldev, + const struct iwl_sap_csme_filters *filters) +{ + struct iwl_mei *mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); + struct iwl_mei_filters *new_filters; + struct iwl_mei_filters *old_filters; + + old_filters = + rcu_dereference_protected(mei->filters, + lockdep_is_held(&iwl_mei_mutex)); + + new_filters = kzalloc(sizeof(*new_filters), GFP_KERNEL); + if (!new_filters) + return; + + /* Copy the OOB filters */ + new_filters->filters = filters->filters; + + rcu_assign_pointer(mei->filters, new_filters); + + if (old_filters) + kfree_rcu(old_filters, rcu_head); +} + +static void +iwl_mei_handle_conn_status(struct mei_cl_device *cldev, + const struct iwl_sap_notif_conn_status *status) +{ + struct iwl_mei *mei = mei_cldev_get_drvdata(cldev); + struct iwl_mei_conn_info conn_info = { + .lp_state = le32_to_cpu(status->link_prot_state), + .ssid_len = le32_to_cpu(status->conn_info.ssid_len), + .channel = status->conn_info.channel, + .band = status->conn_info.band, + .auth_mode = le32_to_cpu(status->conn_info.auth_mode), + .pairwise_cipher = le32_to_cpu(status->conn_info.pairwise_cipher), + }; + + if (!iwl_mei_cache.ops || + conn_info.ssid_len > ARRAY_SIZE(conn_info.ssid)) + return; + + memcpy(conn_info.ssid, status->conn_info.ssid, conn_info.ssid_len); + ether_addr_copy(conn_info.bssid, status->conn_info.bssid); + + iwl_mei_cache.ops->me_conn_status(iwl_mei_cache.priv, &conn_info); + + /* + * Update the Rfkill state in case the host does not own the device: + * if we are in Link Protection, ask to not touch the device, else, + * unblock rfkill. + * If the host owns the device, inform the user space whether it can + * roam. + */ + if (mei->got_ownership) + iwl_mei_cache.ops->roaming_forbidden(iwl_mei_cache.priv, + status->link_prot_state); + else + iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, + status->link_prot_state); +} + +static void iwl_mei_set_init_conf(struct iwl_mei *mei) +{ + struct iwl_sap_notif_host_link_up link_msg = { + .hdr.type = cpu_to_le16(SAP_MSG_NOTIF_HOST_LINK_UP), + .hdr.len = cpu_to_le16(sizeof(link_msg) - sizeof(link_msg.hdr)), + }; + struct iwl_sap_notif_country_code mcc_msg = { + .hdr.type = cpu_to_le16(SAP_MSG_NOTIF_COUNTRY_CODE), + .hdr.len = cpu_to_le16(sizeof(mcc_msg) - sizeof(mcc_msg.hdr)), + .mcc = cpu_to_le16(iwl_mei_cache.mcc), + }; + struct iwl_sap_notif_sar_limits sar_msg = { + .hdr.type = cpu_to_le16(SAP_MSG_NOTIF_SAR_LIMITS), + .hdr.len = cpu_to_le16(sizeof(sar_msg) - sizeof(sar_msg.hdr)), + }; + struct iwl_sap_notif_host_nic_info nic_info_msg = { + .hdr.type = cpu_to_le16(SAP_MSG_NOTIF_NIC_INFO), + .hdr.len = cpu_to_le16(sizeof(nic_info_msg) - sizeof(nic_info_msg.hdr)), + }; + struct iwl_sap_msg_dw rfkill_msg = { + .hdr.type = cpu_to_le16(SAP_MSG_NOTIF_RADIO_STATE), + .hdr.len = cpu_to_le16(sizeof(rfkill_msg) - sizeof(rfkill_msg.hdr)), + .val = cpu_to_le32(iwl_mei_cache.rf_kill), + }; + + iwl_mei_send_sap_msg(mei->cldev, SAP_MSG_NOTIF_WHO_OWNS_NIC); + + if (iwl_mei_cache.conn_info) { + link_msg.conn_info = *iwl_mei_cache.conn_info; + iwl_mei_send_sap_msg_payload(mei->cldev, &link_msg.hdr); + } + + iwl_mei_send_sap_msg_payload(mei->cldev, &mcc_msg.hdr); + + if (iwl_mei_cache.power_limit) { + memcpy(sar_msg.sar_chain_info_table, iwl_mei_cache.power_limit, + sizeof(sar_msg.sar_chain_info_table)); + iwl_mei_send_sap_msg_payload(mei->cldev, &sar_msg.hdr); + } + + ether_addr_copy(nic_info_msg.mac_address, iwl_mei_cache.mac_address); + ether_addr_copy(nic_info_msg.nvm_address, iwl_mei_cache.nvm_address); + iwl_mei_send_sap_msg_payload(mei->cldev, &nic_info_msg.hdr); + + iwl_mei_send_sap_msg_payload(mei->cldev, &rfkill_msg.hdr); +} + +static void iwl_mei_handle_amt_state(struct mei_cl_device *cldev, + const struct iwl_sap_msg_dw *dw) +{ + struct iwl_mei *mei = mei_cldev_get_drvdata(cldev); + struct net_device *netdev; + + /* + * First take rtnl and only then the mutex to avoid an ABBA + * with iwl_mei_set_netdev() + */ + rtnl_lock(); + mutex_lock(&iwl_mei_mutex); + + netdev = rcu_dereference_protected(iwl_mei_cache.netdev, + lockdep_is_held(&iwl_mei_mutex)); + + if (mei->amt_enabled == !!le32_to_cpu(dw->val)) + goto out; + + mei->amt_enabled = dw->val; + + if (mei->amt_enabled) { + if (netdev) + netdev_rx_handler_register(netdev, iwl_mei_rx_handler, mei); + + iwl_mei_set_init_conf(mei); + } else { + if (iwl_mei_cache.ops) + iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, false); + if (netdev) + netdev_rx_handler_unregister(netdev); + } + +out: + mutex_unlock(&iwl_mei_mutex); + rtnl_unlock(); +} + +static void iwl_mei_handle_nic_owner(struct mei_cl_device *cldev, + const struct iwl_sap_msg_dw *dw) +{ + struct iwl_mei *mei = mei_cldev_get_drvdata(cldev); + + mei->got_ownership = dw->val != cpu_to_le32(SAP_NIC_OWNER_ME); +} + +static void iwl_mei_handle_can_release_ownership(struct mei_cl_device *cldev, + const void *payload) +{ + /* We can get ownership and driver is registered, go ahead */ + if (iwl_mei_cache.ops) + iwl_mei_send_sap_msg(cldev, + SAP_MSG_NOTIF_HOST_ASKS_FOR_NIC_OWNERSHIP); +} + +static void iwl_mei_handle_csme_taking_ownership(struct mei_cl_device *cldev, + const void *payload) +{ + struct iwl_mei *mei = mei_cldev_get_drvdata(cldev); + + dev_info(&cldev->dev, "CSME takes ownership\n"); + + mei->got_ownership = false; + + /* + * Remember to send CSME_OWNERSHIP_CONFIRMED when the wifi driver + * is finished taking the device down. + */ + mei->csme_taking_ownership = true; + + if (iwl_mei_cache.ops) + iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, true); +} + +static void iwl_mei_handle_nvm(struct mei_cl_device *cldev, + const struct iwl_sap_nvm *sap_nvm) +{ + struct iwl_mei *mei = mei_cldev_get_drvdata(cldev); + const struct iwl_mei_nvm *mei_nvm = (const void *)sap_nvm; + int i; + + kfree(mei->nvm); + mei->nvm = kzalloc(sizeof(*mei_nvm), GFP_KERNEL); + if (!mei->nvm) + return; + + ether_addr_copy(mei->nvm->hw_addr, sap_nvm->hw_addr); + mei->nvm->n_hw_addrs = sap_nvm->n_hw_addrs; + mei->nvm->radio_cfg = le32_to_cpu(sap_nvm->radio_cfg); + mei->nvm->caps = le32_to_cpu(sap_nvm->caps); + mei->nvm->nvm_version = le32_to_cpu(sap_nvm->nvm_version); + + for (i = 0; i < ARRAY_SIZE(mei->nvm->channels); i++) + mei->nvm->channels[i] = le32_to_cpu(sap_nvm->channels[i]); + + wake_up_all(&mei->get_nvm_wq); +} + +static void iwl_mei_handle_rx_host_own_req(struct mei_cl_device *cldev, + const struct iwl_sap_msg_dw *dw) +{ + struct iwl_mei *mei = mei_cldev_get_drvdata(cldev); + + /* + * This means that we can't use the wifi device right now, CSME is not + * ready to let us use it. + */ + if (!dw->val) { + dev_info(&cldev->dev, "Ownership req denied\n"); + return; + } + + mei->got_ownership = true; + wake_up_all(&mei->get_ownership_wq); + + iwl_mei_send_sap_msg(cldev, + SAP_MSG_NOTIF_HOST_OWNERSHIP_CONFIRMED); + + /* We can now start the connection, unblock rfkill */ + if (iwl_mei_cache.ops) + iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, false); +} + +static void iwl_mei_handle_ping(struct mei_cl_device *cldev, + const struct iwl_sap_hdr *hdr) +{ + iwl_mei_send_sap_msg(cldev, SAP_MSG_NOTIF_PONG); +} + +static void iwl_mei_handle_sap_msg(struct mei_cl_device *cldev, + const struct iwl_sap_hdr *hdr) +{ + u16 len = le16_to_cpu(hdr->len) + sizeof(*hdr); + u16 type = le16_to_cpu(hdr->type); + + dev_dbg(&cldev->dev, + "Got a new SAP message: type %d, len %d, seq %d\n", + le16_to_cpu(hdr->type), len, + le32_to_cpu(hdr->seq_num)); + +#define SAP_MSG_HANDLER(_cmd, _handler, _sz) \ + case SAP_MSG_NOTIF_ ## _cmd: \ + if (len < _sz) { \ + dev_err(&cldev->dev, \ + "Bad size for %d: %u < %u\n", \ + le16_to_cpu(hdr->type), \ + (unsigned int)len, \ + (unsigned int)_sz); \ + break; \ + } \ + mutex_lock(&iwl_mei_mutex); \ + _handler(cldev, (const void *)hdr); \ + mutex_unlock(&iwl_mei_mutex); \ + break + +#define SAP_MSG_HANDLER_NO_LOCK(_cmd, _handler, _sz) \ + case SAP_MSG_NOTIF_ ## _cmd: \ + if (len < _sz) { \ + dev_err(&cldev->dev, \ + "Bad size for %d: %u < %u\n", \ + le16_to_cpu(hdr->type), \ + (unsigned int)len, \ + (unsigned int)_sz); \ + break; \ + } \ + _handler(cldev, (const void *)hdr); \ + break + +#define SAP_MSG_HANDLER_NO_HANDLER(_cmd, _sz) \ + case SAP_MSG_NOTIF_ ## _cmd: \ + if (len < _sz) { \ + dev_err(&cldev->dev, \ + "Bad size for %d: %u < %u\n", \ + le16_to_cpu(hdr->type), \ + (unsigned int)len, \ + (unsigned int)_sz); \ + break; \ + } \ + break + + switch (type) { + SAP_MSG_HANDLER(PING, iwl_mei_handle_ping, 0); + SAP_MSG_HANDLER(CSME_FILTERS, + iwl_mei_handle_csme_filters, + sizeof(struct iwl_sap_csme_filters)); + SAP_MSG_HANDLER(CSME_CONN_STATUS, + iwl_mei_handle_conn_status, + sizeof(struct iwl_sap_notif_conn_status)); + SAP_MSG_HANDLER_NO_LOCK(AMT_STATE, + iwl_mei_handle_amt_state, + sizeof(struct iwl_sap_msg_dw)); + SAP_MSG_HANDLER_NO_HANDLER(PONG, 0); + SAP_MSG_HANDLER(NVM, iwl_mei_handle_nvm, + sizeof(struct iwl_sap_nvm)); + SAP_MSG_HANDLER(CSME_REPLY_TO_HOST_OWNERSHIP_REQ, + iwl_mei_handle_rx_host_own_req, + sizeof(struct iwl_sap_msg_dw)); + SAP_MSG_HANDLER(NIC_OWNER, iwl_mei_handle_nic_owner, + sizeof(struct iwl_sap_msg_dw)); + SAP_MSG_HANDLER(CSME_CAN_RELEASE_OWNERSHIP, + iwl_mei_handle_can_release_ownership, 0); + SAP_MSG_HANDLER(CSME_TAKING_OWNERSHIP, + iwl_mei_handle_csme_taking_ownership, 0); + default: + /* + * This is not really an error, there are message that we decided + * to ignore, yet, it is useful to be able to leave a note if debug + * is enabled. + */ + dev_dbg(&cldev->dev, "Unsupported message: type %d, len %d\n", + le16_to_cpu(hdr->type), len); + } + +#undef SAP_MSG_HANDLER +#undef SAP_MSG_HANDLER_NO_LOCK +} + +static void iwl_mei_read_from_q(const u8 *q_head, u32 q_sz, + u32 *_rd, u32 wr, + void *_buf, u32 len) +{ + u8 *buf = _buf; + u32 rd = *_rd; + + if (rd + len <= q_sz) { + memcpy(buf, q_head + rd, len); + rd += len; + } else { + memcpy(buf, q_head + rd, q_sz - rd); + memcpy(buf + q_sz - rd, q_head, len - (q_sz - rd)); + rd = len - (q_sz - rd); + } + + *_rd = rd; +} + +#define QOS_HDR_IV_SNAP_LEN (sizeof(struct ieee80211_qos_hdr) + \ + IEEE80211_TKIP_IV_LEN + \ + sizeof(rfc1042_header) + ETH_TLEN) + +static void iwl_mei_handle_sap_data(struct mei_cl_device *cldev, + const u8 *q_head, u32 q_sz, + u32 rd, u32 wr, ssize_t valid_rx_sz, + struct sk_buff_head *tx_skbs) +{ + struct iwl_sap_hdr hdr; + struct net_device *netdev = + rcu_dereference_protected(iwl_mei_cache.netdev, + lockdep_is_held(&iwl_mei_mutex)); + + if (!netdev) + return; + + while (valid_rx_sz >= sizeof(hdr)) { + struct ethhdr *ethhdr; + unsigned char *data; + struct sk_buff *skb; + u16 len; + + iwl_mei_read_from_q(q_head, q_sz, &rd, wr, &hdr, sizeof(hdr)); + valid_rx_sz -= sizeof(hdr); + len = le16_to_cpu(hdr.len); + + if (valid_rx_sz < len) { + dev_err(&cldev->dev, + "Data queue is corrupted: valid data len %zd, len %d\n", + valid_rx_sz, len); + break; + } + + if (len < sizeof(*ethhdr)) { + dev_err(&cldev->dev, + "Data len is smaller than an ethernet header? len = %d\n", + len); + } + + valid_rx_sz -= len; + + if (le16_to_cpu(hdr.type) != SAP_MSG_DATA_PACKET) { + dev_err(&cldev->dev, "Unsupported Rx data: type %d, len %d\n", + le16_to_cpu(hdr.type), len); + continue; + } + + /* We need enough room for the WiFi header + SNAP + IV */ + skb = netdev_alloc_skb(netdev, len + QOS_HDR_IV_SNAP_LEN); + + skb_reserve(skb, QOS_HDR_IV_SNAP_LEN); + ethhdr = skb_push(skb, sizeof(*ethhdr)); + + iwl_mei_read_from_q(q_head, q_sz, &rd, wr, + ethhdr, sizeof(*ethhdr)); + len -= sizeof(*ethhdr); + + skb_reset_mac_header(skb); + skb_reset_network_header(skb); + skb->protocol = ethhdr->h_proto; + + data = skb_put(skb, len); + iwl_mei_read_from_q(q_head, q_sz, &rd, wr, data, len); + + /* + * Enqueue the skb here so that it can be sent later when we + * do not hold the mutex. TX'ing a packet with a mutex held is + * possible, but it wouldn't be nice to forbid the TX path to + * call any of iwlmei's functions, since every API from iwlmei + * needs the mutex. + */ + __skb_queue_tail(tx_skbs, skb); + } +} + +static void iwl_mei_handle_sap_rx_cmd(struct mei_cl_device *cldev, + const u8 *q_head, u32 q_sz, + u32 rd, u32 wr, ssize_t valid_rx_sz) +{ + struct page *p = alloc_page(GFP_KERNEL); + struct iwl_sap_hdr *hdr; + + if (!p) + return; + + hdr = page_address(p); + + while (valid_rx_sz >= sizeof(*hdr)) { + u16 len; + + iwl_mei_read_from_q(q_head, q_sz, &rd, wr, hdr, sizeof(*hdr)); + valid_rx_sz -= sizeof(*hdr); + len = le16_to_cpu(hdr->len); + + if (valid_rx_sz < len) + break; + + iwl_mei_read_from_q(q_head, q_sz, &rd, wr, hdr + 1, len); + + trace_iwlmei_sap_cmd(hdr, false); + iwl_mei_handle_sap_msg(cldev, hdr); + valid_rx_sz -= len; + } + + /* valid_rx_sz must be 0 now... */ + if (valid_rx_sz) + dev_err(&cldev->dev, + "More data in the buffer although we read it all\n"); + + __free_page(p); +} + +static void iwl_mei_handle_sap_rx(struct mei_cl_device *cldev, + struct iwl_sap_q_ctrl_blk *notif_q, + const u8 *q_head, + struct sk_buff_head *skbs, + u32 q_sz) +{ + u32 rd = le32_to_cpu(READ_ONCE(notif_q->rd_ptr)); + u32 wr = le32_to_cpu(READ_ONCE(notif_q->wr_ptr)); + ssize_t valid_rx_sz; + + if (rd > q_sz || wr > q_sz) { + dev_err(&cldev->dev, + "Pointers are past the buffer limit\n"); + return; + } + + if (rd == wr) + return; + + valid_rx_sz = wr > rd ? wr - rd : q_sz - rd + wr; + + if (skbs) + iwl_mei_handle_sap_data(cldev, q_head, q_sz, rd, wr, + valid_rx_sz, skbs); + else + iwl_mei_handle_sap_rx_cmd(cldev, q_head, q_sz, rd, wr, + valid_rx_sz); + + /* Increment the read pointer to point to the write pointer */ + WRITE_ONCE(notif_q->rd_ptr, cpu_to_le32(wr)); +} + +static void iwl_mei_handle_check_shared_area(struct mei_cl_device *cldev) +{ + struct iwl_mei *mei = mei_cldev_get_drvdata(cldev); + struct iwl_sap_q_ctrl_blk *notif_q; + struct sk_buff_head tx_skbs; + struct iwl_sap_dir *dir; + void *q_head; + u32 q_sz; + + if (!mei->shared_mem.ctrl) + return; + + dir = &mei->shared_mem.ctrl->dir[SAP_DIRECTION_ME_TO_HOST]; + notif_q = &dir->q_ctrl_blk[SAP_QUEUE_IDX_NOTIF]; + q_head = mei->shared_mem.q_head[SAP_DIRECTION_ME_TO_HOST][SAP_QUEUE_IDX_NOTIF]; + q_sz = mei->shared_mem.q_size[SAP_DIRECTION_ME_TO_HOST][SAP_QUEUE_IDX_NOTIF]; + + /* + * Do not hold the mutex here, but rather each and every message + * handler takes it. + * This allows message handlers to take it at a certain time. + */ + iwl_mei_handle_sap_rx(cldev, notif_q, q_head, NULL, q_sz); + + mutex_lock(&iwl_mei_mutex); + dir = &mei->shared_mem.ctrl->dir[SAP_DIRECTION_ME_TO_HOST]; + notif_q = &dir->q_ctrl_blk[SAP_QUEUE_IDX_DATA]; + q_head = mei->shared_mem.q_head[SAP_DIRECTION_ME_TO_HOST][SAP_QUEUE_IDX_DATA]; + q_sz = mei->shared_mem.q_size[SAP_DIRECTION_ME_TO_HOST][SAP_QUEUE_IDX_DATA]; + + __skb_queue_head_init(&tx_skbs); + + iwl_mei_handle_sap_rx(cldev, notif_q, q_head, &tx_skbs, q_sz); + + if (skb_queue_empty(&tx_skbs)) { + mutex_unlock(&iwl_mei_mutex); + return; + } + + /* + * Take the RCU read lock before we unlock the mutex to make sure that + * even if the netdev is replaced by another non-NULL netdev right after + * we unlock the mutex, the old netdev will still be valid when we + * transmit the frames. We can't allow to replace the netdev here because + * the skbs hold a pointer to the netdev. + */ + rcu_read_lock(); + + mutex_unlock(&iwl_mei_mutex); + + if (!rcu_access_pointer(iwl_mei_cache.netdev)) { + dev_err(&cldev->dev, "Can't Tx without a netdev\n"); + skb_queue_purge(&tx_skbs); + goto out; + } + + while (!skb_queue_empty(&tx_skbs)) { + struct sk_buff *skb = __skb_dequeue(&tx_skbs); + + trace_iwlmei_sap_data(skb, IWL_SAP_RX_DATA_TO_AIR); + dev_queue_xmit(skb); + } + +out: + rcu_read_unlock(); +} + +static void iwl_mei_rx(struct mei_cl_device *cldev) +{ + struct iwl_sap_me_msg_hdr *hdr; + u8 msg[100]; + ssize_t ret; + + ret = mei_cldev_recv(cldev, (u8 *)&msg, sizeof(msg)); + if (ret < 0) { + dev_err(&cldev->dev, "failed to receive data: %zd\n", ret); + return; + } + + if (ret == 0) { + dev_err(&cldev->dev, "got an empty response\n"); + return; + } + + hdr = (void *)msg; + trace_iwlmei_me_msg(hdr, false); + + switch (le32_to_cpu(hdr->type)) { + case SAP_ME_MSG_START_OK: + BUILD_BUG_ON(sizeof(struct iwl_sap_me_msg_start_ok) > + sizeof(msg)); + + iwl_mei_handle_rx_start_ok(cldev, (void *)msg, ret); + break; + case SAP_ME_MSG_CHECK_SHARED_AREA: + iwl_mei_handle_check_shared_area(cldev); + break; + default: + dev_err(&cldev->dev, "got a RX notification: %d\n", + le32_to_cpu(hdr->type)); + break; + } +} + +static int iwl_mei_send_start(struct mei_cl_device *cldev) +{ + struct iwl_mei *mei = mei_cldev_get_drvdata(cldev); + struct iwl_sap_me_msg_start msg = { + .hdr.type = cpu_to_le32(SAP_ME_MSG_START), + .hdr.seq_num = cpu_to_le32(atomic_inc_return(&mei->seq_no)), + .hdr.len = cpu_to_le32(sizeof(msg)), + .supported_versions[0] = SAP_VERSION, + .init_data_seq_num = cpu_to_le16(0x100), + .init_notif_seq_num = cpu_to_le16(0x800), + }; + int ret; + + trace_iwlmei_me_msg(&msg.hdr, true); + ret = mei_cldev_send(cldev, (void *)&msg, sizeof(msg)); + if (ret != sizeof(msg)) { + dev_err(&cldev->dev, + "failed to send the SAP_ME_MSG_START message %d\n", + ret); + return ret; + } + + return 0; +} + +static int iwl_mei_enable(struct mei_cl_device *cldev) +{ + int ret; + + ret = mei_cldev_enable(cldev); + if (ret < 0) { + dev_err(&cldev->dev, "failed to enable the device: %d\n", ret); + return ret; + } + + ret = mei_cldev_register_rx_cb(cldev, iwl_mei_rx); + if (ret) { + dev_err(&cldev->dev, + "failed to register to the rx cb: %d\n", ret); + mei_cldev_disable(cldev); + return ret; + } + + return 0; +} + +struct iwl_mei_nvm *iwl_mei_get_nvm(void) +{ + struct iwl_mei_nvm *nvm = NULL; + struct iwl_mei *mei; + int ret; + + mutex_lock(&iwl_mei_mutex); + + if (!iwl_mei_is_connected()) + goto out; + + mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); + + if (!mei) + goto out; + + ret = iwl_mei_send_sap_msg(iwl_mei_global_cldev, + SAP_MSG_NOTIF_GET_NVM); + if (ret) + goto out; + + mutex_unlock(&iwl_mei_mutex); + + ret = wait_event_timeout(mei->get_nvm_wq, mei->nvm, 2 * HZ); + if (!ret) + return NULL; + + mutex_lock(&iwl_mei_mutex); + + if (!iwl_mei_is_connected()) + goto out; + + mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); + + if (!mei) + goto out; + + if (mei->nvm) + nvm = kmemdup(mei->nvm, sizeof(*mei->nvm), GFP_KERNEL); + +out: + mutex_unlock(&iwl_mei_mutex); + return nvm; +} +EXPORT_SYMBOL_GPL(iwl_mei_get_nvm); + +int iwl_mei_get_ownership(void) +{ + struct iwl_mei *mei; + int ret; + + mutex_lock(&iwl_mei_mutex); + + /* In case we didn't have a bind */ + if (!iwl_mei_is_connected()) { + ret = 0; + goto out; + } + + mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); + + if (!mei) { + ret = -ENODEV; + goto out; + } + + if (!mei->amt_enabled) { + ret = 0; + goto out; + } + + if (mei->got_ownership) { + ret = 0; + goto out; + } + + ret = iwl_mei_send_sap_msg(mei->cldev, + SAP_MSG_NOTIF_HOST_ASKS_FOR_NIC_OWNERSHIP); + if (ret) + goto out; + + mutex_unlock(&iwl_mei_mutex); + + ret = wait_event_timeout(mei->get_ownership_wq, + mei->got_ownership, HZ / 2); + if (!ret) + return -ETIMEDOUT; + + mutex_lock(&iwl_mei_mutex); + + /* In case we didn't have a bind */ + if (!iwl_mei_is_connected()) { + ret = 0; + goto out; + } + + mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); + + if (!mei) { + ret = -ENODEV; + goto out; + } + + ret = !mei->got_ownership; + +out: + mutex_unlock(&iwl_mei_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(iwl_mei_get_ownership); + +void iwl_mei_host_associated(const struct iwl_mei_conn_info *conn_info, + const struct iwl_mei_colloc_info *colloc_info) +{ + struct iwl_sap_notif_host_link_up msg = { + .hdr.type = cpu_to_le16(SAP_MSG_NOTIF_HOST_LINK_UP), + .hdr.len = cpu_to_le16(sizeof(msg) - sizeof(msg.hdr)), + .conn_info = { + .ssid_len = cpu_to_le32(conn_info->ssid_len), + .channel = conn_info->channel, + .band = conn_info->band, + .pairwise_cipher = cpu_to_le32(conn_info->pairwise_cipher), + .auth_mode = cpu_to_le32(conn_info->auth_mode), + }, + }; + struct iwl_mei *mei; + + if (conn_info->ssid_len > ARRAY_SIZE(msg.conn_info.ssid)) + return; + + memcpy(msg.conn_info.ssid, conn_info->ssid, conn_info->ssid_len); + memcpy(msg.conn_info.bssid, conn_info->bssid, ETH_ALEN); + + if (colloc_info) { + msg.colloc_channel = colloc_info->channel; + msg.colloc_band = colloc_info->channel <= 14 ? 0 : 1; + memcpy(msg.colloc_bssid, colloc_info->bssid, ETH_ALEN); + } + + mutex_lock(&iwl_mei_mutex); + + if (!iwl_mei_is_connected()) + goto out; + + mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); + + if (!mei) + goto out; + + if (!mei->amt_enabled) + goto out; + + iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr); + +out: + kfree(iwl_mei_cache.conn_info); + iwl_mei_cache.conn_info = + kmemdup(&msg.conn_info, sizeof(msg.conn_info), GFP_KERNEL); + mutex_unlock(&iwl_mei_mutex); +} +EXPORT_SYMBOL_GPL(iwl_mei_host_associated); + +void iwl_mei_host_disassociated(void) +{ + struct iwl_mei *mei; + struct iwl_sap_notif_host_link_down msg = { + .hdr.type = cpu_to_le16(SAP_MSG_NOTIF_HOST_LINK_DOWN), + .hdr.len = cpu_to_le16(sizeof(msg) - sizeof(msg.hdr)), + .type = HOST_LINK_DOWN_TYPE_LONG, + }; + + mutex_lock(&iwl_mei_mutex); + + if (!iwl_mei_is_connected()) + goto out; + + mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); + + if (!mei) + goto out; + + iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr); + +out: + kfree(iwl_mei_cache.conn_info); + iwl_mei_cache.conn_info = NULL; + mutex_unlock(&iwl_mei_mutex); +} +EXPORT_SYMBOL_GPL(iwl_mei_host_disassociated); + +void iwl_mei_set_rfkill_state(bool hw_rfkill, bool sw_rfkill) +{ + struct iwl_mei *mei; + u32 rfkill_state = 0; + struct iwl_sap_msg_dw msg = { + .hdr.type = cpu_to_le16(SAP_MSG_NOTIF_RADIO_STATE), + .hdr.len = cpu_to_le16(sizeof(msg) - sizeof(msg.hdr)), + }; + + if (!sw_rfkill) + rfkill_state |= SAP_SW_RFKILL_DEASSERTED; + + if (!hw_rfkill) + rfkill_state |= SAP_HW_RFKILL_DEASSERTED; + + mutex_lock(&iwl_mei_mutex); + + if (!iwl_mei_is_connected()) + goto out; + + msg.val = cpu_to_le32(rfkill_state); + + mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); + + if (!mei) + goto out; + + iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr); + +out: + iwl_mei_cache.rf_kill = rfkill_state; + mutex_unlock(&iwl_mei_mutex); +} +EXPORT_SYMBOL_GPL(iwl_mei_set_rfkill_state); + +void iwl_mei_set_nic_info(const u8 *mac_address, const u8 *nvm_address) +{ + struct iwl_mei *mei; + struct iwl_sap_notif_host_nic_info msg = { + .hdr.type = cpu_to_le16(SAP_MSG_NOTIF_NIC_INFO), + .hdr.len = cpu_to_le16(sizeof(msg) - sizeof(msg.hdr)), + }; + + mutex_lock(&iwl_mei_mutex); + + if (!iwl_mei_is_connected()) + goto out; + + ether_addr_copy(msg.mac_address, mac_address); + ether_addr_copy(msg.nvm_address, nvm_address); + + mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); + + if (!mei) + goto out; + + iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr); + +out: + ether_addr_copy(iwl_mei_cache.mac_address, mac_address); + ether_addr_copy(iwl_mei_cache.nvm_address, nvm_address); + mutex_unlock(&iwl_mei_mutex); +} +EXPORT_SYMBOL_GPL(iwl_mei_set_nic_info); + +void iwl_mei_set_country_code(u16 mcc) +{ + struct iwl_mei *mei; + struct iwl_sap_notif_country_code msg = { + .hdr.type = cpu_to_le16(SAP_MSG_NOTIF_COUNTRY_CODE), + .hdr.len = cpu_to_le16(sizeof(msg) - sizeof(msg.hdr)), + .mcc = cpu_to_le16(mcc), + }; + + mutex_lock(&iwl_mei_mutex); + + if (!iwl_mei_is_connected()) + goto out; + + mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); + + if (!mei) + goto out; + + iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr); + +out: + iwl_mei_cache.mcc = mcc; + mutex_unlock(&iwl_mei_mutex); +} +EXPORT_SYMBOL_GPL(iwl_mei_set_country_code); + +void iwl_mei_set_power_limit(const __le16 *power_limit) +{ + struct iwl_mei *mei; + struct iwl_sap_notif_sar_limits msg = { + .hdr.type = cpu_to_le16(SAP_MSG_NOTIF_SAR_LIMITS), + .hdr.len = cpu_to_le16(sizeof(msg) - sizeof(msg.hdr)), + }; + + mutex_lock(&iwl_mei_mutex); + + if (!iwl_mei_is_connected()) + goto out; + + mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); + + if (!mei) + goto out; + + memcpy(msg.sar_chain_info_table, power_limit, sizeof(msg.sar_chain_info_table)); + + iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr); + +out: + kfree(iwl_mei_cache.power_limit); + iwl_mei_cache.power_limit = kmemdup(power_limit, + sizeof(msg.sar_chain_info_table), GFP_KERNEL); + mutex_unlock(&iwl_mei_mutex); +} +EXPORT_SYMBOL_GPL(iwl_mei_set_power_limit); + +void iwl_mei_set_netdev(struct net_device *netdev) +{ + struct iwl_mei *mei; + + mutex_lock(&iwl_mei_mutex); + + if (!iwl_mei_is_connected()) { + rcu_assign_pointer(iwl_mei_cache.netdev, netdev); + goto out; + } + + mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); + + if (!mei) + goto out; + + if (!netdev) { + struct net_device *dev = + rcu_dereference_protected(iwl_mei_cache.netdev, + lockdep_is_held(&iwl_mei_mutex)); + + if (!dev) + goto out; + + netdev_rx_handler_unregister(dev); + } + + rcu_assign_pointer(iwl_mei_cache.netdev, netdev); + + if (netdev && mei->amt_enabled) + netdev_rx_handler_register(netdev, iwl_mei_rx_handler, mei); + +out: + mutex_unlock(&iwl_mei_mutex); +} +EXPORT_SYMBOL_GPL(iwl_mei_set_netdev); + +void iwl_mei_device_down(void) +{ + struct iwl_mei *mei; + + mutex_lock(&iwl_mei_mutex); + + if (!iwl_mei_is_connected()) + goto out; + + mei = mei_cldev_get_drvdata(iwl_mei_global_cldev); + + if (!mei) + goto out; + + if (!mei->csme_taking_ownership) + goto out; + + iwl_mei_send_sap_msg(mei->cldev, + SAP_MSG_NOTIF_CSME_OWNERSHIP_CONFIRMED); + mei->csme_taking_ownership = false; +out: + mutex_unlock(&iwl_mei_mutex); +} +EXPORT_SYMBOL_GPL(iwl_mei_device_down); + +int iwl_mei_register(void *priv, const struct iwl_mei_ops *ops) +{ + int ret; + + /* + * We must have a non-NULL priv pointer to not crash when there are + * multiple WiFi devices. + */ + if (!priv) + return -EINVAL; + + mutex_lock(&iwl_mei_mutex); + + /* do not allow registration if someone else already registered */ + if (iwl_mei_cache.priv || iwl_mei_cache.ops) { + ret = -EBUSY; + goto out; + } + + iwl_mei_cache.priv = priv; + iwl_mei_cache.ops = ops; + + if (iwl_mei_global_cldev) { + struct iwl_mei *mei = + mei_cldev_get_drvdata(iwl_mei_global_cldev); + + /* we have already a SAP connection */ + if (iwl_mei_is_connected()) + iwl_mei_send_sap_msg(mei->cldev, + SAP_MSG_NOTIF_WIFIDR_UP); + } + ret = 0; + +out: + mutex_unlock(&iwl_mei_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(iwl_mei_register); + +void iwl_mei_start_unregister(void) +{ + mutex_lock(&iwl_mei_mutex); + + /* At this point, the wifi driver should have removed the netdev */ + if (rcu_access_pointer(iwl_mei_cache.netdev)) + pr_err("Still had a netdev pointer set upon unregister\n"); + + kfree(iwl_mei_cache.conn_info); + iwl_mei_cache.conn_info = NULL; + kfree(iwl_mei_cache.power_limit); + iwl_mei_cache.power_limit = NULL; + iwl_mei_cache.ops = NULL; + /* leave iwl_mei_cache.priv non-NULL to prevent any new registration */ + + mutex_unlock(&iwl_mei_mutex); +} +EXPORT_SYMBOL_GPL(iwl_mei_start_unregister); + +void iwl_mei_unregister_complete(void) +{ + mutex_lock(&iwl_mei_mutex); + + iwl_mei_cache.priv = NULL; + + if (iwl_mei_global_cldev) { + struct iwl_mei *mei = + mei_cldev_get_drvdata(iwl_mei_global_cldev); + + iwl_mei_send_sap_msg(mei->cldev, SAP_MSG_NOTIF_WIFIDR_DOWN); + } + + mutex_unlock(&iwl_mei_mutex); +} +EXPORT_SYMBOL_GPL(iwl_mei_unregister_complete); + +#if IS_ENABLED(CONFIG_DEBUG_FS) + +static ssize_t +iwl_mei_dbgfs_send_start_message_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + int ret; + + mutex_lock(&iwl_mei_mutex); + + if (!iwl_mei_global_cldev) { + ret = -ENODEV; + goto out; + } + + ret = iwl_mei_send_start(iwl_mei_global_cldev); + +out: + mutex_unlock(&iwl_mei_mutex); + return ret ?: count; +} + +static const struct file_operations iwl_mei_dbgfs_send_start_message_ops = { + .write = iwl_mei_dbgfs_send_start_message_write, + .open = simple_open, + .llseek = default_llseek, +}; + +static ssize_t iwl_mei_dbgfs_req_ownership_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + iwl_mei_get_ownership(); + + return count; +} + +static const struct file_operations iwl_mei_dbgfs_req_ownership_ops = { + .write = iwl_mei_dbgfs_req_ownership_write, + .open = simple_open, + .llseek = default_llseek, +}; + +static void iwl_mei_dbgfs_register(struct iwl_mei *mei) +{ + mei->dbgfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); + + if (!mei->dbgfs_dir) + return; + + debugfs_create_ulong("status", S_IRUSR, + mei->dbgfs_dir, &iwl_mei_status); + debugfs_create_file("send_start_message", S_IWUSR, mei->dbgfs_dir, + mei, &iwl_mei_dbgfs_send_start_message_ops); + debugfs_create_file("req_ownership", S_IWUSR, mei->dbgfs_dir, + mei, &iwl_mei_dbgfs_req_ownership_ops); +} + +static void iwl_mei_dbgfs_unregister(struct iwl_mei *mei) +{ + debugfs_remove_recursive(mei->dbgfs_dir); + mei->dbgfs_dir = NULL; +} + +#else + +static void iwl_mei_dbgfs_register(struct iwl_mei *mei) {} +static void iwl_mei_dbgfs_unregister(struct iwl_mei *mei) {} + +#endif /* CONFIG_DEBUG_FS */ + +/** + * iwl_mei_probe - the probe function called by the mei bus enumeration + * + * This allocates the data needed by iwlmei and sets a pointer to this data + * into the mei_cl_device's drvdata. + * It starts the SAP protocol by sending the SAP_ME_MSG_START without + * waiting for the answer. The answer will be caught later by the Rx callback. + */ +static int iwl_mei_probe(struct mei_cl_device *cldev, + const struct mei_cl_device_id *id) +{ + struct iwl_mei *mei; + int ret; + + mei = devm_kzalloc(&cldev->dev, sizeof(*mei), GFP_KERNEL); + if (!mei) + return -ENOMEM; + + init_waitqueue_head(&mei->get_nvm_wq); + INIT_WORK(&mei->send_csa_msg_wk, iwl_mei_send_csa_msg_wk); + INIT_DELAYED_WORK(&mei->csa_throttle_end_wk, + iwl_mei_csa_throttle_end_wk); + init_waitqueue_head(&mei->get_ownership_wq); + spin_lock_init(&mei->data_q_lock); + + mei_cldev_set_drvdata(cldev, mei); + mei->cldev = cldev; + + ret = iwl_mei_alloc_shared_mem(cldev); + if (ret) + goto free; + + iwl_mei_init_shared_mem(mei); + + ret = iwl_mei_enable(cldev); + if (ret) + goto free_shared_mem; + + iwl_mei_dbgfs_register(mei); + + /* + * We now have a Rx function in place, start the SAP procotol + * we expect to get the SAP_ME_MSG_START_OK response later on. + */ + mutex_lock(&iwl_mei_mutex); + ret = iwl_mei_send_start(cldev); + mutex_unlock(&iwl_mei_mutex); + if (ret) + goto debugfs_unregister; + + /* must be last */ + iwl_mei_global_cldev = cldev; + + return 0; + +debugfs_unregister: + iwl_mei_dbgfs_unregister(mei); + mei_cldev_disable(cldev); +free_shared_mem: + iwl_mei_free_shared_mem(cldev); +free: + mei_cldev_set_drvdata(cldev, NULL); + devm_kfree(&cldev->dev, mei); + + return ret; +} + +#define SEND_SAP_MAX_WAIT_ITERATION 10 + +static void iwl_mei_remove(struct mei_cl_device *cldev) +{ + struct iwl_mei *mei = mei_cldev_get_drvdata(cldev); + int i; + + /* + * We are being removed while the bus is active, it means we are + * going to suspend/ shutdown, so the NIC will disappear. + */ + if (mei_cldev_enabled(cldev) && iwl_mei_cache.ops) + iwl_mei_cache.ops->nic_stolen(iwl_mei_cache.priv); + + if (rcu_access_pointer(iwl_mei_cache.netdev)) { + struct net_device *dev; + + /* + * First take rtnl and only then the mutex to avoid an ABBA + * with iwl_mei_set_netdev() + */ + rtnl_lock(); + mutex_lock(&iwl_mei_mutex); + + /* + * If we are suspending and the wifi driver hasn't removed it's netdev + * yet, do it now. In any case, don't change the cache.netdev pointer. + */ + dev = rcu_dereference_protected(iwl_mei_cache.netdev, + lockdep_is_held(&iwl_mei_mutex)); + + netdev_rx_handler_unregister(dev); + mutex_unlock(&iwl_mei_mutex); + rtnl_unlock(); + } + + mutex_lock(&iwl_mei_mutex); + + /* + * Tell CSME that we are going down so that it won't access the + * memory anymore, make sure this message goes through immediately. + */ + mei->csa_throttled = false; + iwl_mei_send_sap_msg(mei->cldev, + SAP_MSG_NOTIF_HOST_GOES_DOWN); + + for (i = 0; i < SEND_SAP_MAX_WAIT_ITERATION; i++) { + if (!iwl_mei_host_to_me_data_pending(mei)) + break; + + msleep(5); + } + + /* + * If we couldn't make sure that CSME saw the HOST_GOES_DOWN message, + * it means that it will probably keep reading memory that we are going + * to unmap and free, expect IOMMU error messages. + */ + if (i == SEND_SAP_MAX_WAIT_ITERATION) + dev_err(&mei->cldev->dev, + "Couldn't get ACK from CSME on HOST_GOES_DOWN message\n"); + + mutex_unlock(&iwl_mei_mutex); + + /* + * This looks strange, but this lock is taken here to make sure that + * iwl_mei_add_data_to_ring called from the Tx path sees that we + * clear the IWL_MEI_STATUS_SAP_CONNECTED bit. + * Rx isn't a problem because the rx_handler can't be called after + * having been unregistered. + */ + spin_lock_bh(&mei->data_q_lock); + clear_bit(IWL_MEI_STATUS_SAP_CONNECTED, &iwl_mei_status); + spin_unlock_bh(&mei->data_q_lock); + + if (iwl_mei_cache.ops) + iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, false); + + /* + * mei_cldev_disable will return only after all the MEI Rx is done. + * It must be called when iwl_mei_mutex is *not* held, since it waits + * for our Rx handler to complete. + * After it returns, no new Rx will start. + */ + mei_cldev_disable(cldev); + + /* + * Since the netdev was already removed and the netdev's removal + * includes a call to synchronize_net() so that we know there won't be + * any new Rx that will trigger the following workers. + */ + cancel_work_sync(&mei->send_csa_msg_wk); + cancel_delayed_work_sync(&mei->csa_throttle_end_wk); + + /* + * If someone waits for the ownership, let him know that we are going + * down and that we are not connected anymore. He'll be able to take + * the device. + */ + wake_up_all(&mei->get_ownership_wq); + + mutex_lock(&iwl_mei_mutex); + + iwl_mei_global_cldev = NULL; + + wake_up_all(&mei->get_nvm_wq); + + iwl_mei_free_shared_mem(cldev); + + iwl_mei_dbgfs_unregister(mei); + + mei_cldev_set_drvdata(cldev, NULL); + + kfree(mei->nvm); + + kfree(rcu_access_pointer(mei->filters)); + + devm_kfree(&cldev->dev, mei); + + mutex_unlock(&iwl_mei_mutex); +} + +static const struct mei_cl_device_id iwl_mei_tbl[] = { + { KBUILD_MODNAME, MEI_WLAN_UUID, MEI_CL_VERSION_ANY}, + + /* required last entry */ + { } +}; + +/* + * Do not export the device table because this module is loaded by + * iwlwifi's dependency. + */ + +static struct mei_cl_driver iwl_mei_cl_driver = { + .id_table = iwl_mei_tbl, + .name = KBUILD_MODNAME, + .probe = iwl_mei_probe, + .remove = iwl_mei_remove, +}; + +module_mei_cl_driver(iwl_mei_cl_driver); diff --git a/drivers/net/wireless/intel/iwlwifi/mei/net.c b/drivers/net/wireless/intel/iwlwifi/mei/net.c new file mode 100644 index 000000000000..5f966af69720 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mei/net.c @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Intel Corporation + */ + +#include <uapi/linux/if_ether.h> +#include <uapi/linux/if_arp.h> +#include <uapi/linux/icmp.h> + +#include <linux/etherdevice.h> +#include <linux/netdevice.h> +#include <linux/skbuff.h> +#include <linux/ieee80211.h> + +#include <net/cfg80211.h> +#include <net/ip.h> + +#include <linux/if_arp.h> +#include <linux/icmp.h> +#include <linux/udp.h> +#include <linux/ip.h> +#include <linux/mm.h> + +#include "internal.h" +#include "sap.h" +#include "iwl-mei.h" + +/* + * Returns true if further filtering should be stopped. Only in that case + * pass_to_csme and rx_handler_res are set. Otherwise, next level of filters + * should be checked. + */ +static bool iwl_mei_rx_filter_eth(const struct ethhdr *ethhdr, + const struct iwl_sap_oob_filters *filters, + bool *pass_to_csme, + rx_handler_result_t *rx_handler_res) +{ + const struct iwl_sap_eth_filter *filt; + + /* This filter is not relevant for UCAST packet */ + if (!is_multicast_ether_addr(ethhdr->h_dest) || + is_broadcast_ether_addr(ethhdr->h_dest)) + return false; + + for (filt = &filters->eth_filters[0]; + filt < &filters->eth_filters[0] + ARRAY_SIZE(filters->eth_filters); + filt++) { + /* Assume there are no enabled filter after a disabled one */ + if (!(filt->flags & SAP_ETH_FILTER_ENABLED)) + break; + + if (compare_ether_header(filt->mac_address, ethhdr->h_dest)) + continue; + + /* Packet needs to reach the host's stack */ + if (filt->flags & SAP_ETH_FILTER_COPY) + *rx_handler_res = RX_HANDLER_PASS; + else + *rx_handler_res = RX_HANDLER_CONSUMED; + + /* We have an authoritative answer, stop filtering */ + if (filt->flags & SAP_ETH_FILTER_STOP) { + *pass_to_csme = true; + return true; + } + + return false; + } + + /* MCAST frames that don't match layer 2 filters are not sent to ME */ + *pass_to_csme = false; + + return true; +} + +/* + * Returns true iff the frame should be passed to CSME in which case + * rx_handler_res is set. + */ +static bool iwl_mei_rx_filter_arp(struct sk_buff *skb, + const struct iwl_sap_oob_filters *filters, + rx_handler_result_t *rx_handler_res) +{ + const struct iwl_sap_ipv4_filter *filt = &filters->ipv4_filter; + const struct arphdr *arp; + const __be32 *target_ip; + u32 flags = le32_to_cpu(filt->flags); + + if (!pskb_may_pull(skb, arp_hdr_len(skb->dev))) + return false; + + arp = arp_hdr(skb); + + /* Handle only IPv4 over ethernet ARP frames */ + if (arp->ar_hrd != htons(ARPHRD_ETHER) || + arp->ar_pro != htons(ETH_P_IP)) + return false; + + /* + * After the ARP header, we have: + * src MAC address - 6 bytes + * src IP address - 4 bytes + * target MAC addess - 6 bytes + */ + target_ip = (void *)((u8 *)(arp + 1) + + ETH_ALEN + sizeof(__be32) + ETH_ALEN); + + /* + * ARP request is forwarded to ME only if IP address match in the + * ARP request's target ip field. + */ + if (arp->ar_op == htons(ARPOP_REQUEST) && + (filt->flags & cpu_to_le32(SAP_IPV4_FILTER_ARP_REQ_PASS)) && + (filt->ipv4_addr == 0 || filt->ipv4_addr == *target_ip)) { + if (flags & SAP_IPV4_FILTER_ARP_REQ_COPY) + *rx_handler_res = RX_HANDLER_PASS; + else + *rx_handler_res = RX_HANDLER_CONSUMED; + + return true; + } + + /* ARP reply is always forwarded to ME regardless of the IP */ + if (flags & SAP_IPV4_FILTER_ARP_RESP_PASS && + arp->ar_op == htons(ARPOP_REPLY)) { + if (flags & SAP_IPV4_FILTER_ARP_RESP_COPY) + *rx_handler_res = RX_HANDLER_PASS; + else + *rx_handler_res = RX_HANDLER_CONSUMED; + + return true; + } + + return false; +} + +static bool +iwl_mei_rx_filter_tcp_udp(struct sk_buff *skb, bool ip_match, + const struct iwl_sap_oob_filters *filters, + rx_handler_result_t *rx_handler_res) +{ + const struct iwl_sap_flex_filter *filt; + + for (filt = &filters->flex_filters[0]; + filt < &filters->flex_filters[0] + ARRAY_SIZE(filters->flex_filters); + filt++) { + if (!(filt->flags & SAP_FLEX_FILTER_ENABLED)) + break; + + /* + * We are required to have a match on the IP level and we didn't + * have such match. + */ + if ((filt->flags & + (SAP_FLEX_FILTER_IPV4 | SAP_FLEX_FILTER_IPV6)) && + !ip_match) + continue; + + if ((filt->flags & SAP_FLEX_FILTER_UDP) && + ip_hdr(skb)->protocol != IPPROTO_UDP) + continue; + + if ((filt->flags & SAP_FLEX_FILTER_TCP) && + ip_hdr(skb)->protocol != IPPROTO_TCP) + continue; + + /* + * We must have either a TCP header or a UDP header, both + * starts with a source port and then a destination port. + * Both are big endian words. + * Use a UDP header and that will work for TCP as well. + */ + if ((filt->src_port && filt->src_port != udp_hdr(skb)->source) || + (filt->dst_port && filt->dst_port != udp_hdr(skb)->dest)) + continue; + + if (filt->flags & SAP_FLEX_FILTER_COPY) + *rx_handler_res = RX_HANDLER_PASS; + else + *rx_handler_res = RX_HANDLER_CONSUMED; + + return true; + } + + return false; +} + +static bool iwl_mei_rx_filter_ipv4(struct sk_buff *skb, + const struct iwl_sap_oob_filters *filters, + rx_handler_result_t *rx_handler_res) +{ + const struct iwl_sap_ipv4_filter *filt = &filters->ipv4_filter; + const struct iphdr *iphdr; + unsigned int iphdrlen; + bool match; + + if (!pskb_may_pull(skb, skb_network_offset(skb) + sizeof(*iphdr)) || + !pskb_may_pull(skb, skb_network_offset(skb) + + sizeof(ip_hdrlen(skb) - sizeof(*iphdr)))) + return false; + + iphdrlen = ip_hdrlen(skb); + iphdr = ip_hdr(skb); + match = !filters->ipv4_filter.ipv4_addr || + filters->ipv4_filter.ipv4_addr == iphdr->daddr; + + skb_set_transport_header(skb, skb_network_offset(skb) + iphdrlen); + + switch (ip_hdr(skb)->protocol) { + case IPPROTO_UDP: + case IPPROTO_TCP: + /* + * UDP header is shorter than TCP header and we look at the first bytes + * of the header anyway (see below). + * If we have a truncated TCP packet, let CSME handle this. + */ + if (!pskb_may_pull(skb, skb_transport_offset(skb) + + sizeof(struct udphdr))) + return false; + + return iwl_mei_rx_filter_tcp_udp(skb, match, + filters, rx_handler_res); + + case IPPROTO_ICMP: { + struct icmphdr *icmp; + + if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(*icmp))) + return false; + + icmp = icmp_hdr(skb); + + /* + * Don't pass echo requests to ME even if it wants it as we + * want the host to answer. + */ + if ((filt->flags & cpu_to_le32(SAP_IPV4_FILTER_ICMP_PASS)) && + match && (icmp->type != ICMP_ECHO || icmp->code != 0)) { + if (filt->flags & cpu_to_le32(SAP_IPV4_FILTER_ICMP_COPY)) + *rx_handler_res = RX_HANDLER_PASS; + else + *rx_handler_res = RX_HANDLER_CONSUMED; + + return true; + } + break; + } + case IPPROTO_ICMPV6: + /* TODO: Should we have the same ICMP request logic here too? */ + if ((filters->icmpv6_flags & cpu_to_le32(SAP_ICMPV6_FILTER_ENABLED) && + match)) { + if (filters->icmpv6_flags & + cpu_to_le32(SAP_ICMPV6_FILTER_COPY)) + *rx_handler_res = RX_HANDLER_PASS; + else + *rx_handler_res = RX_HANDLER_CONSUMED; + + return true; + } + break; + default: + return false; + } + + return false; +} + +static bool iwl_mei_rx_filter_ipv6(struct sk_buff *skb, + const struct iwl_sap_oob_filters *filters, + rx_handler_result_t *rx_handler_res) +{ + *rx_handler_res = RX_HANDLER_PASS; + + /* TODO */ + + return false; +} + +static rx_handler_result_t +iwl_mei_rx_pass_to_csme(struct sk_buff *skb, + const struct iwl_sap_oob_filters *filters, + bool *pass_to_csme) +{ + const struct ethhdr *ethhdr = (void *)skb_mac_header(skb); + rx_handler_result_t rx_handler_res = RX_HANDLER_PASS; + bool (*filt_handler)(struct sk_buff *skb, + const struct iwl_sap_oob_filters *filters, + rx_handler_result_t *rx_handler_res); + + /* + * skb->data points the IP header / ARP header and the ETH header + * is in the headroom. + */ + skb_reset_network_header(skb); + + /* + * MCAST IP packets sent by us are received again here without + * an ETH header. Drop them here. + */ + if (!skb_mac_offset(skb)) + return RX_HANDLER_PASS; + + if (skb_headroom(skb) < sizeof(*ethhdr)) + return RX_HANDLER_PASS; + + if (iwl_mei_rx_filter_eth(ethhdr, filters, + pass_to_csme, &rx_handler_res)) + return rx_handler_res; + + switch (skb->protocol) { + case htons(ETH_P_IP): + filt_handler = iwl_mei_rx_filter_ipv4; + break; + case htons(ETH_P_ARP): + filt_handler = iwl_mei_rx_filter_arp; + break; + case htons(ETH_P_IPV6): + filt_handler = iwl_mei_rx_filter_ipv6; + break; + default: + *pass_to_csme = false; + return rx_handler_res; + } + + *pass_to_csme = filt_handler(skb, filters, &rx_handler_res); + + return rx_handler_res; +} + +rx_handler_result_t iwl_mei_rx_filter(struct sk_buff *orig_skb, + const struct iwl_sap_oob_filters *filters, + bool *pass_to_csme) +{ + rx_handler_result_t ret; + struct sk_buff *skb; + + ret = iwl_mei_rx_pass_to_csme(orig_skb, filters, pass_to_csme); + + if (!*pass_to_csme) + return RX_HANDLER_PASS; + + if (ret == RX_HANDLER_PASS) + skb = skb_copy(orig_skb, GFP_ATOMIC); + else + skb = orig_skb; + + /* CSME wants the MAC header as well, push it back */ + skb_push(skb, skb->data - skb_mac_header(skb)); + + /* + * Add the packet that CSME wants to get to the ring. Don't send the + * Check Shared Area HECI message since this is not possible from the + * Rx context. The caller will schedule a worker to do just that. + */ + iwl_mei_add_data_to_ring(skb, false); + + /* + * In case we drop the packet, don't free it, the caller will do that + * for us + */ + if (ret == RX_HANDLER_PASS) + dev_kfree_skb(skb); + + return ret; +} + +#define DHCP_SERVER_PORT 67 +#define DHCP_CLIENT_PORT 68 +void iwl_mei_tx_copy_to_csme(struct sk_buff *origskb, unsigned int ivlen) +{ + struct ieee80211_hdr *hdr; + struct sk_buff *skb; + struct ethhdr ethhdr; + struct ethhdr *eth; + + /* Catch DHCP packets */ + if (origskb->protocol != htons(ETH_P_IP) || + ip_hdr(origskb)->protocol != IPPROTO_UDP || + udp_hdr(origskb)->source != htons(DHCP_CLIENT_PORT) || + udp_hdr(origskb)->dest != htons(DHCP_SERVER_PORT)) + return; + + /* + * We could be a bit less aggressive here and not copy everything, but + * this is very rare anyway, do don't bother much. + */ + skb = skb_copy(origskb, GFP_ATOMIC); + if (!skb) + return; + + skb->protocol = origskb->protocol; + + hdr = (void *)skb->data; + + memcpy(ethhdr.h_dest, ieee80211_get_DA(hdr), ETH_ALEN); + memcpy(ethhdr.h_source, ieee80211_get_SA(hdr), ETH_ALEN); + + /* + * Remove the ieee80211 header + IV + SNAP but leave the ethertype + * We still have enough headroom for the sap header. + */ + pskb_pull(skb, ieee80211_hdrlen(hdr->frame_control) + ivlen + 6); + eth = skb_push(skb, sizeof(ethhdr.h_dest) + sizeof(ethhdr.h_source)); + memcpy(eth, ðhdr, sizeof(ethhdr.h_dest) + sizeof(ethhdr.h_source)); + + iwl_mei_add_data_to_ring(skb, true); + + dev_kfree_skb(skb); +} +EXPORT_SYMBOL_GPL(iwl_mei_tx_copy_to_csme); diff --git a/drivers/net/wireless/intel/iwlwifi/mei/sap.h b/drivers/net/wireless/intel/iwlwifi/mei/sap.h new file mode 100644 index 000000000000..11e3009121cc --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mei/sap.h @@ -0,0 +1,733 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Intel Corporation + */ + +#ifndef __sap_h__ +#define __sap_h__ + +#include "mei/iwl-mei.h" + +/** + * DOC: Introduction + * + * SAP is the protocol used by the Intel Wireless driver (iwlwifi) + * and the wireless driver implemented in the CSME firmware. + * It allows to do several things: + * 1) Decide who is the owner of the device: CSME or the host + * 2) When the host is the owner of the device, CSME can still + * send and receive packets through iwlwifi. + * + * The protocol uses the ME interface (mei driver) to send + * messages to the CSME firmware. Those messages have a header + * &struct iwl_sap_me_msg_hdr and this header is followed + * by a payload. + * + * Since this messaging system cannot support high amounts of + * traffic, iwlwifi and the CSME firmware's WLAN driver have an + * addtional communication pipe to exchange information. The body + * of the message is copied to a shared area and the message that + * goes over the ME interface just signals the other side + * that a new message is waiting in the shared area. The ME + * interface is used only for signaling and not to transfer + * the payload. + * + * This shared area of memory is DMA'able mapped to be + * writable by both the CSME firmware and iwlwifi. It is + * mapped to address space of the device that controls the ME + * interface's DMA engine. Any data that iwlwifi needs to + * send to the CSME firmware needs to be copied to there. + */ + +/** + * DOC: Initial Handshake + * + * Once we get a link to the CMSE's WLAN driver we start the handshake + * to establish the shared memory that will allow the communication between + * the CSME's WLAN driver and the host. + * + * 1) Host sends %SAP_ME_MSG_START message with the physical address + * of the shared area. + * 2) CSME replies with %SAP_ME_MSG_START_OK which includes the versions + * protocol versions supported by CSME. + */ + +/** + * DOC: Host and driver state messages + * + * In order to let CSME konw about the host state and the host driver state, + * the host sends messages that let CSME know about the host's state. + * When the host driver is loaded, the host sends %SAP_MSG_NOTIF_WIFIDR_UP. + * When the host driver is unloaded, the host sends %SAP_MSG_NOTIF_WIFIDR_DOWN. + * When the iwlmei is unloaded, %SAP_MSG_NOTIF_HOST_GOES_DOWN is sent to let + * CSME know not to access the shared memory anymore since it'll be freed. + * + * CSME will reply to SAP_MSG_NOTIF_WIFIDR_UP by + * %SAP_MSG_NOTIF_AMT_STATE to let the host driver whether CSME can use the + * WiFi device or not followed by %SAP_MSG_NOTIF_CSME_CONN_STATUS to inform + * the host driver on the connection state of CSME. + * + * When host is associated to an AP, it must send %SAP_MSG_NOTIF_HOST_LINK_UP + * and when it disconnect from the AP, it must send + * %SAP_MSG_NOTIF_HOST_LINK_DOWN. + */ + +/** + * DOC: Ownership + * + * The device can be controlled either by the CSME firmware or + * by the host driver: iwlwifi. There is a negotiaion between + * those two entities to determine who controls (or owns) the + * device. Since the CSME can control the device even when the + * OS is not working or even missing, the CSME can request the + * device if it comes to the conclusion that the OS's host driver + * is not operational. This is why the host driver needs to + * signal CSME that it is up and running. If the driver is + * unloaded, it'll signal CSME that it is going down so that + * CSME can take ownership. + */ + +/** + * DOC: Ownership transfer + * + * When the host driver needs the device, it'll send the + * %SAP_MSG_NOTIF_HOST_ASKS_FOR_NIC_OWNERSHIP that will be replied by + * %SAP_MSG_NOTIF_CSME_REPLY_TO_HOST_OWNERSHIP_REQ which will let the + * host know whether the ownership is granted or no. If the ownership is + * granted, the hosts sends %SAP_MSG_NOTIF_HOST_OWNERSHIP_CONFIRMED. + * + * When CSME requests ownership, it'll send the + * %SAP_MSG_NOTIF_CSME_TAKING_OWNERSHIP and give some time to host to stop + * accessing the device. The host needs to send + * %SAP_MSG_NOTIF_CSME_OWNERSHIP_CONFIRMED to confirm that it won't access + * the device anymore. If the host failed to send this message fast enough, + * CSME will take ownership on the device anyway. + * When CSME is willing to release the ownership, it'll send + * %SAP_MSG_NOTIF_CSME_CAN_RELEASE_OWNERSHIP. + */ + +/** + * DOC: Data messages + * + * Data messages must be sent and receives on a separate queue in the shared + * memory. Almost all the data messages use the %SAP_MSG_DATA_PACKET for both + * packets sent by CSME to the host to be sent to the AP or for packets + * received from the AP and sent by the host to CSME. + * CSME sends filters to the host to let the host what inbound packets it must + * send to CSME. Those filters are received by the host as a + * %SAP_MSG_NOTIF_CSME_FILTERS command. + * The only outbound packets that must be sent to CSME are the DHCP packets. + * Those packets must use the %SAP_MSG_CB_DATA_PACKET message. + */ + +/** + * enum iwl_sap_me_msg_id - the ID of the ME message + * @SAP_ME_MSG_START: See &struct iwl_sap_me_msg_start. + * @SAP_ME_MSG_START_OK: See &struct iwl_sap_me_msg_start_ok. + * @SAP_ME_MSG_CHECK_SHARED_AREA: This message has no payload. + */ +enum iwl_sap_me_msg_id { + SAP_ME_MSG_START = 1, + SAP_ME_MSG_START_OK, + SAP_ME_MSG_CHECK_SHARED_AREA, +}; + +/** + * struct iwl_sap_me_msg_hdr - the header of the ME message + * @type: the type of the message, see &enum iwl_sap_me_msg_id. + * @seq_num: a sequence number used for debug only. + * @len: the length of the mssage. + */ +struct iwl_sap_me_msg_hdr { + __le32 type; + __le32 seq_num; + __le32 len; +} __packed; + +/** + * struct iwl_sap_me_msg_start - used for the %SAP_ME_MSG_START message + * @hdr: See &struct iwl_sap_me_msg_hdr. + * @shared_mem: physical address of SAP shared memory area. + * @init_data_seq_num: seq_num of the first data packet HOST -> CSME. + * @init_notif_seq_num: seq_num of the first notification HOST -> CSME. + * @supported_versions: The host sends to the CSME a zero-terminated array + * of versions its supports. + * + * This message is sent by the host to CSME and will responded by the + * %SAP_ME_MSG_START_OK message. + */ +struct iwl_sap_me_msg_start { + struct iwl_sap_me_msg_hdr hdr; + __le64 shared_mem; + __le16 init_data_seq_num; + __le16 init_notif_seq_num; + u8 supported_versions[64]; +} __packed; + +/** + * struct iwl_sap_me_msg_start_ok - used for the %SAP_ME_MSG_START_OK + * @hdr: See &struct iwl_sap_me_msg_hdr + * @init_data_seq_num: Not used. + * @init_notif_seq_num: Not used + * @supported_version: The version that will be used. + * @reserved: For alignment. + * + * This message is sent by CSME to the host in response to the + * %SAP_ME_MSG_START message. + */ +struct iwl_sap_me_msg_start_ok { + struct iwl_sap_me_msg_hdr hdr; + __le16 init_data_seq_num; + __le16 init_notif_seq_num; + u8 supported_version; + u8 reserved[3]; +} __packed; + +/** + * enum iwl_sap_msg - SAP messages + * @SAP_MSG_NOTIF_BOTH_WAYS_MIN: Not used. + * @SAP_MSG_NOTIF_PING: No payload. Solicitate a response message (check-alive). + * @SAP_MSG_NOTIF_PONG: No payload. The response message. + * @SAP_MSG_NOTIF_BOTH_WAYS_MAX: Not used. + * + * @SAP_MSG_NOTIF_FROM_CSME_MIN: Not used. + * @SAP_MSG_NOTIF_CSME_FILTERS: TODO + * @SAP_MSG_NOTIF_AMT_STATE: Payload is a DW. Any non-zero value means + * that CSME is enabled. + * @SAP_MSG_NOTIF_CSME_REPLY_TO_HOST_OWNERSHIP_REQ: Payload is a DW. 0 means + * the host will not get ownership. Any other value means the host is + * the owner. + * @SAP_MSG_NOTIF_CSME_TAKING_OWNERSHIP: No payload. + * @SAP_MSG_NOTIF_TRIGGER_IP_REFRESH: No payload. + * @SAP_MSG_NOTIF_CSME_CAN_RELEASE_OWNERSHIP: No payload. + * @SAP_MSG_NOTIF_NIC_OWNER: Payload is a DW. See &enum iwl_sap_nic_owner. + * @SAP_MSG_NOTIF_CSME_CONN_STATUS: See &struct iwl_sap_notif_conn_status. + * @SAP_MSG_NOTIF_NVM: See &struct iwl_sap_nvm. + * @SAP_MSG_NOTIF_FROM_CSME_MAX: Not used. + * + * @SAP_MSG_NOTIF_FROM_HOST_MIN: Not used. + * @SAP_MSG_NOTIF_BAND_SELECTION: TODO + * @SAP_MSG_NOTIF_RADIO_STATE: Payload is a DW. + * See &enum iwl_sap_radio_state_bitmap. + * @SAP_MSG_NOTIF_NIC_INFO: See &struct iwl_sap_notif_host_nic_info. + * @SAP_MSG_NOTIF_HOST_ASKS_FOR_NIC_OWNERSHIP: No payload. + * @SAP_MSG_NOTIF_HOST_SUSPENDS: Payload is a DW. Bitmap described in + * &enum iwl_sap_notif_host_suspends_bitmap. + * @SAP_MSG_NOTIF_HOST_RESUMES: Payload is a DW. 0 or 1. 1 says that + * the CSME should re-initialize the init control block. + * @SAP_MSG_NOTIF_HOST_GOES_DOWN: No payload. + * @SAP_MSG_NOTIF_CSME_OWNERSHIP_CONFIRMED: No payload. + * @SAP_MSG_NOTIF_COUNTRY_CODE: See &struct iwl_sap_notif_country_code. + * @SAP_MSG_NOTIF_HOST_LINK_UP: See &struct iwl_sap_notif_host_link_up. + * @SAP_MSG_NOTIF_HOST_LINK_DOWN: See &struct iwl_sap_notif_host_link_down. + * @SAP_MSG_NOTIF_WHO_OWNS_NIC: No payload. + * @SAP_MSG_NOTIF_WIFIDR_DOWN: No payload. + * @SAP_MSG_NOTIF_WIFIDR_UP: No payload. + * @SAP_MSG_NOTIF_HOST_OWNERSHIP_CONFIRMED: No payload. + * @SAP_MSG_NOTIF_SAR_LIMITS: See &struct iwl_sap_notif_sar_limits. + * @SAP_MSG_NOTIF_GET_NVM: No payload. Triggers %SAP_MSG_NOTIF_NVM. + * @SAP_MSG_NOTIF_FROM_HOST_MAX: Not used. + * + * @SAP_MSG_DATA_MIN: Not used. + * @SAP_MSG_DATA_PACKET: Packets that passed the filters defined by + * %SAP_MSG_NOTIF_CSME_FILTERS. The payload is &struct iwl_sap_hdr with + * the payload of the packet immediately afterwards. + * @SAP_MSG_CB_DATA_PACKET: Indicates to CSME that we transmitted a specific + * packet. Used only for DHCP transmitted packets. See + * &struct iwl_sap_cb_data. + * @SAP_MSG_DATA_MAX: Not used. + */ +enum iwl_sap_msg { + SAP_MSG_NOTIF_BOTH_WAYS_MIN = 0, + SAP_MSG_NOTIF_PING = 1, + SAP_MSG_NOTIF_PONG = 2, + SAP_MSG_NOTIF_BOTH_WAYS_MAX, + + SAP_MSG_NOTIF_FROM_CSME_MIN = 500, + SAP_MSG_NOTIF_CSME_FILTERS = SAP_MSG_NOTIF_FROM_CSME_MIN, + /* 501 is deprecated */ + SAP_MSG_NOTIF_AMT_STATE = 502, + SAP_MSG_NOTIF_CSME_REPLY_TO_HOST_OWNERSHIP_REQ = 503, + SAP_MSG_NOTIF_CSME_TAKING_OWNERSHIP = 504, + SAP_MSG_NOTIF_TRIGGER_IP_REFRESH = 505, + SAP_MSG_NOTIF_CSME_CAN_RELEASE_OWNERSHIP = 506, + /* 507 is deprecated */ + /* 508 is deprecated */ + /* 509 is deprecated */ + /* 510 is deprecated */ + SAP_MSG_NOTIF_NIC_OWNER = 511, + SAP_MSG_NOTIF_CSME_CONN_STATUS = 512, + SAP_MSG_NOTIF_NVM = 513, + SAP_MSG_NOTIF_FROM_CSME_MAX, + + SAP_MSG_NOTIF_FROM_HOST_MIN = 1000, + SAP_MSG_NOTIF_BAND_SELECTION = SAP_MSG_NOTIF_FROM_HOST_MIN, + SAP_MSG_NOTIF_RADIO_STATE = 1001, + SAP_MSG_NOTIF_NIC_INFO = 1002, + SAP_MSG_NOTIF_HOST_ASKS_FOR_NIC_OWNERSHIP = 1003, + SAP_MSG_NOTIF_HOST_SUSPENDS = 1004, + SAP_MSG_NOTIF_HOST_RESUMES = 1005, + SAP_MSG_NOTIF_HOST_GOES_DOWN = 1006, + SAP_MSG_NOTIF_CSME_OWNERSHIP_CONFIRMED = 1007, + SAP_MSG_NOTIF_COUNTRY_CODE = 1008, + SAP_MSG_NOTIF_HOST_LINK_UP = 1009, + SAP_MSG_NOTIF_HOST_LINK_DOWN = 1010, + SAP_MSG_NOTIF_WHO_OWNS_NIC = 1011, + SAP_MSG_NOTIF_WIFIDR_DOWN = 1012, + SAP_MSG_NOTIF_WIFIDR_UP = 1013, + /* 1014 is deprecated */ + SAP_MSG_NOTIF_HOST_OWNERSHIP_CONFIRMED = 1015, + SAP_MSG_NOTIF_SAR_LIMITS = 1016, + SAP_MSG_NOTIF_GET_NVM = 1017, + SAP_MSG_NOTIF_FROM_HOST_MAX, + + SAP_MSG_DATA_MIN = 2000, + SAP_MSG_DATA_PACKET = SAP_MSG_DATA_MIN, + SAP_MSG_CB_DATA_PACKET = 2001, + SAP_MSG_DATA_MAX, +}; + +/** + * struct iwl_sap_hdr - prefixes any SAP message + * @type: See &enum iwl_sap_msg. + * @len: The length of the message (header not included). + * @seq_num: For debug. + * @payload: The payload of the message. + */ +struct iwl_sap_hdr { + __le16 type; + __le16 len; + __le32 seq_num; + u8 payload[0]; +}; + +/** + * struct iwl_sap_msg_dw - suits any DW long SAP message + * @hdr: The SAP header + * @val: The value of the DW. + */ +struct iwl_sap_msg_dw { + struct iwl_sap_hdr hdr; + __le32 val; +}; + +/** + * enum iwl_sap_nic_owner - used by %SAP_MSG_NOTIF_NIC_OWNER + * @SAP_NIC_OWNER_UNKNOWN: Not used. + * @SAP_NIC_OWNER_HOST: The host owns the NIC. + * @SAP_NIC_OWNER_ME: CSME owns the NIC. + */ +enum iwl_sap_nic_owner { + SAP_NIC_OWNER_UNKNOWN, + SAP_NIC_OWNER_HOST, + SAP_NIC_OWNER_ME, +}; + +enum iwl_sap_wifi_auth_type { + SAP_WIFI_AUTH_TYPE_OPEN = IWL_MEI_AKM_AUTH_OPEN, + SAP_WIFI_AUTH_TYPE_RSNA = IWL_MEI_AKM_AUTH_RSNA, + SAP_WIFI_AUTH_TYPE_RSNA_PSK = IWL_MEI_AKM_AUTH_RSNA_PSK, + SAP_WIFI_AUTH_TYPE_SAE = IWL_MEI_AKM_AUTH_SAE, + SAP_WIFI_AUTH_TYPE_MAX, +}; + +/** + * enum iwl_sap_wifi_cipher_alg + * @SAP_WIFI_CIPHER_ALG_NONE: TBD + * @SAP_WIFI_CIPHER_ALG_CCMP: TBD + * @SAP_WIFI_CIPHER_ALG_GCMP: TBD + * @SAP_WIFI_CIPHER_ALG_GCMP_256: TBD + */ +enum iwl_sap_wifi_cipher_alg { + SAP_WIFI_CIPHER_ALG_NONE = IWL_MEI_CIPHER_NONE, + SAP_WIFI_CIPHER_ALG_CCMP = IWL_MEI_CIPHER_CCMP, + SAP_WIFI_CIPHER_ALG_GCMP = IWL_MEI_CIPHER_GCMP, + SAP_WIFI_CIPHER_ALG_GCMP_256 = IWL_MEI_CIPHER_GCMP_256, +}; + +/** + * struct iwl_sap_notif_connection_info - nested in other structures + * @ssid_len: The length of the SSID. + * @ssid: The SSID. + * @auth_mode: The authentication mode. See &enum iwl_sap_wifi_auth_type. + * @pairwise_cipher: The cipher used for unicast packets. + * See &enum iwl_sap_wifi_cipher_alg. + * @channel: The channel on which we are associated. + * @band: The band on which we are associated. + * @reserved: For alignment. + * @bssid: The BSSID. + * @reserved1: For alignment. + */ +struct iwl_sap_notif_connection_info { + __le32 ssid_len; + u8 ssid[32]; + __le32 auth_mode; + __le32 pairwise_cipher; + u8 channel; + u8 band; + __le16 reserved; + u8 bssid[6]; + __le16 reserved1; +} __packed; + +/** + * enum iwl_sap_scan_request - for the scan_request field + * @SCAN_REQUEST_FILTERING: Filtering is requested. + * @SCAN_REQUEST_FAST: Fast scan is requested. + */ +enum iwl_sap_scan_request { + SCAN_REQUEST_FILTERING = 1 << 0, + SCAN_REQUEST_FAST = 1 << 1, +}; + +/** + * struct iwl_sap_notif_conn_status - payload of %SAP_MSG_NOTIF_CSME_CONN_STATUS + * @hdr: The SAP header + * @link_prot_state: Non-zero if link protection is active. + * @scan_request: See &enum iwl_sap_scan_request. + * @conn_info: Information about the connection. + */ +struct iwl_sap_notif_conn_status { + struct iwl_sap_hdr hdr; + __le32 link_prot_state; + __le32 scan_request; + struct iwl_sap_notif_connection_info conn_info; +} __packed; + +/** + * enum iwl_sap_radio_state_bitmap - used for %SAP_MSG_NOTIF_RADIO_STATE + * @SAP_SW_RFKILL_DEASSERTED: If set, SW RfKill is de-asserted + * @SAP_HW_RFKILL_DEASSERTED: If set, HW RfKill is de-asserted + * + * If both bits are set, then the radio is on. + */ +enum iwl_sap_radio_state_bitmap { + SAP_SW_RFKILL_DEASSERTED = 1 << 0, + SAP_HW_RFKILL_DEASSERTED = 1 << 1, +}; + +/** + * enum iwl_sap_notif_host_suspends_bitmap - used for %SAP_MSG_NOTIF_HOST_SUSPENDS + * @SAP_OFFER_NIC: TBD + * @SAP_FILTER_CONFIGURED: TBD + * @SAP_NLO_CONFIGURED: TBD + * @SAP_HOST_OWNS_NIC: TBD + * @SAP_LINK_PROTECTED: TBD + */ +enum iwl_sap_notif_host_suspends_bitmap { + SAP_OFFER_NIC = 1 << 0, + SAP_FILTER_CONFIGURED = 1 << 1, + SAP_NLO_CONFIGURED = 1 << 2, + SAP_HOST_OWNS_NIC = 1 << 3, + SAP_LINK_PROTECTED = 1 << 4, +}; + +/** + * struct iwl_sap_notif_country_code - payload of %SAP_MSG_NOTIF_COUNTRY_CODE + * @hdr: The SAP header + * @mcc: The country code. + * @source_id: TBD + * @reserved: For alignment. + * @diff_time: TBD + */ +struct iwl_sap_notif_country_code { + struct iwl_sap_hdr hdr; + __le16 mcc; + u8 source_id; + u8 reserved; + __le32 diff_time; +} __packed; + +/** + * struct iwl_sap_notif_host_link_up - payload of %SAP_MSG_NOTIF_HOST_LINK_UP + * @hdr: The SAP header + * @conn_info: Information about the connection. + * @colloc_channel: The collocated channel + * @colloc_band: The band of the collocated channel. + * @reserved: For alignment. + * @colloc_bssid: The collocated BSSID. + * @reserved1: For alignment. + */ +struct iwl_sap_notif_host_link_up { + struct iwl_sap_hdr hdr; + struct iwl_sap_notif_connection_info conn_info; + u8 colloc_channel; + u8 colloc_band; + __le16 reserved; + u8 colloc_bssid[6]; + __le16 reserved1; +} __packed; + +/** + * enum iwl_sap_notif_link_down_type - used in &struct iwl_sap_notif_host_link_down + * @HOST_LINK_DOWN_TYPE_NONE: TBD + * @HOST_LINK_DOWN_TYPE_TEMPORARY: TBD + * @HOST_LINK_DOWN_TYPE_LONG: TBD + */ +enum iwl_sap_notif_link_down_type { + HOST_LINK_DOWN_TYPE_NONE, + HOST_LINK_DOWN_TYPE_TEMPORARY, + HOST_LINK_DOWN_TYPE_LONG, +}; + +/** + * struct iwl_sap_notif_host_link_down - payload for %SAP_MSG_NOTIF_HOST_LINK_DOWN + * @hdr: The SAP header + * @type: See &enum iwl_sap_notif_link_down_type. + * @reserved: For alignment. + * @reason_valid: If 0, ignore the next field. + * @reason: The reason of the disconnection. + */ +struct iwl_sap_notif_host_link_down { + struct iwl_sap_hdr hdr; + u8 type; + u8 reserved[2]; + u8 reason_valid; + __le32 reason; +} __packed; + +/** + * struct iwl_sap_notif_host_nic_info - payload for %SAP_MSG_NOTIF_NIC_INFO + * @hdr: The SAP header + * @mac_address: The MAC address as configured to the interface. + * @nvm_address: The MAC address as configured in the NVM. + */ +struct iwl_sap_notif_host_nic_info { + struct iwl_sap_hdr hdr; + u8 mac_address[6]; + u8 nvm_address[6]; +} __packed; + +/** + * struct iwl_sap_notif_dw - payload is a dw + * @hdr: The SAP header. + * @dw: The payload. + */ +struct iwl_sap_notif_dw { + struct iwl_sap_hdr hdr; + __le32 dw; +} __packed; + +/** + * struct iwl_sap_notif_sar_limits - payload for %SAP_MSG_NOTIF_SAR_LIMITS + * @hdr: The SAP header + * @sar_chain_info_table: Tx power limits. + */ +struct iwl_sap_notif_sar_limits { + struct iwl_sap_hdr hdr; + __le16 sar_chain_info_table[2][5]; +} __packed; + +/** + * enum iwl_sap_nvm_caps - capabilities for NVM SAP + * @SAP_NVM_CAPS_LARI_SUPPORT: Lari is supported + * @SAP_NVM_CAPS_11AX_SUPPORT: 11AX is supported + */ +enum iwl_sap_nvm_caps { + SAP_NVM_CAPS_LARI_SUPPORT = BIT(0), + SAP_NVM_CAPS_11AX_SUPPORT = BIT(1), +}; + +/** + * struct iwl_sap_nvm - payload for %SAP_MSG_NOTIF_NVM + * @hdr: The SAP header. + * @hw_addr: The MAC address + * @n_hw_addrs: The number of MAC addresses + * @reserved: For alignment. + * @radio_cfg: The radio configuration. + * @caps: See &enum iwl_sap_nvm_caps. + * @nvm_version: The version of the NVM. + * @channels: The data for each channel. + */ +struct iwl_sap_nvm { + struct iwl_sap_hdr hdr; + u8 hw_addr[6]; + u8 n_hw_addrs; + u8 reserved; + __le32 radio_cfg; + __le32 caps; + __le32 nvm_version; + __le32 channels[110]; +} __packed; + +/** + * enum iwl_sap_eth_filter_flags - used in &struct iwl_sap_eth_filter + * @SAP_ETH_FILTER_STOP: Do not process further filters. + * @SAP_ETH_FILTER_COPY: Copy the packet to the CSME. + * @SAP_ETH_FILTER_ENABLED: If false, the filter should be ignored. + */ +enum iwl_sap_eth_filter_flags { + SAP_ETH_FILTER_STOP = BIT(0), + SAP_ETH_FILTER_COPY = BIT(1), + SAP_ETH_FILTER_ENABLED = BIT(2), +}; + +/** + * struct iwl_sap_eth_filter - a L2 filter + * @mac_address: Address to filter. + * @flags: See &enum iwl_sap_eth_filter_flags. + */ +struct iwl_sap_eth_filter { + u8 mac_address[6]; + u8 flags; +} __packed; + +/** + * enum iwl_sap_flex_filter_flags - used in &struct iwl_sap_flex_filter + * @SAP_FLEX_FILTER_COPY: Pass UDP / TCP packets to CSME. + * @SAP_FLEX_FILTER_ENABLED: If false, the filter should be ignored. + * @SAP_FLEX_FILTER_IPV4: Filter requires match on the IP address as well. + * @SAP_FLEX_FILTER_IPV6: Filter requires match on the IP address as well. + * @SAP_FLEX_FILTER_TCP: Filter should be applied on TCP packets. + * @SAP_FLEX_FILTER_UDP: Filter should be applied on UDP packets. + */ +enum iwl_sap_flex_filter_flags { + SAP_FLEX_FILTER_COPY = BIT(0), + SAP_FLEX_FILTER_ENABLED = BIT(1), + SAP_FLEX_FILTER_IPV6 = BIT(2), + SAP_FLEX_FILTER_IPV4 = BIT(3), + SAP_FLEX_FILTER_TCP = BIT(4), + SAP_FLEX_FILTER_UDP = BIT(5), +}; + +/** + * struct iwl_sap_flex_filter - + * @src_port: Source port in network format. + * @dst_port: Destination port in network format. + * @flags: Flags and protocol, see &enum iwl_sap_flex_filter_flags. + * @reserved: For alignment. + */ +struct iwl_sap_flex_filter { + __be16 src_port; + __be16 dst_port; + u8 flags; + u8 reserved; +} __packed; + +/** + * enum iwl_sap_ipv4_filter_flags - used in &struct iwl_sap_ipv4_filter + * @SAP_IPV4_FILTER_ICMP_PASS: Pass ICMP packets to CSME. + * @SAP_IPV4_FILTER_ICMP_COPY: Pass ICMP packets to host. + * @SAP_IPV4_FILTER_ARP_REQ_PASS: Pass ARP requests to CSME. + * @SAP_IPV4_FILTER_ARP_REQ_COPY: Pass ARP requests to host. + * @SAP_IPV4_FILTER_ARP_RESP_PASS: Pass ARP responses to CSME. + * @SAP_IPV4_FILTER_ARP_RESP_COPY: Pass ARP responses to host. + */ +enum iwl_sap_ipv4_filter_flags { + SAP_IPV4_FILTER_ICMP_PASS = BIT(0), + SAP_IPV4_FILTER_ICMP_COPY = BIT(1), + SAP_IPV4_FILTER_ARP_REQ_PASS = BIT(2), + SAP_IPV4_FILTER_ARP_REQ_COPY = BIT(3), + SAP_IPV4_FILTER_ARP_RESP_PASS = BIT(4), + SAP_IPV4_FILTER_ARP_RESP_COPY = BIT(5), +}; + +/** + * struct iwl_sap_ipv4_filter- + * @ipv4_addr: The IP address to filer. + * @flags: See &enum iwl_sap_ipv4_filter_flags. + */ +struct iwl_sap_ipv4_filter { + __be32 ipv4_addr; + __le32 flags; +} __packed; + +/** + * enum iwl_sap_ipv6_filter_flags - + * @SAP_IPV6_ADDR_FILTER_COPY: Pass packets to the host. + * @SAP_IPV6_ADDR_FILTER_ENABLED: If false, the filter should be ignored. + */ +enum iwl_sap_ipv6_filter_flags { + SAP_IPV6_ADDR_FILTER_COPY = BIT(0), + SAP_IPV6_ADDR_FILTER_ENABLED = BIT(1), +}; + +/** + * struct iwl_sap_ipv6_filter - + * @addr_lo24: Lowest 24 bits of the IPv6 address. + * @flags: See &enum iwl_sap_ipv6_filter_flags. + */ +struct iwl_sap_ipv6_filter { + u8 addr_lo24[3]; + u8 flags; +} __packed; + +/** + * enum iwl_sap_icmpv6_filter_flags - + * @SAP_ICMPV6_FILTER_ENABLED: If false, the filter should be ignored. + * @SAP_ICMPV6_FILTER_COPY: Pass packets to the host. + */ +enum iwl_sap_icmpv6_filter_flags { + SAP_ICMPV6_FILTER_ENABLED = BIT(0), + SAP_ICMPV6_FILTER_COPY = BIT(1), +}; + +/** + * enum iwl_sap_vlan_filter_flags - + * @SAP_VLAN_FILTER_VLAN_ID_MSK: TBD + * @SAP_VLAN_FILTER_ENABLED: If false, the filter should be ignored. + */ +enum iwl_sap_vlan_filter_flags { + SAP_VLAN_FILTER_VLAN_ID_MSK = 0x0FFF, + SAP_VLAN_FILTER_ENABLED = BIT(15), +}; + +/** + * struct iwl_sap_oob_filters - Out of band filters (for RX only) + * @flex_filters: Array of &struct iwl_sap_flex_filter. + * @icmpv6_flags: See &enum iwl_sap_icmpv6_filter_flags. + * @ipv6_filters: Array of &struct iwl_sap_ipv6_filter. + * @eth_filters: Array of &struct iwl_sap_eth_filter. + * @reserved: For alignment. + * @ipv4_filter: &struct iwl_sap_ipv4_filter. + * @vlan: See &enum iwl_sap_vlan_filter_flags. + */ +struct iwl_sap_oob_filters { + struct iwl_sap_flex_filter flex_filters[14]; + __le32 icmpv6_flags; + struct iwl_sap_ipv6_filter ipv6_filters[4]; + struct iwl_sap_eth_filter eth_filters[5]; + u8 reserved; + struct iwl_sap_ipv4_filter ipv4_filter; + __le16 vlan[4]; +} __packed; + +/** + * struct iwl_sap_csme_filters - payload of %SAP_MSG_NOTIF_CSME_FILTERS + * @hdr: The SAP header. + * @mode: Not used. + * @mac_address: Not used. + * @reserved: For alignment. + * @cbfilters: Not used. + * @filters: Out of band filters. + */ +struct iwl_sap_csme_filters { + struct iwl_sap_hdr hdr; + __le32 mode; + u8 mac_address[6]; + __le16 reserved; + u8 cbfilters[1728]; + struct iwl_sap_oob_filters filters; +} __packed; + +#define CB_TX_DHCP_FILT_IDX 30 +/** + * struct iwl_sap_cb_data - header to be added for transmitted packets. + * @hdr: The SAP header. + * @reserved: Not used. + * @to_me_filt_status: The filter that matches. Bit %CB_TX_DHCP_FILT_IDX should + * be set for DHCP (the only packet that uses this header). + * @reserved2: Not used. + * @data_len: The length of the payload. + * @payload: The payload of the transmitted packet. + */ +struct iwl_sap_cb_data { + struct iwl_sap_hdr hdr; + __le32 reserved[7]; + __le32 to_me_filt_status; + __le32 reserved2; + __le32 data_len; + u8 payload[]; +}; + +#endif /* __sap_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mei/trace-data.h b/drivers/net/wireless/intel/iwlwifi/mei/trace-data.h new file mode 100644 index 000000000000..83639c6225ca --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mei/trace-data.h @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright(c) 2021 Intel Corporation + */ + +#if !defined(CONFIG_IWLWIFI_DEVICE_TRACING) + +#define trace_iwlmei_sap_data(...) + +#else + +#if !defined(__IWLWIFI_DEVICE_TRACE_IWLWIFI_SAP_DATA) || defined(TRACE_HEADER_MULTI_READ) + +#ifndef __IWLWIFI_DEVICE_TRACE_IWLWIFI_SAP_DATA +enum iwl_sap_data_trace_type { + IWL_SAP_RX_DATA_TO_AIR, + IWL_SAP_TX_DATA_FROM_AIR, + IWL_SAP_RX_DATA_DROPPED_FROM_AIR, + IWL_SAP_TX_DHCP, +}; + +static inline size_t +iwlmei_sap_data_offset(enum iwl_sap_data_trace_type trace_type) +{ + switch (trace_type) { + case IWL_SAP_RX_DATA_TO_AIR: + return 0; + case IWL_SAP_TX_DATA_FROM_AIR: + case IWL_SAP_RX_DATA_DROPPED_FROM_AIR: + return sizeof(struct iwl_sap_hdr); + case IWL_SAP_TX_DHCP: + return sizeof(struct iwl_sap_cb_data); + default: + WARN_ON_ONCE(1); + } + + return 0; +} +#endif + +#define __IWLWIFI_DEVICE_TRACE_IWLWIFI_SAP_DATA + +#include <linux/tracepoint.h> +#include <linux/skbuff.h> +#include "sap.h" + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM iwlmei_sap_data + +TRACE_EVENT(iwlmei_sap_data, + TP_PROTO(const struct sk_buff *skb, + enum iwl_sap_data_trace_type trace_type), + TP_ARGS(skb, trace_type), + TP_STRUCT__entry( + __dynamic_array(u8, data, + skb->len - iwlmei_sap_data_offset(trace_type)) + __field(u32, trace_type) + ), + TP_fast_assign( + size_t offset = iwlmei_sap_data_offset(trace_type); + __entry->trace_type = trace_type; + skb_copy_bits(skb, offset, __get_dynamic_array(data), + skb->len - offset); + ), + TP_printk("sap_data:trace_type %d len %d", + __entry->trace_type, __get_dynamic_array_len(data)) +); + +/* + * If you add something here, add a stub in case + * !defined(CONFIG_IWLWIFI_DEVICE_TRACING) + */ + +#endif /* __IWLWIFI_DEVICE_TRACE_IWLWIFI_SAP_DATA */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace-data +#include <trace/define_trace.h> + +#endif /* CONFIG_IWLWIFI_DEVICE_TRACING */ diff --git a/drivers/net/wireless/intel/iwlwifi/mei/trace.c b/drivers/net/wireless/intel/iwlwifi/mei/trace.c new file mode 100644 index 000000000000..47ac32ef9f69 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mei/trace.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Intel Corporation + */ + +#include <linux/module.h> + +/* sparse doesn't like tracepoint macros */ +#ifndef __CHECKER__ + +#define CREATE_TRACE_POINTS +#include "trace.h" +#include "trace-data.h" + +#endif /* __CHECKER__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mei/trace.h b/drivers/net/wireless/intel/iwlwifi/mei/trace.h new file mode 100644 index 000000000000..45ecb22ec84a --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mei/trace.h @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright(c) 2021 Intel Corporation + */ + +#if !defined(CONFIG_IWLWIFI_DEVICE_TRACING) + +#define trace_iwlmei_sap_cmd(...) +#define trace_iwlmei_me_msg(...) + +#else + +#if !defined(__IWLWIFI_DEVICE_TRACE_IWLWIFI_SAP_CMD) || defined(TRACE_HEADER_MULTI_READ) +#define __IWLWIFI_DEVICE_TRACE_IWLWIFI_SAP_CMD + +#include <linux/tracepoint.h> + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM iwlmei_sap_cmd + +#include "mei/sap.h" + +TRACE_EVENT(iwlmei_sap_cmd, + TP_PROTO(const struct iwl_sap_hdr *sap_cmd, bool tx), + TP_ARGS(sap_cmd, tx), + TP_STRUCT__entry( + __dynamic_array(u8, cmd, + le16_to_cpu(sap_cmd->len) + sizeof(*sap_cmd)) + __field(u8, tx) + __field(u16, type) + __field(u16, len) + __field(u32, seq) + ), + TP_fast_assign( + memcpy(__get_dynamic_array(cmd), sap_cmd, + le16_to_cpu(sap_cmd->len) + sizeof(*sap_cmd)); + __entry->tx = tx; + __entry->type = le16_to_cpu(sap_cmd->type); + __entry->len = le16_to_cpu(sap_cmd->len); + __entry->seq = le32_to_cpu(sap_cmd->seq_num); + ), + TP_printk("sap_cmd %s: type %d len %d seq %d", __entry->tx ? "Tx" : "Rx", + __entry->type, __entry->len, __entry->seq) +); + +TRACE_EVENT(iwlmei_me_msg, + TP_PROTO(const struct iwl_sap_me_msg_hdr *hdr, bool tx), + TP_ARGS(hdr, tx), + TP_STRUCT__entry( + __field(u8, type) + __field(u8, tx) + __field(u32, seq_num) + ), + TP_fast_assign( + __entry->type = le32_to_cpu(hdr->type); + __entry->seq_num = le32_to_cpu(hdr->seq_num); + __entry->tx = tx; + ), + TP_printk("ME message: %s: type %d seq %d", __entry->tx ? "Tx" : "Rx", + __entry->type, __entry->seq_num) +); + +/* + * If you add something here, add a stub in case + * !defined(CONFIG_IWLWIFI_DEVICE_TRACING) + */ + +#endif /* __IWLWIFI_DEVICE_TRACE_IWLWIFI_SAP_CMD */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace +#include <trace/define_trace.h> + +#endif /* CONFIG_IWLWIFI_DEVICE_TRACING */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile index 75fc2d935e5d..11e814b7cad0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile @@ -10,5 +10,6 @@ iwlmvm-y += rfi.o iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o iwlmvm-$(CONFIG_PM) += d3.o +iwlmvm-$(CONFIG_IWLMEI) += vendor-cmd.o ccflags-y += -I $(srctree)/$(src)/../ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index a19f646a324f..b400867e94f0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1391,6 +1391,13 @@ struct iwl_wowlan_status_data { u8 tid_tear_down; struct { + /* including RX MIC key for TKIP */ + u8 key[WOWLAN_KEY_MAX_SIZE]; + u8 len; + u8 flags; + } gtk; + + struct { /* * We store both the TKIP and AES representations * coming from the firmware because we decode the @@ -1400,11 +1407,15 @@ struct iwl_wowlan_status_data { struct { struct ieee80211_key_seq seq[IWL_MAX_TID_COUNT]; } tkip, aes; - /* including RX MIC key for TKIP */ - u8 key[WOWLAN_KEY_MAX_SIZE]; - u8 len; - u8 flags; - } gtk; + + /* + * We use -1 for when we have valid data but don't know + * the key ID from firmware, and thus it needs to be + * installed with the last key (depending on rekeying). + */ + s8 key_id; + bool valid; + } gtk_seq[2]; struct { /* Same as above */ @@ -1556,12 +1567,10 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm, kfree_skb(pkt); } -static void iwl_mvm_aes_sc_to_seq(struct aes_sc *sc, - struct ieee80211_key_seq *seq) +static void iwl_mvm_le64_to_aes_seq(__le64 le_pn, struct ieee80211_key_seq *seq) { - u64 pn; + u64 pn = le64_to_cpu(le_pn); - pn = le64_to_cpu(sc->pn); seq->ccmp.pn[0] = pn >> 40; seq->ccmp.pn[1] = pn >> 32; seq->ccmp.pn[2] = pn >> 24; @@ -1570,6 +1579,20 @@ static void iwl_mvm_aes_sc_to_seq(struct aes_sc *sc, seq->ccmp.pn[5] = pn; } +static void iwl_mvm_aes_sc_to_seq(struct aes_sc *sc, + struct ieee80211_key_seq *seq) +{ + iwl_mvm_le64_to_aes_seq(sc->pn, seq); +} + +static void iwl_mvm_le64_to_tkip_seq(__le64 le_pn, struct ieee80211_key_seq *seq) +{ + u64 pn = le64_to_cpu(le_pn); + + seq->tkip.iv16 = (u16)pn; + seq->tkip.iv32 = (u32)(pn >> 16); +} + static void iwl_mvm_tkip_sc_to_seq(struct tkip_sc *sc, struct ieee80211_key_seq *seq) { @@ -1630,10 +1653,12 @@ static void iwl_mvm_convert_key_counters(struct iwl_wowlan_status_data *status, /* GTK RX counters */ for (i = 0; i < IWL_MAX_TID_COUNT; i++) { iwl_mvm_tkip_sc_to_seq(&sc->tkip.multicast_rsc[i], - &status->gtk.tkip.seq[i]); + &status->gtk_seq[0].tkip.seq[i]); iwl_mvm_aes_sc_to_seq(&sc->aes.multicast_rsc[i], - &status->gtk.aes.seq[i]); + &status->gtk_seq[0].aes.seq[i]); } + status->gtk_seq[0].valid = true; + status->gtk_seq[0].key_id = -1; /* PTK TX counter */ status->ptk.tkip.tx_pn = (u64)le16_to_cpu(sc->tkip.tsc.iv16) | @@ -1649,24 +1674,103 @@ static void iwl_mvm_convert_key_counters(struct iwl_wowlan_status_data *status, } } -static void iwl_mvm_set_key_rx_seq(struct iwl_mvm *mvm, - struct ieee80211_key_conf *key, - struct iwl_wowlan_status_data *status) +static void +iwl_mvm_convert_key_counters_v5_gtk_seq(struct iwl_wowlan_status_data *status, + struct iwl_wowlan_all_rsc_tsc_v5 *sc, + unsigned int idx, unsigned int key_id) +{ + int tid; + + for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { + iwl_mvm_le64_to_tkip_seq(sc->mcast_rsc[idx][tid], + &status->gtk_seq[idx].tkip.seq[tid]); + iwl_mvm_le64_to_aes_seq(sc->mcast_rsc[idx][tid], + &status->gtk_seq[idx].aes.seq[tid]); + } + + status->gtk_seq[idx].valid = true; + status->gtk_seq[idx].key_id = key_id; +} + +static void +iwl_mvm_convert_key_counters_v5(struct iwl_wowlan_status_data *status, + struct iwl_wowlan_all_rsc_tsc_v5 *sc) +{ + int i, tid; + + BUILD_BUG_ON(IWL_MAX_TID_COUNT > IWL_MAX_TID_COUNT); + BUILD_BUG_ON(IWL_MAX_TID_COUNT > IWL_NUM_RSC); + BUILD_BUG_ON(ARRAY_SIZE(sc->mcast_rsc) != ARRAY_SIZE(status->gtk_seq)); + + /* GTK RX counters */ + for (i = 0; i < ARRAY_SIZE(sc->mcast_key_id_map); i++) { + u8 entry = sc->mcast_key_id_map[i]; + + if (entry < ARRAY_SIZE(sc->mcast_rsc)) + iwl_mvm_convert_key_counters_v5_gtk_seq(status, sc, + entry, i); + } + + /* PTK TX counters not needed, assigned in device */ + + /* PTK RX counters */ + for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { + iwl_mvm_le64_to_tkip_seq(sc->ucast_rsc[tid], + &status->ptk.tkip.seq[tid]); + iwl_mvm_le64_to_aes_seq(sc->ucast_rsc[tid], + &status->ptk.aes.seq[tid]); + } +} + +static void iwl_mvm_set_key_rx_seq_idx(struct ieee80211_key_conf *key, + struct iwl_wowlan_status_data *status, + int idx) { switch (key->cipher) { case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: - iwl_mvm_set_key_rx_seq_tids(key, status->gtk.aes.seq); + iwl_mvm_set_key_rx_seq_tids(key, status->gtk_seq[idx].aes.seq); break; case WLAN_CIPHER_SUITE_TKIP: - iwl_mvm_set_key_rx_seq_tids(key, status->gtk.tkip.seq); + iwl_mvm_set_key_rx_seq_tids(key, status->gtk_seq[idx].tkip.seq); break; default: WARN_ON(1); } } +static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, + struct iwl_wowlan_status_data *status, + bool installed) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(status->gtk_seq); i++) { + if (!status->gtk_seq[i].valid) + continue; + + /* Handle the case where we know the key ID */ + if (status->gtk_seq[i].key_id == key->keyidx) { + s8 new_key_id = -1; + + if (status->num_of_gtk_rekeys) + new_key_id = status->gtk.flags & + IWL_WOWLAN_GTK_IDX_MASK; + + /* Don't install a new key's value to an old key */ + if (new_key_id != key->keyidx) + iwl_mvm_set_key_rx_seq_idx(key, status, i); + continue; + } + + /* handle the case where we didn't, last key only */ + if (status->gtk_seq[i].key_id == -1 && + (!status->num_of_gtk_rekeys || installed)) + iwl_mvm_set_key_rx_seq_idx(key, status, i); + } +} + struct iwl_mvm_d3_gtk_iter_data { struct iwl_mvm *mvm; struct iwl_wowlan_status_data *status; @@ -1740,8 +1844,9 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, if (data->status->num_of_gtk_rekeys) ieee80211_remove_key(key); - else if (data->last_gtk == key) - iwl_mvm_set_key_rx_seq(data->mvm, key, data->status); + + if (data->last_gtk == key) + iwl_mvm_set_key_rx_seq(key, data->status, false); } static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, @@ -1825,7 +1930,7 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, key = ieee80211_gtk_rekey_add(vif, &conf.conf); if (IS_ERR(key)) return false; - iwl_mvm_set_key_rx_seq(mvm, key, status); + iwl_mvm_set_key_rx_seq(key, status, true); replay_ctr = cpu_to_be64(status->replay_ctr); @@ -1893,9 +1998,10 @@ iwl_mvm_parse_wowlan_status_common_ ## _ver(struct iwl_mvm *mvm, \ iwl_mvm_parse_wowlan_status_common(v6) iwl_mvm_parse_wowlan_status_common(v7) iwl_mvm_parse_wowlan_status_common(v9) +iwl_mvm_parse_wowlan_status_common(v12) -static void iwl_mvm_convert_gtk(struct iwl_wowlan_status_data *status, - struct iwl_wowlan_gtk_status *data) +static void iwl_mvm_convert_gtk_v2(struct iwl_wowlan_status_data *status, + struct iwl_wowlan_gtk_status_v2 *data) { BUILD_BUG_ON(sizeof(status->gtk.key) < sizeof(data->key)); BUILD_BUG_ON(NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY + @@ -1913,6 +2019,26 @@ static void iwl_mvm_convert_gtk(struct iwl_wowlan_status_data *status, data->tkip_mic_key, sizeof(data->tkip_mic_key)); } +static void iwl_mvm_convert_gtk_v3(struct iwl_wowlan_status_data *status, + struct iwl_wowlan_gtk_status_v3 *data) +{ + /* The parts we need are identical in v2 and v3 */ +#define CHECK(_f) do { \ + BUILD_BUG_ON(offsetof(struct iwl_wowlan_gtk_status_v2, _f) != \ + offsetof(struct iwl_wowlan_gtk_status_v3, _f)); \ + BUILD_BUG_ON(offsetofend(struct iwl_wowlan_gtk_status_v2, _f) !=\ + offsetofend(struct iwl_wowlan_gtk_status_v3, _f)); \ +} while (0) + + CHECK(key); + CHECK(key_len); + CHECK(key_flags); + CHECK(tkip_mic_key); +#undef CHECK + + iwl_mvm_convert_gtk_v2(status, (void *)data); +} + static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status, struct iwl_wowlan_igtk_status *data) { @@ -2012,7 +2138,7 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id) goto out_free_resp; iwl_mvm_convert_key_counters(status, &v7->gtk[0].rsc.all_tsc_rsc); - iwl_mvm_convert_gtk(status, &v7->gtk[0]); + iwl_mvm_convert_gtk_v2(status, &v7->gtk[0]); iwl_mvm_convert_igtk(status, &v7->igtk[0]); } else if (notif_ver == 9 || notif_ver == 10 || notif_ver == 11) { struct iwl_wowlan_status_v9 *v9 = (void *)cmd.resp_pkt->data; @@ -2025,10 +2151,22 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id) goto out_free_resp; iwl_mvm_convert_key_counters(status, &v9->gtk[0].rsc.all_tsc_rsc); - iwl_mvm_convert_gtk(status, &v9->gtk[0]); + iwl_mvm_convert_gtk_v2(status, &v9->gtk[0]); iwl_mvm_convert_igtk(status, &v9->igtk[0]); status->tid_tear_down = v9->tid_tear_down; + } else if (notif_ver == 12) { + struct iwl_wowlan_status_v12 *v12 = (void *)cmd.resp_pkt->data; + + status = iwl_mvm_parse_wowlan_status_common_v12(mvm, v12, len); + if (IS_ERR(status)) + goto out_free_resp; + + iwl_mvm_convert_key_counters_v5(status, &v12->gtk[0].sc); + iwl_mvm_convert_gtk_v3(status, &v12->gtk[0]); + iwl_mvm_convert_igtk(status, &v12->igtk[0]); + + status->tid_tear_down = v12->tid_tear_down; } else { IWL_ERR(mvm, "Firmware advertises unknown WoWLAN status response %d!\n", diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index ff66001d507e..f1e9d2c99051 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1022,6 +1022,11 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, if (mvm->fw_restart >= 0) mvm->fw_restart++; + if (count == 6 && !strcmp(buf, "nolog\n")) { + set_bit(IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, &mvm->status); + set_bit(STATUS_SUPPRESS_CMD_ERROR_ONCE, &mvm->trans->status); + } + /* take the return value to make compiler happy - it will fail anyway */ ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(LONG_GROUP, REPLY_ERROR), @@ -1038,6 +1043,9 @@ static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf, if (!iwl_mvm_firmware_running(mvm)) return -EIO; + if (count == 6 && !strcmp(buf, "nolog\n")) + set_bit(IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, &mvm->status); + iwl_force_nmi(mvm->trans); return count; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 73a82f07dc59..083f86fa5017 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -15,7 +15,7 @@ #include "fw/api/datapath.h" #include "fw/api/phy.h" #include "fw/api/config.h" -#include "fw/api/soc.h" +#include "fw/api/system.h" #include "fw/api/alive.h" #include "fw/api/binding.h" #include "fw/api/cmdhdr.h" diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 863fec150e53..187637c81d1a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -123,13 +123,15 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, struct iwl_lmac_alive *lmac2 = NULL; u16 status; u32 lmac_error_event_table, umac_error_table; + u32 version = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + UCODE_ALIVE_NTFY, 0); /* * For v5 and above, we can check the version, for older * versions we need to check the size. */ - if (iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, - UCODE_ALIVE_NTFY, 0) == 5) { + if (version == 5 || version == 6) { + /* v5 and v6 are compatible (only IMR addition) */ struct iwl_alive_ntf_v5 *palive; if (pkt_len < sizeof(*palive)) @@ -516,7 +518,6 @@ static void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm, cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_D); } } - #else /* CONFIG_ACPI */ static void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm, @@ -525,6 +526,49 @@ static void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm, } #endif /* CONFIG_ACPI */ +#if defined(CONFIG_ACPI) && defined(CONFIG_EFI) +static int iwl_mvm_sgom_init(struct iwl_mvm *mvm) +{ + u8 cmd_ver; + int ret; + struct iwl_host_cmd cmd = { + .id = WIDE_ID(REGULATORY_AND_NVM_GROUP, + SAR_OFFSET_MAPPING_TABLE_CMD), + .flags = 0, + .data[0] = &mvm->fwrt.sgom_table, + .len[0] = sizeof(mvm->fwrt.sgom_table), + .dataflags[0] = IWL_HCMD_DFL_NOCOPY, + }; + + if (!mvm->fwrt.sgom_enabled) { + IWL_DEBUG_RADIO(mvm, "SGOM table is disabled\n"); + return 0; + } + + cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, REGULATORY_AND_NVM_GROUP, + SAR_OFFSET_MAPPING_TABLE_CMD, + IWL_FW_CMD_VER_UNKNOWN); + + if (cmd_ver != 2) { + IWL_DEBUG_RADIO(mvm, "command version is unsupported. version = %d\n", + cmd_ver); + return 0; + } + + ret = iwl_mvm_send_cmd(mvm, &cmd); + if (ret < 0) + IWL_ERR(mvm, "failed to send SAR_OFFSET_MAPPING_CMD (%d)\n", ret); + + return ret; +} +#else + +static int iwl_mvm_sgom_init(struct iwl_mvm *mvm) +{ + return 0; +} +#endif + static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) { struct iwl_phy_cfg_cmd_v3 phy_cfg_cmd; @@ -757,6 +801,8 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) if (ret) return ret; + iwl_mei_set_power_limit(per_chain); + IWL_DEBUG_RADIO(mvm, "Sending REDUCE_TX_POWER_CMD per chain\n"); return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd); } @@ -1336,6 +1382,7 @@ static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) { } + #endif /* CONFIG_ACPI */ void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags) @@ -1401,7 +1448,6 @@ static int iwl_mvm_load_rt_fw(struct iwl_mvm *mvm) if (iwl_mvm_has_unified_ucode(mvm)) return iwl_run_unified_mvm_ucode(mvm); - WARN_ON(!mvm->nvm_data); ret = iwl_run_init_mvm_ucode(mvm); if (ret) { @@ -1631,6 +1677,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm) else if (ret < 0) goto error; + ret = iwl_mvm_sgom_init(mvm); + if (ret) + goto error; + iwl_mvm_tas_init(mvm); iwl_mvm_leds_sync(mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index b96ccabd1596..86077388083a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -16,6 +16,7 @@ #include <net/ieee80211_radiotap.h> #include <net/tcp.h> +#include "iwl-drv.h" #include "iwl-op-mode.h" #include "iwl-io.h" #include "mvm.h" @@ -190,6 +191,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, if (IS_ERR_OR_NULL(resp)) { IWL_DEBUG_LAR(mvm, "Could not get update from FW %d\n", PTR_ERR_OR_ZERO(resp)); + resp = NULL; goto out; } @@ -211,7 +213,6 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, __le16_to_cpu(resp->cap), resp_ver); /* Store the return source id */ src_id = resp->source_id; - kfree(resp); if (IS_ERR_OR_NULL(regd)) { IWL_DEBUG_LAR(mvm, "Could not get parse update from FW %d\n", PTR_ERR_OR_ZERO(regd)); @@ -223,7 +224,10 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, mvm->lar_regdom_set = true; mvm->mcc_src = src_id; + iwl_mei_set_country_code(__le16_to_cpu(resp->mcc)); + out: + kfree(resp); return regd; } @@ -717,6 +721,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_PROTECTED_TWT); + iwl_mvm_vendor_cmds_register(mvm); + hw->wiphy->available_antennas_tx = iwl_mvm_get_valid_tx_ant(mvm); hw->wiphy->available_antennas_rx = iwl_mvm_get_valid_rx_ant(mvm); @@ -1083,6 +1089,27 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm) lockdep_assert_held(&mvm->mutex); + ret = iwl_mvm_mei_get_ownership(mvm); + if (ret) + return ret; + + if (mvm->mei_nvm_data) { + /* We got the NIC, we can now free the MEI NVM data */ + kfree(mvm->mei_nvm_data); + mvm->mei_nvm_data = NULL; + + /* + * We can't free the nvm_data we allocated based on the SAP + * data because we registered to cfg80211 with the channels + * allocated on mvm->nvm_data. Keep a pointer in temp_nvm_data + * just in order to be able free it later. + * NULLify nvm_data so that we will read the NVM from the + * firmware this time. + */ + mvm->temp_nvm_data = mvm->nvm_data; + mvm->nvm_data = NULL; + } + if (test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status)) { /* * Now convert the HW_RESTART_REQUESTED flag to IN_HW_RESTART @@ -1117,11 +1144,34 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; + int retry, max_retry = 0; mutex_lock(&mvm->mutex); - ret = __iwl_mvm_mac_start(mvm); + + /* we are starting the mac not in error flow, and restart is enabled */ + if (!test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status) && + iwlwifi_mod_params.fw_restart) { + max_retry = IWL_MAX_INIT_RETRY; + /* + * This will prevent mac80211 recovery flows to trigger during + * init failures + */ + set_bit(IWL_MVM_STATUS_STARTING, &mvm->status); + } + + for (retry = 0; retry <= max_retry; retry++) { + ret = __iwl_mvm_mac_start(mvm); + if (!ret) + break; + + IWL_ERR(mvm, "mac start retry %d\n", retry); + } + clear_bit(IWL_MVM_STATUS_STARTING, &mvm->status); + mutex_unlock(&mvm->mutex); + iwl_mvm_mei_set_sw_rfkill_state(mvm); + return ret; } @@ -1239,6 +1289,8 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) */ flush_work(&mvm->roc_done_wk); + iwl_mvm_mei_set_sw_rfkill_state(mvm); + mutex_lock(&mvm->mutex); __iwl_mvm_mac_stop(mvm); mutex_unlock(&mvm->mutex); @@ -1509,6 +1561,15 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, mvm->monitor_on = true; iwl_mvm_vif_dbgfs_register(mvm, vif); + + if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && + vif->type == NL80211_IFTYPE_STATION && !vif->p2p && + !mvm->csme_vif && mvm->mei_registered) { + iwl_mei_set_nic_info(vif->addr, mvm->nvm_data->hw_addr); + iwl_mei_set_netdev(ieee80211_vif_to_wdev(vif)->netdev); + mvm->csme_vif = vif; + } + goto out_unlock; out_unbind: @@ -1561,6 +1622,11 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); + if (vif == mvm->csme_vif) { + iwl_mei_set_netdev(NULL); + mvm->csme_vif = NULL; + } + probe_data = rcu_dereference_protected(mvmvif->probe_resp_data, lockdep_is_held(&mvm->mutex)); RCU_INIT_POINTER(mvmvif->probe_resp_data, NULL); @@ -1666,6 +1732,7 @@ static void iwl_mvm_recalc_multicast(struct iwl_mvm *mvm) struct iwl_mvm_mc_iter_data iter_data = { .mvm = mvm, }; + int ret; lockdep_assert_held(&mvm->mutex); @@ -1675,6 +1742,22 @@ static void iwl_mvm_recalc_multicast(struct iwl_mvm *mvm) ieee80211_iterate_active_interfaces_atomic( mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_mc_iface_iterator, &iter_data); + + /* + * Send a (synchronous) ech command so that we wait for the + * multiple asynchronous MCAST_FILTER_CMD commands sent by + * the interface iterator. Otherwise, we might get here over + * and over again (by userspace just sending a lot of these) + * and the CPU can send them faster than the firmware can + * process them. + * Note that the CPU is still faster - but with this we'll + * actually send fewer commands overall because the CPU will + * not schedule the work in mac80211 as frequently if it's + * still running when rescheduled (possibly multiple times). + */ + ret = iwl_mvm_send_cmd_pdu(mvm, ECHO_CMD, 0, 0, NULL); + if (ret) + IWL_ERR(mvm, "Failed to synchronize multicast groups update\n"); } static u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw, @@ -2371,6 +2454,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, IEEE80211_SMPS_DYNAMIC); } } else if (mvmvif->ap_sta_id != IWL_MVM_INVALID_STA) { + iwl_mvm_mei_host_disassociated(mvm); /* * If update fails - SF might be running in associated * mode while disassociated - which is forbidden. @@ -3107,6 +3191,69 @@ static void iwl_mvm_reset_cca_40mhz_workaround(struct iwl_mvm *mvm, } } +static void iwl_mvm_mei_host_associated(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct iwl_mvm_sta *mvm_sta) +{ +#if IS_ENABLED(CONFIG_IWLMEI) + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mei_conn_info conn_info = { + .ssid_len = vif->bss_conf.ssid_len, + .channel = vif->bss_conf.chandef.chan->hw_value, + }; + + if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) + return; + + if (!mvm->mei_registered) + return; + + switch (mvm_sta->pairwise_cipher) { + case WLAN_CIPHER_SUITE_CCMP: + conn_info.pairwise_cipher = IWL_MEI_CIPHER_CCMP; + break; + case WLAN_CIPHER_SUITE_GCMP: + conn_info.pairwise_cipher = IWL_MEI_CIPHER_GCMP; + break; + case WLAN_CIPHER_SUITE_GCMP_256: + conn_info.pairwise_cipher = IWL_MEI_CIPHER_GCMP_256; + break; + case 0: + /* open profile */ + break; + default: + /* cipher not supported, don't send anything to iwlmei */ + return; + } + + switch (mvmvif->rekey_data.akm) { + case WLAN_AKM_SUITE_SAE & 0xff: + conn_info.auth_mode = IWL_MEI_AKM_AUTH_SAE; + break; + case WLAN_AKM_SUITE_PSK & 0xff: + conn_info.auth_mode = IWL_MEI_AKM_AUTH_RSNA_PSK; + break; + case WLAN_AKM_SUITE_8021X & 0xff: + conn_info.auth_mode = IWL_MEI_AKM_AUTH_RSNA; + break; + case 0: + /* open profile */ + conn_info.auth_mode = IWL_MEI_AKM_AUTH_OPEN; + break; + default: + /* auth method / AKM not supported */ + /* TODO: All the FT vesions of these? */ + return; + } + + memcpy(conn_info.ssid, vif->bss_conf.ssid, vif->bss_conf.ssid_len); + memcpy(conn_info.bssid, vif->bss_conf.bssid, ETH_ALEN); + + /* TODO: add support for collocated AP data */ + iwl_mei_host_associated(&conn_info, NULL); +#endif +} + static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -3251,12 +3398,18 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, * multicast data frames can be forwarded to the driver */ iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); + iwl_mvm_mei_host_associated(mvm, vif, mvm_sta); } iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band, true); } else if (old_state == IEEE80211_STA_AUTHORIZED && new_state == IEEE80211_STA_ASSOC) { + /* once we move into assoc state, need to update rate scale to + * disable using wide bandwidth + */ + iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band, + false); if (!sta->tdls) { /* Multicast data frames are no longer allowed */ iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); @@ -3279,16 +3432,16 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, if (vif->type == NL80211_IFTYPE_AP) { mvmvif->ap_assoc_sta_count--; iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); - } else if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { - /* remove session protection if still running */ + } else if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) iwl_mvm_stop_session_protection(mvm, vif); - } ret = 0; } else if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_NONE) { ret = 0; } else if (old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST) { + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) + iwl_mvm_stop_session_protection(mvm, vif); ret = iwl_mvm_rm_sta(mvm, vif, sta); if (sta->tdls) { iwl_mvm_recalc_tdls_state(mvm, vif, false); @@ -3454,12 +3607,15 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_sta *mvmsta; + struct iwl_mvm_sta *mvmsta = NULL; struct iwl_mvm_key_pn *ptk_pn; int keyidx = key->keyidx; int ret, i; u8 key_offset; + if (sta) + mvmsta = iwl_mvm_sta_from_mac80211(sta); + switch (key->cipher) { case WLAN_CIPHER_SUITE_TKIP: if (!mvm->trans->trans_cfg->gen2) { @@ -3560,7 +3716,7 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw, } if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && - sta && iwl_mvm_has_new_rx_api(mvm) && + mvmsta && iwl_mvm_has_new_rx_api(mvm) && key->flags & IEEE80211_KEY_FLAG_PAIRWISE && (key->cipher == WLAN_CIPHER_SUITE_CCMP || key->cipher == WLAN_CIPHER_SUITE_GCMP || @@ -3568,7 +3724,6 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw, struct ieee80211_key_seq seq; int tid, q; - mvmsta = iwl_mvm_sta_from_mac80211(sta); WARN_ON(rcu_access_pointer(mvmsta->ptk_pn[keyidx])); ptk_pn = kzalloc(struct_size(ptk_pn, q, mvm->trans->num_rx_queues), @@ -3595,6 +3750,9 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw, else key_offset = STA_KEY_IDX_INVALID; + if (mvmsta && key->flags & IEEE80211_KEY_FLAG_PAIRWISE) + mvmsta->pairwise_cipher = key->cipher; + IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n"); ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, key_offset); if (ret) { @@ -3635,12 +3793,11 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw, break; } - if (sta && iwl_mvm_has_new_rx_api(mvm) && + if (mvmsta && iwl_mvm_has_new_rx_api(mvm) && key->flags & IEEE80211_KEY_FLAG_PAIRWISE && (key->cipher == WLAN_CIPHER_SUITE_CCMP || key->cipher == WLAN_CIPHER_SUITE_GCMP || key->cipher == WLAN_CIPHER_SUITE_GCMP_256)) { - mvmsta = iwl_mvm_sta_from_mac80211(sta); ptk_pn = rcu_dereference_protected( mvmsta->ptk_pn[keyidx], lockdep_is_held(&mvm->mutex)); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 2b1dcd60e00f..1393e5de2e9a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -30,6 +30,7 @@ #include "fw/runtime.h" #include "fw/dbg.h" #include "fw/acpi.h" +#include "mei/iwl-mei.h" #include "iwl-nvm-parse.h" #include <linux/average.h> @@ -93,11 +94,10 @@ struct iwl_mvm_phy_ctxt { enum nl80211_chan_width width; - /* - * TODO: This should probably be removed. Currently here only for rate - * scaling algorithm - */ struct ieee80211_channel *channel; + + /* track for RLC config command */ + u32 center_freq1; }; struct iwl_mvm_time_event_data { @@ -830,6 +830,18 @@ struct iwl_mvm { const char *nvm_file_name; struct iwl_nvm_data *nvm_data; + struct iwl_mei_nvm *mei_nvm_data; + struct iwl_mvm_csme_conn_info __rcu *csme_conn_info; + bool mei_rfkill_blocked; + bool mei_registered; + struct work_struct sap_connected_wk; + + /* + * NVM built based on the SAP data but that we can't free even after + * we get ownership because it contains the cfg80211's channel. + */ + struct iwl_nvm_data *temp_nvm_data; + /* NVM sections */ struct iwl_nvm_section nvm_sections[NVM_MAX_NUM_SECTIONS]; @@ -1021,6 +1033,8 @@ struct iwl_mvm { /* Indicate if 32Khz external clock is valid */ u32 ext_clock_valid; + /* This vif used by CSME to send / receive traffic */ + struct ieee80211_vif *csme_vif; struct ieee80211_vif __rcu *csa_vif; struct ieee80211_vif __rcu *csa_tx_blocked_vif; u8 csa_tx_block_bcn_timeout; @@ -1123,6 +1137,10 @@ struct iwl_mvm { * @IWL_MVM_STATUS_FIRMWARE_RUNNING: firmware is running * @IWL_MVM_STATUS_NEED_FLUSH_P2P: need to flush P2P bcast STA * @IWL_MVM_STATUS_IN_D3: in D3 (or at least about to go into it) + * @IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE: suppress one error log + * if this is set, when intentionally triggered + * @IWL_MVM_STATUS_STARTING: starting mac, + * used to disable restart flow while in STARTING state */ enum iwl_mvm_status { IWL_MVM_STATUS_HW_RFKILL, @@ -1134,6 +1152,13 @@ enum iwl_mvm_status { IWL_MVM_STATUS_FIRMWARE_RUNNING, IWL_MVM_STATUS_NEED_FLUSH_P2P, IWL_MVM_STATUS_IN_D3, + IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, + IWL_MVM_STATUS_STARTING, +}; + +struct iwl_mvm_csme_conn_info { + struct rcu_head rcu_head; + struct iwl_mei_conn_info conn_info; }; /* Keep track of completed init configuration */ @@ -1939,6 +1964,17 @@ void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm); int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm); int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget); +#if IS_ENABLED(CONFIG_IWLMEI) + +/* vendor commands */ +void iwl_mvm_vendor_cmds_register(struct iwl_mvm *mvm); + +#else + +static inline void iwl_mvm_vendor_cmds_register(struct iwl_mvm *mvm) {} + +#endif + /* Location Aware Regulatory */ struct iwl_mcc_update_resp * iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, @@ -2158,4 +2194,47 @@ enum iwl_location_cipher iwl_mvm_cipher_to_location_cipher(u32 cipher) return IWL_LOCATION_CIPHER_INVALID; } } + +struct iwl_mvm_csme_conn_info *iwl_mvm_get_csme_conn_info(struct iwl_mvm *mvm); +static inline int iwl_mvm_mei_get_ownership(struct iwl_mvm *mvm) +{ + if (mvm->mei_registered) + return iwl_mei_get_ownership(); + return 0; +} + +static inline void iwl_mvm_mei_tx_copy_to_csme(struct iwl_mvm *mvm, + struct sk_buff *skb, + unsigned int ivlen) +{ + if (mvm->mei_registered) + iwl_mei_tx_copy_to_csme(skb, ivlen); +} + +static inline void iwl_mvm_mei_host_disassociated(struct iwl_mvm *mvm) +{ + if (mvm->mei_registered) + iwl_mei_host_disassociated(); +} + +static inline void iwl_mvm_mei_device_down(struct iwl_mvm *mvm) +{ + if (mvm->mei_registered) + iwl_mei_device_down(); +} + +static inline void iwl_mvm_mei_set_sw_rfkill_state(struct iwl_mvm *mvm) +{ + bool sw_rfkill = + mvm->hw_registered ? rfkill_blocked(mvm->hw->wiphy->rfkill) : false; + + if (mvm->mei_registered) + iwl_mei_set_rfkill_state(iwl_mvm_is_radio_killed(mvm), + sw_rfkill); +} + +void iwl_mvm_send_roaming_forbidden_event(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + bool forbidden); + #endif /* __IWL_MVM_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 232ad531d612..f12e571d3581 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -26,6 +26,7 @@ #include "time-event.h" #include "fw-api.h" #include "fw/acpi.h" +#include "fw/uefi.h" #define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux" MODULE_DESCRIPTION(DRV_DESCRIPTION); @@ -78,7 +79,7 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash; - u32 reg_val = 0; + u32 reg_val; u32 phy_config = iwl_mvm_get_phy_config(mvm); radio_cfg_type = (phy_config & FW_PHY_CFG_RADIO_TYPE) >> @@ -89,10 +90,7 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) FW_PHY_CFG_RADIO_DASH_POS; /* SKU control */ - reg_val |= CSR_HW_REV_STEP(mvm->trans->hw_rev) << - CSR_HW_IF_CONFIG_REG_POS_MAC_STEP; - reg_val |= CSR_HW_REV_DASH(mvm->trans->hw_rev) << - CSR_HW_IF_CONFIG_REG_POS_MAC_DASH; + reg_val = CSR_HW_REV_STEP_DASH(mvm->trans->hw_rev); /* radio configuration */ reg_val |= radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE; @@ -117,8 +115,7 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) reg_val |= CSR_HW_IF_CONFIG_REG_D3_DEBUG; iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | - CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP | + CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP_DASH | CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE | CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP | CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH | @@ -502,6 +499,9 @@ static const struct iwl_hcmd_names iwl_mvm_system_names[] = { HCMD_NAME(SHARED_MEM_CFG_CMD), HCMD_NAME(INIT_EXTENDED_CFG_CMD), HCMD_NAME(FW_ERROR_RECOVERY_CMD), + HCMD_NAME(RFI_CONFIG_CMD), + HCMD_NAME(RFI_GET_FREQ_TABLE_CMD), + HCMD_NAME(SYSTEM_FEATURES_CONTROL_CMD), }; /* Please keep this array *SORTED* by hex value. @@ -534,6 +534,7 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = { HCMD_NAME(UPDATE_MU_GROUPS_CMD), HCMD_NAME(TRIGGER_RX_QUEUES_NOTIF_CMD), HCMD_NAME(STA_HE_CTXT_CMD), + HCMD_NAME(RLC_CONFIG_CMD), HCMD_NAME(RFH_QUEUE_CONFIG_CMD), HCMD_NAME(TLC_MNG_CONFIG_CMD), HCMD_NAME(CHEST_COLLECTOR_FILTER_CONFIG_CMD), @@ -683,13 +684,43 @@ static const struct iwl_fw_runtime_ops iwl_mvm_fwrt_ops = { static int iwl_mvm_start_get_nvm(struct iwl_mvm *mvm) { + struct iwl_trans *trans = mvm->trans; int ret; + if (trans->csme_own) { + if (WARN(!mvm->mei_registered, + "csme is owner, but we aren't registered to iwlmei\n")) + goto get_nvm_from_fw; + + mvm->mei_nvm_data = iwl_mei_get_nvm(); + if (mvm->mei_nvm_data) { + /* + * mvm->mei_nvm_data is set and because of that, + * we'll load the NVM from the FW when we'll get + * ownership. + */ + mvm->nvm_data = + iwl_parse_mei_nvm_data(trans, trans->cfg, + mvm->mei_nvm_data, mvm->fw); + return 0; + } + + IWL_ERR(mvm, + "Got a NULL NVM from CSME, trying to get it from the device\n"); + } + +get_nvm_from_fw: rtnl_lock(); + wiphy_lock(mvm->hw->wiphy); mutex_lock(&mvm->mutex); - ret = iwl_run_init_mvm_ucode(mvm); + ret = iwl_trans_start_hw(mvm->trans); + if (ret) { + mutex_unlock(&mvm->mutex); + return ret; + } + ret = iwl_run_init_mvm_ucode(mvm); if (ret && ret != -ERFKILL) iwl_fw_dbg_error_collect(&mvm->fwrt, FW_DBG_TRIGGER_DRIVER); if (!ret && iwl_mvm_is_lar_supported(mvm)) { @@ -701,9 +732,10 @@ static int iwl_mvm_start_get_nvm(struct iwl_mvm *mvm) iwl_mvm_stop_device(mvm); mutex_unlock(&mvm->mutex); + wiphy_unlock(mvm->hw->wiphy); rtnl_unlock(); - if (ret < 0) + if (ret) IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret); return ret; @@ -711,6 +743,7 @@ static int iwl_mvm_start_get_nvm(struct iwl_mvm *mvm) static int iwl_mvm_start_post_nvm(struct iwl_mvm *mvm) { + struct iwl_mvm_csme_conn_info *csme_conn_info __maybe_unused; int ret; iwl_mvm_toggle_tx_ant(mvm, &mvm->mgmt_last_antenna_idx); @@ -718,10 +751,17 @@ static int iwl_mvm_start_post_nvm(struct iwl_mvm *mvm) ret = iwl_mvm_mac_setup_register(mvm); if (ret) return ret; + mvm->hw_registered = true; iwl_mvm_dbgfs_register(mvm); + wiphy_rfkill_set_hw_state_reason(mvm->hw->wiphy, + mvm->mei_rfkill_blocked, + RFKILL_HARD_BLOCK_NOT_OWNER); + + iwl_mvm_mei_set_sw_rfkill_state(mvm); + return 0; } @@ -902,6 +942,109 @@ static const struct iwl_dump_sanitize_ops iwl_mvm_sanitize_ops = { .frob_mem = iwl_mvm_frob_mem, }; +static void iwl_mvm_me_conn_status(void *priv, const struct iwl_mei_conn_info *conn_info) +{ + struct iwl_mvm *mvm = priv; + struct iwl_mvm_csme_conn_info *prev_conn_info, *curr_conn_info; + + /* + * This is protected by the guarantee that this function will not be + * called twice on two different threads + */ + prev_conn_info = rcu_dereference_protected(mvm->csme_conn_info, true); + + curr_conn_info = kzalloc(sizeof(*curr_conn_info), GFP_KERNEL); + if (!curr_conn_info) + return; + + curr_conn_info->conn_info = *conn_info; + + rcu_assign_pointer(mvm->csme_conn_info, curr_conn_info); + + if (prev_conn_info) + kfree_rcu(prev_conn_info, rcu_head); +} + +static void iwl_mvm_mei_rfkill(void *priv, bool blocked) +{ + struct iwl_mvm *mvm = priv; + + mvm->mei_rfkill_blocked = blocked; + if (!mvm->hw_registered) + return; + + wiphy_rfkill_set_hw_state_reason(mvm->hw->wiphy, + mvm->mei_rfkill_blocked, + RFKILL_HARD_BLOCK_NOT_OWNER); +} + +static void iwl_mvm_mei_roaming_forbidden(void *priv, bool forbidden) +{ + struct iwl_mvm *mvm = priv; + + if (!mvm->hw_registered || !mvm->csme_vif) + return; + + iwl_mvm_send_roaming_forbidden_event(mvm, mvm->csme_vif, forbidden); +} + +static void iwl_mvm_sap_connected_wk(struct work_struct *wk) +{ + struct iwl_mvm *mvm = + container_of(wk, struct iwl_mvm, sap_connected_wk); + int ret; + + ret = iwl_mvm_start_get_nvm(mvm); + if (ret) + goto out_free; + + ret = iwl_mvm_start_post_nvm(mvm); + if (ret) + goto out_free; + + return; + +out_free: + IWL_ERR(mvm, "Couldn't get started...\n"); + iwl_mei_start_unregister(); + iwl_mei_unregister_complete(); + iwl_fw_flush_dumps(&mvm->fwrt); + iwl_mvm_thermal_exit(mvm); + iwl_fw_runtime_free(&mvm->fwrt); + iwl_phy_db_free(mvm->phy_db); + kfree(mvm->scan_cmd); + iwl_trans_op_mode_leave(mvm->trans); + kfree(mvm->nvm_data); + kfree(mvm->mei_nvm_data); + + ieee80211_free_hw(mvm->hw); +} + +static void iwl_mvm_mei_sap_connected(void *priv) +{ + struct iwl_mvm *mvm = priv; + + if (!mvm->hw_registered) + schedule_work(&mvm->sap_connected_wk); +} + +static void iwl_mvm_mei_nic_stolen(void *priv) +{ + struct iwl_mvm *mvm = priv; + + rtnl_lock(); + cfg80211_shutdown_all_interfaces(mvm->hw->wiphy); + rtnl_unlock(); +} + +static const struct iwl_mei_ops mei_ops = { + .me_conn_status = iwl_mvm_me_conn_status, + .rfkill = iwl_mvm_mei_rfkill, + .roaming_forbidden = iwl_mvm_mei_roaming_forbidden, + .sap_connected = iwl_mvm_mei_sap_connected, + .nic_stolen = iwl_mvm_mei_nic_stolen, +}; + static struct iwl_op_mode * iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, const struct iwl_fw *fw, struct dentry *dbgfs_dir) @@ -913,9 +1056,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, static const u8 no_reclaim_cmds[] = { TX_CMD, }; - int err, scan_size; + int scan_size; u32 min_backoff; - enum iwl_amsdu_size rb_size_default; + struct iwl_mvm_csme_conn_info *csme_conn_info __maybe_unused; /* * We use IWL_MVM_STATION_COUNT_MAX to check the validity of the station @@ -954,6 +1097,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, &iwl_mvm_sanitize_ops, mvm, dbgfs_dir); iwl_mvm_get_acpi_tables(mvm); + iwl_uefi_get_sgom_table(trans, &mvm->fwrt); mvm->init_status = 0; @@ -1015,6 +1159,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk); INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk); + INIT_WORK(&mvm->sap_connected_wk, iwl_mvm_sap_connected_wk); INIT_DELAYED_WORK(&mvm->tdls_cs.dwork, iwl_mvm_tdls_ch_switch_work); INIT_DELAYED_WORK(&mvm->scan_timeout_dwork, iwl_mvm_scan_timeout_wk); INIT_WORK(&mvm->add_stream_wk, iwl_mvm_add_new_dqa_stream_wk); @@ -1056,14 +1201,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, trans_cfg.no_reclaim_cmds = no_reclaim_cmds; trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); - if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) - rb_size_default = IWL_AMSDU_2K; - else - rb_size_default = IWL_AMSDU_4K; - switch (iwlwifi_mod_params.amsdu_size) { case IWL_AMSDU_DEF: - trans_cfg.rx_buf_size = rb_size_default; + trans_cfg.rx_buf_size = IWL_AMSDU_4K; break; case IWL_AMSDU_4K: trans_cfg.rx_buf_size = IWL_AMSDU_4K; @@ -1077,7 +1217,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, default: pr_err("%s: Unsupported amsdu_size: %d\n", KBUILD_MODNAME, iwlwifi_mod_params.amsdu_size); - trans_cfg.rx_buf_size = rb_size_default; + trans_cfg.rx_buf_size = IWL_AMSDU_4K; } trans->wide_cmd_header = true; @@ -1137,10 +1277,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, IWL_DEBUG_EEPROM(mvm->trans->dev, "working without external nvm file\n"); - err = iwl_trans_start_hw(mvm->trans); - if (err) - goto out_free; - scan_size = iwl_mvm_scan_size(mvm); mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL); @@ -1165,8 +1301,14 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mvm->debugfs_dir = dbgfs_dir; - if (iwl_mvm_start_get_nvm(mvm)) - goto out_thermal_exit; + mvm->mei_registered = !iwl_mei_register(mvm, &mei_ops); + + /* + * Get NVM failed, but we are registered to MEI, we'll get + * the NVM later when it'll be possible to get it from CSME. + */ + if (iwl_mvm_start_get_nvm(mvm) && mvm->mei_registered) + return op_mode; if (iwl_mvm_start_post_nvm(mvm)) goto out_thermal_exit; @@ -1175,6 +1317,10 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, out_thermal_exit: iwl_mvm_thermal_exit(mvm); + if (mvm->mei_registered) { + iwl_mei_start_unregister(); + iwl_mei_unregister_complete(); + } out_free: iwl_fw_flush_dumps(&mvm->fwrt); iwl_fw_runtime_free(&mvm->fwrt); @@ -1201,6 +1347,7 @@ void iwl_mvm_stop_device(struct iwl_mvm *mvm) iwl_trans_stop_device(mvm->trans); iwl_free_fw_paging(&mvm->fwrt); iwl_fw_dump_conf_clear(&mvm->fwrt); + iwl_mvm_mei_device_down(mvm); } static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) @@ -1208,11 +1355,33 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); int i; + if (mvm->mei_registered) { + rtnl_lock(); + iwl_mei_set_netdev(NULL); + rtnl_unlock(); + iwl_mei_start_unregister(); + } + + /* + * After we unregister from mei, the worker can't be scheduled + * anymore. + */ + cancel_work_sync(&mvm->sap_connected_wk); + iwl_mvm_leds_exit(mvm); iwl_mvm_thermal_exit(mvm); - ieee80211_unregister_hw(mvm->hw); + /* + * If we couldn't get ownership on the device and we couldn't + * get the NVM from CSME, we haven't registered to mac80211. + * In that case, we didn't fail op_mode_start, because we are + * waiting for CSME to allow us to get the NVM to register to + * mac80211. If that didn't happen, we haven't registered to + * mac80211, hence the if below. + */ + if (mvm->hw_registered) + ieee80211_unregister_hw(mvm->hw); kfree(mvm->scan_cmd); kfree(mvm->mcast_filter_cmd); @@ -1227,6 +1396,9 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) mvm->phy_db = NULL; kfree(mvm->nvm_data); + kfree(mvm->mei_nvm_data); + kfree(rcu_access_pointer(mvm->csme_conn_info)); + kfree(mvm->temp_nvm_data); for (i = 0; i < NVM_MAX_NUM_SECTIONS; i++) kfree(mvm->nvm_sections[i].data); @@ -1235,6 +1407,9 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) iwl_fw_runtime_free(&mvm->fwrt); mutex_destroy(&mvm->mutex); + if (mvm->mei_registered) + iwl_mei_unregister_complete(); + ieee80211_free_hw(mvm->hw); } @@ -1517,6 +1692,12 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state) iwl_mvm_set_rfkill_state(mvm); } +struct iwl_mvm_csme_conn_info *iwl_mvm_get_csme_conn_info(struct iwl_mvm *mvm) +{ + return rcu_dereference_protected(mvm->csme_conn_info, + lockdep_is_held(&mvm->mutex)); +} + static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); @@ -1600,6 +1781,9 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) */ if (!mvm->fw_restart && fw_error) { iwl_fw_error_collect(&mvm->fwrt, false); + } else if (test_bit(IWL_MVM_STATUS_STARTING, + &mvm->status)) { + IWL_ERR(mvm, "Starting mac, retry will be triggered anyway\n"); } else if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { struct iwl_mvm_reprobe *reprobe; @@ -1662,7 +1846,9 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode, bool sync) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - if (!test_bit(STATUS_TRANS_DEAD, &mvm->trans->status)) + if (!test_bit(STATUS_TRANS_DEAD, &mvm->trans->status) && + !test_and_clear_bit(IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, + &mvm->status)) iwl_mvm_dump_nic_error_log(mvm); if (sync) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index 035336a9e755..9af40b0fa37a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -157,8 +157,43 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, /* Set the channel info data */ iwl_mvm_set_chan_info_chandef(mvm, &cmd->ci, chandef); - iwl_mvm_phy_ctxt_set_rxchain(mvm, ctxt, &cmd->rxchain_info, + /* we only support RLC command version 2 */ + if (iwl_fw_lookup_cmd_ver(mvm->fw, DATA_PATH_GROUP, + RLC_CONFIG_CMD, 0) < 2) + iwl_mvm_phy_ctxt_set_rxchain(mvm, ctxt, &cmd->rxchain_info, + chains_static, chains_dynamic); +} + +static int iwl_mvm_phy_send_rlc(struct iwl_mvm *mvm, + struct iwl_mvm_phy_ctxt *ctxt, + u8 chains_static, u8 chains_dynamic) +{ + struct iwl_rlc_config_cmd cmd = { + .phy_id = cpu_to_le32(ctxt->id), + }; + + if (iwl_fw_lookup_cmd_ver(mvm->fw, DATA_PATH_GROUP, + RLC_CONFIG_CMD, 0) < 2) + return 0; + + BUILD_BUG_ON(IWL_RLC_CHAIN_INFO_DRIVER_FORCE != + PHY_RX_CHAIN_DRIVER_FORCE_MSK); + BUILD_BUG_ON(IWL_RLC_CHAIN_INFO_VALID != + PHY_RX_CHAIN_VALID_MSK); + BUILD_BUG_ON(IWL_RLC_CHAIN_INFO_FORCE != + PHY_RX_CHAIN_FORCE_SEL_MSK); + BUILD_BUG_ON(IWL_RLC_CHAIN_INFO_FORCE_MIMO != + PHY_RX_CHAIN_FORCE_MIMO_SEL_MSK); + BUILD_BUG_ON(IWL_RLC_CHAIN_INFO_COUNT != PHY_RX_CHAIN_CNT_MSK); + BUILD_BUG_ON(IWL_RLC_CHAIN_INFO_MIMO_COUNT != + PHY_RX_CHAIN_MIMO_CNT_MSK); + + iwl_mvm_phy_ctxt_set_rxchain(mvm, ctxt, &cmd.rlc.rx_chain_info, chains_static, chains_dynamic); + + return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(RLC_CONFIG_CMD, + DATA_PATH_GROUP, 2), + 0, sizeof(cmd), &cmd); } /* @@ -177,7 +212,7 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, int ver = iwl_fw_lookup_cmd_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP, PHY_CONTEXT_CMD, 1); - if (ver == 3) { + if (ver == 3 || ver == 4) { struct iwl_phy_context_cmd cmd = {}; /* Set the command header fields */ @@ -211,9 +246,16 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, } - if (ret) + if (ret) { IWL_ERR(mvm, "PHY ctxt cmd error. ret=%d\n", ret); - return ret; + return ret; + } + + if (action != FW_CTXT_ACTION_REMOVE) + return iwl_mvm_phy_send_rlc(mvm, ctxt, chains_static, + chains_dynamic); + + return 0; } /* @@ -228,6 +270,8 @@ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, lockdep_assert_held(&mvm->mutex); ctxt->channel = chandef->chan; + ctxt->width = chandef->width; + ctxt->center_freq1 = chandef->center_freq1; return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, chains_static, chains_dynamic, @@ -257,6 +301,14 @@ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, lockdep_assert_held(&mvm->mutex); + if (iwl_fw_lookup_cmd_ver(mvm->fw, DATA_PATH_GROUP, + RLC_CONFIG_CMD, 0) >= 2 && + ctxt->channel == chandef->chan && + ctxt->width == chandef->width && + ctxt->center_freq1 == chandef->center_freq1) + return iwl_mvm_phy_send_rlc(mvm, ctxt, chains_static, + chains_dynamic); + if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT) && ctxt->channel->band != chandef->chan->band) { @@ -275,6 +327,8 @@ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, ctxt->channel = chandef->chan; ctxt->width = chandef->width; + ctxt->center_freq1 = chandef->center_freq1; + return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, chains_static, chains_dynamic, action); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c b/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c index 44344216a1a9..f1ed73c9f3dd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c @@ -7,7 +7,7 @@ #include "fw/api/commands.h" #include "fw/api/phy-ctxt.h" -/** +/* * DDR needs frequency in units of 16.666MHz, so provide FW with the * frequency values in the adjusted format. */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 958702403a45..970b92fd7042 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -291,8 +291,12 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, notif = (void *)pkt->data; sta = rcu_dereference(mvm->fw_id_to_mac_id[notif->sta_id]); if (IS_ERR_OR_NULL(sta)) { - IWL_ERR(mvm, "Invalid sta id (%d) in FW TLC notification\n", - notif->sta_id); + /* can happen in remove station flow where mvm removed internally + * the station before removing from FW + */ + IWL_DEBUG_RATE(mvm, + "Invalid mvm RCU pointer for sta id (%d) in TLC notification\n", + notif->sta_id); goto out; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index d22f40a5354d..64446a11ef98 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -527,40 +527,19 @@ struct iwl_mvm_stat_data { u8 *beacon_average_energy; }; -static void iwl_mvm_stat_iterator(void *_data, u8 *mac, - struct ieee80211_vif *vif) +struct iwl_mvm_stat_data_all_macs { + struct iwl_mvm *mvm; + __le32 flags; + struct iwl_statistics_ntfy_per_mac *per_mac_stats; +}; + +static void iwl_mvm_update_vif_sig(struct ieee80211_vif *vif, int sig) { - struct iwl_mvm_stat_data *data = _data; - struct iwl_mvm *mvm = data->mvm; - int sig = -data->beacon_filter_average_energy; - int last_event; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; int thold = vif->bss_conf.cqm_rssi_thold; int hyst = vif->bss_conf.cqm_rssi_hyst; - u16 id = le32_to_cpu(data->mac_id); - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - u16 vif_id = mvmvif->id; - - /* This doesn't need the MAC ID check since it's not taking the - * data copied into the "data" struct, but rather the data from - * the notification directly. - */ - mvmvif->beacon_stats.num_beacons = - le32_to_cpu(data->beacon_counter[vif_id]); - mvmvif->beacon_stats.avg_signal = - -data->beacon_average_energy[vif_id]; - - /* make sure that beacon statistics don't go backwards with TCM - * request to clear statistics - */ - if (le32_to_cpu(data->flags) & IWL_STATISTICS_REPLY_FLG_CLEAR) - mvmvif->beacon_stats.accu_num_beacons += - mvmvif->beacon_stats.num_beacons; - - if (mvmvif->id != id) - return; - - if (vif->type != NL80211_IFTYPE_STATION) - return; + int last_event; if (sig == 0) { IWL_DEBUG_RX(mvm, "RSSI is 0 - skip signal based decision\n"); @@ -618,6 +597,73 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac, } } +static void iwl_mvm_stat_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_stat_data *data = _data; + int sig = -data->beacon_filter_average_energy; + u16 id = le32_to_cpu(data->mac_id); + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + u16 vif_id = mvmvif->id; + + /* This doesn't need the MAC ID check since it's not taking the + * data copied into the "data" struct, but rather the data from + * the notification directly. + */ + mvmvif->beacon_stats.num_beacons = + le32_to_cpu(data->beacon_counter[vif_id]); + mvmvif->beacon_stats.avg_signal = + -data->beacon_average_energy[vif_id]; + + if (mvmvif->id != id) + return; + + if (vif->type != NL80211_IFTYPE_STATION) + return; + + /* make sure that beacon statistics don't go backwards with TCM + * request to clear statistics + */ + if (le32_to_cpu(data->flags) & IWL_STATISTICS_REPLY_FLG_CLEAR) + mvmvif->beacon_stats.accu_num_beacons += + mvmvif->beacon_stats.num_beacons; + + iwl_mvm_update_vif_sig(vif, sig); +} + +static void iwl_mvm_stat_iterator_all_macs(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_stat_data_all_macs *data = _data; + struct iwl_statistics_ntfy_per_mac *mac_stats; + int sig; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + u16 vif_id = mvmvif->id; + + if (WARN_ONCE(vif_id > MAC_INDEX_AUX, "invalid vif id: %d", vif_id)) + return; + + if (vif->type != NL80211_IFTYPE_STATION) + return; + + mac_stats = &data->per_mac_stats[vif_id]; + + mvmvif->beacon_stats.num_beacons = + le32_to_cpu(mac_stats->beacon_counter); + mvmvif->beacon_stats.avg_signal = + -le32_to_cpu(mac_stats->beacon_average_energy); + + /* make sure that beacon statistics don't go backwards with TCM + * request to clear statistics + */ + if (le32_to_cpu(data->flags) & IWL_STATISTICS_REPLY_FLG_CLEAR) + mvmvif->beacon_stats.accu_num_beacons += + mvmvif->beacon_stats.num_beacons; + + sig = -le32_to_cpu(mac_stats->beacon_filter_average_energy); + iwl_mvm_update_vif_sig(vif, sig); +} + static inline void iwl_mvm_rx_stats_check_trigger(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) { @@ -684,47 +730,41 @@ iwl_mvm_update_tcm_from_stats(struct iwl_mvm *mvm, __le32 *air_time_le, } static void -iwl_mvm_handle_rx_statistics_tlv(struct iwl_mvm *mvm, - struct iwl_rx_packet *pkt) +iwl_mvm_stats_ver_15(struct iwl_mvm *mvm, + struct iwl_statistics_operational_ntfy *stats) +{ + struct iwl_mvm_stat_data_all_macs data = { + .mvm = mvm, + .flags = stats->flags, + .per_mac_stats = stats->per_mac_stats, + }; + + ieee80211_iterate_active_interfaces(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_stat_iterator_all_macs, + &data); +} + +static void +iwl_mvm_stats_ver_14(struct iwl_mvm *mvm, + struct iwl_statistics_operational_ntfy_ver_14 *stats) { struct iwl_mvm_stat_data data = { .mvm = mvm, }; + u8 beacon_average_energy[MAC_INDEX_AUX]; - u8 average_energy[IWL_MVM_STATION_COUNT_MAX]; - struct iwl_statistics_operational_ntfy *stats; - int expected_size; __le32 flags; int i; - expected_size = sizeof(*stats); - if (WARN_ONCE(iwl_rx_packet_payload_len(pkt) < expected_size, - "received invalid statistics size (%d)!, expected_size: %d\n", - iwl_rx_packet_payload_len(pkt), expected_size)) - return; - - stats = (void *)&pkt->data; - - if (WARN_ONCE(stats->hdr.type != FW_STATISTICS_OPERATIONAL || - stats->hdr.version != - iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, STATISTICS_CMD, 0), - "received unsupported hdr type %d, version %d\n", - stats->hdr.type, stats->hdr.version)) - return; - flags = stats->flags; - mvm->radio_stats.rx_time = le64_to_cpu(stats->rx_time); - mvm->radio_stats.tx_time = le64_to_cpu(stats->tx_time); - mvm->radio_stats.on_time_rf = le64_to_cpu(stats->on_time_rf); - mvm->radio_stats.on_time_scan = le64_to_cpu(stats->on_time_scan); - - iwl_mvm_rx_stats_check_trigger(mvm, pkt); data.mac_id = stats->mac_id; data.beacon_filter_average_energy = le32_to_cpu(stats->beacon_filter_average_energy); data.flags = flags; data.beacon_counter = stats->beacon_counter; + for (i = 0; i < ARRAY_SIZE(beacon_average_energy); i++) beacon_average_energy[i] = le32_to_cpu(stats->beacon_average_energy[i]); @@ -735,9 +775,105 @@ iwl_mvm_handle_rx_statistics_tlv(struct iwl_mvm *mvm, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_stat_iterator, &data); +} + +static bool iwl_mvm_verify_stats_len(struct iwl_mvm *mvm, + struct iwl_rx_packet *pkt, + u32 expected_size) +{ + struct iwl_statistics_ntfy_hdr *hdr; + + if (WARN_ONCE(iwl_rx_packet_payload_len(pkt) < expected_size, + "received invalid statistics size (%d)!, expected_size: %d\n", + iwl_rx_packet_payload_len(pkt), expected_size)) + return false; + + hdr = (void *)&pkt->data; + + if (WARN_ONCE((hdr->type & IWL_STATISTICS_TYPE_MSK) != FW_STATISTICS_OPERATIONAL || + hdr->version != + iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, STATISTICS_NOTIFICATION, 0), + "received unsupported hdr type %d, version %d\n", + hdr->type, hdr->version)) + return false; + + if (WARN_ONCE(le16_to_cpu(hdr->size) != expected_size, + "received invalid statistics size in header (%d)!, expected_size: %d\n", + le16_to_cpu(hdr->size), expected_size)) + return false; + + return true; +} + +static void +iwl_mvm_handle_rx_statistics_tlv(struct iwl_mvm *mvm, + struct iwl_rx_packet *pkt) +{ + u8 average_energy[IWL_MVM_STATION_COUNT_MAX]; + __le32 air_time[MAC_INDEX_AUX]; + __le32 rx_bytes[MAC_INDEX_AUX]; + __le32 flags = 0; + int i; + u32 notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + STATISTICS_NOTIFICATION, 0); + + if (WARN_ONCE(notif_ver > 15, + "invalid statistics version id: %d\n", notif_ver)) + return; + + if (notif_ver == 14) { + struct iwl_statistics_operational_ntfy_ver_14 *stats = + (void *)pkt->data; + + if (!iwl_mvm_verify_stats_len(mvm, pkt, sizeof(*stats))) + return; + + iwl_mvm_stats_ver_14(mvm, stats); + + flags = stats->flags; + mvm->radio_stats.rx_time = le64_to_cpu(stats->rx_time); + mvm->radio_stats.tx_time = le64_to_cpu(stats->tx_time); + mvm->radio_stats.on_time_rf = le64_to_cpu(stats->on_time_rf); + mvm->radio_stats.on_time_scan = + le64_to_cpu(stats->on_time_scan); + + for (i = 0; i < ARRAY_SIZE(average_energy); i++) + average_energy[i] = le32_to_cpu(stats->average_energy[i]); + + for (i = 0; i < ARRAY_SIZE(air_time); i++) { + air_time[i] = stats->air_time[i]; + rx_bytes[i] = stats->rx_bytes[i]; + } + } + + if (notif_ver == 15) { + struct iwl_statistics_operational_ntfy *stats = + (void *)pkt->data; + + if (!iwl_mvm_verify_stats_len(mvm, pkt, sizeof(*stats))) + return; + + iwl_mvm_stats_ver_15(mvm, stats); + + flags = stats->flags; + mvm->radio_stats.rx_time = le64_to_cpu(stats->rx_time); + mvm->radio_stats.tx_time = le64_to_cpu(stats->tx_time); + mvm->radio_stats.on_time_rf = le64_to_cpu(stats->on_time_rf); + mvm->radio_stats.on_time_scan = + le64_to_cpu(stats->on_time_scan); + + for (i = 0; i < ARRAY_SIZE(average_energy); i++) + average_energy[i] = + le32_to_cpu(stats->per_sta_stats[i].average_energy); + + for (i = 0; i < ARRAY_SIZE(air_time); i++) { + air_time[i] = stats->per_mac_stats[i].air_time; + rx_bytes[i] = stats->per_mac_stats[i].rx_bytes; + } + } + + iwl_mvm_rx_stats_check_trigger(mvm, pkt); - for (i = 0; i < ARRAY_SIZE(average_energy); i++) - average_energy[i] = le32_to_cpu(stats->average_energy[i]); ieee80211_iterate_stations_atomic(mvm->hw, iwl_mvm_stats_energy_iter, average_energy); /* @@ -746,8 +882,7 @@ iwl_mvm_handle_rx_statistics_tlv(struct iwl_mvm *mvm, * request and once in statistics notification. */ if (le32_to_cpu(flags) & IWL_STATISTICS_REPLY_FLG_CLEAR) - iwl_mvm_update_tcm_from_stats(mvm, stats->air_time, - stats->rx_bytes); + iwl_mvm_update_tcm_from_stats(mvm, air_time, rx_bytes); } void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, @@ -761,8 +896,8 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, u8 *energy; /* From ver 14 and up we use TLV statistics format */ - if (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, - STATISTICS_CMD, 0) >= 14) + if (iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + STATISTICS_NOTIFICATION, 0) >= 14) return iwl_mvm_handle_rx_statistics_tlv(mvm, pkt); if (!iwl_mvm_has_new_rx_stats_api(mvm)) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index e0601f802628..03e90087576c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -766,8 +766,11 @@ static void iwl_mvm_release_frames_from_notif(struct iwl_mvm *mvm, rcu_read_lock(); ba_data = rcu_dereference(mvm->baid_map[baid]); - if (WARN_ON_ONCE(!ba_data)) + if (!ba_data) { + WARN(!(flags & IWL_MVM_RELEASE_FROM_RSS_SYNC), + "BAID %d not found in map\n", baid); goto out; + } sta = rcu_dereference(mvm->fw_id_to_mac_id[ba_data->sta_id]); if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index a138b5c4cce8..54ec5eb6c763 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1394,8 +1394,8 @@ static u32 iwl_mvm_scan_umac_ooc_priority(struct iwl_mvm_scan_params *params) } static void -iwl_mvm_scan_umac_dwell_v10(struct iwl_mvm *mvm, - struct iwl_scan_general_params_v10 *general_params, +iwl_mvm_scan_umac_dwell_v11(struct iwl_mvm *mvm, + struct iwl_scan_general_params_v11 *general_params, struct iwl_mvm_scan_params *params) { struct iwl_mvm_scan_timing_params *timing, *hb_timing; @@ -2238,15 +2238,15 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, } static void -iwl_mvm_scan_umac_fill_general_p_v10(struct iwl_mvm *mvm, +iwl_mvm_scan_umac_fill_general_p_v11(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params, struct ieee80211_vif *vif, - struct iwl_scan_general_params_v10 *gp, + struct iwl_scan_general_params_v11 *gp, u16 gen_flags) { struct iwl_mvm_vif *scan_vif = iwl_mvm_vif_from_mac80211(vif); - iwl_mvm_scan_umac_dwell_v10(mvm, gp, params); + iwl_mvm_scan_umac_dwell_v11(mvm, gp, params); gp->flags = cpu_to_le16(gen_flags); @@ -2350,7 +2350,7 @@ static int iwl_mvm_scan_umac_v12(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cmd->uid = cpu_to_le32(uid); gen_flags = iwl_mvm_scan_umac_flags_v2(mvm, params, vif, type); - iwl_mvm_scan_umac_fill_general_p_v10(mvm, params, vif, + iwl_mvm_scan_umac_fill_general_p_v11(mvm, params, vif, &scan_p->general_params, gen_flags); @@ -2367,12 +2367,13 @@ static int iwl_mvm_scan_umac_v12(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return 0; } -static int iwl_mvm_scan_umac_v14(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_mvm_scan_params *params, int type, - int uid) +static int iwl_mvm_scan_umac_v14_and_above(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct iwl_mvm_scan_params *params, + int type, int uid, u32 version) { - struct iwl_scan_req_umac_v14 *cmd = mvm->scan_cmd; - struct iwl_scan_req_params_v14 *scan_p = &cmd->scan_params; + struct iwl_scan_req_umac_v15 *cmd = mvm->scan_cmd; + struct iwl_scan_req_params_v15 *scan_p = &cmd->scan_params; struct iwl_scan_channel_params_v6 *cp = &scan_p->channel_params; struct iwl_scan_probe_params_v4 *pb = &scan_p->probe_params; int ret; @@ -2385,7 +2386,7 @@ static int iwl_mvm_scan_umac_v14(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cmd->uid = cpu_to_le32(uid); gen_flags = iwl_mvm_scan_umac_flags_v2(mvm, params, vif, type); - iwl_mvm_scan_umac_fill_general_p_v10(mvm, params, vif, + iwl_mvm_scan_umac_fill_general_p_v11(mvm, params, vif, &scan_p->general_params, gen_flags); @@ -2425,6 +2426,20 @@ static int iwl_mvm_scan_umac_v14(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return 0; } +static int iwl_mvm_scan_umac_v14(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_mvm_scan_params *params, int type, + int uid) +{ + return iwl_mvm_scan_umac_v14_and_above(mvm, vif, params, type, uid, 14); +} + +static int iwl_mvm_scan_umac_v15(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_mvm_scan_params *params, int type, + int uid) +{ + return iwl_mvm_scan_umac_v14_and_above(mvm, vif, params, type, uid, 15); +} + static int iwl_mvm_num_scans(struct iwl_mvm *mvm) { return hweight32(mvm->scan_status & IWL_MVM_SCAN_MASK); @@ -2540,6 +2555,7 @@ struct iwl_scan_umac_handler { static const struct iwl_scan_umac_handler iwl_scan_umac_handlers[] = { /* set the newest version first to shorten the list traverse time */ + IWL_SCAN_UMAC_HANDLER(15), IWL_SCAN_UMAC_HANDLER(14), IWL_SCAN_UMAC_HANDLER(12), }; @@ -2940,15 +2956,14 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type) 1 * HZ); } -#define IWL_SCAN_REQ_UMAC_HANDLE_SIZE(_ver) { \ - case (_ver): return sizeof(struct iwl_scan_req_umac_v##_ver); \ -} - static int iwl_scan_req_umac_get_size(u8 scan_ver) { switch (scan_ver) { - IWL_SCAN_REQ_UMAC_HANDLE_SIZE(14); - IWL_SCAN_REQ_UMAC_HANDLE_SIZE(12); + case 12: + return sizeof(struct iwl_scan_req_umac_v12); + case 14: + case 15: + return sizeof(struct iwl_scan_req_umac_v15); } return 0; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index a64874c05ced..feab0bfcd7a2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2684,6 +2684,16 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, RCU_INIT_POINTER(mvm->baid_map[baid], NULL); kfree_rcu(baid_data, rcu_head); IWL_DEBUG_HT(mvm, "BAID %d is free\n", baid); + + /* + * After we've deleted it, do another queue sync + * so if an IWL_MVM_RXQ_NSSN_SYNC was concurrently + * running it won't find a new session in the old + * BAID. It can find the NULL pointer for the BAID, + * but we must not have it find a different session. + */ + iwl_mvm_sync_rx_queues_internal(mvm, IWL_MVM_RXQ_EMPTY, + true, NULL, 0); } return 0; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index 32b4d1935788..e34b82b2a288 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2016 Intel Deutschland GmbH */ @@ -373,6 +373,7 @@ struct iwl_mvm_rxq_dup_data { * @tx_ant: the index of the antenna to use for data tx to this station. Only * used during connection establishment (e.g. for the 4 way handshake * exchange). + * @pairwise_cipher: used to feed iwlmei upon authorization * * When mac80211 creates a station it reserves some space (hw->sta_data_size) * in the structure for use by driver. This structure is placed in that @@ -415,6 +416,7 @@ struct iwl_mvm_sta { u8 sleep_tx_count; u8 avg_energy; u8 tx_ant; + u32 pairwise_cipher; }; u16 iwl_mvm_tid_queued(struct iwl_mvm *mvm, struct iwl_mvm_tid_data *tid_data); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index e91f8e889df7..e6813317edf3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -1158,15 +1158,10 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)), .action = cpu_to_le32(FW_CTXT_ACTION_ADD), + .conf_id = cpu_to_le32(SESSION_PROTECT_CONF_ASSOC), .duration_tu = cpu_to_le32(MSEC_TO_TU(duration)), }; - /* The time_event_data.id field is reused to save session - * protection's configuration. - */ - mvmvif->time_event_data.id = SESSION_PROTECT_CONF_ASSOC; - cmd.conf_id = cpu_to_le32(mvmvif->time_event_data.id); - lockdep_assert_held(&mvm->mutex); spin_lock_bh(&mvm->time_event_lock); @@ -1180,6 +1175,11 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, } iwl_mvm_te_clear_data(mvm, te_data); + /* + * The time_event_data.id field is reused to save session + * protection's configuration. + */ + te_data->id = le32_to_cpu(cmd.conf_id); te_data->duration = le32_to_cpu(cmd.duration_tu); te_data->vif = vif; spin_unlock_bh(&mvm->time_event_lock); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index bdd4ee432548..ce73cb8b06ee 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -269,17 +269,18 @@ static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm, u8 rate_plcp; u32 rate_flags = 0; bool is_cck; - struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); /* info->control is only relevant for non HW rate control */ if (!ieee80211_hw_check(mvm->hw, HAS_RATE_CONTROL)) { + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + /* HT rate doesn't make sense for a non data frame */ WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS && !ieee80211_is_data(fc), "Got a HT rate (flags:0x%x/mcs:%d/fc:0x%x/state:%d) for a non data frame\n", info->control.rates[0].flags, info->control.rates[0].idx, - le16_to_cpu(fc), mvmsta->sta_state); + le16_to_cpu(fc), sta ? mvmsta->sta_state : -1); rate_idx = info->control.rates[0].idx; } @@ -1128,6 +1129,11 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, /* From now on, we cannot access info->control */ iwl_mvm_skb_prepare_status(skb, dev_cmd); + if (ieee80211_is_data(fc)) + iwl_mvm_mei_tx_copy_to_csme(mvm, skb, + info->control.hw_key ? + info->control.hw_key->iv_len : 0); + if (iwl_trans_tx(mvm->trans, skb, dev_cmd, txq_id)) goto drop_unlock_sta; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index caf1dcf48888..1f3e90e5dbd4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -340,25 +340,64 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ieee80211_request_smps(vif, smps_mode); } +static bool iwl_wait_stats_complete(struct iwl_notif_wait_data *notif_wait, + struct iwl_rx_packet *pkt, void *data) +{ + WARN_ON(pkt->hdr.cmd != STATISTICS_NOTIFICATION); + + return true; +} + int iwl_mvm_request_statistics(struct iwl_mvm *mvm, bool clear) { struct iwl_statistics_cmd scmd = { .flags = clear ? cpu_to_le32(IWL_STATISTICS_FLG_CLEAR) : 0, }; + struct iwl_host_cmd cmd = { .id = STATISTICS_CMD, .len[0] = sizeof(scmd), .data[0] = &scmd, - .flags = CMD_WANT_SKB, }; int ret; - ret = iwl_mvm_send_cmd(mvm, &cmd); - if (ret) - return ret; + /* From version 15 - STATISTICS_NOTIFICATION, the reply for + * STATISTICS_CMD is empty, and the response is with + * STATISTICS_NOTIFICATION notification + */ + if (iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + STATISTICS_NOTIFICATION, 0) < 15) { + cmd.flags = CMD_WANT_SKB; - iwl_mvm_handle_rx_statistics(mvm, cmd.resp_pkt); - iwl_free_resp(&cmd); + ret = iwl_mvm_send_cmd(mvm, &cmd); + if (ret) + return ret; + + iwl_mvm_handle_rx_statistics(mvm, cmd.resp_pkt); + iwl_free_resp(&cmd); + } else { + struct iwl_notification_wait stats_wait; + static const u16 stats_complete[] = { + STATISTICS_NOTIFICATION, + }; + + iwl_init_notification_wait(&mvm->notif_wait, &stats_wait, + stats_complete, ARRAY_SIZE(stats_complete), + iwl_wait_stats_complete, NULL); + + ret = iwl_mvm_send_cmd(mvm, &cmd); + if (ret) { + iwl_remove_notification(&mvm->notif_wait, &stats_wait); + return ret; + } + + /* 200ms should be enough for FW to collect data from all + * LMACs and send STATISTICS_NOTIFICATION to host + */ + ret = iwl_wait_notification(&mvm->notif_wait, &stats_wait, HZ / 5); + if (ret) + return ret; + } if (clear) iwl_mvm_accu_radio_stats(mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/vendor-cmd.c b/drivers/net/wireless/intel/iwlwifi/mvm/vendor-cmd.c new file mode 100644 index 000000000000..f702ad85e609 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mvm/vendor-cmd.c @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Intel Corporation + */ +#include "mvm.h" +#include <linux/nl80211-vnd-intel.h> + +static const struct nla_policy +iwl_mvm_vendor_attr_policy[NUM_IWL_MVM_VENDOR_ATTR] = { + [IWL_MVM_VENDOR_ATTR_ROAMING_FORBIDDEN] = { .type = NLA_U8 }, + [IWL_MVM_VENDOR_ATTR_AUTH_MODE] = { .type = NLA_U32 }, + [IWL_MVM_VENDOR_ATTR_CHANNEL_NUM] = { .type = NLA_U8 }, + [IWL_MVM_VENDOR_ATTR_SSID] = { .type = NLA_BINARY, + .len = IEEE80211_MAX_SSID_LEN }, + [IWL_MVM_VENDOR_ATTR_BAND] = { .type = NLA_U8 }, + [IWL_MVM_VENDOR_ATTR_COLLOC_CHANNEL] = { .type = NLA_U8 }, + [IWL_MVM_VENDOR_ATTR_COLLOC_ADDR] = { .type = NLA_BINARY, .len = ETH_ALEN }, +}; + +static int iwl_mvm_vendor_get_csme_conn_info(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct iwl_mvm_csme_conn_info *csme_conn_info; + struct sk_buff *skb; + int err = 0; + + mutex_lock(&mvm->mutex); + csme_conn_info = iwl_mvm_get_csme_conn_info(mvm); + + if (!csme_conn_info) { + err = -EINVAL; + goto out_unlock; + } + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 200); + if (!skb) { + err = -ENOMEM; + goto out_unlock; + } + + if (nla_put_u32(skb, IWL_MVM_VENDOR_ATTR_AUTH_MODE, + csme_conn_info->conn_info.auth_mode) || + nla_put(skb, IWL_MVM_VENDOR_ATTR_SSID, + csme_conn_info->conn_info.ssid_len, + csme_conn_info->conn_info.ssid) || + nla_put_u32(skb, IWL_MVM_VENDOR_ATTR_STA_CIPHER, + csme_conn_info->conn_info.pairwise_cipher) || + nla_put_u8(skb, IWL_MVM_VENDOR_ATTR_CHANNEL_NUM, + csme_conn_info->conn_info.channel) || + nla_put(skb, IWL_MVM_VENDOR_ATTR_ADDR, ETH_ALEN, + csme_conn_info->conn_info.bssid)) { + kfree_skb(skb); + err = -ENOBUFS; + } + +out_unlock: + mutex_unlock(&mvm->mutex); + if (err) + return err; + + return cfg80211_vendor_cmd_reply(skb); +} + +static int iwl_mvm_vendor_host_get_ownership(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + + mutex_lock(&mvm->mutex); + iwl_mvm_mei_get_ownership(mvm); + mutex_unlock(&mvm->mutex); + + return 0; +} + +static const struct wiphy_vendor_command iwl_mvm_vendor_commands[] = { + { + .info = { + .vendor_id = INTEL_OUI, + .subcmd = IWL_MVM_VENDOR_CMD_GET_CSME_CONN_INFO, + }, + .doit = iwl_mvm_vendor_get_csme_conn_info, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV, + .policy = iwl_mvm_vendor_attr_policy, + .maxattr = MAX_IWL_MVM_VENDOR_ATTR, + }, + { + .info = { + .vendor_id = INTEL_OUI, + .subcmd = IWL_MVM_VENDOR_CMD_HOST_GET_OWNERSHIP, + }, + .doit = iwl_mvm_vendor_host_get_ownership, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV, + .policy = iwl_mvm_vendor_attr_policy, + .maxattr = MAX_IWL_MVM_VENDOR_ATTR, + }, +}; + +enum iwl_mvm_vendor_events_idx { + /* 0x0 - 0x3 are deprecated */ + IWL_MVM_VENDOR_EVENT_IDX_ROAMING_FORBIDDEN = 4, + NUM_IWL_MVM_VENDOR_EVENT_IDX +}; + +static const struct nl80211_vendor_cmd_info +iwl_mvm_vendor_events[NUM_IWL_MVM_VENDOR_EVENT_IDX] = { + [IWL_MVM_VENDOR_EVENT_IDX_ROAMING_FORBIDDEN] = { + .vendor_id = INTEL_OUI, + .subcmd = IWL_MVM_VENDOR_CMD_ROAMING_FORBIDDEN_EVENT, + }, +}; + +void iwl_mvm_vendor_cmds_register(struct iwl_mvm *mvm) +{ + mvm->hw->wiphy->vendor_commands = iwl_mvm_vendor_commands; + mvm->hw->wiphy->n_vendor_commands = ARRAY_SIZE(iwl_mvm_vendor_commands); + mvm->hw->wiphy->vendor_events = iwl_mvm_vendor_events; + mvm->hw->wiphy->n_vendor_events = ARRAY_SIZE(iwl_mvm_vendor_events); +} + +void iwl_mvm_send_roaming_forbidden_event(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + bool forbidden) +{ + struct sk_buff *msg = + cfg80211_vendor_event_alloc(mvm->hw->wiphy, + ieee80211_vif_to_wdev(vif), + 200, IWL_MVM_VENDOR_EVENT_IDX_ROAMING_FORBIDDEN, + GFP_ATOMIC); + if (!msg) + return; + + if (WARN_ON(!vif)) + return; + + if (nla_put(msg, IWL_MVM_VENDOR_ATTR_VIF_ADDR, + ETH_ALEN, vif->addr) || + nla_put_u8(msg, IWL_MVM_VENDOR_ATTR_ROAMING_FORBIDDEN, forbidden)) + goto nla_put_failure; + + cfg80211_vendor_event(msg, GFP_ATOMIC); + return; + + nla_put_failure: + kfree_skb(msg); +} diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index c574f041f096..fd31bc600ce5 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -562,6 +562,7 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_DEV_INFO(0x43F0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0, iwl_ax201_killer_1650i_name), IWL_DEV_INFO(0x43F0, 0x2074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x43F0, 0x4070, iwl_ax201_cfg_qu_hr, NULL), + IWL_DEV_INFO(0x43F0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0, iwl_ax201_killer_1650s_name), IWL_DEV_INFO(0xA0F0, 0x0070, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0xA0F0, 0x0074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0xA0F0, 0x0078, iwl_ax201_cfg_qu_hr, NULL), @@ -959,6 +960,11 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_qu_c0_hr_b0, iwl_ax203_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_QU, SILICON_C_STEP, + IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, + iwl_qu_c0_hr_b0, iwl_ax201_name), /* QuZ */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, @@ -1097,6 +1103,11 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_CDB, + iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_name), /* Bz */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, @@ -1130,6 +1141,13 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_gl_a0_fm_a0, iwl_bz_name), +/* BZ Z step */ + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_BZ, SILICON_Z_STEP, + IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, + iwl_cfg_bz_z0_gf_a0, iwl_bz_name), + /* SoF with JF2 */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, @@ -1204,6 +1222,11 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_CDB, + iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_name), /* So with JF2 */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, @@ -1339,9 +1362,13 @@ iwl_pci_find_dev_info(u16 device, u16 subsystem_device, u16 mac_type, u8 mac_step, u16 rf_type, u8 cdb, u8 rf_id, u8 no_160, u8 cores) { + int num_devices = ARRAY_SIZE(iwl_dev_info_table); int i; - for (i = ARRAY_SIZE(iwl_dev_info_table) - 1; i >= 0; i--) { + if (!num_devices) + return NULL; + + for (i = num_devices - 1; i >= 0; i--) { const struct iwl_dev_info *dev_info = &iwl_dev_info_table[i]; if (dev_info->device != (u16)IWL_CFG_ANY && @@ -1422,15 +1449,18 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * first trying to load the firmware etc. and potentially only * detecting any problems when the first interface is brought up. */ - ret = iwl_finish_nic_init(iwl_trans); - if (ret) - goto out_free_trans; - if (iwl_trans_grab_nic_access(iwl_trans)) { - /* all good */ - iwl_trans_release_nic_access(iwl_trans); - } else { - ret = -EIO; - goto out_free_trans; + ret = iwl_pcie_prepare_card_hw(iwl_trans); + if (!ret) { + ret = iwl_finish_nic_init(iwl_trans); + if (ret) + goto out_free_trans; + if (iwl_trans_grab_nic_access(iwl_trans)) { + /* all good */ + iwl_trans_release_nic_access(iwl_trans); + } else { + ret = -EIO; + goto out_free_trans; + } } iwl_trans->hw_rf_id = iwl_read32(iwl_trans, CSR_HW_RF_ID); @@ -1442,12 +1472,14 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) */ if (iwl_trans->trans_cfg->rf_id && iwl_trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_9000 && - !CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) && get_crf_id(iwl_trans)) + !CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) && get_crf_id(iwl_trans)) { + ret = -EINVAL; goto out_free_trans; + } dev_info = iwl_pci_find_dev_info(pdev->device, pdev->subsystem_device, CSR_HW_REV_TYPE(iwl_trans->hw_rev), - CSR_HW_REV_STEP(iwl_trans->hw_rev), + iwl_trans->hw_rev_step, CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id), CSR_HW_RFID_IS_CDB(iwl_trans->hw_rf_id), IWL_SUBDEVICE_RF_ID(pdev->subsystem_device), @@ -1488,21 +1520,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) (iwl_trans->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_7265D) iwl_trans->cfg = cfg_7265d; - if (cfg == &iwlax210_2ax_cfg_so_hr_a0) { - if (iwl_trans->hw_rev == CSR_HW_REV_TYPE_TY) { - iwl_trans->cfg = &iwlax210_2ax_cfg_ty_gf_a0; - } else if (CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) == - CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF)) { - iwl_trans->cfg = &iwlax210_2ax_cfg_so_jf_b0; - } else if (CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) == - CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_GF)) { - iwl_trans->cfg = &iwlax211_2ax_cfg_so_gf_a0; - } else if (CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) == - CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_GF4)) { - iwl_trans->cfg = &iwlax411_2ax_cfg_so_gf4_a0; - } - } - /* * This is a hack to switch from Qu B0 to Qu C0. We need to * do this for all cfgs that use Qu B0, except for those using @@ -1563,6 +1580,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_free_trans; pci_set_drvdata(pdev, iwl_trans); + + /* try to get ownership so that we'll know if we don't own it */ + iwl_pcie_prepare_card_hw(iwl_trans); + iwl_trans->drv = iwl_drv_start(iwl_trans); if (IS_ERR(iwl_trans->drv)) { diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index 645cb4dd4e5a..0febdcacbd42 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -81,7 +81,7 @@ static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave) /* Stop device's DMA activity */ iwl_pcie_apm_stop_master(trans); - iwl_trans_sw_reset(trans); + iwl_trans_sw_reset(trans, false); /* * Clear "initialization complete" bit to move adapter from @@ -105,9 +105,12 @@ static void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) iwl_write_umac_prph(trans, UREG_NIC_SET_NMI_DRIVER, UREG_NIC_SET_NMI_DRIVER_RESET_HANDSHAKE); - else + else if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_AX210) iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, UREG_DOORBELL_TO_ISR6_RESET_HANDSHAKE); + else + iwl_write32(trans, CSR_DOORBELL_VECTOR, + UREG_DOORBELL_TO_ISR6_RESET_HANDSHAKE); /* wait 200ms */ ret = wait_event_timeout(trans_pcie->fw_reset_waitq, @@ -166,7 +169,8 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) /* Stop the device, and put it in low power state */ iwl_pcie_gen2_apm_stop(trans, false); - iwl_trans_sw_reset(trans); + /* re-take ownership to prevent other users from stealing the device */ + iwl_trans_sw_reset(trans, true); /* * Upon stop, the IVAR table gets erased, so msi-x won't @@ -196,9 +200,6 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) * interrupt */ iwl_enable_rfkill_int(trans); - - /* re-take ownership to prevent other users from stealing the device */ - iwl_pcie_prepare_card_hw(trans); } void iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 1efb53f78a62..a63386a01232 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -24,6 +24,7 @@ #include "fw/error-dump.h" #include "fw/dbg.h" #include "fw/api/tx.h" +#include "mei/iwl-mei.h" #include "internal.h" #include "iwl-fh.h" #include "iwl-context-info-gen3.h" @@ -126,7 +127,8 @@ out: kfree(buf); } -static void iwl_trans_pcie_sw_reset(struct iwl_trans *trans) +static int iwl_trans_pcie_sw_reset(struct iwl_trans *trans, + bool retake_ownership) { /* Reset entire device - do controller reset (results in SHRD_HW_RST) */ if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) @@ -136,6 +138,11 @@ static void iwl_trans_pcie_sw_reset(struct iwl_trans *trans) iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); usleep_range(5000, 6000); + + if (retake_ownership) + return iwl_pcie_prepare_card_hw(trans); + + return 0; } static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans) @@ -381,9 +388,11 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_XTAL_ON); - iwl_trans_pcie_sw_reset(trans); + ret = iwl_trans_pcie_sw_reset(trans, true); + + if (!ret) + ret = iwl_finish_nic_init(trans); - ret = iwl_finish_nic_init(trans); if (WARN_ON(ret)) { /* Release XTAL ON request */ __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, @@ -408,7 +417,10 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) apmg_xtal_cfg_reg | SHR_APMG_XTAL_CFG_XTAL_ON_REQ); - iwl_trans_pcie_sw_reset(trans); + ret = iwl_trans_pcie_sw_reset(trans, true); + if (ret) + IWL_ERR(trans, + "iwl_pcie_apm_lp_xtal_enable: failed to retake NIC ownership\n"); /* Enable LP XTAL by indirect access through CSR */ apmg_gp1_reg = iwl_trans_pcie_read_shr(trans, SHR_APMG_GP1_REG); @@ -514,7 +526,7 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave) return; } - iwl_trans_pcie_sw_reset(trans); + iwl_trans_pcie_sw_reset(trans, false); /* * Clear "initialization complete" bit to move adapter from @@ -594,8 +606,10 @@ int iwl_pcie_prepare_card_hw(struct iwl_trans *trans) ret = iwl_pcie_set_hw_ready(trans); /* If the card is ready, exit 0 */ - if (ret >= 0) + if (ret >= 0) { + trans->csme_own = false; return 0; + } iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, CSR_RESET_LINK_PWR_MGMT_DISABLED); @@ -608,8 +622,22 @@ int iwl_pcie_prepare_card_hw(struct iwl_trans *trans) do { ret = iwl_pcie_set_hw_ready(trans); - if (ret >= 0) + if (ret >= 0) { + trans->csme_own = false; return 0; + } + + if (iwl_mei_is_connected()) { + IWL_DEBUG_INFO(trans, + "Couldn't prepare the card but SAP is connected\n"); + trans->csme_own = true; + if (trans->trans_cfg->device_family != + IWL_DEVICE_FAMILY_9000) + IWL_ERR(trans, + "SAP not supported for this NIC family\n"); + + return -EBUSY; + } usleep_range(200, 1000); t += 200; @@ -1244,7 +1272,8 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans) /* Stop the device, and put it in low power state */ iwl_pcie_apm_stop(trans, false); - iwl_trans_pcie_sw_reset(trans); + /* re-take ownership to prevent other users from stealing the device */ + iwl_trans_pcie_sw_reset(trans, true); /* * Upon stop, the IVAR table gets erased, so msi-x won't @@ -1274,9 +1303,6 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans) * interrupt */ iwl_enable_rfkill_int(trans); - - /* re-take ownership to prevent other users from stealing the device */ - iwl_pcie_prepare_card_hw(trans); } void iwl_pcie_synchronize_irqs(struct iwl_trans *trans) @@ -1482,33 +1508,54 @@ void iwl_pcie_d3_complete_suspend(struct iwl_trans *trans, iwl_pcie_set_pwr(trans, true); } +static int iwl_pcie_d3_handshake(struct iwl_trans *trans, bool suspend) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int ret; + + if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_AX210) { + iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, + suspend ? UREG_DOORBELL_TO_ISR6_SUSPEND : + UREG_DOORBELL_TO_ISR6_RESUME); + } else if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { + iwl_write32(trans, CSR_IPC_SLEEP_CONTROL, + suspend ? CSR_IPC_SLEEP_CONTROL_SUSPEND : + CSR_IPC_SLEEP_CONTROL_RESUME); + iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, + UREG_DOORBELL_TO_ISR6_SLEEP_CTRL); + } else { + return 0; + } + + ret = wait_event_timeout(trans_pcie->sx_waitq, + trans_pcie->sx_complete, 2 * HZ); + + /* Invalidate it toward next suspend or resume */ + trans_pcie->sx_complete = false; + + if (!ret) { + IWL_ERR(trans, "Timeout %s D3\n", + suspend ? "entering" : "exiting"); + return -ETIMEDOUT; + } + + return 0; +} + static int iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test, bool reset) { int ret; - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); if (!reset) /* Enable persistence mode to avoid reset */ iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_PERSIST_MODE); - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { - iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, - UREG_DOORBELL_TO_ISR6_SUSPEND); - - ret = wait_event_timeout(trans_pcie->sx_waitq, - trans_pcie->sx_complete, 2 * HZ); - /* - * Invalidate it toward resume. - */ - trans_pcie->sx_complete = false; + ret = iwl_pcie_d3_handshake(trans, true); + if (ret) + return ret; - if (!ret) { - IWL_ERR(trans, "Timeout entering D3\n"); - return -ETIMEDOUT; - } - } iwl_pcie_d3_complete_suspend(trans, test, reset); return 0; @@ -1525,6 +1572,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, if (test) { iwl_enable_interrupts(trans); *status = IWL_D3_STATUS_ALIVE; + ret = 0; goto out; } @@ -1573,25 +1621,10 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, *status = IWL_D3_STATUS_ALIVE; out: - if (*status == IWL_D3_STATUS_ALIVE && - trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { - trans_pcie->sx_complete = false; - iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, - UREG_DOORBELL_TO_ISR6_RESUME); - - ret = wait_event_timeout(trans_pcie->sx_waitq, - trans_pcie->sx_complete, 2 * HZ); - /* - * Invalidate it toward next suspend. - */ - trans_pcie->sx_complete = false; + if (*status == IWL_D3_STATUS_ALIVE) + ret = iwl_pcie_d3_handshake(trans, false); - if (!ret) { - IWL_ERR(trans, "Timeout exiting D3\n"); - return -ETIMEDOUT; - } - } - return 0; + return ret; } static void @@ -1778,9 +1811,7 @@ static int iwl_pcie_gen2_force_power_gating(struct iwl_trans *trans) iwl_clear_bits_prph(trans, HPM_HIPM_GEN_CFG, HPM_HIPM_GEN_CFG_CR_FORCE_ACTIVE); - iwl_trans_pcie_sw_reset(trans); - - return 0; + return iwl_trans_pcie_sw_reset(trans, true); } static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans) @@ -1800,7 +1831,9 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans) if (err) return err; - iwl_trans_pcie_sw_reset(trans); + err = iwl_trans_pcie_sw_reset(trans, true); + if (err) + return err; if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_22000 && trans->trans_cfg->integrated) { @@ -3599,8 +3632,9 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, * in the old format. */ if (cfg_trans->device_family >= IWL_DEVICE_FAMILY_8000) - trans->hw_rev = (trans->hw_rev & 0xfff0) | - (CSR_HW_REV_STEP(trans->hw_rev << 2) << 2); + trans->hw_rev_step = trans->hw_rev & 0xF; + else + trans->hw_rev_step = (trans->hw_rev & 0xC) >> 2; IWL_DEBUG_INFO(trans, "HW REV: 0x%0x\n", trans->hw_rev); diff --git a/drivers/net/wireless/intel/iwlwifi/queue/tx.c b/drivers/net/wireless/intel/iwlwifi/queue/tx.c index 451b06069350..0730657d54bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/queue/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/queue/tx.c @@ -1072,6 +1072,7 @@ int iwl_txq_alloc(struct iwl_trans *trans, struct iwl_txq *txq, int slots_num, return 0; err_free_tfds: dma_free_coherent(trans->dev, tfd_sz, txq->tfds, txq->dma_addr); + txq->tfds = NULL; error: if (txq->entries && cmd_queue) for (i = 0; i < slots_num; i++) @@ -1752,8 +1753,11 @@ static int iwl_trans_txq_send_hcmd_sync(struct iwl_trans *trans, } if (test_bit(STATUS_FW_ERROR, &trans->status)) { - IWL_ERR(trans, "FW error in SYNC CMD %s\n", cmd_str); - dump_stack(); + if (!test_and_clear_bit(STATUS_SUPPRESS_CMD_ERROR_ONCE, + &trans->status)) { + IWL_ERR(trans, "FW error in SYNC CMD %s\n", cmd_str); + dump_stack(); + } ret = -EIO; goto cancel; } diff --git a/drivers/net/wireless/intersil/hostap/hostap_hw.c b/drivers/net/wireless/intersil/hostap/hostap_hw.c index e459e7192ae9..b74f4cb5d6d3 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_hw.c +++ b/drivers/net/wireless/intersil/hostap/hostap_hw.c @@ -1815,8 +1815,9 @@ static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev) memset(&txdesc, 0, sizeof(txdesc)); /* skb->data starts with txdesc->frame_control */ - hdr_len = 24; - skb_copy_from_linear_data(skb, &txdesc.frame_control, hdr_len); + hdr_len = sizeof(txdesc.header); + BUILD_BUG_ON(hdr_len != 24); + skb_copy_from_linear_data(skb, &txdesc.header, hdr_len); if (ieee80211_is_data(txdesc.frame_control) && ieee80211_has_a4(txdesc.frame_control) && skb->len >= 30) { diff --git a/drivers/net/wireless/intersil/hostap/hostap_wlan.h b/drivers/net/wireless/intersil/hostap/hostap_wlan.h index dd2603d9b5d3..c25cd21d18bd 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_wlan.h +++ b/drivers/net/wireless/intersil/hostap/hostap_wlan.h @@ -115,12 +115,14 @@ struct hfa384x_tx_frame { __le16 tx_control; /* HFA384X_TX_CTRL_ flags */ /* 802.11 */ - __le16 frame_control; /* parts not used */ - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; /* filled by firmware */ - u8 addr3[ETH_ALEN]; - __le16 seq_ctrl; /* filled by firmware */ + struct_group(header, + __le16 frame_control; /* parts not used */ + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; /* filled by firmware */ + u8 addr3[ETH_ALEN]; + __le16 seq_ctrl; /* filled by firmware */ + ); u8 addr4[ETH_ALEN]; __le16 data_len; diff --git a/drivers/net/wireless/marvell/libertas/host.h b/drivers/net/wireless/marvell/libertas/host.h index dfa22468b14a..ceff4b92e7a1 100644 --- a/drivers/net/wireless/marvell/libertas/host.h +++ b/drivers/net/wireless/marvell/libertas/host.h @@ -308,10 +308,12 @@ struct txpd { __le32 tx_packet_location; /* Tx packet length */ __le16 tx_packet_length; - /* First 2 byte of destination MAC address */ - u8 tx_dest_addr_high[2]; - /* Last 4 byte of destination MAC address */ - u8 tx_dest_addr_low[4]; + struct_group_attr(tx_dest_addr, __packed, + /* First 2 byte of destination MAC address */ + u8 tx_dest_addr_high[2]; + /* Last 4 byte of destination MAC address */ + u8 tx_dest_addr_low[4]; + ); /* Pkt Priority */ u8 priority; /* Pkt Trasnit Power control */ diff --git a/drivers/net/wireless/marvell/libertas/tx.c b/drivers/net/wireless/marvell/libertas/tx.c index aeb481740df6..27304a98787d 100644 --- a/drivers/net/wireless/marvell/libertas/tx.c +++ b/drivers/net/wireless/marvell/libertas/tx.c @@ -113,6 +113,7 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) p802x_hdr = skb->data; pkt_len = skb->len; + BUILD_BUG_ON(sizeof(txpd->tx_dest_addr) != ETH_ALEN); if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) { struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data; @@ -124,10 +125,10 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) pkt_len -= sizeof(*rtap_hdr); /* copy destination address from 802.11 header */ - memcpy(txpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN); + memcpy(&txpd->tx_dest_addr, p802x_hdr + 4, ETH_ALEN); } else { /* copy destination address from 802.3 header */ - memcpy(txpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN); + memcpy(&txpd->tx_dest_addr, p802x_hdr, ETH_ALEN); } txpd->tx_packet_length = cpu_to_le16(pkt_len); diff --git a/drivers/net/wireless/marvell/libertas_tf/libertas_tf.h b/drivers/net/wireless/marvell/libertas_tf/libertas_tf.h index 5d726545d987..631b5da09f86 100644 --- a/drivers/net/wireless/marvell/libertas_tf/libertas_tf.h +++ b/drivers/net/wireless/marvell/libertas_tf/libertas_tf.h @@ -268,10 +268,12 @@ struct txpd { __le32 tx_packet_location; /* Tx packet length */ __le16 tx_packet_length; - /* First 2 byte of destination MAC address */ - u8 tx_dest_addr_high[2]; - /* Last 4 byte of destination MAC address */ - u8 tx_dest_addr_low[4]; + struct_group_attr(tx_dest_addr, __packed, + /* First 2 byte of destination MAC address */ + u8 tx_dest_addr_high[2]; + /* Last 4 byte of destination MAC address */ + u8 tx_dest_addr_low[4]; + ); /* Pkt Priority */ u8 priority; /* Pkt Trasnit Power control */ @@ -280,7 +282,7 @@ struct txpd { u8 pktdelay_2ms; /* reserved */ u8 reserved1; -}; +} __packed; /* RxPD Descriptor */ struct rxpd { @@ -311,7 +313,7 @@ struct rxpd { /* Pkt Priority */ u8 priority; u8 reserved[3]; -}; +} __packed; struct cmd_header { __le16 command; @@ -377,14 +379,14 @@ struct cmd_ds_mac_control { struct cmd_header hdr; __le16 action; u16 reserved; -}; +} __packed; struct cmd_ds_802_11_mac_address { struct cmd_header hdr; __le16 action; uint8_t macadd[ETH_ALEN]; -}; +} __packed; struct cmd_ds_mac_multicast_addr { struct cmd_header hdr; @@ -392,27 +394,27 @@ struct cmd_ds_mac_multicast_addr { __le16 action; __le16 nr_of_adrs; u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE]; -}; +} __packed; struct cmd_ds_set_mode { struct cmd_header hdr; __le16 mode; -}; +} __packed; struct cmd_ds_set_bssid { struct cmd_header hdr; u8 bssid[6]; u8 activate; -}; +} __packed; struct cmd_ds_802_11_radio_control { struct cmd_header hdr; __le16 action; __le16 control; -}; +} __packed; struct cmd_ds_802_11_rf_channel { @@ -423,20 +425,20 @@ struct cmd_ds_802_11_rf_channel { __le16 rftype; /* unused */ __le16 reserved; /* unused */ u8 channellist[32]; /* unused */ -}; +} __packed; struct cmd_ds_set_boot2_ver { struct cmd_header hdr; __le16 action; __le16 version; -}; +} __packed; struct cmd_ds_802_11_reset { struct cmd_header hdr; __le16 action; -}; +} __packed; struct cmd_ds_802_11_beacon_control { struct cmd_header hdr; @@ -444,14 +446,14 @@ struct cmd_ds_802_11_beacon_control { __le16 action; __le16 beacon_enable; __le16 beacon_period; -}; +} __packed; struct cmd_ds_802_11_beacon_set { struct cmd_header hdr; __le16 len; u8 beacon[MRVL_MAX_BCN_SIZE]; -}; +} __packed; struct cmd_ctrl_node; diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c index 71492211904b..02a1e1f547d8 100644 --- a/drivers/net/wireless/marvell/libertas_tf/main.c +++ b/drivers/net/wireless/marvell/libertas_tf/main.c @@ -232,7 +232,8 @@ static void lbtf_tx_work(struct work_struct *work) ieee80211_get_tx_rate(priv->hw, info)->hw_value); /* copy destination address from 802.11 header */ - memcpy(txpd->tx_dest_addr_high, skb->data + sizeof(struct txpd) + 4, + BUILD_BUG_ON(sizeof(txpd->tx_dest_addr) != ETH_ALEN); + memcpy(&txpd->tx_dest_addr, skb->data + sizeof(struct txpd) + 4, ETH_ALEN); txpd->tx_packet_length = cpu_to_le16(len); txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd)); diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index 2ff23ab259ab..63c25c69ed2b 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -2071,9 +2071,11 @@ struct mwifiex_ie_types_robust_coex { __le32 mode; } __packed; +#define MWIFIEX_VERSION_STR_LENGTH 128 + struct host_cmd_ds_version_ext { u8 version_str_sel; - char version_str[128]; + char version_str[MWIFIEX_VERSION_STR_LENGTH]; } __packed; struct host_cmd_ds_mgmt_frame_reg { diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 19b996c6a260..ace7371c4773 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -226,6 +226,23 @@ exit_rx_proc: return 0; } +static void maybe_quirk_fw_disable_ds(struct mwifiex_adapter *adapter) +{ + struct mwifiex_private *priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); + struct mwifiex_ver_ext ver_ext; + + if (test_and_set_bit(MWIFIEX_IS_REQUESTING_FW_VEREXT, &adapter->work_flags)) + return; + + memset(&ver_ext, 0, sizeof(ver_ext)); + ver_ext.version_str_sel = 1; + if (mwifiex_send_cmd(priv, HostCmd_CMD_VERSION_EXT, + HostCmd_ACT_GEN_GET, 0, &ver_ext, false)) { + mwifiex_dbg(priv->adapter, MSG, + "Checking hardware revision failed.\n"); + } +} + /* * The main process. * @@ -356,6 +373,7 @@ process_start: if (adapter->hw_status == MWIFIEX_HW_STATUS_INIT_DONE) { adapter->hw_status = MWIFIEX_HW_STATUS_READY; mwifiex_init_fw_complete(adapter); + maybe_quirk_fw_disable_ds(adapter); } } diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 90012cbcfd15..332dd1c8db35 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -524,6 +524,7 @@ enum mwifiex_adapter_work_flags { MWIFIEX_IS_SUSPENDED, MWIFIEX_IS_HS_CONFIGURED, MWIFIEX_IS_HS_ENABLING, + MWIFIEX_IS_REQUESTING_FW_VEREXT, }; struct mwifiex_band_config { @@ -646,7 +647,7 @@ struct mwifiex_private { struct wireless_dev wdev; struct mwifiex_chan_freq_power cfp; u32 versionstrsel; - char version_str[128]; + char version_str[MWIFIEX_VERSION_STR_LENGTH]; #ifdef CONFIG_DEBUG_FS struct dentry *dfs_dev_dir; #endif @@ -1055,6 +1056,8 @@ struct mwifiex_adapter { void *devdump_data; int devdump_len; struct timer_list devdump_timer; + + bool ignore_btcoex_events; }; void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter); diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index c3f5583ea70d..d5fb29400bad 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -3152,6 +3152,9 @@ static int mwifiex_init_pcie(struct mwifiex_adapter *adapter) if (ret) goto err_alloc_buffers; + if (pdev->device == PCIE_DEVICE_ID_MARVELL_88W8897) + adapter->ignore_btcoex_events = true; + return 0; err_alloc_buffers: diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c index 6b5d35d9e69f..1a4ae8a42a31 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c @@ -708,11 +708,35 @@ static int mwifiex_ret_ver_ext(struct mwifiex_private *priv, { struct host_cmd_ds_version_ext *ver_ext = &resp->params.verext; + if (test_and_clear_bit(MWIFIEX_IS_REQUESTING_FW_VEREXT, &priv->adapter->work_flags)) { + if (strncmp(ver_ext->version_str, "ChipRev:20, BB:9b(10.00), RF:40(21)", + MWIFIEX_VERSION_STR_LENGTH) == 0) { + struct mwifiex_ds_auto_ds auto_ds = { + .auto_ds = DEEP_SLEEP_OFF, + }; + + mwifiex_dbg(priv->adapter, MSG, + "Bad HW revision detected, disabling deep sleep\n"); + + if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, + DIS_AUTO_PS, BITMAP_AUTO_DS, &auto_ds, false)) { + mwifiex_dbg(priv->adapter, MSG, + "Disabling deep sleep failed.\n"); + } + } + + return 0; + } + if (version_ext) { version_ext->version_str_sel = ver_ext->version_str_sel; memcpy(version_ext->version_str, ver_ext->version_str, - sizeof(char) * 128); - memcpy(priv->version_str, ver_ext->version_str, 128); + MWIFIEX_VERSION_STR_LENGTH); + memcpy(priv->version_str, ver_ext->version_str, + MWIFIEX_VERSION_STR_LENGTH); + + /* Ensure the version string from the firmware is 0-terminated */ + priv->version_str[MWIFIEX_VERSION_STR_LENGTH - 1] = '\0'; } return 0; } diff --git a/drivers/net/wireless/marvell/mwifiex/sta_event.c b/drivers/net/wireless/marvell/mwifiex/sta_event.c index 68c63268e2e6..7d42c5d2dbf6 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_event.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_event.c @@ -365,10 +365,12 @@ static void mwifiex_process_uap_tx_pause(struct mwifiex_private *priv, sta_ptr = mwifiex_get_sta_entry(priv, tp->peermac); if (sta_ptr && sta_ptr->tx_pause != tp->tx_pause) { sta_ptr->tx_pause = tp->tx_pause; + spin_unlock_bh(&priv->sta_list_spinlock); mwifiex_update_ralist_tx_pause(priv, tp->peermac, tp->tx_pause); + } else { + spin_unlock_bh(&priv->sta_list_spinlock); } - spin_unlock_bh(&priv->sta_list_spinlock); } } @@ -400,11 +402,13 @@ static void mwifiex_process_sta_tx_pause(struct mwifiex_private *priv, sta_ptr = mwifiex_get_sta_entry(priv, tp->peermac); if (sta_ptr && sta_ptr->tx_pause != tp->tx_pause) { sta_ptr->tx_pause = tp->tx_pause; + spin_unlock_bh(&priv->sta_list_spinlock); mwifiex_update_ralist_tx_pause(priv, tp->peermac, tp->tx_pause); + } else { + spin_unlock_bh(&priv->sta_list_spinlock); } - spin_unlock_bh(&priv->sta_list_spinlock); } } } @@ -1058,6 +1062,9 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) break; case EVENT_BT_COEX_WLAN_PARA_CHANGE: dev_dbg(adapter->dev, "EVENT: BT coex wlan param update\n"); + if (adapter->ignore_btcoex_events) + break; + mwifiex_bt_coex_wlan_param_update_event(priv, adapter->event_skb); break; diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index 9736aa0ab7fd..8f01fcbe9396 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -130,7 +130,8 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter, default: mwifiex_dbg(adapter, ERROR, "unknown recv_type %#x\n", recv_type); - return -1; + ret = -1; + goto exit_restore_skb; } break; case MWIFIEX_USB_EP_DATA: diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c index 529e325498cd..864a2ba9efee 100644 --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c @@ -4225,9 +4225,11 @@ struct mwl8k_cmd_set_key { __le32 key_info; __le32 key_id; __le16 key_len; - __u8 key_material[MAX_ENCR_KEY_LENGTH]; - __u8 tkip_tx_mic_key[MIC_KEY_LENGTH]; - __u8 tkip_rx_mic_key[MIC_KEY_LENGTH]; + struct { + __u8 key_material[MAX_ENCR_KEY_LENGTH]; + __u8 tkip_tx_mic_key[MIC_KEY_LENGTH]; + __u8 tkip_rx_mic_key[MIC_KEY_LENGTH]; + } tkip; __le16 tkip_rsc_low; __le32 tkip_rsc_high; __le16 tkip_tsc_low; @@ -4375,7 +4377,7 @@ static int mwl8k_cmd_encryption_set_key(struct ieee80211_hw *hw, goto done; } - memcpy(cmd->key_material, key->key, keymlen); + memcpy(&cmd->tkip, key->key, keymlen); cmd->action = cpu_to_le32(action); rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index 79ab850a45a2..c78ae4b89761 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -34,4 +34,4 @@ obj-$(CONFIG_MT76x2_COMMON) += mt76x2/ obj-$(CONFIG_MT7603E) += mt7603/ obj-$(CONFIG_MT7615_COMMON) += mt7615/ obj-$(CONFIG_MT7915E) += mt7915/ -obj-$(CONFIG_MT7921E) += mt7921/ +obj-$(CONFIG_MT7921_COMMON) += mt7921/ diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c index b8bcf22a07fd..027d9ea17d04 100644 --- a/drivers/net/wireless/mediatek/mt76/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/debugfs.c @@ -74,13 +74,12 @@ EXPORT_SYMBOL_GPL(mt76_queues_read); static int mt76_rx_queues_read(struct seq_file *s, void *data) { struct mt76_dev *dev = dev_get_drvdata(s->private); - int i, queued; + int i; seq_puts(s, " queue | hw-queued | head | tail |\n"); mt76_for_each_q_rx(dev, i) { struct mt76_queue *q = &dev->q_rx[i]; - queued = mt76_is_usb(dev) ? q->ndesc - q->queued : q->queued; seq_printf(s, " %9d | %9d | %9d | %9d |\n", i, q->queued, q->head, q->tail); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c index 5ee52cd70a4b..d1806f198aed 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c @@ -143,8 +143,6 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (!wcid) wcid = &dev->mt76.global_wcid; - pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); - if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && msta) { struct mt7615_phy *phy = &dev->phy; @@ -164,6 +162,7 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (id < 0) return id; + pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); mt7615_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, sta, pid, key, false); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c index bd2939ebcbf4..5a6d7829c6e0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c @@ -43,19 +43,11 @@ EXPORT_SYMBOL_GPL(mt7663_usb_sdio_reg_map); static void mt7663_usb_sdio_write_txwi(struct mt7615_dev *dev, struct mt76_wcid *wcid, enum mt76_txq_id qid, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, int pid, struct sk_buff *skb) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_key_conf *key = info->control.hw_key; - __le32 *txwi; - int pid; - - if (!wcid) - wcid = &dev->mt76.global_wcid; - - pid = mt76_tx_status_skb_add(&dev->mt76, wcid, skb); + __le32 *txwi = (__le32 *)(skb->data - MT_USB_TXD_SIZE); - txwi = (__le32 *)(skb->data - MT_USB_TXD_SIZE); memset(txwi, 0, MT_USB_TXD_SIZE); mt7615_mac_write_txwi(dev, txwi, skb, wcid, sta, pid, key, false); skb_push(skb, MT_USB_TXD_SIZE); @@ -194,10 +186,14 @@ int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); struct sk_buff *skb = tx_info->skb; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_key_conf *key = info->control.hw_key; struct mt7615_sta *msta; - int pad; + int pad, err, pktid; msta = wcid ? container_of(wcid, struct mt7615_sta, wcid) : NULL; + if (!wcid) + wcid = &dev->mt76.global_wcid; + if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && msta && !msta->rate_probe) { /* request to configure sampling rate */ @@ -207,7 +203,8 @@ int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, spin_unlock_bh(&dev->mt76.lock); } - mt7663_usb_sdio_write_txwi(dev, wcid, qid, sta, skb); + pktid = mt76_tx_status_skb_add(&dev->mt76, wcid, skb); + mt7663_usb_sdio_write_txwi(dev, wcid, qid, sta, key, pktid, skb); if (mt76_is_usb(mdev)) { u32 len = skb->len; @@ -217,7 +214,12 @@ int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, pad = round_up(skb->len, 4) - skb->len; } - return mt76_skb_adjust_pad(skb, pad); + err = mt76_skb_adjust_pad(skb, pad); + if (err) + /* Release pktid in case of error. */ + idr_remove(&wcid->pktid, pktid); + + return err; } EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_prepare_skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index efd70ddc2fd1..2c6c03809b20 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -72,6 +72,7 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data, bool ampdu = IEEE80211_SKB_CB(tx_info->skb)->flags & IEEE80211_TX_CTL_AMPDU; enum mt76_qsel qsel; u32 flags; + int err; mt76_insert_hdr_pad(tx_info->skb); @@ -106,7 +107,12 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data, ewma_pktlen_add(&msta->pktlen, tx_info->skb->len); } - return mt76x02u_skb_dma_info(tx_info->skb, WLAN_PORT, flags); + err = mt76x02u_skb_dma_info(tx_info->skb, WLAN_PORT, flags); + if (err && wcid) + /* Release pktid in case of error. */ + idr_remove(&wcid->pktid, pid); + + return err; } EXPORT_SYMBOL_GPL(mt76x02u_tx_prepare_skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 5fcf35f2d9fb..809dc18e5083 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1151,8 +1151,14 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, } } - pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); + t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size); + t->skb = tx_info->skb; + + id = mt76_token_consume(mdev, &t); + if (id < 0) + return id; + pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid, key, false); @@ -1178,13 +1184,6 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, txp->bss_idx = mvif->idx; } - t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size); - t->skb = tx_info->skb; - - id = mt76_token_consume(mdev, &t); - if (id < 0) - return id; - txp->token = cpu_to_le16(id); if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) txp->rept_wds_wcid = cpu_to_le16(wcid->idx); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 899957b9d0f1..852d5d97c70b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -176,7 +176,7 @@ mt7915_get_phy_mode(struct ieee80211_vif *vif, struct ieee80211_sta *sta) if (ht_cap->ht_supported) mode |= PHY_MODE_GN; - if (he_cap->has_he) + if (he_cap && he_cap->has_he) mode |= PHY_MODE_AX_24G; } else if (band == NL80211_BAND_5GHZ) { mode |= PHY_MODE_A; @@ -187,7 +187,7 @@ mt7915_get_phy_mode(struct ieee80211_vif *vif, struct ieee80211_sta *sta) if (vht_cap->vht_supported) mode |= PHY_MODE_AC; - if (he_cap->has_he) + if (he_cap && he_cap->has_he) mode |= PHY_MODE_AX_5G; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c index 137f86a6dbf8..bdec508b6b9f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c @@ -142,15 +142,11 @@ out: static void mt7921s_write_txwi(struct mt7921_dev *dev, struct mt76_wcid *wcid, enum mt76_txq_id qid, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, int pid, struct sk_buff *skb) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_key_conf *key = info->control.hw_key; - __le32 *txwi; - int pid; + __le32 *txwi = (__le32 *)(skb->data - MT_SDIO_TXD_SIZE); - pid = mt76_tx_status_skb_add(&dev->mt76, wcid, skb); - txwi = (__le32 *)(skb->data - MT_SDIO_TXD_SIZE); memset(txwi, 0, MT_SDIO_TXD_SIZE); mt7921_mac_write_txwi(dev, txwi, skb, wcid, key, pid, false); skb_push(skb, MT_SDIO_TXD_SIZE); @@ -163,8 +159,9 @@ int mt7921s_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, { struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); + struct ieee80211_key_conf *key = info->control.hw_key; struct sk_buff *skb = tx_info->skb; - int pad; + int err, pad, pktid; if (unlikely(tx_info->skb->len <= ETH_HLEN)) return -EINVAL; @@ -181,12 +178,18 @@ int mt7921s_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, } } - mt7921s_write_txwi(dev, wcid, qid, sta, skb); + pktid = mt76_tx_status_skb_add(&dev->mt76, wcid, skb); + mt7921s_write_txwi(dev, wcid, qid, sta, key, pktid, skb); mt7921_skb_add_sdio_hdr(skb, MT7921_SDIO_DATA); pad = round_up(skb->len, 4) - skb->len; - return mt76_skb_adjust_pad(skb, pad); + err = mt76_skb_adjust_pad(skb, pad); + if (err) + /* Release pktid in case of error. */ + idr_remove(&wcid->pktid, pktid); + + return err; } void mt7921s_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 11719ef034d8..6b8c9dc80542 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -173,7 +173,7 @@ mt76_tx_status_skb_get(struct mt76_dev *dev, struct mt76_wcid *wcid, int pktid, if (!(cb->flags & MT_TX_CB_DMA_DONE)) continue; - if (!time_is_after_jiffies(cb->jiffies + + if (time_is_after_jiffies(cb->jiffies + MT_TX_STATUS_SKB_TIMEOUT)) continue; } diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index dc4bfe7be378..8d8378bafd9b 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -1737,23 +1737,15 @@ int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, INIT_LIST_HEAD(&wl->rxq_head.list); INIT_LIST_HEAD(&wl->vif_list); - wl->hif_workqueue = create_singlethread_workqueue("WILC_wq"); - if (!wl->hif_workqueue) { - ret = -ENOMEM; - goto free_cfg; - } vif = wilc_netdev_ifc_init(wl, "wlan%d", WILC_STATION_MODE, NL80211_IFTYPE_STATION, false); if (IS_ERR(vif)) { ret = PTR_ERR(vif); - goto free_hq; + goto free_cfg; } return 0; -free_hq: - destroy_workqueue(wl->hif_workqueue); - free_cfg: wilc_wlan_cfg_deinit(wl); diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c index e69b9c7f3d31..71b44cfe0dfc 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.c +++ b/drivers/net/wireless/microchip/wilc1000/hif.c @@ -1312,7 +1312,7 @@ int wilc_set_mac_address(struct wilc_vif *vif, u8 *mac_addr) result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); if (result) - netdev_err(vif->ndev, "Failed to get mac address\n"); + netdev_err(vif->ndev, "Failed to set mac address\n"); return result; } @@ -1929,6 +1929,7 @@ int wilc_edit_station(struct wilc_vif *vif, const u8 *mac, int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout) { + struct wilc *wilc = vif->wilc; struct wid wid; int result; s8 power_mode; @@ -1944,6 +1945,8 @@ int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout) result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); if (result) netdev_err(vif->ndev, "Failed to send power management\n"); + else + wilc->power_save_mode = enabled; return result; } diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c index 690572e01a2a..03e3485d7e7f 100644 --- a/drivers/net/wireless/microchip/wilc1000/netdev.c +++ b/drivers/net/wireless/microchip/wilc1000/netdev.c @@ -27,7 +27,7 @@ static irqreturn_t isr_uh_routine(int irq, void *user_data) struct wilc *wilc = user_data; if (wilc->close) { - pr_err("Can't handle UH interrupt"); + pr_err("Can't handle UH interrupt\n"); return IRQ_HANDLED; } return IRQ_WAKE_THREAD; @@ -56,7 +56,7 @@ static int init_irq(struct net_device *dev) ret = request_threaded_irq(wl->dev_irq_num, isr_uh_routine, isr_bh_routine, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - "WILC_IRQ", wl); + dev->name, wl); if (ret) { netdev_err(dev, "Failed to request IRQ [%d]\n", ret); return ret; @@ -468,7 +468,7 @@ static int wlan_initialize_threads(struct net_device *dev) struct wilc *wilc = vif->wilc; wilc->txq_thread = kthread_run(wilc_txq_task, (void *)wilc, - "K_TXQ_TASK"); + "%s-tx", dev->name); if (IS_ERR(wilc->txq_thread)) { netdev_err(dev, "couldn't create TXQ thread\n"); wilc->close = 0; @@ -574,6 +574,7 @@ static int wilc_mac_open(struct net_device *ndev) struct wilc *wl = vif->wilc; int ret = 0; struct mgmt_frame_regs mgmt_regs = {}; + u8 addr[ETH_ALEN] __aligned(2); if (!wl || !wl->dev) { netdev_err(ndev, "device not ready\n"); @@ -596,10 +597,9 @@ static int wilc_mac_open(struct net_device *ndev) vif->idx); if (is_valid_ether_addr(ndev->dev_addr)) { - wilc_set_mac_address(vif, ndev->dev_addr); + ether_addr_copy(addr, ndev->dev_addr); + wilc_set_mac_address(vif, addr); } else { - u8 addr[ETH_ALEN]; - wilc_get_mac_address(vif, addr); eth_hw_addr_set(ndev, addr); } @@ -962,8 +962,15 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name, ret = register_netdev(ndev); if (ret) { - free_netdev(ndev); - return ERR_PTR(-EFAULT); + ret = -EFAULT; + goto error; + } + + wl->hif_workqueue = alloc_ordered_workqueue("%s-wq", WQ_MEM_RECLAIM, + ndev->name); + if (!wl->hif_workqueue) { + ret = -ENOMEM; + goto error; } ndev->needs_free_netdev = true; @@ -977,6 +984,10 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name, synchronize_srcu(&wl->srcu); return vif; + + error: + free_netdev(ndev); + return ERR_PTR(ret); } MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.h b/drivers/net/wireless/microchip/wilc1000/netdev.h index b9a88b3e322f..6c0e634d0249 100644 --- a/drivers/net/wireless/microchip/wilc1000/netdev.h +++ b/drivers/net/wireless/microchip/wilc1000/netdev.h @@ -212,6 +212,7 @@ struct wilc { s8 mac_status; struct clk *rtc_clk; bool initialized; + bool power_save_mode; int dev_irq_num; int close; u8 vif_num; diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c index 640850f989dd..e0871b89917d 100644 --- a/drivers/net/wireless/microchip/wilc1000/spi.c +++ b/drivers/net/wireless/microchip/wilc1000/spi.c @@ -12,6 +12,8 @@ #include "netdev.h" #include "cfg80211.h" +#define SPI_MODALIAS "wilc1000_spi" + static bool enable_crc7; /* protect SPI commands with CRC7 */ module_param(enable_crc7, bool, 0644); MODULE_PARM_DESC(enable_crc7, @@ -99,8 +101,6 @@ static int wilc_spi_reset(struct wilc *wilc); #define DATA_PKT_LOG_SZ DATA_PKT_LOG_SZ_MAX #define DATA_PKT_SZ (1 << DATA_PKT_LOG_SZ) -#define USE_SPI_DMA 0 - #define WILC_SPI_COMMAND_STAT_SUCCESS 0 #define WILC_GET_RESP_HDR_START(h) (((h) >> 4) & 0xf) @@ -203,11 +203,18 @@ static const struct of_device_id wilc_of_match[] = { }; MODULE_DEVICE_TABLE(of, wilc_of_match); +static const struct spi_device_id wilc_spi_id[] = { + { "wilc1000", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(spi, wilc_spi_id); + static struct spi_driver wilc_spi_driver = { .driver = { - .name = MODALIAS, + .name = SPI_MODALIAS, .of_match_table = wilc_of_match, }, + .id_table = wilc_spi_id, .probe = wilc_bus_probe, .remove = wilc_bus_remove, }; @@ -240,7 +247,6 @@ static int wilc_spi_tx(struct wilc *wilc, u8 *b, u32 len) memset(&msg, 0, sizeof(msg)); spi_message_init(&msg); msg.spi = spi; - msg.is_dma_mapped = USE_SPI_DMA; spi_message_add_tail(&tr, &msg); ret = spi_sync(spi, &msg); @@ -284,7 +290,6 @@ static int wilc_spi_rx(struct wilc *wilc, u8 *rb, u32 rlen) memset(&msg, 0, sizeof(msg)); spi_message_init(&msg); msg.spi = spi; - msg.is_dma_mapped = USE_SPI_DMA; spi_message_add_tail(&tr, &msg); ret = spi_sync(spi, &msg); @@ -323,7 +328,6 @@ static int wilc_spi_tx_rx(struct wilc *wilc, u8 *wb, u8 *rb, u32 rlen) memset(&msg, 0, sizeof(msg)); spi_message_init(&msg); msg.spi = spi; - msg.is_dma_mapped = USE_SPI_DMA; spi_message_add_tail(&tr, &msg); ret = spi_sync(spi, &msg); diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c index ea81ef120fd1..3f339c2f46f1 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.c +++ b/drivers/net/wireless/microchip/wilc1000/wlan.c @@ -20,13 +20,13 @@ static inline bool is_wilc1000(u32 id) static inline void acquire_bus(struct wilc *wilc, enum bus_acquire acquire) { mutex_lock(&wilc->hif_cs); - if (acquire == WILC_BUS_ACQUIRE_AND_WAKEUP) + if (acquire == WILC_BUS_ACQUIRE_AND_WAKEUP && wilc->power_save_mode) chip_wakeup(wilc); } static inline void release_bus(struct wilc *wilc, enum bus_release release) { - if (release == WILC_BUS_RELEASE_ALLOW_SLEEP) + if (release == WILC_BUS_RELEASE_ALLOW_SLEEP && wilc->power_save_mode) chip_allow_sleep(wilc); mutex_unlock(&wilc->hif_cs); } @@ -626,7 +626,6 @@ void chip_wakeup(struct wilc *wilc) u32 clk_status_val = 0, trials = 0; u32 wakeup_reg, wakeup_bit; u32 clk_status_reg, clk_status_bit; - u32 to_host_from_fw_reg, to_host_from_fw_bit; u32 from_host_to_fw_reg, from_host_to_fw_bit; const struct wilc_hif_func *hif_func = wilc->hif_func; @@ -637,8 +636,6 @@ void chip_wakeup(struct wilc *wilc) clk_status_bit = WILC_SDIO_CLK_STATUS_BIT; from_host_to_fw_reg = WILC_SDIO_HOST_TO_FW_REG; from_host_to_fw_bit = WILC_SDIO_HOST_TO_FW_BIT; - to_host_from_fw_reg = WILC_SDIO_FW_TO_HOST_REG; - to_host_from_fw_bit = WILC_SDIO_FW_TO_HOST_BIT; } else { wakeup_reg = WILC_SPI_WAKEUP_REG; wakeup_bit = WILC_SPI_WAKEUP_BIT; @@ -646,8 +643,6 @@ void chip_wakeup(struct wilc *wilc) clk_status_bit = WILC_SPI_CLK_STATUS_BIT; from_host_to_fw_reg = WILC_SPI_HOST_TO_FW_REG; from_host_to_fw_bit = WILC_SPI_HOST_TO_FW_BIT; - to_host_from_fw_reg = WILC_SPI_FW_TO_HOST_REG; - to_host_from_fw_bit = WILC_SPI_FW_TO_HOST_BIT; } /* indicate host wakeup */ @@ -1229,7 +1224,8 @@ int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif) ret = 0; release: - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + /* host comm is disabled - we can't issue sleep command anymore: */ + release_bus(wilc, WILC_BUS_RELEASE_ONLY); return ret; } diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.h b/drivers/net/wireless/microchip/wilc1000/wlan.h index 13fde636aa0e..eb7978166d73 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.h +++ b/drivers/net/wireless/microchip/wilc1000/wlan.h @@ -213,8 +213,6 @@ #define WILC_RX_BUFF_SIZE (96 * 1024) #define WILC_TX_BUFF_SIZE (64 * 1024) -#define MODALIAS "WILC_SPI" - #define NQUEUES 4 #define AC_BUFFER_SIZE 1000 diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c index e4473a551241..74c3d8cb3100 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c @@ -25,6 +25,9 @@ static bool rt2x00usb_check_usb_error(struct rt2x00_dev *rt2x00dev, int status) if (status == -ENODEV || status == -ENOENT) return true; + if (!test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) + return false; + if (status == -EPROTO || status == -ETIMEDOUT) rt2x00dev->num_proto_errs++; else diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c index 9b83c710c9b8..51fe51bb0504 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c @@ -899,7 +899,7 @@ static u8 _rtl92c_phy_get_rightchnlplace(u8 chnl) u8 place = chnl; if (chnl > 14) { - for (place = 14; place < sizeof(channel5g); place++) { + for (place = 14; place < ARRAY_SIZE(channel5g); place++) { if (channel5g[place] == chnl) { place++; break; @@ -1366,7 +1366,7 @@ u8 rtl92d_get_rightchnlplace_for_iqk(u8 chnl) u8 place; if (chnl > 14) { - for (place = 14; place < sizeof(channel_all); place++) { + for (place = 14; place < ARRAY_SIZE(channel_all); place++) { if (channel_all[place] == chnl) return place - 13; } @@ -2428,7 +2428,7 @@ static bool _rtl92d_is_legal_5g_channel(struct ieee80211_hw *hw, u8 channel) int i; - for (i = 0; i < sizeof(channel5g); i++) + for (i = 0; i < ARRAY_SIZE(channel5g); i++) if (channel == channel5g[i]) return true; return false; @@ -2692,9 +2692,8 @@ void rtl92d_phy_reset_iqk_result(struct ieee80211_hw *hw) u8 i; rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, - "settings regs %d default regs %d\n", - (int)(sizeof(rtlphy->iqk_matrix) / - sizeof(struct iqk_matrix_regs)), + "settings regs %zu default regs %d\n", + ARRAY_SIZE(rtlphy->iqk_matrix), IQK_MATRIX_REG_NUM); /* 0xe94, 0xe9c, 0xea4, 0xeac, 0xeb4, 0xebc, 0xec4, 0xecc */ for (i = 0; i < IQK_MATRIX_SETTINGS_NUM; i++) { @@ -2861,16 +2860,14 @@ u8 rtl92d_phy_sw_chnl(struct ieee80211_hw *hw) case BAND_ON_5G: /* Get first channel error when change between * 5G and 2.4G band. */ - if (channel <= 14) + if (WARN_ONCE(channel <= 14, "rtl8192de: 5G but channel<=14\n")) return 0; - WARN_ONCE((channel <= 14), "rtl8192de: 5G but channel<=14\n"); break; case BAND_ON_2_4G: /* Get first channel error when change between * 5G and 2.4G band. */ - if (channel > 14) + if (WARN_ONCE(channel > 14, "rtl8192de: 2G but channel>14\n")) return 0; - WARN_ONCE((channel > 14), "rtl8192de: 2G but channel>14\n"); break; default: WARN_ONCE(true, "rtl8192de: Invalid WirelessMode(%#x)!!\n", diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index aa07856411b1..31f9e9e5c680 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -108,7 +108,6 @@ #define CHANNEL_GROUP_IDX_5GM 6 #define CHANNEL_GROUP_IDX_5GH 9 #define CHANNEL_GROUP_MAX_5G 9 -#define CHANNEL_MAX_NUMBER_2G 14 #define AVG_THERMAL_NUM 8 #define AVG_THERMAL_NUM_88E 4 #define AVG_THERMAL_NUM_8723BE 4 diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c index 682b23502e6e..b863c74b51e6 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.c +++ b/drivers/net/wireless/realtek/rtw88/debug.c @@ -152,6 +152,22 @@ static int rtw_debugfs_get_rf_read(struct seq_file *m, void *v) return 0; } +static int rtw_debugfs_get_fix_rate(struct seq_file *m, void *v) +{ + struct rtw_debugfs_priv *debugfs_priv = m->private; + struct rtw_dev *rtwdev = debugfs_priv->rtwdev; + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 fix_rate = dm_info->fix_rate; + + if (fix_rate >= DESC_RATE_MAX) { + seq_printf(m, "Fix rate disabled, fix_rate = %u\n", fix_rate); + return 0; + } + + seq_printf(m, "Data frames fixed at desc rate %u\n", fix_rate); + return 0; +} + static int rtw_debugfs_copy_from_user(char tmp[], int size, const char __user *buffer, size_t count, int num) @@ -437,6 +453,31 @@ static ssize_t rtw_debugfs_set_rf_read(struct file *filp, return count; } +static ssize_t rtw_debugfs_set_fix_rate(struct file *filp, + const char __user *buffer, + size_t count, loff_t *loff) +{ + struct seq_file *seqpriv = (struct seq_file *)filp->private_data; + struct rtw_debugfs_priv *debugfs_priv = seqpriv->private; + struct rtw_dev *rtwdev = debugfs_priv->rtwdev; + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 fix_rate; + char tmp[32 + 1]; + int ret; + + rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); + + ret = kstrtou8(tmp, 0, &fix_rate); + if (ret) { + rtw_warn(rtwdev, "invalid args, [rate]\n"); + return ret; + } + + dm_info->fix_rate = fix_rate; + + return count; +} + static int rtw_debug_get_mac_page(struct seq_file *m, void *v) { struct rtw_debugfs_priv *debugfs_priv = m->private; @@ -590,6 +631,8 @@ static int rtw_debugfs_get_tx_pwr_tbl(struct seq_file *m, void *v) u8 ch = hal->current_channel; u8 regd = rtw_regd_get(rtwdev); + seq_printf(m, "channel: %u\n", ch); + seq_printf(m, "bandwidth: %u\n", bw); seq_printf(m, "regulatory: %s\n", rtw_get_regd_string(regd)); seq_printf(m, "%-4s %-10s %-3s%6s %-4s %4s (%-4s %-4s) %-4s\n", "path", "rate", "pwr", "", "base", "", "byr", "lmt", "rem"); @@ -904,6 +947,39 @@ static int rtw_debugfs_get_fw_crash(struct seq_file *m, void *v) return 0; } +static ssize_t rtw_debugfs_set_force_lowest_basic_rate(struct file *filp, + const char __user *buffer, + size_t count, loff_t *loff) +{ + struct seq_file *seqpriv = (struct seq_file *)filp->private_data; + struct rtw_debugfs_priv *debugfs_priv = seqpriv->private; + struct rtw_dev *rtwdev = debugfs_priv->rtwdev; + bool input; + int err; + + err = kstrtobool_from_user(buffer, count, &input); + if (err) + return err; + + if (input) + set_bit(RTW_FLAG_FORCE_LOWEST_RATE, rtwdev->flags); + else + clear_bit(RTW_FLAG_FORCE_LOWEST_RATE, rtwdev->flags); + + return count; +} + +static int rtw_debugfs_get_force_lowest_basic_rate(struct seq_file *m, void *v) +{ + struct rtw_debugfs_priv *debugfs_priv = m->private; + struct rtw_dev *rtwdev = debugfs_priv->rtwdev; + + seq_printf(m, "force lowest basic rate: %d\n", + test_bit(RTW_FLAG_FORCE_LOWEST_RATE, rtwdev->flags)); + + return 0; +} + static ssize_t rtw_debugfs_set_dm_cap(struct file *filp, const char __user *buffer, size_t count, loff_t *loff) @@ -1061,6 +1137,11 @@ static struct rtw_debugfs_priv rtw_debug_priv_read_reg = { .cb_read = rtw_debugfs_get_read_reg, }; +static struct rtw_debugfs_priv rtw_debug_priv_fix_rate = { + .cb_write = rtw_debugfs_set_fix_rate, + .cb_read = rtw_debugfs_get_fix_rate, +}; + static struct rtw_debugfs_priv rtw_debug_priv_dump_cam = { .cb_write = rtw_debugfs_set_single_input, .cb_read = rtw_debugfs_get_dump_cam, @@ -1094,6 +1175,11 @@ static struct rtw_debugfs_priv rtw_debug_priv_fw_crash = { .cb_read = rtw_debugfs_get_fw_crash, }; +static struct rtw_debugfs_priv rtw_debug_priv_force_lowest_basic_rate = { + .cb_write = rtw_debugfs_set_force_lowest_basic_rate, + .cb_read = rtw_debugfs_get_force_lowest_basic_rate, +}; + static struct rtw_debugfs_priv rtw_debug_priv_dm_cap = { .cb_write = rtw_debugfs_set_dm_cap, .cb_read = rtw_debugfs_get_dm_cap, @@ -1126,6 +1212,7 @@ void rtw_debugfs_init(struct rtw_dev *rtwdev) rtw_debugfs_add_rw(read_reg); rtw_debugfs_add_w(rf_write); rtw_debugfs_add_rw(rf_read); + rtw_debugfs_add_rw(fix_rate); rtw_debugfs_add_rw(dump_cam); rtw_debugfs_add_rw(rsvd_page); rtw_debugfs_add_r(phy_info); @@ -1174,6 +1261,7 @@ void rtw_debugfs_init(struct rtw_dev *rtwdev) rtw_debugfs_add_r(tx_pwr_tbl); rtw_debugfs_add_rw(edcca_enable); rtw_debugfs_add_rw(fw_crash); + rtw_debugfs_add_rw(force_lowest_basic_rate); rtw_debugfs_add_rw(dm_cap); } diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index a0d4d6e31fb4..78fcbc20942d 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1862,6 +1862,7 @@ int rtw_core_init(struct rtw_dev *rtwdev) rtwdev->sec.total_cam_num = 32; rtwdev->hal.current_channel = 1; + rtwdev->dm_info.fix_rate = U8_MAX; set_bit(RTW_BC_MC_MACID, rtwdev->mac_id_map); rtw_stats_init(rtwdev); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index bbdd535b64e7..5e043101ee74 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -364,6 +364,7 @@ enum rtw_flags { RTW_FLAG_WOWLAN, RTW_FLAG_RESTARTING, RTW_FLAG_RESTART_TRIGGERING, + RTW_FLAG_FORCE_LOWEST_RATE, NUM_OF_RTW_FLAGS, }; @@ -1630,6 +1631,7 @@ struct rtw_dm_info { u8 cck_gi_u_bnd; u8 cck_gi_l_bnd; + u8 fix_rate; u8 tx_rate; u32 rrsr_val_init; u32 rrsr_mask_min; diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index a7a6ebfaa203..3b367c9085eb 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -1738,6 +1738,15 @@ static const struct dmi_system_id rtw88_pci_quirks[] = { }, .driver_data = (void *)BIT(QUIRK_DIS_PCI_CAP_ASPM), }, + { + .callback = disable_pci_caps, + .ident = "HP HP 250 G7 Notebook PC", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP 250 G7 Notebook PC"), + }, + .driver_data = (void *)BIT(QUIRK_DIS_PCI_CAP_ASPM), + }, {} }; diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c index 3a101aa139ed..efcc1b0371a8 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -233,17 +233,34 @@ void rtw_tx_report_handle(struct rtw_dev *rtwdev, struct sk_buff *skb, int src) spin_unlock_irqrestore(&tx_report->q_lock, flags); } +static u8 rtw_get_mgmt_rate(struct rtw_dev *rtwdev, struct sk_buff *skb, + u8 lowest_rate, bool ignore_rate) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_vif *vif = tx_info->control.vif; + bool force_lowest = test_bit(RTW_FLAG_FORCE_LOWEST_RATE, rtwdev->flags); + + if (!vif || !vif->bss_conf.basic_rates || ignore_rate || force_lowest) + return lowest_rate; + + return __ffs(vif->bss_conf.basic_rates) + lowest_rate; +} + static void rtw_tx_pkt_info_update_rate(struct rtw_dev *rtwdev, struct rtw_tx_pkt_info *pkt_info, - struct sk_buff *skb) + struct sk_buff *skb, + bool ignore_rate) { if (rtwdev->hal.current_band_type == RTW_BAND_2G) { pkt_info->rate_id = RTW_RATEID_B_20M; - pkt_info->rate = DESC_RATE1M; + pkt_info->rate = rtw_get_mgmt_rate(rtwdev, skb, DESC_RATE1M, + ignore_rate); } else { pkt_info->rate_id = RTW_RATEID_G; - pkt_info->rate = DESC_RATE6M; + pkt_info->rate = rtw_get_mgmt_rate(rtwdev, skb, DESC_RATE6M, + ignore_rate); } + pkt_info->use_rate = true; pkt_info->dis_rate_fallback = true; } @@ -280,7 +297,7 @@ static void rtw_tx_mgmt_pkt_info_update(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, struct sk_buff *skb) { - rtw_tx_pkt_info_update_rate(rtwdev, pkt_info, skb); + rtw_tx_pkt_info_update_rate(rtwdev, pkt_info, skb, false); pkt_info->dis_qselseq = true; pkt_info->en_hwseq = true; pkt_info->hw_ssn_sel = 0; @@ -295,7 +312,9 @@ static void rtw_tx_data_pkt_info_update(struct rtw_dev *rtwdev, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hw *hw = rtwdev->hw; + struct rtw_dm_info *dm_info = &rtwdev->dm_info; struct rtw_sta_info *si; + u8 fix_rate; u16 seq; u8 ampdu_factor = 0; u8 ampdu_density = 0; @@ -347,6 +366,13 @@ out: pkt_info->bw = bw; pkt_info->stbc = stbc; pkt_info->ldpc = ldpc; + + fix_rate = dm_info->fix_rate; + if (fix_rate < DESC_RATE_MAX) { + pkt_info->rate = fix_rate; + pkt_info->dis_rate_fallback = true; + pkt_info->use_rate = true; + } } void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, @@ -404,7 +430,7 @@ void rtw_tx_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev, if (type != RSVD_BEACON && type != RSVD_DUMMY) pkt_info->qsel = TX_DESC_QSEL_MGMT; - rtw_tx_pkt_info_update_rate(rtwdev, pkt_info, skb); + rtw_tx_pkt_info_update_rate(rtwdev, pkt_info, skb, true); bmc = is_broadcast_ether_addr(hdr->addr1) || is_multicast_ether_addr(hdr->addr1); diff --git a/drivers/net/wireless/realtek/rtw89/cam.c b/drivers/net/wireless/realtek/rtw89/cam.c index ad7a8155dbed..bd34e4bbe107 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.c +++ b/drivers/net/wireless/realtek/rtw89/cam.c @@ -219,6 +219,7 @@ static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev, struct ieee80211_key_conf *key, struct rtw89_sec_cam_entry *sec_cam) { + struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); struct rtw89_vif *rtwvif; struct rtw89_addr_cam_entry *addr_cam; u8 key_idx = 0; @@ -243,7 +244,7 @@ static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev, addr_cam->sec_ent[key_idx] = sec_cam->sec_cam_idx; addr_cam->sec_entries[key_idx] = sec_cam; set_bit(key_idx, addr_cam->sec_cam_map); - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); if (ret) { rtw89_err(rtwdev, "failed to update addr cam sec entry: %d\n", ret); @@ -371,6 +372,7 @@ int rtw89_cam_sec_key_del(struct rtw89_dev *rtwdev, struct ieee80211_key_conf *key, bool inform_fw) { + struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); struct rtw89_cam_info *cam_info = &rtwdev->cam_info; struct rtw89_vif *rtwvif; struct rtw89_addr_cam_entry *addr_cam; @@ -394,7 +396,7 @@ int rtw89_cam_sec_key_del(struct rtw89_dev *rtwdev, clear_bit(key_idx, addr_cam->sec_cam_map); addr_cam->sec_entries[key_idx] = NULL; if (inform_fw) { - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); if (ret) rtw89_err(rtwdev, "failed to update cam del key: %d\n", ret); } @@ -536,12 +538,8 @@ static int rtw89_cam_init_bssid_cam(struct rtw89_dev *rtwdev, void rtw89_cam_bssid_changed(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); - struct rtw89_addr_cam_entry *addr_cam = &rtwvif->addr_cam; struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam; - if (vif->type == NL80211_IFTYPE_STATION) - ether_addr_copy(addr_cam->tma, rtwvif->bssid); ether_addr_copy(bssid_cam->bssid, rtwvif->bssid); } @@ -593,7 +591,7 @@ int rtw89_cam_fill_bssid_cam_info(struct rtw89_dev *rtwdev, return 0; } -static u8 rtw89_cam_addr_hash(u8 start, u8 *addr) +static u8 rtw89_cam_addr_hash(u8 start, const u8 *addr) { u8 hash = 0; u8 i; @@ -606,15 +604,18 @@ static u8 rtw89_cam_addr_hash(u8 start, u8 *addr) void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta, + const u8 *scan_mac_addr, u8 *cmd) { struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); - struct ieee80211_sta *sta; - struct rtw89_sta *rtwsta; struct rtw89_addr_cam_entry *addr_cam = &rtwvif->addr_cam; + struct ieee80211_sta *sta = rtwsta_to_sta_safe(rtwsta); + const u8 *sma = scan_mac_addr ? scan_mac_addr : rtwvif->mac_addr; u8 sma_hash, tma_hash, addr_msk_start; u8 sma_start = 0; u8 tma_start = 0; + u8 *tma = sta ? sta->addr : rtwvif->bssid; if (addr_cam->addr_mask != 0) { addr_msk_start = __ffs(addr_cam->addr_mask); @@ -623,8 +624,8 @@ void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev, else if (addr_cam->mask_sel == RTW89_TMA) tma_start = addr_msk_start; } - sma_hash = rtw89_cam_addr_hash(sma_start, rtwvif->mac_addr); - tma_hash = rtw89_cam_addr_hash(tma_start, addr_cam->tma); + sma_hash = rtw89_cam_addr_hash(sma_start, sma); + tma_hash = rtw89_cam_addr_hash(tma_start, tma); FWCMD_SET_ADDR_IDX(cmd, addr_cam->addr_cam_idx); FWCMD_SET_ADDR_OFFSET(cmd, addr_cam->offset); @@ -642,19 +643,19 @@ void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev, FWCMD_SET_ADDR_BSSID_CAM_IDX(cmd, addr_cam->bssid_cam_idx); - FWCMD_SET_ADDR_SMA0(cmd, rtwvif->mac_addr[0]); - FWCMD_SET_ADDR_SMA1(cmd, rtwvif->mac_addr[1]); - FWCMD_SET_ADDR_SMA2(cmd, rtwvif->mac_addr[2]); - FWCMD_SET_ADDR_SMA3(cmd, rtwvif->mac_addr[3]); - FWCMD_SET_ADDR_SMA4(cmd, rtwvif->mac_addr[4]); - FWCMD_SET_ADDR_SMA5(cmd, rtwvif->mac_addr[5]); + FWCMD_SET_ADDR_SMA0(cmd, sma[0]); + FWCMD_SET_ADDR_SMA1(cmd, sma[1]); + FWCMD_SET_ADDR_SMA2(cmd, sma[2]); + FWCMD_SET_ADDR_SMA3(cmd, sma[3]); + FWCMD_SET_ADDR_SMA4(cmd, sma[4]); + FWCMD_SET_ADDR_SMA5(cmd, sma[5]); - FWCMD_SET_ADDR_TMA0(cmd, addr_cam->tma[0]); - FWCMD_SET_ADDR_TMA1(cmd, addr_cam->tma[1]); - FWCMD_SET_ADDR_TMA2(cmd, addr_cam->tma[2]); - FWCMD_SET_ADDR_TMA3(cmd, addr_cam->tma[3]); - FWCMD_SET_ADDR_TMA4(cmd, addr_cam->tma[4]); - FWCMD_SET_ADDR_TMA5(cmd, addr_cam->tma[5]); + FWCMD_SET_ADDR_TMA0(cmd, tma[0]); + FWCMD_SET_ADDR_TMA1(cmd, tma[1]); + FWCMD_SET_ADDR_TMA2(cmd, tma[2]); + FWCMD_SET_ADDR_TMA3(cmd, tma[3]); + FWCMD_SET_ADDR_TMA4(cmd, tma[4]); + FWCMD_SET_ADDR_TMA5(cmd, tma[5]); FWCMD_SET_ADDR_PORT_INT(cmd, rtwvif->port); FWCMD_SET_ADDR_TSF_SYNC(cmd, rtwvif->port); @@ -662,15 +663,11 @@ void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev, FWCMD_SET_ADDR_LSIG_TXOP(cmd, rtwvif->lsig_txop); FWCMD_SET_ADDR_TGT_IND(cmd, rtwvif->tgt_ind); FWCMD_SET_ADDR_FRM_TGT_IND(cmd, rtwvif->frm_tgt_ind); - - if (vif->type == NL80211_IFTYPE_STATION) { - sta = rtwvif->mgd.ap; - if (sta) { - rtwsta = (struct rtw89_sta *)sta->drv_priv; - FWCMD_SET_ADDR_MACID(cmd, rtwsta->mac_id); - FWCMD_SET_ADDR_AID12(cmd, vif->bss_conf.aid & 0xfff); - } - } + FWCMD_SET_ADDR_MACID(cmd, rtwsta ? rtwsta->mac_id : rtwvif->mac_id); + if (rtwvif->net_type == RTW89_NET_TYPE_INFRA) + FWCMD_SET_ADDR_AID12(cmd, vif->bss_conf.aid & 0xfff); + else if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) + FWCMD_SET_ADDR_AID12(cmd, sta ? sta->aid & 0xfff : 0); FWCMD_SET_ADDR_WOL_PATTERN(cmd, rtwvif->wowlan_pattern); FWCMD_SET_ADDR_WOL_UC(cmd, rtwvif->wowlan_uc); FWCMD_SET_ADDR_WOL_MAGIC(cmd, rtwvif->wowlan_magic); diff --git a/drivers/net/wireless/realtek/rtw89/cam.h b/drivers/net/wireless/realtek/rtw89/cam.h index 90a20a5375c6..33a3ad582b81 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.h +++ b/drivers/net/wireless/realtek/rtw89/cam.h @@ -9,145 +9,347 @@ #define RTW89_SEC_CAM_LEN 20 -#define FWCMD_SET_ADDR_IDX(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 1, value, GENMASK(7, 0)) -#define FWCMD_SET_ADDR_OFFSET(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 1, value, GENMASK(15, 8)) -#define FWCMD_SET_ADDR_LEN(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 1, value, GENMASK(23, 16)) -#define FWCMD_SET_ADDR_VALID(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 2, value, BIT(0)) -#define FWCMD_SET_ADDR_NET_TYPE(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(2, 1)) -#define FWCMD_SET_ADDR_BCN_HIT_COND(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(4, 3)) -#define FWCMD_SET_ADDR_HIT_RULE(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(6, 5)) -#define FWCMD_SET_ADDR_BB_SEL(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 2, value, BIT(7)) -#define FWCMD_SET_ADDR_ADDR_MASK(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(13, 8)) -#define FWCMD_SET_ADDR_MASK_SEL(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(15, 14)) -#define FWCMD_SET_ADDR_SMA_HASH(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(23, 16)) -#define FWCMD_SET_ADDR_TMA_HASH(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(31, 24)) -#define FWCMD_SET_ADDR_BSSID_CAM_IDX(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 3, value, GENMASK(5, 0)) -#define FWCMD_SET_ADDR_SMA0(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 4, value, GENMASK(7, 0)) -#define FWCMD_SET_ADDR_SMA1(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 4, value, GENMASK(15, 8)) -#define FWCMD_SET_ADDR_SMA2(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 4, value, GENMASK(23, 16)) -#define FWCMD_SET_ADDR_SMA3(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 4, value, GENMASK(31, 24)) -#define FWCMD_SET_ADDR_SMA4(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 5, value, GENMASK(7, 0)) -#define FWCMD_SET_ADDR_SMA5(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 5, value, GENMASK(15, 8)) -#define FWCMD_SET_ADDR_TMA0(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 5, value, GENMASK(23, 16)) -#define FWCMD_SET_ADDR_TMA1(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 5, value, GENMASK(31, 24)) -#define FWCMD_SET_ADDR_TMA2(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 6, value, GENMASK(7, 0)) -#define FWCMD_SET_ADDR_TMA3(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 6, value, GENMASK(15, 8)) -#define FWCMD_SET_ADDR_TMA4(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 6, value, GENMASK(23, 16)) -#define FWCMD_SET_ADDR_TMA5(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 6, value, GENMASK(31, 24)) -#define FWCMD_SET_ADDR_MACID(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 8, value, GENMASK(7, 0)) -#define FWCMD_SET_ADDR_PORT_INT(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 8, value, GENMASK(10, 8)) -#define FWCMD_SET_ADDR_TSF_SYNC(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 8, value, GENMASK(13, 11)) -#define FWCMD_SET_ADDR_TF_TRS(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 8, value, BIT(14)) -#define FWCMD_SET_ADDR_LSIG_TXOP(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 8, value, BIT(15)) -#define FWCMD_SET_ADDR_TGT_IND(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 8, value, GENMASK(26, 24)) -#define FWCMD_SET_ADDR_FRM_TGT_IND(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 8, value, GENMASK(29, 27)) -#define FWCMD_SET_ADDR_AID12(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(11, 0)) -#define FWCMD_SET_ADDR_AID12_0(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(7, 0)) -#define FWCMD_SET_ADDR_AID12_1(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(11, 8)) -#define FWCMD_SET_ADDR_WOL_PATTERN(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 9, value, BIT(12)) -#define FWCMD_SET_ADDR_WOL_UC(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 9, value, BIT(13)) -#define FWCMD_SET_ADDR_WOL_MAGIC(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 9, value, BIT(14)) -#define FWCMD_SET_ADDR_WAPI(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 9, value, BIT(15)) -#define FWCMD_SET_ADDR_SEC_ENT_MODE(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(17, 16)) -#define FWCMD_SET_ADDR_SEC_ENT0_KEYID(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(19, 18)) -#define FWCMD_SET_ADDR_SEC_ENT1_KEYID(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(21, 20)) -#define FWCMD_SET_ADDR_SEC_ENT2_KEYID(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(23, 22)) -#define FWCMD_SET_ADDR_SEC_ENT3_KEYID(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(25, 24)) -#define FWCMD_SET_ADDR_SEC_ENT4_KEYID(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(27, 26)) -#define FWCMD_SET_ADDR_SEC_ENT5_KEYID(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(29, 28)) -#define FWCMD_SET_ADDR_SEC_ENT6_KEYID(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(31, 30)) -#define FWCMD_SET_ADDR_SEC_ENT_VALID(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 10, value, GENMASK(7, 0)) -#define FWCMD_SET_ADDR_SEC_ENT0(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 10, value, GENMASK(15, 8)) -#define FWCMD_SET_ADDR_SEC_ENT1(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 10, value, GENMASK(23, 16)) -#define FWCMD_SET_ADDR_SEC_ENT2(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 10, value, GENMASK(31, 24)) -#define FWCMD_SET_ADDR_SEC_ENT3(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 11, value, GENMASK(7, 0)) -#define FWCMD_SET_ADDR_SEC_ENT4(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 11, value, GENMASK(15, 8)) -#define FWCMD_SET_ADDR_SEC_ENT5(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 11, value, GENMASK(23, 16)) -#define FWCMD_SET_ADDR_SEC_ENT6(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 11, value, GENMASK(31, 24)) -#define FWCMD_SET_ADDR_BSSID_IDX(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 12, value, GENMASK(7, 0)) -#define FWCMD_SET_ADDR_BSSID_OFFSET(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 12, value, GENMASK(15, 8)) -#define FWCMD_SET_ADDR_BSSID_LEN(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 12, value, GENMASK(23, 16)) -#define FWCMD_SET_ADDR_BSSID_VALID(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 13, value, BIT(0)) -#define FWCMD_SET_ADDR_BSSID_BB_SEL(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 13, value, BIT(1)) -#define FWCMD_SET_ADDR_BSSID_BSS_COLOR(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 13, value, GENMASK(13, 8)) -#define FWCMD_SET_ADDR_BSSID_BSSID0(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 13, value, GENMASK(23, 16)) -#define FWCMD_SET_ADDR_BSSID_BSSID1(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 13, value, GENMASK(31, 24)) -#define FWCMD_SET_ADDR_BSSID_BSSID2(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 14, value, GENMASK(7, 0)) -#define FWCMD_SET_ADDR_BSSID_BSSID3(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 14, value, GENMASK(15, 8)) -#define FWCMD_SET_ADDR_BSSID_BSSID4(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 14, value, GENMASK(23, 16)) -#define FWCMD_SET_ADDR_BSSID_BSSID5(cmd, value) \ - le32p_replace_bits((__le32 *)(cmd) + 14, value, GENMASK(31, 24)) +static inline void FWCMD_SET_ADDR_IDX(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 1, value, GENMASK(7, 0)); +} + +static inline void FWCMD_SET_ADDR_OFFSET(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 1, value, GENMASK(15, 8)); +} + +static inline void FWCMD_SET_ADDR_LEN(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 1, value, GENMASK(23, 16)); +} + +static inline void FWCMD_SET_ADDR_VALID(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 2, value, BIT(0)); +} + +static inline void FWCMD_SET_ADDR_NET_TYPE(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(2, 1)); +} + +static inline void FWCMD_SET_ADDR_BCN_HIT_COND(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(4, 3)); +} + +static inline void FWCMD_SET_ADDR_HIT_RULE(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(6, 5)); +} + +static inline void FWCMD_SET_ADDR_BB_SEL(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 2, value, BIT(7)); +} + +static inline void FWCMD_SET_ADDR_ADDR_MASK(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(13, 8)); +} + +static inline void FWCMD_SET_ADDR_MASK_SEL(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(15, 14)); +} + +static inline void FWCMD_SET_ADDR_SMA_HASH(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(23, 16)); +} + +static inline void FWCMD_SET_ADDR_TMA_HASH(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 2, value, GENMASK(31, 24)); +} + +static inline void FWCMD_SET_ADDR_BSSID_CAM_IDX(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 3, value, GENMASK(5, 0)); +} + +static inline void FWCMD_SET_ADDR_SMA0(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 4, value, GENMASK(7, 0)); +} + +static inline void FWCMD_SET_ADDR_SMA1(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 4, value, GENMASK(15, 8)); +} + +static inline void FWCMD_SET_ADDR_SMA2(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 4, value, GENMASK(23, 16)); +} + +static inline void FWCMD_SET_ADDR_SMA3(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 4, value, GENMASK(31, 24)); +} + +static inline void FWCMD_SET_ADDR_SMA4(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 5, value, GENMASK(7, 0)); +} + +static inline void FWCMD_SET_ADDR_SMA5(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 5, value, GENMASK(15, 8)); +} + +static inline void FWCMD_SET_ADDR_TMA0(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 5, value, GENMASK(23, 16)); +} + +static inline void FWCMD_SET_ADDR_TMA1(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 5, value, GENMASK(31, 24)); +} + +static inline void FWCMD_SET_ADDR_TMA2(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 6, value, GENMASK(7, 0)); +} + +static inline void FWCMD_SET_ADDR_TMA3(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 6, value, GENMASK(15, 8)); +} + +static inline void FWCMD_SET_ADDR_TMA4(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 6, value, GENMASK(23, 16)); +} + +static inline void FWCMD_SET_ADDR_TMA5(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 6, value, GENMASK(31, 24)); +} + +static inline void FWCMD_SET_ADDR_MACID(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 8, value, GENMASK(7, 0)); +} + +static inline void FWCMD_SET_ADDR_PORT_INT(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 8, value, GENMASK(10, 8)); +} + +static inline void FWCMD_SET_ADDR_TSF_SYNC(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 8, value, GENMASK(13, 11)); +} + +static inline void FWCMD_SET_ADDR_TF_TRS(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 8, value, BIT(14)); +} + +static inline void FWCMD_SET_ADDR_LSIG_TXOP(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 8, value, BIT(15)); +} + +static inline void FWCMD_SET_ADDR_TGT_IND(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 8, value, GENMASK(26, 24)); +} + +static inline void FWCMD_SET_ADDR_FRM_TGT_IND(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 8, value, GENMASK(29, 27)); +} + +static inline void FWCMD_SET_ADDR_AID12(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(11, 0)); +} + +static inline void FWCMD_SET_ADDR_AID12_0(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(7, 0)); +} + +static inline void FWCMD_SET_ADDR_AID12_1(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(11, 8)); +} + +static inline void FWCMD_SET_ADDR_WOL_PATTERN(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 9, value, BIT(12)); +} + +static inline void FWCMD_SET_ADDR_WOL_UC(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 9, value, BIT(13)); +} + +static inline void FWCMD_SET_ADDR_WOL_MAGIC(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 9, value, BIT(14)); +} + +static inline void FWCMD_SET_ADDR_WAPI(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 9, value, BIT(15)); +} + +static inline void FWCMD_SET_ADDR_SEC_ENT_MODE(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(17, 16)); +} + +static inline void FWCMD_SET_ADDR_SEC_ENT0_KEYID(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(19, 18)); +} + +static inline void FWCMD_SET_ADDR_SEC_ENT1_KEYID(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(21, 20)); +} + +static inline void FWCMD_SET_ADDR_SEC_ENT2_KEYID(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(23, 22)); +} + +static inline void FWCMD_SET_ADDR_SEC_ENT3_KEYID(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(25, 24)); +} + +static inline void FWCMD_SET_ADDR_SEC_ENT4_KEYID(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(27, 26)); +} + +static inline void FWCMD_SET_ADDR_SEC_ENT5_KEYID(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(29, 28)); +} + +static inline void FWCMD_SET_ADDR_SEC_ENT6_KEYID(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 9, value, GENMASK(31, 30)); +} + +static inline void FWCMD_SET_ADDR_SEC_ENT_VALID(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 10, value, GENMASK(7, 0)); +} + +static inline void FWCMD_SET_ADDR_SEC_ENT0(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 10, value, GENMASK(15, 8)); +} + +static inline void FWCMD_SET_ADDR_SEC_ENT1(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 10, value, GENMASK(23, 16)); +} + +static inline void FWCMD_SET_ADDR_SEC_ENT2(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 10, value, GENMASK(31, 24)); +} + +static inline void FWCMD_SET_ADDR_SEC_ENT3(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 11, value, GENMASK(7, 0)); +} + +static inline void FWCMD_SET_ADDR_SEC_ENT4(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 11, value, GENMASK(15, 8)); +} + +static inline void FWCMD_SET_ADDR_SEC_ENT5(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 11, value, GENMASK(23, 16)); +} + +static inline void FWCMD_SET_ADDR_SEC_ENT6(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 11, value, GENMASK(31, 24)); +} + +static inline void FWCMD_SET_ADDR_BSSID_IDX(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 12, value, GENMASK(7, 0)); +} + +static inline void FWCMD_SET_ADDR_BSSID_OFFSET(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 12, value, GENMASK(15, 8)); +} + +static inline void FWCMD_SET_ADDR_BSSID_LEN(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 12, value, GENMASK(23, 16)); +} + +static inline void FWCMD_SET_ADDR_BSSID_VALID(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 13, value, BIT(0)); +} + +static inline void FWCMD_SET_ADDR_BSSID_BB_SEL(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 13, value, BIT(1)); +} + +static inline void FWCMD_SET_ADDR_BSSID_BSS_COLOR(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 13, value, GENMASK(13, 8)); +} + +static inline void FWCMD_SET_ADDR_BSSID_BSSID0(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 13, value, GENMASK(23, 16)); +} + +static inline void FWCMD_SET_ADDR_BSSID_BSSID1(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 13, value, GENMASK(31, 24)); +} + +static inline void FWCMD_SET_ADDR_BSSID_BSSID2(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 14, value, GENMASK(7, 0)); +} + +static inline void FWCMD_SET_ADDR_BSSID_BSSID3(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 14, value, GENMASK(15, 8)); +} + +static inline void FWCMD_SET_ADDR_BSSID_BSSID4(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 14, value, GENMASK(23, 16)); +} + +static inline void FWCMD_SET_ADDR_BSSID_BSSID5(void *cmd, u32 value) +{ + le32p_replace_bits((__le32 *)(cmd) + 14, value, GENMASK(31, 24)); +} int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev, - struct rtw89_vif *vif, u8 *cmd); + struct rtw89_vif *vif, + struct rtw89_sta *rtwsta, + const u8 *scan_mac_addr, u8 *cmd); int rtw89_cam_fill_bssid_cam_info(struct rtw89_dev *rtwdev, struct rtw89_vif *vif, u8 *cmd); int rtw89_cam_sec_key_add(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index abe4b6549ab2..9f7d4f8d0c56 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -540,8 +540,31 @@ static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update); static void _send_fw_cmd(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func, void *param, u16 len) { - rtw89_fw_h2c_raw_with_hdr(rtwdev, h2c_class, h2c_func, param, len, - false, true); + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; + struct rtw89_btc_cx *cx = &btc->cx; + struct rtw89_btc_wl_info *wl = &cx->wl; + int ret; + + if (!wl->status.map.init_ok) { + rtw89_debug(rtwdev, RTW89_DBG_BTC, + "[BTC], %s(): return by btc not init!!\n", __func__); + pfwinfo->cnt_h2c_fail++; + return; + } else if ((wl->status.map.rf_off_pre == 1 && wl->status.map.rf_off == 1) || + (wl->status.map.lps_pre == 1 && wl->status.map.lps == 1)) { + rtw89_debug(rtwdev, RTW89_DBG_BTC, + "[BTC], %s(): return by wl off!!\n", __func__); + pfwinfo->cnt_h2c_fail++; + return; + } + + pfwinfo->cnt_h2c++; + + ret = rtw89_fw_h2c_raw_with_hdr(rtwdev, h2c_class, h2c_func, param, len, + false, true); + if (ret != 0) + pfwinfo->cnt_h2c_fail++; } static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type) @@ -1095,6 +1118,10 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, diff_t = pcysta->tavg_cycle[CXT_WL] - wl_slot_set; _chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t); } + + _chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, pcysta->slot_cnt[CXST_W1]); + _chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, pcysta->slot_cnt[CXST_W1]); + _chk_btc_err(rtwdev, BTC_DCNT_CYCLE_FREEZE, (u32)pcysta->cycles); } if (rpt_type == BTC_RPT_TYPE_CTRL) { @@ -1103,6 +1130,18 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, wl->ver_info.fw_coex = prpt->wl_fw_coex_ver; wl->ver_info.fw = prpt->wl_fw_ver; dm->wl_fw_cx_offload = !!(prpt->wl_fw_cx_offload); + + _chk_btc_err(rtwdev, BTC_DCNT_RPT_FREEZE, + pfwinfo->event[BTF_EVNT_RPT]); + + /* To avoid I/O if WL LPS or power-off */ + if (wl->status.map.lps != BTC_LPS_RF_OFF && !wl->status.map.rf_off) { + rtwdev->chip->ops->btc_update_bt_cnt(rtwdev); + _chk_btc_err(rtwdev, BTC_DCNT_BTCNT_FREEZE, 0); + + btc->cx.cnt_bt[BTC_BCNT_POLUT] = + rtw89_mac_get_plt_cnt(rtwdev, RTW89_MAC_0); + } } if (rpt_type >= BTC_RPT_TYPE_BT_VER && @@ -1596,7 +1635,7 @@ static void _set_rf_trx_para(struct rtw89_dev *rtwdev) _set_bt_rx_gain(rtwdev, para.bt_rx_gain); if (bt->enable.now == 0 || wl->status.map.rf_off == 1 || - wl->status.map.lps == 1) + wl->status.map.lps == BTC_LPS_RF_OFF) wl_stb_chg = 0; else wl_stb_chg = 1; @@ -4199,16 +4238,16 @@ void rtw89_btc_ntfy_radio_state(struct rtw89_dev *rtwdev, enum btc_rfctrl rf_sta switch (rf_state) { case BTC_RFCTRL_WL_OFF: wl->status.map.rf_off = 1; - wl->status.map.lps = 0; + wl->status.map.lps = BTC_LPS_OFF; break; case BTC_RFCTRL_FW_CTRL: wl->status.map.rf_off = 0; - wl->status.map.lps = 1; + wl->status.map.lps = BTC_LPS_RF_OFF; break; case BTC_RFCTRL_WL_ON: default: wl->status.map.rf_off = 0; - wl->status.map.lps = 0; + wl->status.map.lps = BTC_LPS_OFF; break; } @@ -4494,6 +4533,8 @@ void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo; u8 *buf = &skb->data[RTW89_C2H_HEADER_LEN]; + len -= RTW89_C2H_HEADER_LEN; + rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): C2H BT len:%d class:%d fun:%d\n", __func__, len, class, func); @@ -4512,14 +4553,12 @@ void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], handle C2H BT INFO with data %8ph\n", buf); btc->cx.cnt_bt[BTC_BCNT_INFOUPDATE]++; - rtw89_leave_ps_mode(rtwdev); _update_bt_info(rtwdev, buf, len); break; case BTF_EVNT_BT_SCBD: rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], handle C2H BT SCBD with data %8ph\n", buf); btc->cx.cnt_bt[BTC_BCNT_SCBDUPDATE]++; - rtw89_leave_ps_mode(rtwdev); _update_bt_scbd(rtwdev, false); break; case BTF_EVNT_BT_PSD: @@ -4765,7 +4804,6 @@ static void _show_bt_profile_info(struct rtw89_dev *rtwdev, struct seq_file *m) static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m) { - const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_bt_info *bt = &cx->bt; @@ -4773,7 +4811,6 @@ static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m) struct rtw89_btc_module *module = &btc->mdinfo; struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info; u8 *afh = bt_linfo->afh_map; - u16 polt_cnt = 0; if (!(btc->dm.coex_info_map & BTC_COEX_INFO_BT)) return; @@ -4849,17 +4886,11 @@ static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m) cx->cnt_bt[BTC_BCNT_INFOUPDATE], cx->cnt_bt[BTC_BCNT_INFOSAME]); - if (wl->status.map.lps || wl->status.map.rf_off) - return; - - chip->ops->btc_update_bt_cnt(rtwdev); - _chk_btc_err(rtwdev, BTC_DCNT_BTCNT_FREEZE, 0); - seq_printf(m, " %-15s : Hi-rx = %d, Hi-tx = %d, Lo-rx = %d, Lo-tx = %d (bt_polut_wl_tx = %d)\n", "[trx_req_cnt]", cx->cnt_bt[BTC_BCNT_HIPRI_RX], cx->cnt_bt[BTC_BCNT_HIPRI_TX], cx->cnt_bt[BTC_BCNT_LOPRI_RX], - cx->cnt_bt[BTC_BCNT_LOPRI_TX], polt_cnt); + cx->cnt_bt[BTC_BCNT_LOPRI_TX], cx->cnt_bt[BTC_BCNT_POLUT]); } #define CASE_BTC_RSN_STR(e) case BTC_RSN_ ## e: return #e @@ -5227,8 +5258,6 @@ static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m) pcysta->bcn_cnt[CXBCN_BT_SLOT], pcysta->bcn_cnt[CXBCN_BT_OK]); - _chk_btc_err(rtwdev, BTC_DCNT_CYCLE_FREEZE, (u32)pcysta->cycles); - for (i = 0; i < CXST_MAX; i++) { if (!pcysta->slot_cnt[i]) continue; @@ -5252,9 +5281,6 @@ static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m) } seq_puts(m, "\n"); - _chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, pcysta->slot_cnt[CXST_W1]); - _chk_btc_err(rtwdev, BTC_DCNT_B1_FREEZE, pcysta->slot_cnt[CXST_B1]); - seq_printf(m, " %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]", "[cycle_time]", pcysta->tavg_cycle[CXT_WL], @@ -5606,9 +5632,6 @@ static void _show_summary(struct rtw89_dev *rtwdev, struct seq_file *m) pfwinfo->event[BTF_EVNT_RPT], prptctrl->rpt_cnt, prptctrl->rpt_enable, dm->error.val); - _chk_btc_err(rtwdev, BTC_DCNT_RPT_FREEZE, - pfwinfo->event[BTF_EVNT_RPT]); - if (dm->error.map.wl_fw_hang) seq_puts(m, " (WL FW Hang!!)"); seq_puts(m, "\n"); diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h index 4b4565d15c9e..c3a722d259d7 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.h +++ b/drivers/net/wireless/realtek/rtw89/coex.h @@ -130,6 +130,12 @@ enum btc_rfctrl { BTC_RFCTRL_MAX }; +enum btc_lps_state { + BTC_LPS_OFF = 0, + BTC_LPS_RF_OFF = 1, + BTC_LPS_RF_ON = 2 +}; + void rtw89_btc_ntfy_poweron(struct rtw89_dev *rtwdev); void rtw89_btc_ntfy_poweroff(struct rtw89_dev *rtwdev); void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode); diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 2bbe77ae7713..cf05baf88640 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -143,20 +143,15 @@ static void rtw89_get_channel_params(struct cfg80211_chan_def *chandef, { struct ieee80211_channel *channel = chandef->chan; enum nl80211_chan_width width = chandef->width; - u8 *cch_by_bw = chan_param->cch_by_bw; u32 primary_freq, center_freq; u8 center_chan; u8 bandwidth = RTW89_CHANNEL_WIDTH_20; u8 primary_chan_idx = 0; - u8 i; center_chan = channel->hw_value; primary_freq = channel->center_freq; center_freq = chandef->center_freq1; - /* assign the center channel used while 20M bw is selected */ - cch_by_bw[RTW89_CHANNEL_WIDTH_20] = channel->hw_value; - switch (width) { case NL80211_CHAN_WIDTH_20_NOHT: case NL80211_CHAN_WIDTH_20: @@ -183,10 +178,6 @@ static void rtw89_get_channel_params(struct cfg80211_chan_def *chandef, primary_chan_idx = RTW89_SC_20_UPMOST; center_chan -= 6; } - /* assign the center channel used - * while 40M bw is selected - */ - cch_by_bw[RTW89_CHANNEL_WIDTH_40] = center_chan + 4; } else { if (center_freq - primary_freq == 10) { primary_chan_idx = RTW89_SC_20_LOWER; @@ -195,10 +186,6 @@ static void rtw89_get_channel_params(struct cfg80211_chan_def *chandef, primary_chan_idx = RTW89_SC_20_LOWEST; center_chan += 6; } - /* assign the center channel used - * while 40M bw is selected - */ - cch_by_bw[RTW89_CHANNEL_WIDTH_40] = center_chan - 4; } break; default: @@ -210,12 +197,6 @@ static void rtw89_get_channel_params(struct cfg80211_chan_def *chandef, chan_param->primary_chan = channel->hw_value; chan_param->bandwidth = bandwidth; chan_param->pri_ch_idx = primary_chan_idx; - - /* assign the center channel used while current bw is selected */ - cch_by_bw[bandwidth] = center_chan; - - for (i = bandwidth + 1; i <= RTW89_MAX_CHANNEL_WIDTH; i++) - cch_by_bw[i] = 0; } void rtw89_set_channel(struct rtw89_dev *rtwdev) @@ -228,7 +209,6 @@ void rtw89_set_channel(struct rtw89_dev *rtwdev) u8 center_chan, bandwidth; u8 band_type; bool band_changed; - u8 i; rtw89_get_channel_params(&hw->conf.chandef, &ch_param); if (WARN(ch_param.center_chan == 0, "Invalid channel\n")) @@ -242,6 +222,7 @@ void rtw89_set_channel(struct rtw89_dev *rtwdev) hal->current_band_width = bandwidth; hal->current_channel = center_chan; + hal->prev_primary_channel = hal->current_primary_channel; hal->current_primary_channel = ch_param.primary_chan; hal->current_band_type = band_type; @@ -260,9 +241,6 @@ void rtw89_set_channel(struct rtw89_dev *rtwdev) break; } - for (i = RTW89_CHANNEL_WIDTH_20; i <= RTW89_MAX_CHANNEL_WIDTH; i++) - hal->cch_by_bw[i] = ch_param.cch_by_bw[i]; - rtw89_chip_set_channel_prepare(rtwdev, &bak); chip->ops->set_channel(rtwdev, &ch_param); @@ -881,8 +859,11 @@ static void rtw89_core_parse_phy_status_ie01(struct rtw89_dev *rtwdev, u8 *addr, { s16 cfo; + phy_ppdu->chan_idx = RTW89_GET_PHY_STS_IE01_CH_IDX(addr); + if (phy_ppdu->rate < RTW89_HW_RATE_OFDM6) + return; /* sign conversion for S(12,2) */ - cfo = sign_extend32(RTW89_GET_PHY_STS_IE0_CFO(addr), 11); + cfo = sign_extend32(RTW89_GET_PHY_STS_IE01_CFO(addr), 11); rtw89_phy_cfo_parse(rtwdev, cfo, phy_ppdu); } @@ -908,6 +889,7 @@ static void rtw89_core_update_phy_ppdu(struct rtw89_rx_phy_ppdu *phy_ppdu) s8 *rssi = phy_ppdu->rssi; u8 *buf = phy_ppdu->buf; + phy_ppdu->ie = RTW89_GET_PHY_STS_IE_MAP(buf); phy_ppdu->rssi_avg = RTW89_GET_PHY_STS_RSSI_AVG(buf); rssi[RF_PATH_A] = RTW89_RSSI_RAW_TO_DBM(RTW89_GET_PHY_STS_RSSI_A(buf)); rssi[RF_PATH_B] = RTW89_RSSI_RAW_TO_DBM(RTW89_GET_PHY_STS_RSSI_B(buf)); @@ -936,8 +918,9 @@ static int rtw89_core_rx_parse_phy_sts(struct rtw89_dev *rtwdev, u16 ie_len; u8 *pos, *end; - if (!phy_ppdu->to_self) - return 0; + /* mark invalid reports and bypass them */ + if (phy_ppdu->ie < RTW89_CCK_PKT) + return -EINVAL; pos = (u8 *)phy_ppdu->buf + PHY_STS_HDR_LEN; end = (u8 *)phy_ppdu->buf + phy_ppdu->len; @@ -1000,9 +983,7 @@ static bool rtw89_core_rx_ppdu_match(struct rtw89_dev *rtwdev, data_rate_mode = GET_DATA_RATE_MODE(data_rate); if (data_rate_mode == DATA_RATE_MODE_NON_HT) { rate_idx = GET_DATA_RATE_NOT_HT_IDX(data_rate); - /* No 4 CCK rates for 5G */ - if (status->band == NL80211_BAND_5GHZ) - rate_idx -= 4; + /* rate_idx is still hardware value here */ } else if (data_rate_mode == DATA_RATE_MODE_HT) { rate_idx = GET_DATA_RATE_HT_IDX(data_rate); } else if (data_rate_mode == DATA_RATE_MODE_VHT) { @@ -1081,6 +1062,29 @@ static void rtw89_core_rx_stats(struct rtw89_dev *rtwdev, rtw89_iterate_vifs_bh(rtwdev, rtw89_vif_rx_stats_iter, &iter_data); } +static void rtw89_correct_cck_chan(struct rtw89_dev *rtwdev, + struct ieee80211_rx_status *status) +{ + u16 chan = rtwdev->hal.prev_primary_channel; + u8 band = chan <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; + + if (status->band != NL80211_BAND_2GHZ && + status->encoding == RX_ENC_LEGACY && + status->rate_idx < RTW89_HW_RATE_OFDM6) { + status->freq = ieee80211_channel_to_frequency(chan, band); + status->band = band; + } +} + +static void rtw89_core_hw_to_sband_rate(struct ieee80211_rx_status *rx_status) +{ + if (rx_status->band == NL80211_BAND_2GHZ || + rx_status->encoding != RX_ENC_LEGACY) + return; + /* No 4 CCK rates for non-2G */ + rx_status->rate_idx -= 4; +} + static void rtw89_core_rx_pending_skb(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu, struct rtw89_rx_desc_info *desc_info, @@ -1099,6 +1103,8 @@ static void rtw89_core_rx_pending_skb(struct rtw89_dev *rtwdev, rx_status = IEEE80211_SKB_RXCB(skb_ppdu); if (rtw89_core_rx_ppdu_match(rtwdev, desc_info, rx_status)) rtw89_chip_query_ppdu(rtwdev, phy_ppdu, rx_status); + rtw89_correct_cck_chan(rtwdev, rx_status); + rtw89_core_hw_to_sband_rate(rx_status); rtw89_core_rx_stats(rtwdev, phy_ppdu, desc_info, skb_ppdu); ieee80211_rx_napi(rtwdev->hw, NULL, skb_ppdu, &rtwdev->napi); rtwdev->napi_budget_countdown--; @@ -1112,6 +1118,7 @@ static void rtw89_core_rx_process_ppdu_sts(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu phy_ppdu = {.buf = skb->data, .valid = false, .len = skb->len, .to_self = desc_info->addr1_match, + .rate = desc_info->data_rate, .mac_id = desc_info->mac_id}; int ret; @@ -1267,12 +1274,7 @@ static void rtw89_core_update_rx_status(struct rtw89_dev *rtwdev, if (data_rate_mode == DATA_RATE_MODE_NON_HT) { rx_status->encoding = RX_ENC_LEGACY; rx_status->rate_idx = GET_DATA_RATE_NOT_HT_IDX(data_rate); - /* No 4 CCK rates for 5G */ - if (rx_status->band == NL80211_BAND_5GHZ) - rx_status->rate_idx -= 4; - if (rtwdev->scanning) - rx_status->rate_idx = min_t(u8, rx_status->rate_idx, - ARRAY_SIZE(rtw89_bitrates) - 5); + /* convert rate_idx after we get the correct band */ } else if (data_rate_mode == DATA_RATE_MODE_HT) { rx_status->encoding = RX_ENC_HT; rx_status->rate_idx = GET_DATA_RATE_HT_IDX(data_rate); @@ -1324,10 +1326,13 @@ static void rtw89_core_flush_ppdu_rx_queue(struct rtw89_dev *rtwdev, { struct rtw89_ppdu_sts_info *ppdu_sts = &rtwdev->ppdu_sts; u8 band = desc_info->bb_sel ? RTW89_PHY_1 : RTW89_PHY_0; + struct ieee80211_rx_status *rx_status; struct sk_buff *skb_ppdu, *tmp; skb_queue_walk_safe(&ppdu_sts->rx_queue[band], skb_ppdu, tmp) { skb_unlink(skb_ppdu, &ppdu_sts->rx_queue[band]); + rx_status = IEEE80211_SKB_RXCB(skb_ppdu); + rtw89_core_hw_to_sband_rate(rx_status); rtw89_core_rx_stats(rtwdev, NULL, desc_info, skb_ppdu); ieee80211_rx_napi(rtwdev->hw, NULL, skb_ppdu, &rtwdev->napi); rtwdev->napi_budget_countdown--; @@ -1360,6 +1365,7 @@ void rtw89_core_rx(struct rtw89_dev *rtwdev, BIT(desc_info->frame_type) & PPDU_FILTER_BITMAP) { skb_queue_tail(&ppdu_sts->rx_queue[band], skb); } else { + rtw89_core_hw_to_sband_rate(rx_status); rtw89_core_rx_stats(rtwdev, NULL, desc_info, skb); ieee80211_rx_napi(rtwdev->hw, NULL, skb, &rtwdev->napi); rtwdev->napi_budget_countdown--; @@ -1825,7 +1831,8 @@ int rtw89_core_sta_add(struct rtw89_dev *rtwdev, ewma_rssi_init(&rtwsta->avg_rssi); if (vif->type == NL80211_IFTYPE_STATION) { - rtwvif->mgd.ap = sta; + /* for station mode, assign the mac_id from itself */ + rtwsta->mac_id = rtwvif->mac_id; rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta, BTC_ROLE_MSTS_STA_CONN_START); rtw89_chip_rfk_channel(rtwdev); @@ -1851,6 +1858,7 @@ int rtw89_core_sta_disconnect(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta) { struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; int ret; rtw89_mac_bf_monitor_calc(rtwdev, sta, true); @@ -1872,7 +1880,7 @@ int rtw89_core_sta_disconnect(struct rtw89_dev *rtwdev, } /* update cam aid mac_id net_type */ - rtw89_fw_h2c_cam(rtwdev, rtwvif); + rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); if (ret) { rtw89_warn(rtwdev, "failed to send h2c cam\n"); return ret; @@ -1897,10 +1905,6 @@ int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev, return ret; } - /* for station mode, assign the mac_id from itself */ - if (vif->type == NL80211_IFTYPE_STATION) - rtwsta->mac_id = rtwvif->mac_id; - ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, 0); if (ret) { rtw89_warn(rtwdev, "failed to send h2c join info\n"); @@ -1908,7 +1912,7 @@ int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev, } /* update cam aid mac_id net_type */ - rtw89_fw_h2c_cam(rtwdev, rtwvif); + rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); if (ret) { rtw89_warn(rtwdev, "failed to send h2c cam\n"); return ret; diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index c2885e4dd882..7c84556ec4ad 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -411,12 +411,13 @@ enum rtw89_regulation_type { RTW89_NA = 4, RTW89_IC = 5, RTW89_KCC = 6, - RTW89_NCC = 7, - RTW89_CHILE = 8, - RTW89_ACMA = 9, - RTW89_MEXICO = 10, + RTW89_ACMA = 7, + RTW89_NCC = 8, + RTW89_MEXICO = 9, + RTW89_CHILE = 10, RTW89_UKRAINE = 11, RTW89_CN = 12, + RTW89_QATAR = 13, RTW89_REGD_NUM, }; @@ -472,6 +473,9 @@ struct rtw89_rx_phy_ppdu { u8 rssi_avg; s8 rssi[RF_PATH_MAX]; u8 mac_id; + u8 chan_idx; + u8 ie; + u16 rate; bool to_self; bool valid; }; @@ -543,7 +547,6 @@ enum rtw89_ps_mode { RTW89_PS_MODE_PWR_GATED = 3, }; -#define RTW89_MAX_CHANNEL_WIDTH RTW89_CHANNEL_WIDTH_80 #define RTW89_2G_BW_NUM (RTW89_CHANNEL_WIDTH_40 + 1) #define RTW89_5G_BW_NUM (RTW89_CHANNEL_WIDTH_80 + 1) #define RTW89_PPE_BW_NUM (RTW89_CHANNEL_WIDTH_80 + 1) @@ -570,7 +573,6 @@ struct rtw89_channel_params { u8 primary_chan; u8 bandwidth; u8 pri_ch_idx; - u8 cch_by_bw[RTW89_MAX_CHANNEL_WIDTH + 1]; }; struct rtw89_channel_help_params { @@ -803,6 +805,7 @@ enum rtw89_btc_bt_state_cnt { BTC_BCNT_HIPRI_RX, BTC_BCNT_LOPRI_TX, BTC_BCNT_LOPRI_RX, + BTC_BCNT_POLUT, BTC_BCNT_RATECHG, BTC_BCNT_NUM }; @@ -1865,7 +1868,6 @@ struct rtw89_addr_cam_entry { u8 wapi : 1; u8 mask_sel : 2; u8 bssid_cam_idx: 6; - u8 tma[ETH_ALEN]; u8 sma[ETH_ALEN]; u8 sec_ent_mode; @@ -1934,14 +1936,6 @@ struct rtw89_vif { bool wowlan_magic; bool is_hesta; bool last_a_ctrl; - union { - struct { - struct ieee80211_sta *ap; - } mgd; - struct { - struct list_head sta_list; - } ap; - }; struct rtw89_addr_cam_entry addr_cam; struct rtw89_bssid_cam_entry bssid_cam; struct ieee80211_tx_queue_params tx_params[IEEE80211_NUM_ACS]; @@ -2354,14 +2348,11 @@ struct rtw89_hal { u32 rx_fltr; u8 cv; u8 current_channel; + u8 prev_primary_channel; u8 current_primary_channel; enum rtw89_subband current_subband; u8 current_band_width; u8 current_band_type; - /* center channel for different available bandwidth, - * val of (bw > current_band_width) is invalid - */ - u8 cch_by_bw[RTW89_MAX_CHANNEL_WIDTH + 1]; u32 sw_amsdu_max_size; u32 antenna_tx; u32 antenna_rx; @@ -3127,6 +3118,16 @@ static inline struct ieee80211_sta *rtwsta_to_sta(struct rtw89_sta *rtwsta) return container_of(p, struct ieee80211_sta, drv_priv); } +static inline struct ieee80211_sta *rtwsta_to_sta_safe(struct rtw89_sta *rtwsta) +{ + return rtwsta ? rtwsta_to_sta(rtwsta) : NULL; +} + +static inline struct rtw89_sta *sta_to_rtwsta_safe(struct ieee80211_sta *sta) +{ + return sta ? (struct rtw89_sta *)sta->drv_priv : NULL; +} + static inline void rtw89_chip_set_channel_prepare(struct rtw89_dev *rtwdev, struct rtw89_channel_help_params *p) diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index 29eb188c888c..9756d75ef24e 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -723,6 +723,7 @@ rtw89_debug_priv_mac_mem_dump_select(struct file *filp, } static const u32 mac_mem_base_addr_table[RTW89_MAC_MEM_MAX] = { + [RTW89_MAC_MEM_AXIDMA] = AXIDMA_BASE_ADDR, [RTW89_MAC_MEM_SHARED_BUF] = SHARED_BUF_BASE_ADDR, [RTW89_MAC_MEM_DMAC_TBL] = DMAC_TBL_BASE_ADDR, [RTW89_MAC_MEM_SHCUT_MACHDR] = SHCUT_MACHDR_BASE_ADDR, @@ -735,6 +736,10 @@ static const u32 mac_mem_base_addr_table[RTW89_MAC_MEM_MAX] = { [RTW89_MAC_MEM_BA_CAM] = BA_CAM_BASE_ADDR, [RTW89_MAC_MEM_BCN_IE_CAM0] = BCN_IE_CAM0_BASE_ADDR, [RTW89_MAC_MEM_BCN_IE_CAM1] = BCN_IE_CAM1_BASE_ADDR, + [RTW89_MAC_MEM_TXD_FIFO_0] = TXD_FIFO_0_BASE_ADDR, + [RTW89_MAC_MEM_TXD_FIFO_1] = TXD_FIFO_1_BASE_ADDR, + [RTW89_MAC_MEM_TXDATA_FIFO_0] = TXDATA_FIFO_0_BASE_ADDR, + [RTW89_MAC_MEM_TXDATA_FIFO_1] = TXDATA_FIFO_1_BASE_ADDR, }; static void rtw89_debug_dump_mac_mem(struct seq_file *m, @@ -814,7 +819,7 @@ rtw89_debug_priv_mac_dbg_port_dump_select(struct file *filp, return -EINVAL; } - enable = set == 0 ? false : true; + enable = set != 0; switch (sel) { case 0: debugfs_priv->dbgpkg_en.ss_dbg = enable; @@ -2280,7 +2285,7 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) switch (status->encoding) { case RX_ENC_LEGACY: seq_printf(m, "Legacy %d", status->rate_idx + - (status->band == NL80211_BAND_5GHZ ? 4 : 0)); + (status->band != NL80211_BAND_2GHZ ? 4 : 0)); break; case RX_ENC_HT: seq_printf(m, "HT MCS-%d%s", status->rate_idx, diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 460d63dd6779..8a57b75b07c0 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -91,7 +91,6 @@ static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len, info->section_num = GET_FW_HDR_SEC_NUM(fw); info->hdr_len = RTW89_FW_HDR_SIZE + info->section_num * RTW89_FW_SECTION_HDR_SIZE; - SET_FW_HDR_PART_SIZE(fw, FWDL_SECTION_PER_PKT_LEN); bin = fw + info->hdr_len; @@ -275,6 +274,7 @@ static int __rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, const u8 *fw, u32 l } skb_put_data(skb, fw, len); + SET_FW_HDR_PART_SIZE(skb->data, FWDL_SECTION_PER_PKT_LEN); rtw89_h2c_pkt_set_hdr_fwdl(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_FWDL, H2C_FUNC_MAC_FWHDR_DL, len); @@ -523,7 +523,8 @@ void rtw89_unload_firmware(struct rtw89_dev *rtwdev) } #define H2C_CAM_LEN 60 -int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta, const u8 *scan_mac_addr) { struct sk_buff *skb; @@ -533,7 +534,7 @@ int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) return -ENOMEM; } skb_put(skb, H2C_CAM_LEN); - rtw89_cam_fill_addr_cam_info(rtwdev, rtwvif, skb->data); + rtw89_cam_fill_addr_cam_info(rtwdev, rtwvif, rtwsta, scan_mac_addr, skb->data); rtw89_cam_fill_bssid_cam_info(rtwdev, rtwvif, skb->data); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 7ee0d9323310..2d36dc27222f 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -156,861 +156,1125 @@ struct rtw89_h2creg_sch_tx_en { u16 rsvd:15; } __packed; -#define RTW89_SET_FWCMD_RA_IS_DIS(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(0)) -#define RTW89_SET_FWCMD_RA_MODE(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(5, 1)) -#define RTW89_SET_FWCMD_RA_BW_CAP(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(7, 6)) -#define RTW89_SET_FWCMD_RA_MACID(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(15, 8)) -#define RTW89_SET_FWCMD_RA_DCM(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(16)) -#define RTW89_SET_FWCMD_RA_ER(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(17)) -#define RTW89_SET_FWCMD_RA_INIT_RATE_LV(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(19, 18)) -#define RTW89_SET_FWCMD_RA_UPD_ALL(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(20)) -#define RTW89_SET_FWCMD_RA_SGI(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(21)) -#define RTW89_SET_FWCMD_RA_LDPC(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(22)) -#define RTW89_SET_FWCMD_RA_STBC(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(23)) -#define RTW89_SET_FWCMD_RA_SS_NUM(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(26, 24)) -#define RTW89_SET_FWCMD_RA_GILTF(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(29, 27)) -#define RTW89_SET_FWCMD_RA_UPD_BW_NSS_MASK(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(30)) -#define RTW89_SET_FWCMD_RA_UPD_MASK(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(31)) -#define RTW89_SET_FWCMD_RA_MASK_0(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x01, val, GENMASK(7, 0)) -#define RTW89_SET_FWCMD_RA_MASK_1(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x01, val, GENMASK(15, 8)) -#define RTW89_SET_FWCMD_RA_MASK_2(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x01, val, GENMASK(23, 16)) -#define RTW89_SET_FWCMD_RA_MASK_3(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x01, val, GENMASK(31, 24)) -#define RTW89_SET_FWCMD_RA_MASK_4(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x02, val, GENMASK(7, 0)) -#define RTW89_SET_FWCMD_RA_BFEE_CSI_CTL(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x02, val, BIT(31)) -#define RTW89_SET_FWCMD_RA_BAND_NUM(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x03, val, GENMASK(7, 0)) -#define RTW89_SET_FWCMD_RA_RA_CSI_RATE_EN(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x03, val, BIT(8)) -#define RTW89_SET_FWCMD_RA_FIXED_CSI_RATE_EN(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x03, val, BIT(9)) -#define RTW89_SET_FWCMD_RA_CR_TBL_SEL(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x03, val, BIT(10)) -#define RTW89_SET_FWCMD_RA_FIXED_CSI_MCS_SS_IDX(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x03, val, GENMASK(23, 16)) -#define RTW89_SET_FWCMD_RA_FIXED_CSI_MODE(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x03, val, GENMASK(25, 24)) -#define RTW89_SET_FWCMD_RA_FIXED_CSI_GI_LTF(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x03, val, GENMASK(28, 26)) -#define RTW89_SET_FWCMD_RA_FIXED_CSI_BW(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x03, val, GENMASK(31, 29)) - -#define RTW89_SET_FWCMD_SEC_IDX(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(7, 0)) -#define RTW89_SET_FWCMD_SEC_OFFSET(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(15, 8)) -#define RTW89_SET_FWCMD_SEC_LEN(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(23, 16)) -#define RTW89_SET_FWCMD_SEC_TYPE(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x01, val, GENMASK(3, 0)) -#define RTW89_SET_FWCMD_SEC_EXT_KEY(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x01, val, BIT(4)) -#define RTW89_SET_FWCMD_SEC_SPP_MODE(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x01, val, BIT(5)) -#define RTW89_SET_FWCMD_SEC_KEY0(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x02, val, GENMASK(31, 0)) -#define RTW89_SET_FWCMD_SEC_KEY1(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x03, val, GENMASK(31, 0)) -#define RTW89_SET_FWCMD_SEC_KEY2(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x04, val, GENMASK(31, 0)) -#define RTW89_SET_FWCMD_SEC_KEY3(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x05, val, GENMASK(31, 0)) - -#define RTW89_SET_EDCA_SEL(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(1, 0)) -#define RTW89_SET_EDCA_BAND(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(3)) -#define RTW89_SET_EDCA_WMM(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(4)) -#define RTW89_SET_EDCA_AC(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(6, 5)) -#define RTW89_SET_EDCA_PARAM(cmd, val) \ - le32p_replace_bits((__le32 *)(cmd) + 0x01, val, GENMASK(31, 0)) +static inline void RTW89_SET_FWCMD_RA_IS_DIS(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(0)); +} + +static inline void RTW89_SET_FWCMD_RA_MODE(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(5, 1)); +} + +static inline void RTW89_SET_FWCMD_RA_BW_CAP(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(7, 6)); +} + +static inline void RTW89_SET_FWCMD_RA_MACID(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(15, 8)); +} + +static inline void RTW89_SET_FWCMD_RA_DCM(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(16)); +} + +static inline void RTW89_SET_FWCMD_RA_ER(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(17)); +} + +static inline void RTW89_SET_FWCMD_RA_INIT_RATE_LV(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(19, 18)); +} + +static inline void RTW89_SET_FWCMD_RA_UPD_ALL(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(20)); +} + +static inline void RTW89_SET_FWCMD_RA_SGI(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(21)); +} + +static inline void RTW89_SET_FWCMD_RA_LDPC(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(22)); +} + +static inline void RTW89_SET_FWCMD_RA_STBC(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(23)); +} + +static inline void RTW89_SET_FWCMD_RA_SS_NUM(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(26, 24)); +} + +static inline void RTW89_SET_FWCMD_RA_GILTF(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(29, 27)); +} + +static inline void RTW89_SET_FWCMD_RA_UPD_BW_NSS_MASK(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(30)); +} + +static inline void RTW89_SET_FWCMD_RA_UPD_MASK(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(31)); +} + +static inline void RTW89_SET_FWCMD_RA_MASK_0(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x01, val, GENMASK(7, 0)); +} + +static inline void RTW89_SET_FWCMD_RA_MASK_1(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x01, val, GENMASK(15, 8)); +} + +static inline void RTW89_SET_FWCMD_RA_MASK_2(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x01, val, GENMASK(23, 16)); +} + +static inline void RTW89_SET_FWCMD_RA_MASK_3(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x01, val, GENMASK(31, 24)); +} + +static inline void RTW89_SET_FWCMD_RA_MASK_4(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x02, val, GENMASK(7, 0)); +} + +static inline void RTW89_SET_FWCMD_RA_BFEE_CSI_CTL(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x02, val, BIT(31)); +} + +static inline void RTW89_SET_FWCMD_RA_BAND_NUM(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x03, val, GENMASK(7, 0)); +} + +static inline void RTW89_SET_FWCMD_RA_RA_CSI_RATE_EN(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x03, val, BIT(8)); +} + +static inline void RTW89_SET_FWCMD_RA_FIXED_CSI_RATE_EN(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x03, val, BIT(9)); +} + +static inline void RTW89_SET_FWCMD_RA_CR_TBL_SEL(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x03, val, BIT(10)); +} + +static inline void RTW89_SET_FWCMD_RA_FIXED_CSI_MCS_SS_IDX(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x03, val, GENMASK(23, 16)); +} + +static inline void RTW89_SET_FWCMD_RA_FIXED_CSI_MODE(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x03, val, GENMASK(25, 24)); +} + +static inline void RTW89_SET_FWCMD_RA_FIXED_CSI_GI_LTF(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x03, val, GENMASK(28, 26)); +} + +static inline void RTW89_SET_FWCMD_RA_FIXED_CSI_BW(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x03, val, GENMASK(31, 29)); +} + +static inline void RTW89_SET_FWCMD_SEC_IDX(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(7, 0)); +} + +static inline void RTW89_SET_FWCMD_SEC_OFFSET(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(15, 8)); +} + +static inline void RTW89_SET_FWCMD_SEC_LEN(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(23, 16)); +} + +static inline void RTW89_SET_FWCMD_SEC_TYPE(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x01, val, GENMASK(3, 0)); +} + +static inline void RTW89_SET_FWCMD_SEC_EXT_KEY(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x01, val, BIT(4)); +} + +static inline void RTW89_SET_FWCMD_SEC_SPP_MODE(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x01, val, BIT(5)); +} + +static inline void RTW89_SET_FWCMD_SEC_KEY0(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x02, val, GENMASK(31, 0)); +} + +static inline void RTW89_SET_FWCMD_SEC_KEY1(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x03, val, GENMASK(31, 0)); +} + +static inline void RTW89_SET_FWCMD_SEC_KEY2(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x04, val, GENMASK(31, 0)); +} + +static inline void RTW89_SET_FWCMD_SEC_KEY3(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x05, val, GENMASK(31, 0)); +} + +static inline void RTW89_SET_EDCA_SEL(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(1, 0)); +} + +static inline void RTW89_SET_EDCA_BAND(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(3)); +} + +static inline void RTW89_SET_EDCA_WMM(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(4)); +} + +static inline void RTW89_SET_EDCA_AC(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(6, 5)); +} + +static inline void RTW89_SET_EDCA_PARAM(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)(cmd) + 0x01, val, GENMASK(31, 0)); +} #define FW_EDCA_PARAM_TXOPLMT_MSK GENMASK(26, 16) #define FW_EDCA_PARAM_CWMAX_MSK GENMASK(15, 12) #define FW_EDCA_PARAM_CWMIN_MSK GENMASK(11, 8) #define FW_EDCA_PARAM_AIFS_MSK GENMASK(7, 0) #define GET_FWSECTION_HDR_SEC_SIZE(fwhdr) \ - le32_get_bits(*((__le32 *)(fwhdr) + 1), GENMASK(23, 0)) + le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(23, 0)) #define GET_FWSECTION_HDR_CHECKSUM(fwhdr) \ - le32_get_bits(*((__le32 *)(fwhdr) + 1), BIT(28)) + le32_get_bits(*((const __le32 *)(fwhdr) + 1), BIT(28)) #define GET_FWSECTION_HDR_REDL(fwhdr) \ - le32_get_bits(*((__le32 *)(fwhdr) + 1), BIT(29)) + le32_get_bits(*((const __le32 *)(fwhdr) + 1), BIT(29)) #define GET_FWSECTION_HDR_DL_ADDR(fwhdr) \ - le32_get_bits(*((__le32 *)(fwhdr)), GENMASK(31, 0)) + le32_get_bits(*((const __le32 *)(fwhdr)), GENMASK(31, 0)) #define GET_FW_HDR_MAJOR_VERSION(fwhdr) \ - le32_get_bits(*((__le32 *)(fwhdr) + 1), GENMASK(7, 0)) + le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(7, 0)) #define GET_FW_HDR_MINOR_VERSION(fwhdr) \ - le32_get_bits(*((__le32 *)(fwhdr) + 1), GENMASK(15, 8)) + le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(15, 8)) #define GET_FW_HDR_SUBVERSION(fwhdr) \ - le32_get_bits(*((__le32 *)(fwhdr) + 1), GENMASK(23, 16)) + le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(23, 16)) #define GET_FW_HDR_SUBINDEX(fwhdr) \ - le32_get_bits(*((__le32 *)(fwhdr) + 1), GENMASK(31, 24)) + le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(31, 24)) #define GET_FW_HDR_MONTH(fwhdr) \ - le32_get_bits(*((__le32 *)(fwhdr) + 4), GENMASK(7, 0)) + le32_get_bits(*((const __le32 *)(fwhdr) + 4), GENMASK(7, 0)) #define GET_FW_HDR_DATE(fwhdr) \ - le32_get_bits(*((__le32 *)(fwhdr) + 4), GENMASK(15, 8)) + le32_get_bits(*((const __le32 *)(fwhdr) + 4), GENMASK(15, 8)) #define GET_FW_HDR_HOUR(fwhdr) \ - le32_get_bits(*((__le32 *)(fwhdr) + 4), GENMASK(23, 16)) + le32_get_bits(*((const __le32 *)(fwhdr) + 4), GENMASK(23, 16)) #define GET_FW_HDR_MIN(fwhdr) \ - le32_get_bits(*((__le32 *)(fwhdr) + 4), GENMASK(31, 24)) + le32_get_bits(*((const __le32 *)(fwhdr) + 4), GENMASK(31, 24)) #define GET_FW_HDR_YEAR(fwhdr) \ - le32_get_bits(*((__le32 *)(fwhdr) + 5), GENMASK(31, 0)) + le32_get_bits(*((const __le32 *)(fwhdr) + 5), GENMASK(31, 0)) #define GET_FW_HDR_SEC_NUM(fwhdr) \ - le32_get_bits(*((__le32 *)(fwhdr) + 6), GENMASK(15, 8)) + le32_get_bits(*((const __le32 *)(fwhdr) + 6), GENMASK(15, 8)) #define GET_FW_HDR_CMD_VERSERION(fwhdr) \ - le32_get_bits(*((__le32 *)(fwhdr) + 7), GENMASK(31, 24)) -#define SET_FW_HDR_PART_SIZE(fwhdr, val) \ - le32p_replace_bits((__le32 *)(fwhdr) + 7, val, GENMASK(15, 0)) - -#define SET_CTRL_INFO_MACID(table, val) \ - le32p_replace_bits((__le32 *)(table) + 0, val, GENMASK(6, 0)) -#define SET_CTRL_INFO_OPERATION(table, val) \ - le32p_replace_bits((__le32 *)(table) + 0, val, BIT(7)) + le32_get_bits(*((const __le32 *)(fwhdr) + 7), GENMASK(31, 24)) +static inline void SET_FW_HDR_PART_SIZE(void *fwhdr, u32 val) +{ + le32p_replace_bits((__le32 *)fwhdr + 7, val, GENMASK(15, 0)); +} + +static inline void SET_CTRL_INFO_MACID(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 0, val, GENMASK(6, 0)); +} + +static inline void SET_CTRL_INFO_OPERATION(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 0, val, BIT(7)); +} #define SET_CMC_TBL_MASK_DATARATE GENMASK(8, 0) -#define SET_CMC_TBL_DATARATE(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 1, val, GENMASK(8, 0)); \ - le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_DATARATE, \ - GENMASK(8, 0)); \ -} while (0) +static inline void SET_CMC_TBL_DATARATE(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 1, val, GENMASK(8, 0)); + le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_DATARATE, + GENMASK(8, 0)); +} #define SET_CMC_TBL_MASK_FORCE_TXOP BIT(0) -#define SET_CMC_TBL_FORCE_TXOP(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 1, val, BIT(9)); \ - le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_FORCE_TXOP, \ - BIT(9)); \ -} while (0) +static inline void SET_CMC_TBL_FORCE_TXOP(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 1, val, BIT(9)); + le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_FORCE_TXOP, + BIT(9)); +} #define SET_CMC_TBL_MASK_DATA_BW GENMASK(1, 0) -#define SET_CMC_TBL_DATA_BW(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 1, val, GENMASK(11, 10)); \ - le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_DATA_BW, \ - GENMASK(11, 10)); \ -} while (0) +static inline void SET_CMC_TBL_DATA_BW(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 1, val, GENMASK(11, 10)); + le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_DATA_BW, + GENMASK(11, 10)); +} #define SET_CMC_TBL_MASK_DATA_GI_LTF GENMASK(2, 0) -#define SET_CMC_TBL_DATA_GI_LTF(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 1, val, GENMASK(14, 12)); \ - le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_DATA_GI_LTF, \ - GENMASK(14, 12)); \ -} while (0) +static inline void SET_CMC_TBL_DATA_GI_LTF(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 1, val, GENMASK(14, 12)); + le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_DATA_GI_LTF, + GENMASK(14, 12)); +} #define SET_CMC_TBL_MASK_DARF_TC_INDEX BIT(0) -#define SET_CMC_TBL_DARF_TC_INDEX(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 1, val, BIT(15)); \ - le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_DARF_TC_INDEX, \ - BIT(15)); \ -} while (0) +static inline void SET_CMC_TBL_DARF_TC_INDEX(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 1, val, BIT(15)); + le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_DARF_TC_INDEX, + BIT(15)); +} #define SET_CMC_TBL_MASK_ARFR_CTRL GENMASK(3, 0) -#define SET_CMC_TBL_ARFR_CTRL(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 1, val, GENMASK(19, 16)); \ - le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_ARFR_CTRL, \ - GENMASK(19, 16)); \ -} while (0) +static inline void SET_CMC_TBL_ARFR_CTRL(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 1, val, GENMASK(19, 16)); + le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_ARFR_CTRL, + GENMASK(19, 16)); +} #define SET_CMC_TBL_MASK_ACQ_RPT_EN BIT(0) -#define SET_CMC_TBL_ACQ_RPT_EN(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 1, val, BIT(20)); \ - le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_ACQ_RPT_EN, \ - BIT(20)); \ -} while (0) +static inline void SET_CMC_TBL_ACQ_RPT_EN(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 1, val, BIT(20)); + le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_ACQ_RPT_EN, + BIT(20)); +} #define SET_CMC_TBL_MASK_MGQ_RPT_EN BIT(0) -#define SET_CMC_TBL_MGQ_RPT_EN(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 1, val, BIT(21)); \ - le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_MGQ_RPT_EN, \ - BIT(21)); \ -} while (0) +static inline void SET_CMC_TBL_MGQ_RPT_EN(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 1, val, BIT(21)); + le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_MGQ_RPT_EN, + BIT(21)); +} #define SET_CMC_TBL_MASK_ULQ_RPT_EN BIT(0) -#define SET_CMC_TBL_ULQ_RPT_EN(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 1, val, BIT(22)); \ - le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_ULQ_RPT_EN, \ - BIT(22)); \ -} while (0) +static inline void SET_CMC_TBL_ULQ_RPT_EN(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 1, val, BIT(22)); + le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_ULQ_RPT_EN, + BIT(22)); +} #define SET_CMC_TBL_MASK_TWTQ_RPT_EN BIT(0) -#define SET_CMC_TBL_TWTQ_RPT_EN(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 1, val, BIT(23)); \ - le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_TWTQ_RPT_EN, \ - BIT(23)); \ -} while (0) +static inline void SET_CMC_TBL_TWTQ_RPT_EN(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 1, val, BIT(23)); + le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_TWTQ_RPT_EN, + BIT(23)); +} #define SET_CMC_TBL_MASK_DISRTSFB BIT(0) -#define SET_CMC_TBL_DISRTSFB(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 1, val, BIT(25)); \ - le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_DISRTSFB, \ - BIT(25)); \ -} while (0) +static inline void SET_CMC_TBL_DISRTSFB(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 1, val, BIT(25)); + le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_DISRTSFB, + BIT(25)); +} #define SET_CMC_TBL_MASK_DISDATAFB BIT(0) -#define SET_CMC_TBL_DISDATAFB(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 1, val, BIT(26)); \ - le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_DISDATAFB, \ - BIT(26)); \ -} while (0) +static inline void SET_CMC_TBL_DISDATAFB(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 1, val, BIT(26)); + le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_DISDATAFB, + BIT(26)); +} #define SET_CMC_TBL_MASK_TRYRATE BIT(0) -#define SET_CMC_TBL_TRYRATE(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 1, val, BIT(27)); \ - le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_TRYRATE, \ - BIT(27)); \ -} while (0) +static inline void SET_CMC_TBL_TRYRATE(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 1, val, BIT(27)); + le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_TRYRATE, + BIT(27)); +} #define SET_CMC_TBL_MASK_AMPDU_DENSITY GENMASK(3, 0) -#define SET_CMC_TBL_AMPDU_DENSITY(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 1, val, GENMASK(31, 28)); \ - le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_AMPDU_DENSITY, \ - GENMASK(31, 28)); \ -} while (0) +static inline void SET_CMC_TBL_AMPDU_DENSITY(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 1, val, GENMASK(31, 28)); + le32p_replace_bits((__le32 *)(table) + 9, SET_CMC_TBL_MASK_AMPDU_DENSITY, + GENMASK(31, 28)); +} #define SET_CMC_TBL_MASK_DATA_RTY_LOWEST_RATE GENMASK(8, 0) -#define SET_CMC_TBL_DATA_RTY_LOWEST_RATE(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 2, val, GENMASK(8, 0)); \ - le32p_replace_bits((__le32 *)(table) + 10, SET_CMC_TBL_MASK_DATA_RTY_LOWEST_RATE, \ - GENMASK(8, 0)); \ -} while (0) +static inline void SET_CMC_TBL_DATA_RTY_LOWEST_RATE(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 2, val, GENMASK(8, 0)); + le32p_replace_bits((__le32 *)(table) + 10, SET_CMC_TBL_MASK_DATA_RTY_LOWEST_RATE, + GENMASK(8, 0)); +} #define SET_CMC_TBL_MASK_AMPDU_TIME_SEL BIT(0) -#define SET_CMC_TBL_AMPDU_TIME_SEL(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 2, val, BIT(9)); \ - le32p_replace_bits((__le32 *)(table) + 10, SET_CMC_TBL_MASK_AMPDU_TIME_SEL, \ - BIT(9)); \ -} while (0) +static inline void SET_CMC_TBL_AMPDU_TIME_SEL(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 2, val, BIT(9)); + le32p_replace_bits((__le32 *)(table) + 10, SET_CMC_TBL_MASK_AMPDU_TIME_SEL, + BIT(9)); +} #define SET_CMC_TBL_MASK_AMPDU_LEN_SEL BIT(0) -#define SET_CMC_TBL_AMPDU_LEN_SEL(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 2, val, BIT(10)); \ - le32p_replace_bits((__le32 *)(table) + 10, SET_CMC_TBL_MASK_AMPDU_LEN_SEL, \ - BIT(10)); \ -} while (0) +static inline void SET_CMC_TBL_AMPDU_LEN_SEL(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 2, val, BIT(10)); + le32p_replace_bits((__le32 *)(table) + 10, SET_CMC_TBL_MASK_AMPDU_LEN_SEL, + BIT(10)); +} #define SET_CMC_TBL_MASK_RTS_TXCNT_LMT_SEL BIT(0) -#define SET_CMC_TBL_RTS_TXCNT_LMT_SEL(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 2, val, BIT(11)); \ - le32p_replace_bits((__le32 *)(table) + 10, SET_CMC_TBL_MASK_RTS_TXCNT_LMT_SEL, \ - BIT(11)); \ -} while (0) +static inline void SET_CMC_TBL_RTS_TXCNT_LMT_SEL(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 2, val, BIT(11)); + le32p_replace_bits((__le32 *)(table) + 10, SET_CMC_TBL_MASK_RTS_TXCNT_LMT_SEL, + BIT(11)); +} #define SET_CMC_TBL_MASK_RTS_TXCNT_LMT GENMASK(3, 0) -#define SET_CMC_TBL_RTS_TXCNT_LMT(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 2, val, GENMASK(15, 12)); \ - le32p_replace_bits((__le32 *)(table) + 10, SET_CMC_TBL_MASK_RTS_TXCNT_LMT, \ - GENMASK(15, 12)); \ -} while (0) +static inline void SET_CMC_TBL_RTS_TXCNT_LMT(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 2, val, GENMASK(15, 12)); + le32p_replace_bits((__le32 *)(table) + 10, SET_CMC_TBL_MASK_RTS_TXCNT_LMT, + GENMASK(15, 12)); +} #define SET_CMC_TBL_MASK_RTSRATE GENMASK(8, 0) -#define SET_CMC_TBL_RTSRATE(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 2, val, GENMASK(24, 16)); \ - le32p_replace_bits((__le32 *)(table) + 10, SET_CMC_TBL_MASK_RTSRATE, \ - GENMASK(24, 16)); \ -} while (0) +static inline void SET_CMC_TBL_RTSRATE(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 2, val, GENMASK(24, 16)); + le32p_replace_bits((__le32 *)(table) + 10, SET_CMC_TBL_MASK_RTSRATE, + GENMASK(24, 16)); +} #define SET_CMC_TBL_MASK_VCS_STBC BIT(0) -#define SET_CMC_TBL_VCS_STBC(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 2, val, BIT(27)); \ - le32p_replace_bits((__le32 *)(table) + 10, SET_CMC_TBL_MASK_VCS_STBC, \ - BIT(27)); \ -} while (0) +static inline void SET_CMC_TBL_VCS_STBC(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 2, val, BIT(27)); + le32p_replace_bits((__le32 *)(table) + 10, SET_CMC_TBL_MASK_VCS_STBC, + BIT(27)); +} #define SET_CMC_TBL_MASK_RTS_RTY_LOWEST_RATE GENMASK(3, 0) -#define SET_CMC_TBL_RTS_RTY_LOWEST_RATE(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 2, val, GENMASK(31, 28)); \ - le32p_replace_bits((__le32 *)(table) + 10, SET_CMC_TBL_MASK_RTS_RTY_LOWEST_RATE, \ - GENMASK(31, 28)); \ -} while (0) +static inline void SET_CMC_TBL_RTS_RTY_LOWEST_RATE(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 2, val, GENMASK(31, 28)); + le32p_replace_bits((__le32 *)(table) + 10, SET_CMC_TBL_MASK_RTS_RTY_LOWEST_RATE, + GENMASK(31, 28)); +} #define SET_CMC_TBL_MASK_DATA_TX_CNT_LMT GENMASK(5, 0) -#define SET_CMC_TBL_DATA_TX_CNT_LMT(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 3, val, GENMASK(5, 0)); \ - le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_DATA_TX_CNT_LMT, \ - GENMASK(5, 0)); \ -} while (0) +static inline void SET_CMC_TBL_DATA_TX_CNT_LMT(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 3, val, GENMASK(5, 0)); + le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_DATA_TX_CNT_LMT, + GENMASK(5, 0)); +} #define SET_CMC_TBL_MASK_DATA_TXCNT_LMT_SEL BIT(0) -#define SET_CMC_TBL_DATA_TXCNT_LMT_SEL(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 3, val, BIT(6)); \ - le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_DATA_TXCNT_LMT_SEL, \ - BIT(6)); \ -} while (0) +static inline void SET_CMC_TBL_DATA_TXCNT_LMT_SEL(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 3, val, BIT(6)); + le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_DATA_TXCNT_LMT_SEL, + BIT(6)); +} #define SET_CMC_TBL_MASK_MAX_AGG_NUM_SEL BIT(0) -#define SET_CMC_TBL_MAX_AGG_NUM_SEL(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 3, val, BIT(7)); \ - le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_MAX_AGG_NUM_SEL, \ - BIT(7)); \ -} while (0) +static inline void SET_CMC_TBL_MAX_AGG_NUM_SEL(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 3, val, BIT(7)); + le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_MAX_AGG_NUM_SEL, + BIT(7)); +} #define SET_CMC_TBL_MASK_RTS_EN BIT(0) -#define SET_CMC_TBL_RTS_EN(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 3, val, BIT(8)); \ - le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_RTS_EN, \ - BIT(8)); \ -} while (0) +static inline void SET_CMC_TBL_RTS_EN(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 3, val, BIT(8)); + le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_RTS_EN, + BIT(8)); +} #define SET_CMC_TBL_MASK_CTS2SELF_EN BIT(0) -#define SET_CMC_TBL_CTS2SELF_EN(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 3, val, BIT(9)); \ - le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_CTS2SELF_EN, \ - BIT(9)); \ -} while (0) +static inline void SET_CMC_TBL_CTS2SELF_EN(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 3, val, BIT(9)); + le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_CTS2SELF_EN, + BIT(9)); +} #define SET_CMC_TBL_MASK_CCA_RTS GENMASK(1, 0) -#define SET_CMC_TBL_CCA_RTS(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 3, val, GENMASK(11, 10)); \ - le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_CCA_RTS, \ - GENMASK(11, 10)); \ -} while (0) +static inline void SET_CMC_TBL_CCA_RTS(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 3, val, GENMASK(11, 10)); + le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_CCA_RTS, + GENMASK(11, 10)); +} #define SET_CMC_TBL_MASK_HW_RTS_EN BIT(0) -#define SET_CMC_TBL_HW_RTS_EN(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 3, val, BIT(12)); \ - le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_HW_RTS_EN, \ - BIT(12)); \ -} while (0) +static inline void SET_CMC_TBL_HW_RTS_EN(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 3, val, BIT(12)); + le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_HW_RTS_EN, + BIT(12)); +} #define SET_CMC_TBL_MASK_RTS_DROP_DATA_MODE GENMASK(1, 0) -#define SET_CMC_TBL_RTS_DROP_DATA_MODE(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 3, val, GENMASK(14, 13)); \ - le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_RTS_DROP_DATA_MODE, \ - GENMASK(14, 13)); \ -} while (0) +static inline void SET_CMC_TBL_RTS_DROP_DATA_MODE(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 3, val, GENMASK(14, 13)); + le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_RTS_DROP_DATA_MODE, + GENMASK(14, 13)); +} #define SET_CMC_TBL_MASK_AMPDU_MAX_LEN GENMASK(10, 0) -#define SET_CMC_TBL_AMPDU_MAX_LEN(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 3, val, GENMASK(26, 16)); \ - le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_AMPDU_MAX_LEN, \ - GENMASK(26, 16)); \ -} while (0) +static inline void SET_CMC_TBL_AMPDU_MAX_LEN(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 3, val, GENMASK(26, 16)); + le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_AMPDU_MAX_LEN, + GENMASK(26, 16)); +} #define SET_CMC_TBL_MASK_UL_MU_DIS BIT(0) -#define SET_CMC_TBL_UL_MU_DIS(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 3, val, BIT(27)); \ - le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_UL_MU_DIS, \ - BIT(27)); \ -} while (0) +static inline void SET_CMC_TBL_UL_MU_DIS(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 3, val, BIT(27)); + le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_UL_MU_DIS, + BIT(27)); +} #define SET_CMC_TBL_MASK_AMPDU_MAX_TIME GENMASK(3, 0) -#define SET_CMC_TBL_AMPDU_MAX_TIME(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 3, val, GENMASK(31, 28)); \ - le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_AMPDU_MAX_TIME, \ - GENMASK(31, 28)); \ -} while (0) +static inline void SET_CMC_TBL_AMPDU_MAX_TIME(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 3, val, GENMASK(31, 28)); + le32p_replace_bits((__le32 *)(table) + 11, SET_CMC_TBL_MASK_AMPDU_MAX_TIME, + GENMASK(31, 28)); +} #define SET_CMC_TBL_MASK_MAX_AGG_NUM GENMASK(7, 0) -#define SET_CMC_TBL_MAX_AGG_NUM(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 4, val, GENMASK(7, 0)); \ - le32p_replace_bits((__le32 *)(table) + 12, SET_CMC_TBL_MASK_MAX_AGG_NUM, \ - GENMASK(7, 0)); \ -} while (0) +static inline void SET_CMC_TBL_MAX_AGG_NUM(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 4, val, GENMASK(7, 0)); + le32p_replace_bits((__le32 *)(table) + 12, SET_CMC_TBL_MASK_MAX_AGG_NUM, + GENMASK(7, 0)); +} #define SET_CMC_TBL_MASK_BA_BMAP GENMASK(1, 0) -#define SET_CMC_TBL_BA_BMAP(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 4, val, GENMASK(9, 8)); \ - le32p_replace_bits((__le32 *)(table) + 12, SET_CMC_TBL_MASK_BA_BMAP, \ - GENMASK(9, 8)); \ -} while (0) +static inline void SET_CMC_TBL_BA_BMAP(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 4, val, GENMASK(9, 8)); + le32p_replace_bits((__le32 *)(table) + 12, SET_CMC_TBL_MASK_BA_BMAP, + GENMASK(9, 8)); +} #define SET_CMC_TBL_MASK_VO_LFTIME_SEL GENMASK(2, 0) -#define SET_CMC_TBL_VO_LFTIME_SEL(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 4, val, GENMASK(18, 16)); \ - le32p_replace_bits((__le32 *)(table) + 12, SET_CMC_TBL_MASK_VO_LFTIME_SEL, \ - GENMASK(18, 16)); \ -} while (0) +static inline void SET_CMC_TBL_VO_LFTIME_SEL(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 4, val, GENMASK(18, 16)); + le32p_replace_bits((__le32 *)(table) + 12, SET_CMC_TBL_MASK_VO_LFTIME_SEL, + GENMASK(18, 16)); +} #define SET_CMC_TBL_MASK_VI_LFTIME_SEL GENMASK(2, 0) -#define SET_CMC_TBL_VI_LFTIME_SEL(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 4, val, GENMASK(21, 19)); \ - le32p_replace_bits((__le32 *)(table) + 12, SET_CMC_TBL_MASK_VI_LFTIME_SEL, \ - GENMASK(21, 19)); \ -} while (0) +static inline void SET_CMC_TBL_VI_LFTIME_SEL(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 4, val, GENMASK(21, 19)); + le32p_replace_bits((__le32 *)(table) + 12, SET_CMC_TBL_MASK_VI_LFTIME_SEL, + GENMASK(21, 19)); +} #define SET_CMC_TBL_MASK_BE_LFTIME_SEL GENMASK(2, 0) -#define SET_CMC_TBL_BE_LFTIME_SEL(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 4, val, GENMASK(24, 22)); \ - le32p_replace_bits((__le32 *)(table) + 12, SET_CMC_TBL_MASK_BE_LFTIME_SEL, \ - GENMASK(24, 22)); \ -} while (0) +static inline void SET_CMC_TBL_BE_LFTIME_SEL(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 4, val, GENMASK(24, 22)); + le32p_replace_bits((__le32 *)(table) + 12, SET_CMC_TBL_MASK_BE_LFTIME_SEL, + GENMASK(24, 22)); +} #define SET_CMC_TBL_MASK_BK_LFTIME_SEL GENMASK(2, 0) -#define SET_CMC_TBL_BK_LFTIME_SEL(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 4, val, GENMASK(27, 25)); \ - le32p_replace_bits((__le32 *)(table) + 12, SET_CMC_TBL_MASK_BK_LFTIME_SEL, \ - GENMASK(27, 25)); \ -} while (0) +static inline void SET_CMC_TBL_BK_LFTIME_SEL(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 4, val, GENMASK(27, 25)); + le32p_replace_bits((__le32 *)(table) + 12, SET_CMC_TBL_MASK_BK_LFTIME_SEL, + GENMASK(27, 25)); +} #define SET_CMC_TBL_MASK_SECTYPE GENMASK(3, 0) -#define SET_CMC_TBL_SECTYPE(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 4, val, GENMASK(31, 28)); \ - le32p_replace_bits((__le32 *)(table) + 12, SET_CMC_TBL_MASK_SECTYPE, \ - GENMASK(31, 28)); \ -} while (0) +static inline void SET_CMC_TBL_SECTYPE(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 4, val, GENMASK(31, 28)); + le32p_replace_bits((__le32 *)(table) + 12, SET_CMC_TBL_MASK_SECTYPE, + GENMASK(31, 28)); +} #define SET_CMC_TBL_MASK_MULTI_PORT_ID GENMASK(2, 0) -#define SET_CMC_TBL_MULTI_PORT_ID(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 5, val, GENMASK(2, 0)); \ - le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_MULTI_PORT_ID, \ - GENMASK(2, 0)); \ -} while (0) +static inline void SET_CMC_TBL_MULTI_PORT_ID(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 5, val, GENMASK(2, 0)); + le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_MULTI_PORT_ID, + GENMASK(2, 0)); +} #define SET_CMC_TBL_MASK_BMC BIT(0) -#define SET_CMC_TBL_BMC(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 5, val, BIT(3)); \ - le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_BMC, \ - BIT(3)); \ -} while (0) +static inline void SET_CMC_TBL_BMC(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 5, val, BIT(3)); + le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_BMC, + BIT(3)); +} #define SET_CMC_TBL_MASK_MBSSID GENMASK(3, 0) -#define SET_CMC_TBL_MBSSID(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 5, val, GENMASK(7, 4)); \ - le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_MBSSID, \ - GENMASK(7, 4)); \ -} while (0) +static inline void SET_CMC_TBL_MBSSID(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 5, val, GENMASK(7, 4)); + le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_MBSSID, + GENMASK(7, 4)); +} #define SET_CMC_TBL_MASK_NAVUSEHDR BIT(0) -#define SET_CMC_TBL_NAVUSEHDR(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 5, val, BIT(8)); \ - le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_NAVUSEHDR, \ - BIT(8)); \ -} while (0) +static inline void SET_CMC_TBL_NAVUSEHDR(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 5, val, BIT(8)); + le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_NAVUSEHDR, + BIT(8)); +} #define SET_CMC_TBL_MASK_TXPWR_MODE GENMASK(2, 0) -#define SET_CMC_TBL_TXPWR_MODE(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 5, val, GENMASK(11, 9)); \ - le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_TXPWR_MODE, \ - GENMASK(11, 9)); \ -} while (0) +static inline void SET_CMC_TBL_TXPWR_MODE(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 5, val, GENMASK(11, 9)); + le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_TXPWR_MODE, + GENMASK(11, 9)); +} #define SET_CMC_TBL_MASK_DATA_DCM BIT(0) -#define SET_CMC_TBL_DATA_DCM(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 5, val, BIT(12)); \ - le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_DATA_DCM, \ - BIT(12)); \ -} while (0) +static inline void SET_CMC_TBL_DATA_DCM(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 5, val, BIT(12)); + le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_DATA_DCM, + BIT(12)); +} #define SET_CMC_TBL_MASK_DATA_ER BIT(0) -#define SET_CMC_TBL_DATA_ER(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 5, val, BIT(13)); \ - le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_DATA_ER, \ - BIT(13)); \ -} while (0) +static inline void SET_CMC_TBL_DATA_ER(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 5, val, BIT(13)); + le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_DATA_ER, + BIT(13)); +} #define SET_CMC_TBL_MASK_DATA_LDPC BIT(0) -#define SET_CMC_TBL_DATA_LDPC(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 5, val, BIT(14)); \ - le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_DATA_LDPC, \ - BIT(14)); \ -} while (0) +static inline void SET_CMC_TBL_DATA_LDPC(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 5, val, BIT(14)); + le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_DATA_LDPC, + BIT(14)); +} #define SET_CMC_TBL_MASK_DATA_STBC BIT(0) -#define SET_CMC_TBL_DATA_STBC(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 5, val, BIT(15)); \ - le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_DATA_STBC, \ - BIT(15)); \ -} while (0) +static inline void SET_CMC_TBL_DATA_STBC(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 5, val, BIT(15)); + le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_DATA_STBC, + BIT(15)); +} #define SET_CMC_TBL_MASK_A_CTRL_BQR BIT(0) -#define SET_CMC_TBL_A_CTRL_BQR(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 5, val, BIT(16)); \ - le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_A_CTRL_BQR, \ - BIT(16)); \ -} while (0) +static inline void SET_CMC_TBL_A_CTRL_BQR(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 5, val, BIT(16)); + le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_A_CTRL_BQR, + BIT(16)); +} #define SET_CMC_TBL_MASK_A_CTRL_UPH BIT(0) -#define SET_CMC_TBL_A_CTRL_UPH(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 5, val, BIT(17)); \ - le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_A_CTRL_UPH, \ - BIT(17)); \ -} while (0) +static inline void SET_CMC_TBL_A_CTRL_UPH(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 5, val, BIT(17)); + le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_A_CTRL_UPH, + BIT(17)); +} #define SET_CMC_TBL_MASK_A_CTRL_BSR BIT(0) -#define SET_CMC_TBL_A_CTRL_BSR(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 5, val, BIT(18)); \ - le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_A_CTRL_BSR, \ - BIT(18)); \ -} while (0) +static inline void SET_CMC_TBL_A_CTRL_BSR(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 5, val, BIT(18)); + le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_A_CTRL_BSR, + BIT(18)); +} #define SET_CMC_TBL_MASK_A_CTRL_CAS BIT(0) -#define SET_CMC_TBL_A_CTRL_CAS(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 5, val, BIT(19)); \ - le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_A_CTRL_CAS, \ - BIT(19)); \ -} while (0) +static inline void SET_CMC_TBL_A_CTRL_CAS(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 5, val, BIT(19)); + le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_A_CTRL_CAS, + BIT(19)); +} #define SET_CMC_TBL_MASK_DATA_BW_ER BIT(0) -#define SET_CMC_TBL_DATA_BW_ER(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 5, val, BIT(20)); \ - le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_DATA_BW_ER, \ - BIT(20)); \ -} while (0) +static inline void SET_CMC_TBL_DATA_BW_ER(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 5, val, BIT(20)); + le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_DATA_BW_ER, + BIT(20)); +} #define SET_CMC_TBL_MASK_LSIG_TXOP_EN BIT(0) -#define SET_CMC_TBL_LSIG_TXOP_EN(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 5, val, BIT(21)); \ - le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_LSIG_TXOP_EN, \ - BIT(21)); \ -} while (0) +static inline void SET_CMC_TBL_LSIG_TXOP_EN(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 5, val, BIT(21)); + le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_LSIG_TXOP_EN, + BIT(21)); +} #define SET_CMC_TBL_MASK_CTRL_CNT_VLD BIT(0) -#define SET_CMC_TBL_CTRL_CNT_VLD(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 5, val, BIT(27)); \ - le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_CTRL_CNT_VLD, \ - BIT(27)); \ -} while (0) +static inline void SET_CMC_TBL_CTRL_CNT_VLD(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 5, val, BIT(27)); + le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_CTRL_CNT_VLD, + BIT(27)); +} #define SET_CMC_TBL_MASK_CTRL_CNT GENMASK(3, 0) -#define SET_CMC_TBL_CTRL_CNT(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 5, val, GENMASK(31, 28)); \ - le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_CTRL_CNT, \ - GENMASK(31, 28)); \ -} while (0) +static inline void SET_CMC_TBL_CTRL_CNT(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 5, val, GENMASK(31, 28)); + le32p_replace_bits((__le32 *)(table) + 13, SET_CMC_TBL_MASK_CTRL_CNT, + GENMASK(31, 28)); +} #define SET_CMC_TBL_MASK_RESP_REF_RATE GENMASK(8, 0) -#define SET_CMC_TBL_RESP_REF_RATE(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 6, val, GENMASK(8, 0)); \ - le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_RESP_REF_RATE, \ - GENMASK(8, 0)); \ -} while (0) +static inline void SET_CMC_TBL_RESP_REF_RATE(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 6, val, GENMASK(8, 0)); + le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_RESP_REF_RATE, + GENMASK(8, 0)); +} #define SET_CMC_TBL_MASK_ALL_ACK_SUPPORT BIT(0) -#define SET_CMC_TBL_ALL_ACK_SUPPORT(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 6, val, BIT(12)); \ - le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_ALL_ACK_SUPPORT, \ - BIT(12)); \ -} while (0) +static inline void SET_CMC_TBL_ALL_ACK_SUPPORT(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 6, val, BIT(12)); + le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_ALL_ACK_SUPPORT, + BIT(12)); +} #define SET_CMC_TBL_MASK_BSR_QUEUE_SIZE_FORMAT BIT(0) -#define SET_CMC_TBL_BSR_QUEUE_SIZE_FORMAT(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 6, val, BIT(13)); \ - le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_BSR_QUEUE_SIZE_FORMAT, \ - BIT(13)); \ -} while (0) +static inline void SET_CMC_TBL_BSR_QUEUE_SIZE_FORMAT(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 6, val, BIT(13)); + le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_BSR_QUEUE_SIZE_FORMAT, + BIT(13)); +} #define SET_CMC_TBL_MASK_NTX_PATH_EN GENMASK(3, 0) -#define SET_CMC_TBL_NTX_PATH_EN(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 6, val, GENMASK(19, 16)); \ - le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_NTX_PATH_EN, \ - GENMASK(19, 16)); \ -} while (0) +static inline void SET_CMC_TBL_NTX_PATH_EN(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 6, val, GENMASK(19, 16)); + le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_NTX_PATH_EN, + GENMASK(19, 16)); +} #define SET_CMC_TBL_MASK_PATH_MAP_A GENMASK(1, 0) -#define SET_CMC_TBL_PATH_MAP_A(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 6, val, GENMASK(21, 20)); \ - le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_PATH_MAP_A, \ - GENMASK(21, 20)); \ -} while (0) +static inline void SET_CMC_TBL_PATH_MAP_A(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 6, val, GENMASK(21, 20)); + le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_PATH_MAP_A, + GENMASK(21, 20)); +} #define SET_CMC_TBL_MASK_PATH_MAP_B GENMASK(1, 0) -#define SET_CMC_TBL_PATH_MAP_B(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 6, val, GENMASK(23, 22)); \ - le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_PATH_MAP_B, \ - GENMASK(23, 22)); \ -} while (0) +static inline void SET_CMC_TBL_PATH_MAP_B(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 6, val, GENMASK(23, 22)); + le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_PATH_MAP_B, + GENMASK(23, 22)); +} #define SET_CMC_TBL_MASK_PATH_MAP_C GENMASK(1, 0) -#define SET_CMC_TBL_PATH_MAP_C(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 6, val, GENMASK(25, 24)); \ - le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_PATH_MAP_C, \ - GENMASK(25, 24)); \ -} while (0) +static inline void SET_CMC_TBL_PATH_MAP_C(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 6, val, GENMASK(25, 24)); + le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_PATH_MAP_C, + GENMASK(25, 24)); +} #define SET_CMC_TBL_MASK_PATH_MAP_D GENMASK(1, 0) -#define SET_CMC_TBL_PATH_MAP_D(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 6, val, GENMASK(27, 26)); \ - le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_PATH_MAP_D, \ - GENMASK(27, 26)); \ -} while (0) +static inline void SET_CMC_TBL_PATH_MAP_D(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 6, val, GENMASK(27, 26)); + le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_PATH_MAP_D, + GENMASK(27, 26)); +} #define SET_CMC_TBL_MASK_ANTSEL_A BIT(0) -#define SET_CMC_TBL_ANTSEL_A(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 6, val, BIT(28)); \ - le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_ANTSEL_A, \ - BIT(28)); \ -} while (0) +static inline void SET_CMC_TBL_ANTSEL_A(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 6, val, BIT(28)); + le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_ANTSEL_A, + BIT(28)); +} #define SET_CMC_TBL_MASK_ANTSEL_B BIT(0) -#define SET_CMC_TBL_ANTSEL_B(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 6, val, BIT(29)); \ - le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_ANTSEL_B, \ - BIT(29)); \ -} while (0) +static inline void SET_CMC_TBL_ANTSEL_B(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 6, val, BIT(29)); + le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_ANTSEL_B, + BIT(29)); +} #define SET_CMC_TBL_MASK_ANTSEL_C BIT(0) -#define SET_CMC_TBL_ANTSEL_C(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 6, val, BIT(30)); \ - le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_ANTSEL_C, \ - BIT(30)); \ -} while (0) +static inline void SET_CMC_TBL_ANTSEL_C(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 6, val, BIT(30)); + le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_ANTSEL_C, + BIT(30)); +} #define SET_CMC_TBL_MASK_ANTSEL_D BIT(0) -#define SET_CMC_TBL_ANTSEL_D(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 6, val, BIT(31)); \ - le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_ANTSEL_D, \ - BIT(31)); \ -} while (0) +static inline void SET_CMC_TBL_ANTSEL_D(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 6, val, BIT(31)); + le32p_replace_bits((__le32 *)(table) + 14, SET_CMC_TBL_MASK_ANTSEL_D, + BIT(31)); +} #define SET_CMC_TBL_MASK_ADDR_CAM_INDEX GENMASK(7, 0) -#define SET_CMC_TBL_ADDR_CAM_INDEX(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 7, val, GENMASK(7, 0)); \ - le32p_replace_bits((__le32 *)(table) + 15, SET_CMC_TBL_MASK_ADDR_CAM_INDEX, \ - GENMASK(7, 0)); \ -} while (0) +static inline void SET_CMC_TBL_ADDR_CAM_INDEX(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 7, val, GENMASK(7, 0)); + le32p_replace_bits((__le32 *)(table) + 15, SET_CMC_TBL_MASK_ADDR_CAM_INDEX, + GENMASK(7, 0)); +} #define SET_CMC_TBL_MASK_PAID GENMASK(8, 0) -#define SET_CMC_TBL_PAID(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 7, val, GENMASK(16, 8)); \ - le32p_replace_bits((__le32 *)(table) + 15, SET_CMC_TBL_MASK_PAID, \ - GENMASK(16, 8)); \ -} while (0) +static inline void SET_CMC_TBL_PAID(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 7, val, GENMASK(16, 8)); + le32p_replace_bits((__le32 *)(table) + 15, SET_CMC_TBL_MASK_PAID, + GENMASK(16, 8)); +} #define SET_CMC_TBL_MASK_ULDL BIT(0) -#define SET_CMC_TBL_ULDL(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 7, val, BIT(17)); \ - le32p_replace_bits((__le32 *)(table) + 15, SET_CMC_TBL_MASK_ULDL, \ - BIT(17)); \ -} while (0) +static inline void SET_CMC_TBL_ULDL(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 7, val, BIT(17)); + le32p_replace_bits((__le32 *)(table) + 15, SET_CMC_TBL_MASK_ULDL, + BIT(17)); +} #define SET_CMC_TBL_MASK_DOPPLER_CTRL GENMASK(1, 0) -#define SET_CMC_TBL_DOPPLER_CTRL(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 7, val, GENMASK(19, 18)); \ - le32p_replace_bits((__le32 *)(table) + 15, SET_CMC_TBL_MASK_DOPPLER_CTRL, \ - GENMASK(19, 18)); \ -} while (0) +static inline void SET_CMC_TBL_DOPPLER_CTRL(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 7, val, GENMASK(19, 18)); + le32p_replace_bits((__le32 *)(table) + 15, SET_CMC_TBL_MASK_DOPPLER_CTRL, + GENMASK(19, 18)); +} #define SET_CMC_TBL_MASK_NOMINAL_PKT_PADDING GENMASK(1, 0) -#define SET_CMC_TBL_NOMINAL_PKT_PADDING(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 7, val, GENMASK(21, 20)); \ - le32p_replace_bits((__le32 *)(table) + 15, SET_CMC_TBL_MASK_NOMINAL_PKT_PADDING, \ - GENMASK(21, 20)); \ -} while (0) -#define SET_CMC_TBL_NOMINAL_PKT_PADDING40(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 7, val, GENMASK(23, 22)); \ - le32p_replace_bits((__le32 *)(table) + 15, SET_CMC_TBL_MASK_NOMINAL_PKT_PADDING, \ - GENMASK(23, 22)); \ -} while (0) +static inline void SET_CMC_TBL_NOMINAL_PKT_PADDING(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 7, val, GENMASK(21, 20)); + le32p_replace_bits((__le32 *)(table) + 15, SET_CMC_TBL_MASK_NOMINAL_PKT_PADDING, + GENMASK(21, 20)); +} + +static inline void SET_CMC_TBL_NOMINAL_PKT_PADDING40(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 7, val, GENMASK(23, 22)); + le32p_replace_bits((__le32 *)(table) + 15, SET_CMC_TBL_MASK_NOMINAL_PKT_PADDING, + GENMASK(23, 22)); +} #define SET_CMC_TBL_MASK_TXPWR_TOLERENCE GENMASK(3, 0) -#define SET_CMC_TBL_TXPWR_TOLERENCE(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 7, val, GENMASK(27, 24)); \ - le32p_replace_bits((__le32 *)(table) + 15, SET_CMC_TBL_MASK_TXPWR_TOLERENCE, \ - GENMASK(27, 24)); \ -} while (0) -#define SET_CMC_TBL_NOMINAL_PKT_PADDING80(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 7, val, GENMASK(31, 30)); \ - le32p_replace_bits((__le32 *)(table) + 15, SET_CMC_TBL_MASK_NOMINAL_PKT_PADDING, \ - GENMASK(31, 30)); \ -} while (0) +static inline void SET_CMC_TBL_TXPWR_TOLERENCE(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 7, val, GENMASK(27, 24)); + le32p_replace_bits((__le32 *)(table) + 15, SET_CMC_TBL_MASK_TXPWR_TOLERENCE, + GENMASK(27, 24)); +} + +static inline void SET_CMC_TBL_NOMINAL_PKT_PADDING80(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 7, val, GENMASK(31, 30)); + le32p_replace_bits((__le32 *)(table) + 15, SET_CMC_TBL_MASK_NOMINAL_PKT_PADDING, + GENMASK(31, 30)); +} #define SET_CMC_TBL_MASK_NC GENMASK(2, 0) -#define SET_CMC_TBL_NC(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 8, val, GENMASK(2, 0)); \ - le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_NC, \ - GENMASK(2, 0)); \ -} while (0) +static inline void SET_CMC_TBL_NC(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 8, val, GENMASK(2, 0)); + le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_NC, + GENMASK(2, 0)); +} #define SET_CMC_TBL_MASK_NR GENMASK(2, 0) -#define SET_CMC_TBL_NR(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 8, val, GENMASK(5, 3)); \ - le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_NR, \ - GENMASK(5, 3)); \ -} while (0) +static inline void SET_CMC_TBL_NR(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 8, val, GENMASK(5, 3)); + le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_NR, + GENMASK(5, 3)); +} #define SET_CMC_TBL_MASK_NG GENMASK(1, 0) -#define SET_CMC_TBL_NG(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 8, val, GENMASK(7, 6)); \ - le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_NG, \ - GENMASK(7, 6)); \ -} while (0) +static inline void SET_CMC_TBL_NG(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 8, val, GENMASK(7, 6)); + le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_NG, + GENMASK(7, 6)); +} #define SET_CMC_TBL_MASK_CB GENMASK(1, 0) -#define SET_CMC_TBL_CB(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 8, val, GENMASK(9, 8)); \ - le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_CB, \ - GENMASK(9, 8)); \ -} while (0) +static inline void SET_CMC_TBL_CB(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 8, val, GENMASK(9, 8)); + le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_CB, + GENMASK(9, 8)); +} #define SET_CMC_TBL_MASK_CS GENMASK(1, 0) -#define SET_CMC_TBL_CS(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 8, val, GENMASK(11, 10)); \ - le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_CS, \ - GENMASK(11, 10)); \ -} while (0) +static inline void SET_CMC_TBL_CS(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 8, val, GENMASK(11, 10)); + le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_CS, + GENMASK(11, 10)); +} #define SET_CMC_TBL_MASK_CSI_TXBF_EN BIT(0) -#define SET_CMC_TBL_CSI_TXBF_EN(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 8, val, BIT(12)); \ - le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_CSI_TXBF_EN, \ - BIT(12)); \ -} while (0) +static inline void SET_CMC_TBL_CSI_TXBF_EN(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 8, val, BIT(12)); + le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_CSI_TXBF_EN, + BIT(12)); +} #define SET_CMC_TBL_MASK_CSI_STBC_EN BIT(0) -#define SET_CMC_TBL_CSI_STBC_EN(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 8, val, BIT(13)); \ - le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_CSI_STBC_EN, \ - BIT(13)); \ -} while (0) +static inline void SET_CMC_TBL_CSI_STBC_EN(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 8, val, BIT(13)); + le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_CSI_STBC_EN, + BIT(13)); +} #define SET_CMC_TBL_MASK_CSI_LDPC_EN BIT(0) -#define SET_CMC_TBL_CSI_LDPC_EN(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 8, val, BIT(14)); \ - le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_CSI_LDPC_EN, \ - BIT(14)); \ -} while (0) +static inline void SET_CMC_TBL_CSI_LDPC_EN(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 8, val, BIT(14)); + le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_CSI_LDPC_EN, + BIT(14)); +} #define SET_CMC_TBL_MASK_CSI_PARA_EN BIT(0) -#define SET_CMC_TBL_CSI_PARA_EN(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 8, val, BIT(15)); \ - le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_CSI_PARA_EN, \ - BIT(15)); \ -} while (0) +static inline void SET_CMC_TBL_CSI_PARA_EN(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 8, val, BIT(15)); + le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_CSI_PARA_EN, + BIT(15)); +} #define SET_CMC_TBL_MASK_CSI_FIX_RATE GENMASK(8, 0) -#define SET_CMC_TBL_CSI_FIX_RATE(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 8, val, GENMASK(24, 16)); \ - le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_CSI_FIX_RATE, \ - GENMASK(24, 16)); \ -} while (0) +static inline void SET_CMC_TBL_CSI_FIX_RATE(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 8, val, GENMASK(24, 16)); + le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_CSI_FIX_RATE, + GENMASK(24, 16)); +} #define SET_CMC_TBL_MASK_CSI_GI_LTF GENMASK(2, 0) -#define SET_CMC_TBL_CSI_GI_LTF(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 8, val, GENMASK(27, 25)); \ - le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_CSI_GI_LTF, \ - GENMASK(27, 25)); \ -} while (0) +static inline void SET_CMC_TBL_CSI_GI_LTF(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 8, val, GENMASK(27, 25)); + le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_CSI_GI_LTF, + GENMASK(27, 25)); +} #define SET_CMC_TBL_MASK_CSI_GID_SEL BIT(0) -#define SET_CMC_TBL_CSI_GID_SEL(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 8, val, BIT(29)); \ - le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_CSI_GID_SEL, \ - BIT(29)); \ -} while (0) +static inline void SET_CMC_TBL_CSI_GID_SEL(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 8, val, BIT(29)); + le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_CSI_GID_SEL, + BIT(29)); +} #define SET_CMC_TBL_MASK_CSI_BW GENMASK(1, 0) -#define SET_CMC_TBL_CSI_BW(table, val) \ -do { \ - le32p_replace_bits((__le32 *)(table) + 8, val, GENMASK(31, 30)); \ - le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_CSI_BW, \ - GENMASK(31, 30)); \ -} while (0) - -#define SET_FWROLE_MAINTAIN_MACID(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)) -#define SET_FWROLE_MAINTAIN_SELF_ROLE(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(9, 8)) -#define SET_FWROLE_MAINTAIN_UPD_MODE(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(12, 10)) -#define SET_FWROLE_MAINTAIN_WIFI_ROLE(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(16, 13)) - -#define SET_JOININFO_MACID(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)) -#define SET_JOININFO_OP(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, BIT(8)) -#define SET_JOININFO_BAND(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, BIT(9)) -#define SET_JOININFO_WMM(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(11, 10)) -#define SET_JOININFO_TGR(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, BIT(12)) -#define SET_JOININFO_ISHESTA(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, BIT(13)) -#define SET_JOININFO_DLBW(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 14)) -#define SET_JOININFO_TF_MAC_PAD(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(17, 16)) -#define SET_JOININFO_DL_T_PE(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(20, 18)) -#define SET_JOININFO_PORT_ID(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(23, 21)) -#define SET_JOININFO_NET_TYPE(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(25, 24)) -#define SET_JOININFO_WIFI_ROLE(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(29, 26)) -#define SET_JOININFO_SELF_ROLE(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 30)) - -#define SET_GENERAL_PKT_MACID(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)) -#define SET_GENERAL_PKT_PROBRSP_ID(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 8)) -#define SET_GENERAL_PKT_PSPOLL_ID(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(23, 16)) -#define SET_GENERAL_PKT_NULL_ID(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 24)) -#define SET_GENERAL_PKT_QOS_NULL_ID(h2c, val) \ - le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(7, 0)) -#define SET_GENERAL_PKT_CTS2SELF_ID(h2c, val) \ - le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(15, 8)) - -#define SET_LOG_CFG_LEVEL(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)) -#define SET_LOG_CFG_PATH(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 8)) -#define SET_LOG_CFG_COMP(h2c, val) \ - le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(31, 0)) -#define SET_LOG_CFG_COMP_EXT(h2c, val) \ - le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(31, 0)) - -#define SET_BA_CAM_VALID(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, BIT(0)) -#define SET_BA_CAM_INIT_REQ(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, BIT(1)) -#define SET_BA_CAM_ENTRY_IDX(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(3, 2)) -#define SET_BA_CAM_TID(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 4)) -#define SET_BA_CAM_MACID(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 8)) -#define SET_BA_CAM_BMAP_SIZE(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(19, 16)) -#define SET_BA_CAM_SSN(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 20)) - -#define SET_LPS_PARM_MACID(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)) -#define SET_LPS_PARM_PSMODE(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 8)) -#define SET_LPS_PARM_RLBM(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(19, 16)) -#define SET_LPS_PARM_SMARTPS(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(23, 20)) -#define SET_LPS_PARM_AWAKEINTERVAL(h2c, val) \ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 24)) -#define SET_LPS_PARM_VOUAPSD(h2c, val) \ - le32p_replace_bits((__le32 *)(h2c) + 1, val, BIT(0)) -#define SET_LPS_PARM_VIUAPSD(h2c, val) \ - le32p_replace_bits((__le32 *)(h2c) + 1, val, BIT(1)) -#define SET_LPS_PARM_BEUAPSD(h2c, val) \ - le32p_replace_bits((__le32 *)(h2c) + 1, val, BIT(2)) -#define SET_LPS_PARM_BKUAPSD(h2c, val) \ - le32p_replace_bits((__le32 *)(h2c) + 1, val, BIT(3)) -#define SET_LPS_PARM_LASTRPWM(h2c, val) \ - le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(15, 8)) +static inline void SET_CMC_TBL_CSI_BW(void *table, u32 val) +{ + le32p_replace_bits((__le32 *)(table) + 8, val, GENMASK(31, 30)); + le32p_replace_bits((__le32 *)(table) + 16, SET_CMC_TBL_MASK_CSI_BW, + GENMASK(31, 30)); +} + +static inline void SET_FWROLE_MAINTAIN_MACID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)); +} + +static inline void SET_FWROLE_MAINTAIN_SELF_ROLE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(9, 8)); +} + +static inline void SET_FWROLE_MAINTAIN_UPD_MODE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(12, 10)); +} + +static inline void SET_FWROLE_MAINTAIN_WIFI_ROLE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(16, 13)); +} + +static inline void SET_JOININFO_MACID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)); +} + +static inline void SET_JOININFO_OP(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(8)); +} + +static inline void SET_JOININFO_BAND(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(9)); +} + +static inline void SET_JOININFO_WMM(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(11, 10)); +} + +static inline void SET_JOININFO_TGR(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(12)); +} + +static inline void SET_JOININFO_ISHESTA(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(13)); +} + +static inline void SET_JOININFO_DLBW(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 14)); +} + +static inline void SET_JOININFO_TF_MAC_PAD(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(17, 16)); +} + +static inline void SET_JOININFO_DL_T_PE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(20, 18)); +} + +static inline void SET_JOININFO_PORT_ID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(23, 21)); +} + +static inline void SET_JOININFO_NET_TYPE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(25, 24)); +} + +static inline void SET_JOININFO_WIFI_ROLE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(29, 26)); +} + +static inline void SET_JOININFO_SELF_ROLE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 30)); +} + +static inline void SET_GENERAL_PKT_MACID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)); +} + +static inline void SET_GENERAL_PKT_PROBRSP_ID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 8)); +} + +static inline void SET_GENERAL_PKT_PSPOLL_ID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(23, 16)); +} + +static inline void SET_GENERAL_PKT_NULL_ID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 24)); +} + +static inline void SET_GENERAL_PKT_QOS_NULL_ID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(7, 0)); +} + +static inline void SET_GENERAL_PKT_CTS2SELF_ID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(15, 8)); +} + +static inline void SET_LOG_CFG_LEVEL(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)); +} + +static inline void SET_LOG_CFG_PATH(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 8)); +} + +static inline void SET_LOG_CFG_COMP(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(31, 0)); +} + +static inline void SET_LOG_CFG_COMP_EXT(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(31, 0)); +} + +static inline void SET_BA_CAM_VALID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(0)); +} + +static inline void SET_BA_CAM_INIT_REQ(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, BIT(1)); +} + +static inline void SET_BA_CAM_ENTRY_IDX(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(3, 2)); +} + +static inline void SET_BA_CAM_TID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 4)); +} + +static inline void SET_BA_CAM_MACID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 8)); +} + +static inline void SET_BA_CAM_BMAP_SIZE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(19, 16)); +} + +static inline void SET_BA_CAM_SSN(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 20)); +} + +static inline void SET_LPS_PARM_MACID(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)); +} + +static inline void SET_LPS_PARM_PSMODE(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 8)); +} + +static inline void SET_LPS_PARM_RLBM(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(19, 16)); +} + +static inline void SET_LPS_PARM_SMARTPS(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(23, 20)); +} + +static inline void SET_LPS_PARM_AWAKEINTERVAL(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 24)); +} + +static inline void SET_LPS_PARM_VOUAPSD(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 1, val, BIT(0)); +} + +static inline void SET_LPS_PARM_VIUAPSD(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 1, val, BIT(1)); +} + +static inline void SET_LPS_PARM_BEUAPSD(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 1, val, BIT(2)); +} + +static inline void SET_LPS_PARM_BKUAPSD(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 1, val, BIT(3)); +} + +static inline void SET_LPS_PARM_LASTRPWM(void *h2c, u32 val) +{ + le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(15, 8)); +} enum rtw89_btc_btf_h2c_class { BTFC_SET = 0x10, @@ -1052,165 +1316,322 @@ enum rtw89_btc_cxdrvinfo { CXDRVINFO_MAX, }; -#define RTW89_SET_FWCMD_CXHDR_TYPE(cmd, val) \ - u8p_replace_bits((u8 *)(cmd) + 0, val, GENMASK(7, 0)) -#define RTW89_SET_FWCMD_CXHDR_LEN(cmd, val) \ - u8p_replace_bits((u8 *)(cmd) + 1, val, GENMASK(7, 0)) - -#define RTW89_SET_FWCMD_CXINIT_ANT_TYPE(cmd, val) \ - u8p_replace_bits((u8 *)(cmd) + 2, val, GENMASK(7, 0)) -#define RTW89_SET_FWCMD_CXINIT_ANT_NUM(cmd, val) \ - u8p_replace_bits((u8 *)(cmd) + 3, val, GENMASK(7, 0)) -#define RTW89_SET_FWCMD_CXINIT_ANT_ISO(cmd, val) \ - u8p_replace_bits((u8 *)(cmd) + 4, val, GENMASK(7, 0)) -#define RTW89_SET_FWCMD_CXINIT_ANT_POS(cmd, val) \ - u8p_replace_bits((u8 *)(cmd) + 5, val, BIT(0)) -#define RTW89_SET_FWCMD_CXINIT_ANT_DIVERSITY(cmd, val) \ - u8p_replace_bits((u8 *)(cmd) + 5, val, BIT(1)) -#define RTW89_SET_FWCMD_CXINIT_MOD_RFE(cmd, val) \ - u8p_replace_bits((u8 *)(cmd) + 6, val, GENMASK(7, 0)) -#define RTW89_SET_FWCMD_CXINIT_MOD_CV(cmd, val) \ - u8p_replace_bits((u8 *)(cmd) + 7, val, GENMASK(7, 0)) -#define RTW89_SET_FWCMD_CXINIT_MOD_BT_SOLO(cmd, val) \ - u8p_replace_bits((u8 *)(cmd) + 8, val, BIT(0)) -#define RTW89_SET_FWCMD_CXINIT_MOD_BT_POS(cmd, val) \ - u8p_replace_bits((u8 *)(cmd) + 8, val, BIT(1)) -#define RTW89_SET_FWCMD_CXINIT_MOD_SW_TYPE(cmd, val) \ - u8p_replace_bits((u8 *)(cmd) + 8, val, BIT(2)) -#define RTW89_SET_FWCMD_CXINIT_WL_GCH(cmd, val) \ - u8p_replace_bits((u8 *)(cmd) + 10, val, GENMASK(7, 0)) -#define RTW89_SET_FWCMD_CXINIT_WL_ONLY(cmd, val) \ - u8p_replace_bits((u8 *)(cmd) + 11, val, BIT(0)) -#define RTW89_SET_FWCMD_CXINIT_WL_INITOK(cmd, val) \ - u8p_replace_bits((u8 *)(cmd) + 11, val, BIT(1)) -#define RTW89_SET_FWCMD_CXINIT_DBCC_EN(cmd, val) \ - u8p_replace_bits((u8 *)(cmd) + 11, val, BIT(2)) -#define RTW89_SET_FWCMD_CXINIT_CX_OTHER(cmd, val) \ - u8p_replace_bits((u8 *)(cmd) + 11, val, BIT(3)) -#define RTW89_SET_FWCMD_CXINIT_BT_ONLY(cmd, val) \ - u8p_replace_bits((u8 *)(cmd) + 11, val, BIT(4)) - -#define RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(cmd, val) \ - u8p_replace_bits((u8 *)(cmd) + 2, val, GENMASK(7, 0)) -#define RTW89_SET_FWCMD_CXROLE_LINK_MODE(cmd, val) \ - u8p_replace_bits((u8 *)(cmd) + 3, val, GENMASK(7, 0)) -#define RTW89_SET_FWCMD_CXROLE_ROLE_NONE(cmd, val) \ - le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(0)) -#define RTW89_SET_FWCMD_CXROLE_ROLE_STA(cmd, val) \ - le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(1)) -#define RTW89_SET_FWCMD_CXROLE_ROLE_AP(cmd, val) \ - le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(2)) -#define RTW89_SET_FWCMD_CXROLE_ROLE_VAP(cmd, val) \ - le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(3)) -#define RTW89_SET_FWCMD_CXROLE_ROLE_ADHOC(cmd, val) \ - le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(4)) -#define RTW89_SET_FWCMD_CXROLE_ROLE_ADHOC_MASTER(cmd, val) \ - le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(5)) -#define RTW89_SET_FWCMD_CXROLE_ROLE_MESH(cmd, val) \ - le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(6)) -#define RTW89_SET_FWCMD_CXROLE_ROLE_MONITOR(cmd, val) \ - le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(7)) -#define RTW89_SET_FWCMD_CXROLE_ROLE_P2P_DEV(cmd, val) \ - le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(8)) -#define RTW89_SET_FWCMD_CXROLE_ROLE_P2P_GC(cmd, val) \ - le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(9)) -#define RTW89_SET_FWCMD_CXROLE_ROLE_P2P_GO(cmd, val) \ - le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(10)) -#define RTW89_SET_FWCMD_CXROLE_ROLE_NAN(cmd, val) \ - le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(11)) -#define RTW89_SET_FWCMD_CXROLE_ACT_CONNECTED(cmd, val, n) \ - u8p_replace_bits((u8 *)(cmd) + (6 + 12 * (n)), val, BIT(0)) -#define RTW89_SET_FWCMD_CXROLE_ACT_PID(cmd, val, n) \ - u8p_replace_bits((u8 *)(cmd) + (6 + 12 * (n)), val, GENMASK(3, 1)) -#define RTW89_SET_FWCMD_CXROLE_ACT_PHY(cmd, val, n) \ - u8p_replace_bits((u8 *)(cmd) + (6 + 12 * (n)), val, BIT(4)) -#define RTW89_SET_FWCMD_CXROLE_ACT_NOA(cmd, val, n) \ - u8p_replace_bits((u8 *)(cmd) + (6 + 12 * (n)), val, BIT(5)) -#define RTW89_SET_FWCMD_CXROLE_ACT_BAND(cmd, val, n) \ - u8p_replace_bits((u8 *)(cmd) + (6 + 12 * (n)), val, GENMASK(7, 6)) -#define RTW89_SET_FWCMD_CXROLE_ACT_CLIENT_PS(cmd, val, n) \ - u8p_replace_bits((u8 *)(cmd) + (7 + 12 * (n)), val, BIT(0)) -#define RTW89_SET_FWCMD_CXROLE_ACT_BW(cmd, val, n) \ - u8p_replace_bits((u8 *)(cmd) + (7 + 12 * (n)), val, GENMASK(7, 1)) -#define RTW89_SET_FWCMD_CXROLE_ACT_ROLE(cmd, val, n) \ - u8p_replace_bits((u8 *)(cmd) + (8 + 12 * (n)), val, GENMASK(7, 0)) -#define RTW89_SET_FWCMD_CXROLE_ACT_CH(cmd, val, n) \ - u8p_replace_bits((u8 *)(cmd) + (9 + 12 * (n)), val, GENMASK(7, 0)) -#define RTW89_SET_FWCMD_CXROLE_ACT_TX_LVL(cmd, val, n) \ - le16p_replace_bits((__le16 *)((u8 *)(cmd) + (10 + 12 * (n))), val, GENMASK(15, 0)) -#define RTW89_SET_FWCMD_CXROLE_ACT_RX_LVL(cmd, val, n) \ - le16p_replace_bits((__le16 *)((u8 *)(cmd) + (12 + 12 * (n))), val, GENMASK(15, 0)) -#define RTW89_SET_FWCMD_CXROLE_ACT_TX_RATE(cmd, val, n) \ - le16p_replace_bits((__le16 *)((u8 *)(cmd) + (14 + 12 * (n))), val, GENMASK(15, 0)) -#define RTW89_SET_FWCMD_CXROLE_ACT_RX_RATE(cmd, val, n) \ - le16p_replace_bits((__le16 *)((u8 *)(cmd) + (16 + 12 * (n))), val, GENMASK(15, 0)) - -#define RTW89_SET_FWCMD_CXCTRL_MANUAL(cmd, val) \ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 2), val, BIT(0)) -#define RTW89_SET_FWCMD_CXCTRL_IGNORE_BT(cmd, val) \ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 2), val, BIT(1)) -#define RTW89_SET_FWCMD_CXCTRL_ALWAYS_FREERUN(cmd, val) \ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 2), val, BIT(2)) -#define RTW89_SET_FWCMD_CXCTRL_TRACE_STEP(cmd, val) \ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 2), val, GENMASK(18, 3)) - -#define RTW89_SET_FWCMD_CXRFK_STATE(cmd, val) \ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 2), val, GENMASK(1, 0)) -#define RTW89_SET_FWCMD_CXRFK_PATH_MAP(cmd, val) \ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 2), val, GENMASK(5, 2)) -#define RTW89_SET_FWCMD_CXRFK_PHY_MAP(cmd, val) \ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 2), val, GENMASK(7, 6)) -#define RTW89_SET_FWCMD_CXRFK_BAND(cmd, val) \ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 2), val, GENMASK(9, 8)) -#define RTW89_SET_FWCMD_CXRFK_TYPE(cmd, val) \ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 2), val, GENMASK(17, 10)) +static inline void RTW89_SET_FWCMD_CXHDR_TYPE(void *cmd, u8 val) +{ + u8p_replace_bits((u8 *)(cmd) + 0, val, GENMASK(7, 0)); +} + +static inline void RTW89_SET_FWCMD_CXHDR_LEN(void *cmd, u8 val) +{ + u8p_replace_bits((u8 *)(cmd) + 1, val, GENMASK(7, 0)); +} + +static inline void RTW89_SET_FWCMD_CXINIT_ANT_TYPE(void *cmd, u8 val) +{ + u8p_replace_bits((u8 *)(cmd) + 2, val, GENMASK(7, 0)); +} + +static inline void RTW89_SET_FWCMD_CXINIT_ANT_NUM(void *cmd, u8 val) +{ + u8p_replace_bits((u8 *)(cmd) + 3, val, GENMASK(7, 0)); +} + +static inline void RTW89_SET_FWCMD_CXINIT_ANT_ISO(void *cmd, u8 val) +{ + u8p_replace_bits((u8 *)(cmd) + 4, val, GENMASK(7, 0)); +} + +static inline void RTW89_SET_FWCMD_CXINIT_ANT_POS(void *cmd, u8 val) +{ + u8p_replace_bits((u8 *)(cmd) + 5, val, BIT(0)); +} + +static inline void RTW89_SET_FWCMD_CXINIT_ANT_DIVERSITY(void *cmd, u8 val) +{ + u8p_replace_bits((u8 *)(cmd) + 5, val, BIT(1)); +} + +static inline void RTW89_SET_FWCMD_CXINIT_MOD_RFE(void *cmd, u8 val) +{ + u8p_replace_bits((u8 *)(cmd) + 6, val, GENMASK(7, 0)); +} + +static inline void RTW89_SET_FWCMD_CXINIT_MOD_CV(void *cmd, u8 val) +{ + u8p_replace_bits((u8 *)(cmd) + 7, val, GENMASK(7, 0)); +} + +static inline void RTW89_SET_FWCMD_CXINIT_MOD_BT_SOLO(void *cmd, u8 val) +{ + u8p_replace_bits((u8 *)(cmd) + 8, val, BIT(0)); +} + +static inline void RTW89_SET_FWCMD_CXINIT_MOD_BT_POS(void *cmd, u8 val) +{ + u8p_replace_bits((u8 *)(cmd) + 8, val, BIT(1)); +} + +static inline void RTW89_SET_FWCMD_CXINIT_MOD_SW_TYPE(void *cmd, u8 val) +{ + u8p_replace_bits((u8 *)(cmd) + 8, val, BIT(2)); +} + +static inline void RTW89_SET_FWCMD_CXINIT_WL_GCH(void *cmd, u8 val) +{ + u8p_replace_bits((u8 *)(cmd) + 10, val, GENMASK(7, 0)); +} + +static inline void RTW89_SET_FWCMD_CXINIT_WL_ONLY(void *cmd, u8 val) +{ + u8p_replace_bits((u8 *)(cmd) + 11, val, BIT(0)); +} + +static inline void RTW89_SET_FWCMD_CXINIT_WL_INITOK(void *cmd, u8 val) +{ + u8p_replace_bits((u8 *)(cmd) + 11, val, BIT(1)); +} + +static inline void RTW89_SET_FWCMD_CXINIT_DBCC_EN(void *cmd, u8 val) +{ + u8p_replace_bits((u8 *)(cmd) + 11, val, BIT(2)); +} + +static inline void RTW89_SET_FWCMD_CXINIT_CX_OTHER(void *cmd, u8 val) +{ + u8p_replace_bits((u8 *)(cmd) + 11, val, BIT(3)); +} + +static inline void RTW89_SET_FWCMD_CXINIT_BT_ONLY(void *cmd, u8 val) +{ + u8p_replace_bits((u8 *)(cmd) + 11, val, BIT(4)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(void *cmd, u8 val) +{ + u8p_replace_bits((u8 *)(cmd) + 2, val, GENMASK(7, 0)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_LINK_MODE(void *cmd, u8 val) +{ + u8p_replace_bits((u8 *)(cmd) + 3, val, GENMASK(7, 0)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ROLE_NONE(void *cmd, u16 val) +{ + le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(0)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ROLE_STA(void *cmd, u16 val) +{ + le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(1)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ROLE_AP(void *cmd, u16 val) +{ + le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(2)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ROLE_VAP(void *cmd, u16 val) +{ + le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(3)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ROLE_ADHOC(void *cmd, u16 val) +{ + le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(4)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ROLE_ADHOC_MASTER(void *cmd, u16 val) +{ + le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(5)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ROLE_MESH(void *cmd, u16 val) +{ + le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(6)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ROLE_MONITOR(void *cmd, u16 val) +{ + le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(7)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ROLE_P2P_DEV(void *cmd, u16 val) +{ + le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(8)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ROLE_P2P_GC(void *cmd, u16 val) +{ + le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(9)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ROLE_P2P_GO(void *cmd, u16 val) +{ + le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(10)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ROLE_NAN(void *cmd, u16 val) +{ + le16p_replace_bits((__le16 *)((u8 *)(cmd) + 4), val, BIT(11)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ACT_CONNECTED(void *cmd, u8 val, int n) +{ + u8p_replace_bits((u8 *)(cmd) + (6 + 12 * (n)), val, BIT(0)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ACT_PID(void *cmd, u8 val, int n) +{ + u8p_replace_bits((u8 *)(cmd) + (6 + 12 * (n)), val, GENMASK(3, 1)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ACT_PHY(void *cmd, u8 val, int n) +{ + u8p_replace_bits((u8 *)(cmd) + (6 + 12 * (n)), val, BIT(4)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ACT_NOA(void *cmd, u8 val, int n) +{ + u8p_replace_bits((u8 *)(cmd) + (6 + 12 * (n)), val, BIT(5)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ACT_BAND(void *cmd, u8 val, int n) +{ + u8p_replace_bits((u8 *)(cmd) + (6 + 12 * (n)), val, GENMASK(7, 6)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ACT_CLIENT_PS(void *cmd, u8 val, int n) +{ + u8p_replace_bits((u8 *)(cmd) + (7 + 12 * (n)), val, BIT(0)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ACT_BW(void *cmd, u8 val, int n) +{ + u8p_replace_bits((u8 *)(cmd) + (7 + 12 * (n)), val, GENMASK(7, 1)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ACT_ROLE(void *cmd, u8 val, int n) +{ + u8p_replace_bits((u8 *)(cmd) + (8 + 12 * (n)), val, GENMASK(7, 0)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ACT_CH(void *cmd, u8 val, int n) +{ + u8p_replace_bits((u8 *)(cmd) + (9 + 12 * (n)), val, GENMASK(7, 0)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ACT_TX_LVL(void *cmd, u16 val, int n) +{ + le16p_replace_bits((__le16 *)((u8 *)(cmd) + (10 + 12 * (n))), val, GENMASK(15, 0)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ACT_RX_LVL(void *cmd, u16 val, int n) +{ + le16p_replace_bits((__le16 *)((u8 *)(cmd) + (12 + 12 * (n))), val, GENMASK(15, 0)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ACT_TX_RATE(void *cmd, u16 val, int n) +{ + le16p_replace_bits((__le16 *)((u8 *)(cmd) + (14 + 12 * (n))), val, GENMASK(15, 0)); +} + +static inline void RTW89_SET_FWCMD_CXROLE_ACT_RX_RATE(void *cmd, u16 val, int n) +{ + le16p_replace_bits((__le16 *)((u8 *)(cmd) + (16 + 12 * (n))), val, GENMASK(15, 0)); +} + +static inline void RTW89_SET_FWCMD_CXCTRL_MANUAL(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)((u8 *)(cmd) + 2), val, BIT(0)); +} + +static inline void RTW89_SET_FWCMD_CXCTRL_IGNORE_BT(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)((u8 *)(cmd) + 2), val, BIT(1)); +} + +static inline void RTW89_SET_FWCMD_CXCTRL_ALWAYS_FREERUN(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)((u8 *)(cmd) + 2), val, BIT(2)); +} + +static inline void RTW89_SET_FWCMD_CXCTRL_TRACE_STEP(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)((u8 *)(cmd) + 2), val, GENMASK(18, 3)); +} + +static inline void RTW89_SET_FWCMD_CXRFK_STATE(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)((u8 *)(cmd) + 2), val, GENMASK(1, 0)); +} + +static inline void RTW89_SET_FWCMD_CXRFK_PATH_MAP(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)((u8 *)(cmd) + 2), val, GENMASK(5, 2)); +} + +static inline void RTW89_SET_FWCMD_CXRFK_PHY_MAP(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)((u8 *)(cmd) + 2), val, GENMASK(7, 6)); +} + +static inline void RTW89_SET_FWCMD_CXRFK_BAND(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)((u8 *)(cmd) + 2), val, GENMASK(9, 8)); +} + +static inline void RTW89_SET_FWCMD_CXRFK_TYPE(void *cmd, u32 val) +{ + le32p_replace_bits((__le32 *)((u8 *)(cmd) + 2), val, GENMASK(17, 10)); +} #define RTW89_C2H_HEADER_LEN 8 #define RTW89_GET_C2H_CATEGORY(c2h) \ - le32_get_bits(*((__le32 *)c2h), GENMASK(1, 0)) + le32_get_bits(*((const __le32 *)c2h), GENMASK(1, 0)) #define RTW89_GET_C2H_CLASS(c2h) \ - le32_get_bits(*((__le32 *)c2h), GENMASK(7, 2)) + le32_get_bits(*((const __le32 *)c2h), GENMASK(7, 2)) #define RTW89_GET_C2H_FUNC(c2h) \ - le32_get_bits(*((__le32 *)c2h), GENMASK(15, 8)) + le32_get_bits(*((const __le32 *)c2h), GENMASK(15, 8)) #define RTW89_GET_C2H_LEN(c2h) \ - le32_get_bits(*((__le32 *)(c2h) + 1), GENMASK(13, 0)) + le32_get_bits(*((const __le32 *)(c2h) + 1), GENMASK(13, 0)) #define RTW89_GET_C2H_LOG_SRT_PRT(c2h) (char *)((__le32 *)(c2h) + 2) #define RTW89_GET_C2H_LOG_LEN(len) ((len) - RTW89_C2H_HEADER_LEN) #define RTW89_GET_MAC_C2H_DONE_ACK_CAT(c2h) \ - le32_get_bits(*((__le32 *)(c2h) + 2), GENMASK(1, 0)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(1, 0)) #define RTW89_GET_MAC_C2H_DONE_ACK_CLASS(c2h) \ - le32_get_bits(*((__le32 *)(c2h) + 2), GENMASK(7, 2)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(7, 2)) #define RTW89_GET_MAC_C2H_DONE_ACK_FUNC(c2h) \ - le32_get_bits(*((__le32 *)(c2h) + 2), GENMASK(15, 8)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(15, 8)) #define RTW89_GET_MAC_C2H_DONE_ACK_H2C_RETURN(c2h) \ - le32_get_bits(*((__le32 *)(c2h) + 2), GENMASK(23, 16)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(23, 16)) #define RTW89_GET_MAC_C2H_DONE_ACK_H2C_SEQ(c2h) \ - le32_get_bits(*((__le32 *)(c2h) + 2), GENMASK(31, 24)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(31, 24)) #define RTW89_GET_MAC_C2H_REV_ACK_CAT(c2h) \ - le32_get_bits(*((__le32 *)(c2h) + 2), GENMASK(1, 0)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(1, 0)) #define RTW89_GET_MAC_C2H_REV_ACK_CLASS(c2h) \ - le32_get_bits(*((__le32 *)(c2h) + 2), GENMASK(7, 2)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(7, 2)) #define RTW89_GET_MAC_C2H_REV_ACK_FUNC(c2h) \ - le32_get_bits(*((__le32 *)(c2h) + 2), GENMASK(15, 8)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(15, 8)) #define RTW89_GET_MAC_C2H_REV_ACK_H2C_SEQ(c2h) \ - le32_get_bits(*((__le32 *)(c2h) + 2), GENMASK(23, 16)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(23, 16)) #define RTW89_GET_PHY_C2H_RA_RPT_MACID(c2h) \ - le32_get_bits(*((__le32 *)(c2h) + 2), GENMASK(15, 0)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(15, 0)) #define RTW89_GET_PHY_C2H_RA_RPT_RETRY_RATIO(c2h) \ - le32_get_bits(*((__le32 *)(c2h) + 2), GENMASK(23, 16)) + le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(23, 16)) #define RTW89_GET_PHY_C2H_RA_RPT_MCSNSS(c2h) \ - le32_get_bits(*((__le32 *)(c2h) + 3), GENMASK(6, 0)) + le32_get_bits(*((const __le32 *)(c2h) + 3), GENMASK(6, 0)) #define RTW89_GET_PHY_C2H_RA_RPT_MD_SEL(c2h) \ - le32_get_bits(*((__le32 *)(c2h) + 3), GENMASK(9, 8)) + le32_get_bits(*((const __le32 *)(c2h) + 3), GENMASK(9, 8)) #define RTW89_GET_PHY_C2H_RA_RPT_GILTF(c2h) \ - le32_get_bits(*((__le32 *)(c2h) + 3), GENMASK(12, 10)) + le32_get_bits(*((const __le32 *)(c2h) + 3), GENMASK(12, 10)) #define RTW89_GET_PHY_C2H_RA_RPT_BW(c2h) \ - le32_get_bits(*((__le32 *)(c2h) + 3), GENMASK(14, 13)) + le32_get_bits(*((const __le32 *)(c2h) + 3), GENMASK(14, 13)) /* VHT, HE, HT-old: [6:4]: NSS, [3:0]: MCS * HT-new: [6:5]: NA, [4:0]: MCS @@ -1335,7 +1756,8 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta); int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta); -int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); +int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *vif, + struct rtw89_sta *rtwsta, const u8 *scan_mac_addr); void rtw89_fw_c2h_irqsafe(struct rtw89_dev *rtwdev, struct sk_buff *c2h); void rtw89_fw_c2h_work(struct work_struct *work); int rtw89_fw_h2c_vif_maintain(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index afcd07ab1de7..b98c47e9ecfe 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1093,7 +1093,6 @@ static int cmac_func_en(struct rtw89_dev *rtwdev, u8 mac_idx, bool en) static int dmac_func_en(struct rtw89_dev *rtwdev) { u32 val32; - u32 ret = 0; val32 = (B_AX_MAC_FUNC_EN | B_AX_DMAC_FUNC_EN | B_AX_MAC_SEC_EN | B_AX_DISPATCHER_EN | B_AX_DLE_CPUIO_EN | B_AX_PKT_IN_EN | @@ -1107,7 +1106,7 @@ static int dmac_func_en(struct rtw89_dev *rtwdev) B_AX_WD_RLS_CLK_EN); rtw89_write32(rtwdev, R_AX_DMAC_CLK_EN, val32); - return ret; + return 0; } static int chip_func_en(struct rtw89_dev *rtwdev) @@ -2991,7 +2990,7 @@ int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) if (ret) return ret; - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); if (ret) return ret; @@ -3012,7 +3011,7 @@ int rtw89_mac_vif_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) rtw89_cam_deinit(rtwdev, rtwvif); - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); if (ret) return ret; @@ -3451,6 +3450,18 @@ bool rtw89_mac_get_ctrl_path(struct rtw89_dev *rtwdev) return FIELD_GET(B_AX_LTE_MUX_CTRL_PATH >> 24, val); } +u16 rtw89_mac_get_plt_cnt(struct rtw89_dev *rtwdev, u8 band) +{ + u32 reg; + u16 cnt; + + reg = rtw89_mac_reg_by_idx(R_AX_BT_PLT, band); + cnt = rtw89_read32_mask(rtwdev, reg, B_AX_BT_PLT_PKT_CNT_MASK); + rtw89_write16_set(rtwdev, reg, B_AX_BT_PLT_RST); + + return cnt; +} + static void rtw89_mac_bfee_ctrl(struct rtw89_dev *rtwdev, u8 mac_idx, bool en) { u32 reg; @@ -3695,7 +3706,7 @@ void _rtw89_mac_bf_monitor_track(struct rtw89_dev *rtwdev) { struct rtw89_traffic_stats *stats = &rtwdev->stats; struct rtw89_vif *rtwvif; - bool en = stats->tx_tfc_lv > stats->rx_tfc_lv ? false : true; + bool en = stats->tx_tfc_lv <= stats->rx_tfc_lv; bool old = test_bit(RTW89_FLAG_BFEE_EN, rtwdev->flags); if (en == old) diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 6f3db8a2a9c2..b7d13edf7dd1 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -227,6 +227,7 @@ enum rtw89_mac_dbg_port_sel { /* SRAM mem dump */ #define R_AX_INDIR_ACCESS_ENTRY 0x40000 +#define AXIDMA_BASE_ADDR 0x18006000 #define STA_SCHED_BASE_ADDR 0x18808000 #define RXPLD_FLTR_CAM_BASE_ADDR 0x18813000 #define SECURITY_CAM_BASE_ADDR 0x18814000 @@ -240,10 +241,15 @@ enum rtw89_mac_dbg_port_sel { #define DMAC_TBL_BASE_ADDR 0x18800000 #define SHCUT_MACHDR_BASE_ADDR 0x18800800 #define BCN_IE_CAM1_BASE_ADDR 0x188A0000 +#define TXD_FIFO_0_BASE_ADDR 0x18856200 +#define TXD_FIFO_1_BASE_ADDR 0x188A1080 +#define TXDATA_FIFO_0_BASE_ADDR 0x18856000 +#define TXDATA_FIFO_1_BASE_ADDR 0x188A1000 #define CCTL_INFO_SIZE 32 enum rtw89_mac_mem_sel { + RTW89_MAC_MEM_AXIDMA, RTW89_MAC_MEM_SHARED_BUF, RTW89_MAC_MEM_DMAC_TBL, RTW89_MAC_MEM_SHCUT_MACHDR, @@ -256,6 +262,10 @@ enum rtw89_mac_mem_sel { RTW89_MAC_MEM_BA_CAM, RTW89_MAC_MEM_BCN_IE_CAM0, RTW89_MAC_MEM_BCN_IE_CAM1, + RTW89_MAC_MEM_TXD_FIFO_0, + RTW89_MAC_MEM_TXD_FIFO_1, + RTW89_MAC_MEM_TXDATA_FIFO_0, + RTW89_MAC_MEM_TXDATA_FIFO_1, /* keep last */ RTW89_MAC_MEM_LAST, @@ -778,6 +788,7 @@ int rtw89_mac_coex_init(struct rtw89_dev *rtwdev, const struct rtw89_mac_ax_coex int rtw89_mac_cfg_gnt(struct rtw89_dev *rtwdev, const struct rtw89_mac_ax_coex_gnt *gnt_cfg); int rtw89_mac_cfg_plt(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_plt *plt); +u16 rtw89_mac_get_plt_cnt(struct rtw89_dev *rtwdev, u8 band); void rtw89_mac_cfg_sb(struct rtw89_dev *rtwdev, u32 val); u32 rtw89_mac_get_sb(struct rtw89_dev *rtwdev); bool rtw89_mac_get_ctrl_path(struct rtw89_dev *rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 16dc6fb7dbb0..a322259f4cc4 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -27,6 +27,7 @@ static void rtw89_ops_tx(struct ieee80211_hw *hw, if (ret) { rtw89_err(rtwdev, "failed to transmit skb: %d\n", ret); ieee80211_free_txskb(hw, skb); + return; } rtw89_core_tx_kick_off(rtwdev, qsel); } @@ -336,7 +337,7 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BSSID) { ether_addr_copy(rtwvif->bssid, conf->bssid); rtw89_cam_bssid_changed(rtwdev, rtwvif); - rtw89_fw_h2c_cam(rtwdev, rtwvif); + rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); } if (changed & BSS_CHANGED_ERP_SLOT) @@ -615,6 +616,7 @@ static void rtw89_ops_sw_scan_start(struct ieee80211_hw *hw, const u8 *mac_addr) { struct rtw89_dev *rtwdev = hw->priv; + struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; struct rtw89_hal *hal = &rtwdev->hal; mutex_lock(&rtwdev->mutex); @@ -623,6 +625,7 @@ static void rtw89_ops_sw_scan_start(struct ieee80211_hw *hw, rtw89_btc_ntfy_scan_start(rtwdev, RTW89_PHY_0, hal->current_band_type); rtw89_chip_rfk_scan(rtwdev, true); rtw89_hci_recalc_int_mit(rtwdev); + rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, mac_addr); mutex_unlock(&rtwdev->mutex); } @@ -630,8 +633,10 @@ static void rtw89_ops_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rtw89_dev *rtwdev = hw->priv; + struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; mutex_lock(&rtwdev->mutex); + rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); rtw89_chip_rfk_scan(rtwdev, false); rtw89_btc_ntfy_scan_finish(rtwdev, RTW89_PHY_0); rtwdev->scanning = false; diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index ab134856baac..147009888de0 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -654,6 +654,12 @@ rtw89_phy_cofig_rf_reg_store(struct rtw89_dev *rtwdev, u16 idx = info->curr_idx % RTW89_H2C_RF_PAGE_SIZE; u8 page = info->curr_idx / RTW89_H2C_RF_PAGE_SIZE; + if (page >= RTW89_H2C_RF_PAGE_NUM) { + rtw89_warn(rtwdev, "RF parameters exceed size. path=%d, idx=%d", + rf_path, info->curr_idx); + return; + } + info->rtw89_phy_config_rf_h2c[page][idx] = cpu_to_le32((reg->addr << 20) | reg->data); info->curr_idx++; @@ -662,30 +668,29 @@ rtw89_phy_cofig_rf_reg_store(struct rtw89_dev *rtwdev, static int rtw89_phy_config_rf_reg_fw(struct rtw89_dev *rtwdev, struct rtw89_fw_h2c_rf_reg_info *info) { - u16 page = info->curr_idx / RTW89_H2C_RF_PAGE_SIZE; - u16 len = (info->curr_idx % RTW89_H2C_RF_PAGE_SIZE) * 4; + u16 remain = info->curr_idx; + u16 len = 0; u8 i; int ret = 0; - if (page > RTW89_H2C_RF_PAGE_NUM) { + if (remain > RTW89_H2C_RF_PAGE_NUM * RTW89_H2C_RF_PAGE_SIZE) { rtw89_warn(rtwdev, - "rf reg h2c total page num %d larger than %d (RTW89_H2C_RF_PAGE_NUM)\n", - page, RTW89_H2C_RF_PAGE_NUM); - return -EINVAL; + "rf reg h2c total len %d larger than %d\n", + remain, RTW89_H2C_RF_PAGE_NUM * RTW89_H2C_RF_PAGE_SIZE); + ret = -EINVAL; + goto out; } - for (i = 0; i < page; i++) { - ret = rtw89_fw_h2c_rf_reg(rtwdev, info, - RTW89_H2C_RF_PAGE_SIZE * 4, i); + for (i = 0; i < RTW89_H2C_RF_PAGE_NUM && remain; i++, remain -= len) { + len = remain > RTW89_H2C_RF_PAGE_SIZE ? RTW89_H2C_RF_PAGE_SIZE : remain; + ret = rtw89_fw_h2c_rf_reg(rtwdev, info, len * 4, i); if (ret) - return ret; + goto out; } - ret = rtw89_fw_h2c_rf_reg(rtwdev, info, len, i); - if (ret) - return ret; +out: info->curr_idx = 0; - return 0; + return ret; } static void rtw89_phy_config_rf_reg(struct rtw89_dev *rtwdev, @@ -1099,9 +1104,15 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, switch (band) { case RTW89_BAND_2G: lmt = (*chip->txpwr_lmt_2g)[bw][ntx][rs][bf][regd][ch_idx]; + if (!lmt) + lmt = (*chip->txpwr_lmt_2g)[bw][ntx][rs][bf] + [RTW89_WW][ch_idx]; break; case RTW89_BAND_5G: lmt = (*chip->txpwr_lmt_5g)[bw][ntx][rs][bf][regd][ch_idx]; + if (!lmt) + lmt = (*chip->txpwr_lmt_5g)[bw][ntx][rs][bf] + [RTW89_WW][ch_idx]; break; default: rtw89_warn(rtwdev, "unknown band type: %d\n", band); @@ -1224,9 +1235,15 @@ static s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, switch (band) { case RTW89_BAND_2G: lmt_ru = (*chip->txpwr_lmt_ru_2g)[ru][ntx][regd][ch_idx]; + if (!lmt_ru) + lmt_ru = (*chip->txpwr_lmt_ru_2g)[ru][ntx] + [RTW89_WW][ch_idx]; break; case RTW89_BAND_5G: lmt_ru = (*chip->txpwr_lmt_ru_5g)[ru][ntx][regd][ch_idx]; + if (!lmt_ru) + lmt_ru = (*chip->txpwr_lmt_ru_5g)[ru][ntx] + [RTW89_WW][ch_idx]; break; default: rtw89_warn(rtwdev, "unknown band type: %d\n", band); @@ -1767,7 +1784,7 @@ static void rtw89_phy_cfo_dm(struct rtw89_dev *rtwdev) } rtw89_phy_cfo_crystal_cap_adjust(rtwdev, new_cfo); cfo->cfo_avg_pre = new_cfo; - x_cap_update = cfo->crystal_cap == pre_x_cap ? false : true; + x_cap_update = cfo->crystal_cap != pre_x_cap; rtw89_debug(rtwdev, RTW89_DBG_CFO, "Xcap_up=%d\n", x_cap_update); rtw89_debug(rtwdev, RTW89_DBG_CFO, "Xcap: D:%x C:%x->%x, ofst=%d\n", cfo->def_x_cap, pre_x_cap, cfo->crystal_cap, @@ -2404,6 +2421,116 @@ void rtw89_phy_env_monitor_track(struct rtw89_dev *rtwdev) env->ccx_watchdog_result, chk_result); } +static bool rtw89_physts_ie_page_valid(enum rtw89_phy_status_bitmap *ie_page) +{ + if (*ie_page > RTW89_PHYSTS_BITMAP_NUM || + *ie_page == RTW89_RSVD_9) + return false; + else if (*ie_page > RTW89_RSVD_9) + *ie_page -= 1; + + return true; +} + +static u32 rtw89_phy_get_ie_bitmap_addr(enum rtw89_phy_status_bitmap ie_page) +{ + static const u8 ie_page_shift = 2; + + return R_PHY_STS_BITMAP_ADDR_START + (ie_page << ie_page_shift); +} + +static u32 rtw89_physts_get_ie_bitmap(struct rtw89_dev *rtwdev, + enum rtw89_phy_status_bitmap ie_page) +{ + u32 addr; + + if (!rtw89_physts_ie_page_valid(&ie_page)) + return 0; + + addr = rtw89_phy_get_ie_bitmap_addr(ie_page); + + return rtw89_phy_read32(rtwdev, addr); +} + +static void rtw89_physts_set_ie_bitmap(struct rtw89_dev *rtwdev, + enum rtw89_phy_status_bitmap ie_page, + u32 val) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + u32 addr; + + if (!rtw89_physts_ie_page_valid(&ie_page)) + return; + + if (chip->chip_id == RTL8852A) + val &= B_PHY_STS_BITMAP_MSK_52A; + + addr = rtw89_phy_get_ie_bitmap_addr(ie_page); + rtw89_phy_write32(rtwdev, addr, val); +} + +static void rtw89_physts_enable_ie_bitmap(struct rtw89_dev *rtwdev, + enum rtw89_phy_status_bitmap bitmap, + enum rtw89_phy_status_ie_type ie, + bool enable) +{ + u32 val = rtw89_physts_get_ie_bitmap(rtwdev, bitmap); + + if (enable) + val |= BIT(ie); + else + val &= ~BIT(ie); + + rtw89_physts_set_ie_bitmap(rtwdev, bitmap, val); +} + +static void rtw89_physts_enable_fail_report(struct rtw89_dev *rtwdev, + bool enable, + enum rtw89_phy_idx phy_idx) +{ + if (enable) { + rtw89_phy_write32_clr(rtwdev, R_PLCP_HISTOGRAM, + B_STS_DIS_TRIG_BY_FAIL); + rtw89_phy_write32_clr(rtwdev, R_PLCP_HISTOGRAM, + B_STS_DIS_TRIG_BY_BRK); + } else { + rtw89_phy_write32_set(rtwdev, R_PLCP_HISTOGRAM, + B_STS_DIS_TRIG_BY_FAIL); + rtw89_phy_write32_set(rtwdev, R_PLCP_HISTOGRAM, + B_STS_DIS_TRIG_BY_BRK); + } +} + +static void rtw89_physts_parsing_init(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + u8 i; + + if (chip->chip_id == RTL8852A && rtwdev->hal.cv == CHIP_CBV) + rtw89_physts_enable_fail_report(rtwdev, false, RTW89_PHY_0); + + for (i = 0; i < RTW89_PHYSTS_BITMAP_NUM; i++) { + if (i >= RTW89_CCK_PKT) + rtw89_physts_enable_ie_bitmap(rtwdev, i, + RTW89_PHYSTS_IE09_FTR_0, + true); + if ((i >= RTW89_CCK_BRK && i <= RTW89_VHT_MU) || + (i >= RTW89_RSVD_9 && i <= RTW89_CCK_PKT)) + continue; + rtw89_physts_enable_ie_bitmap(rtwdev, i, + RTW89_PHYSTS_IE24_OFDM_TD_PATH_A, + true); + } + rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_VHT_PKT, + RTW89_PHYSTS_IE13_DL_MU_DEF, true); + rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_HE_PKT, + RTW89_PHYSTS_IE13_DL_MU_DEF, true); + + /* force IE01 for channel index, only channel field is valid */ + rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_CCK_PKT, + RTW89_PHYSTS_IE01_CMN_OFDM, true); +} + static void rtw89_phy_dig_read_gain_table(struct rtw89_dev *rtwdev, int type) { const struct rtw89_chip_info *chip = rtwdev->chip; @@ -2839,6 +2966,7 @@ void rtw89_phy_dm_init(struct rtw89_dev *rtwdev) rtw89_chip_bb_sethw(rtwdev); rtw89_phy_env_monitor_init(rtwdev); + rtw89_physts_parsing_init(rtwdev); rtw89_phy_dig_init(rtwdev); rtw89_phy_cfo_init(rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 370129345e0f..b1f059b725a1 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -134,6 +134,66 @@ enum rtw89_ccx_unit { RTW89_CCX_32_US = 3 }; +enum rtw89_phy_status_ie_type { + RTW89_PHYSTS_IE00_CMN_CCK = 0, + RTW89_PHYSTS_IE01_CMN_OFDM = 1, + RTW89_PHYSTS_IE02_CMN_EXT_AX = 2, + RTW89_PHYSTS_IE03_CMN_EXT_SEG_1 = 3, + RTW89_PHYSTS_IE04_CMN_EXT_PATH_A = 4, + RTW89_PHYSTS_IE05_CMN_EXT_PATH_B = 5, + RTW89_PHYSTS_IE06_CMN_EXT_PATH_C = 6, + RTW89_PHYSTS_IE07_CMN_EXT_PATH_D = 7, + RTW89_PHYSTS_IE08_FTR_CH = 8, + RTW89_PHYSTS_IE09_FTR_0 = 9, + RTW89_PHYSTS_IE10_FTR_PLCP_EXT = 10, + RTW89_PHYSTS_IE11_FTR_PLCP_HISTOGRAM = 11, + RTW89_PHYSTS_IE12_MU_EIGEN_INFO = 12, + RTW89_PHYSTS_IE13_DL_MU_DEF = 13, + RTW89_PHYSTS_IE14_TB_UL_CQI = 14, + RTW89_PHYSTS_IE15_TB_UL_DEF = 15, + RTW89_PHYSTS_IE16_RSVD16 = 16, + RTW89_PHYSTS_IE17_TB_UL_CTRL = 17, + RTW89_PHYSTS_IE18_DBG_OFDM_FD_CMN = 18, + RTW89_PHYSTS_IE19_DBG_OFDM_TD_CMN = 19, + RTW89_PHYSTS_IE20_DBG_OFDM_FD_USER_SEG_0 = 20, + RTW89_PHYSTS_IE21_DBG_OFDM_FD_USER_SEG_1 = 21, + RTW89_PHYSTS_IE22_DBG_OFDM_FD_USER_AGC = 22, + RTW89_PHYSTS_IE23_RSVD23 = 23, + RTW89_PHYSTS_IE24_OFDM_TD_PATH_A = 24, + RTW89_PHYSTS_IE25_OFDM_TD_PATH_B = 25, + RTW89_PHYSTS_IE26_OFDM_TD_PATH_C = 26, + RTW89_PHYSTS_IE27_OFDM_TD_PATH_D = 27, + RTW89_PHYSTS_IE28_DBG_CCK_PATH_A = 28, + RTW89_PHYSTS_IE29_DBG_CCK_PATH_B = 29, + RTW89_PHYSTS_IE30_DBG_CCK_PATH_C = 30, + RTW89_PHYSTS_IE31_DBG_CCK_PATH_D = 31, + + /* keep last */ + RTW89_PHYSTS_IE_NUM, + RTW89_PHYSTS_IE_MAX = RTW89_PHYSTS_IE_NUM - 1 +}; + +enum rtw89_phy_status_bitmap { + RTW89_TD_SEARCH_FAIL = 0, + RTW89_BRK_BY_TX_PKT = 1, + RTW89_CCA_SPOOF = 2, + RTW89_OFDM_BRK = 3, + RTW89_CCK_BRK = 4, + RTW89_DL_MU_SPOOFING = 5, + RTW89_HE_MU = 6, + RTW89_VHT_MU = 7, + RTW89_UL_TB_SPOOFING = 8, + RTW89_RSVD_9 = 9, + RTW89_TRIG_BASE_PPDU = 10, + RTW89_CCK_PKT = 11, + RTW89_LEGACY_OFDM_PKT = 12, + RTW89_HT_PKT = 13, + RTW89_VHT_PKT = 14, + RTW89_HE_PKT = 15, + + RTW89_PHYSTS_BITMAP_NUM +}; + enum rtw89_dig_gain_type { RTW89_DIG_GAIN_LNA_G = 0, RTW89_DIG_GAIN_TIA_G = 1, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 365d8c8ce57b..b6049009f183 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -1674,6 +1674,29 @@ #define B_UPD_CLK_ADC_VAL GENMASK(26, 25) #define R_RSTB_ASYNC 0x0704 #define B_RSTB_ASYNC_ALL BIT(1) +#define R_MAC_PIN_SEL 0x0734 +#define B_CH_IDX_SEG0 GENMASK(23, 16) +#define R_PLCP_HISTOGRAM 0x0738 +#define B_STS_DIS_TRIG_BY_BRK BIT(2) +#define B_STS_DIS_TRIG_BY_FAIL BIT(3) +#define R_PHY_STS_BITMAP_ADDR_START R_PHY_STS_BITMAP_SEARCH_FAIL +#define B_PHY_STS_BITMAP_ADDR_MASK GENMASK(6, 2) +#define R_PHY_STS_BITMAP_SEARCH_FAIL 0x073C +#define B_PHY_STS_BITMAP_MSK_52A 0x337cff3f +#define R_PHY_STS_BITMAP_R2T 0x0740 +#define R_PHY_STS_BITMAP_CCA_SPOOF 0x0744 +#define R_PHY_STS_BITMAP_OFDM_BRK 0x0748 +#define R_PHY_STS_BITMAP_CCK_BRK 0x074C +#define R_PHY_STS_BITMAP_DL_MU_SPOOF 0x0750 +#define R_PHY_STS_BITMAP_HE_MU 0x0754 +#define R_PHY_STS_BITMAP_VHT_MU 0x0758 +#define R_PHY_STS_BITMAP_UL_TB_SPOOF 0x075C +#define R_PHY_STS_BITMAP_TRIGBASE 0x0760 +#define R_PHY_STS_BITMAP_CCK 0x0764 +#define R_PHY_STS_BITMAP_LEGACY 0x0768 +#define R_PHY_STS_BITMAP_HT 0x076C +#define R_PHY_STS_BITMAP_VHT 0x0770 +#define R_PHY_STS_BITMAP_HE 0x0774 #define R_PMAC_GNT 0x0980 #define B_PMAC_GNT_TXEN BIT(0) #define B_PMAC_GNT_RXEN BIT(16) diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index f00b94ecfff4..4c37e590e43c 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -15,243 +15,244 @@ static const struct rtw89_regulatory rtw89_ww_regd = COUNTRY_REGD("00", RTW89_WW, RTW89_WW); static const struct rtw89_regulatory rtw89_regd_map[] = { - COUNTRY_REGD("AR", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("BO", RTW89_WW, RTW89_FCC), + COUNTRY_REGD("AR", RTW89_MEXICO, RTW89_MEXICO), + COUNTRY_REGD("BO", RTW89_FCC, RTW89_FCC), COUNTRY_REGD("BR", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("CL", RTW89_WW, RTW89_CHILE), + COUNTRY_REGD("CL", RTW89_CHILE, RTW89_CHILE), COUNTRY_REGD("CO", RTW89_FCC, RTW89_FCC), COUNTRY_REGD("CR", RTW89_FCC, RTW89_FCC), COUNTRY_REGD("EC", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("SV", RTW89_WW, RTW89_FCC), + COUNTRY_REGD("SV", RTW89_FCC, RTW89_FCC), COUNTRY_REGD("GT", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("HN", RTW89_WW, RTW89_FCC), - COUNTRY_REGD("MX", RTW89_FCC, RTW89_MEXICO), + COUNTRY_REGD("HN", RTW89_FCC, RTW89_FCC), + COUNTRY_REGD("MX", RTW89_MEXICO, RTW89_MEXICO), COUNTRY_REGD("NI", RTW89_FCC, RTW89_FCC), COUNTRY_REGD("PA", RTW89_FCC, RTW89_FCC), COUNTRY_REGD("PY", RTW89_FCC, RTW89_FCC), COUNTRY_REGD("PE", RTW89_FCC, RTW89_FCC), COUNTRY_REGD("US", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("UY", RTW89_WW, RTW89_FCC), - COUNTRY_REGD("VE", RTW89_WW, RTW89_FCC), + COUNTRY_REGD("UY", RTW89_FCC, RTW89_FCC), + COUNTRY_REGD("VE", RTW89_FCC, RTW89_FCC), COUNTRY_REGD("PR", RTW89_FCC, RTW89_FCC), COUNTRY_REGD("DO", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("AT", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("BE", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("CY", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("CZ", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("DK", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("EE", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("FI", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("FR", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("DE", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("GR", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("HU", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("IS", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("IE", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("IT", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("LV", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("LI", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("LT", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("LU", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("MT", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("MC", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("NL", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("NO", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("PL", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("PT", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("SK", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("SI", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("ES", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("SE", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("CH", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("GB", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("AL", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("AZ", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("BH", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("BA", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("BG", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("HR", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("EG", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("GH", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("IQ", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("IL", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("JO", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("KZ", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("KE", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("KW", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("KG", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("LB", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("LS", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("MK", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("MA", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("MZ", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("NA", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("NG", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("OM", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("QA", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("RO", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("RU", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("SA", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("SN", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("RS", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("ME", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("ZA", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("TR", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("UA", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("AE", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("YE", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("ZW", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("BD", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("KH", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("CN", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("HK", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("IN", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("AT", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("BE", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("CY", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("CZ", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("DK", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("EE", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("FI", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("FR", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("DE", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("GR", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("HU", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("IS", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("IE", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("IT", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("LV", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("LI", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("LT", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("LU", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("MT", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("MC", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("NL", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("NO", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("PL", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("PT", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("SK", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("SI", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("ES", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("SE", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("CH", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("GB", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("AL", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("AZ", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("BH", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("BA", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("BG", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("HR", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("EG", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("GH", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("IQ", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("IL", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("JO", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("KZ", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("KE", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("KW", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("KG", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("LB", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("LS", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("MK", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("MA", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("MZ", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("NA", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("NG", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("OM", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("QA", RTW89_QATAR, RTW89_QATAR), + COUNTRY_REGD("RO", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("RU", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("SA", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("SN", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("RS", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("ME", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("ZA", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("TR", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("UA", RTW89_UKRAINE, RTW89_UKRAINE), + COUNTRY_REGD("AE", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("YE", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("ZW", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("BD", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("KH", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("CN", RTW89_CN, RTW89_CN), + COUNTRY_REGD("HK", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("IN", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("ID", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("KR", RTW89_KCC, RTW89_KCC), - COUNTRY_REGD("MY", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("PK", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("PH", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("SG", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("LK", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("MY", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("PK", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("PH", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("SG", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("LK", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("TW", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("TH", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("VN", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("AU", RTW89_WW, RTW89_ACMA), - COUNTRY_REGD("NZ", RTW89_WW, RTW89_ACMA), - COUNTRY_REGD("PG", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("TH", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("VN", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("AU", RTW89_ACMA, RTW89_ACMA), + COUNTRY_REGD("NZ", RTW89_ACMA, RTW89_ACMA), + COUNTRY_REGD("PG", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("CA", RTW89_IC, RTW89_IC), COUNTRY_REGD("JP", RTW89_MKK, RTW89_MKK), - COUNTRY_REGD("JM", RTW89_WW, RTW89_FCC), + COUNTRY_REGD("JM", RTW89_FCC, RTW89_FCC), COUNTRY_REGD("AN", RTW89_FCC, RTW89_FCC), COUNTRY_REGD("TT", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("TN", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("TN", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("AF", RTW89_ETSI, RTW89_ETSI), - COUNTRY_REGD("DZ", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("DZ", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("AS", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("AD", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("AO", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("AI", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("AQ", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("AD", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("AO", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("AI", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("AQ", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("AG", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("AM", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("AM", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("AW", RTW89_FCC, RTW89_FCC), COUNTRY_REGD("BS", RTW89_FCC, RTW89_FCC), COUNTRY_REGD("BB", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("BY", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("BY", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("BZ", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("BJ", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("BJ", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("BM", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("BT", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("BW", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("BV", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("IO", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("BT", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("BW", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("BV", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("IO", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("VG", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("BN", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("BF", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("MM", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("BI", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("CM", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("CV", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("BN", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("BF", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("MM", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("BI", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("CM", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("CV", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("KY", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("CF", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("TD", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("CX", RTW89_WW, RTW89_ACMA), - COUNTRY_REGD("CC", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("KM", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("CG", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("CD", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("CK", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("CF", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("TD", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("CX", RTW89_ACMA, RTW89_ACMA), + COUNTRY_REGD("CC", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("KM", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("CG", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("CD", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("CK", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("CI", RTW89_ETSI, RTW89_ETSI), - COUNTRY_REGD("DJ", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("DJ", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("DM", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("GQ", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("ER", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("ET", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("FK", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("FO", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("GQ", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("ER", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("ET", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("FK", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("FO", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("FJ", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("GF", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("PF", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("TF", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("GA", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("GM", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("GE", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("GI", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("GL", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("GF", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("PF", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("TF", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("GA", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("GM", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("GE", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("GI", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("GL", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("GD", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("GP", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("GP", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("GU", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("GG", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("GN", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("GW", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("GY", RTW89_FCC, RTW89_NCC), + COUNTRY_REGD("GG", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("GN", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("GW", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("GY", RTW89_NCC, RTW89_NCC), COUNTRY_REGD("HT", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("HM", RTW89_WW, RTW89_ACMA), - COUNTRY_REGD("VA", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("IM", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("JE", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("KI", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("LA", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("LR", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("LY", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("MO", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("MG", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("MW", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("MV", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("ML", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("HM", RTW89_ACMA, RTW89_ACMA), + COUNTRY_REGD("VA", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("IM", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("JE", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("KI", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("LA", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("LR", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("LY", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("MO", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("MG", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("MW", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("MV", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("ML", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("MH", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("MQ", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("MR", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("MU", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("YT", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("MQ", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("MR", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("MU", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("YT", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("FM", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("MD", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("MN", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("MS", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("NR", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("NP", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("NC", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("NE", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("NU", RTW89_WW, RTW89_ACMA), - COUNTRY_REGD("NF", RTW89_WW, RTW89_ACMA), + COUNTRY_REGD("MD", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("MN", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("MS", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("NR", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("NP", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("NC", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("NE", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("NU", RTW89_ACMA, RTW89_ACMA), + COUNTRY_REGD("NF", RTW89_ACMA, RTW89_ACMA), COUNTRY_REGD("MP", RTW89_FCC, RTW89_FCC), COUNTRY_REGD("PW", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("RE", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("RW", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("SH", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("RE", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("RW", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("SH", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("KN", RTW89_FCC, RTW89_FCC), COUNTRY_REGD("LC", RTW89_FCC, RTW89_FCC), COUNTRY_REGD("MF", RTW89_FCC, RTW89_FCC), COUNTRY_REGD("SX", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("PM", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("PM", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("VC", RTW89_FCC, RTW89_FCC), COUNTRY_REGD("WS", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("SM", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("SM", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("ST", RTW89_FCC, RTW89_FCC), COUNTRY_REGD("SC", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("SL", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("SB", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("SO", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("GS", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("SL", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("SB", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("SO", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("GS", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("SR", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("SJ", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("SZ", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("TJ", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("TZ", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("TG", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("TK", RTW89_WW, RTW89_ACMA), - COUNTRY_REGD("TO", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("TM", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("TC", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("SJ", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("SZ", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("TJ", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("TZ", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("TG", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("TK", RTW89_ACMA, RTW89_ACMA), + COUNTRY_REGD("TO", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("TM", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("TC", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("TV", RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("UG", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("UG", RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("VI", RTW89_FCC, RTW89_FCC), - COUNTRY_REGD("UZ", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("VU", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("WF", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("EH", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("ZM", RTW89_WW, RTW89_ETSI), - COUNTRY_REGD("IR", RTW89_WW, RTW89_ETSI), + COUNTRY_REGD("UZ", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("VU", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("WF", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("EH", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("ZM", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("IR", RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("PS", RTW89_ETSI, RTW89_ETSI), }; static const struct rtw89_regulatory *rtw89_regd_find_reg_by_name(char *alpha2) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 5c6ffca3a324..6b75e4bc7352 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -1053,10 +1053,10 @@ static void rtw8852a_set_channel_bb(struct rtw89_dev *rtwdev, struct rtw89_channel_params *param, enum rtw89_phy_idx phy_idx) { - bool cck_en = param->center_chan > 14 ? false : true; + bool cck_en = param->center_chan <= 14; u8 pri_ch_idx = param->pri_ch_idx; - if (param->center_chan <= 14) + if (cck_en) rtw8852a_ctrl_sco_cck(rtwdev, param->center_chan, param->primary_chan, param->bandwidth); @@ -1069,6 +1069,8 @@ static void rtw8852a_set_channel_bb(struct rtw89_dev *rtwdev, rtw8852a_bbrst_for_rfk(rtwdev, phy_idx); } rtw8852a_spur_elimination(rtwdev, param->center_chan); + rtw89_phy_write32_mask(rtwdev, R_MAC_PIN_SEL, B_CH_IDX_SEG0, + param->primary_chan); rtw8852a_bb_reset_all(rtwdev, phy_idx); } @@ -1927,6 +1929,21 @@ void rtw8852a_btc_wl_s1_standby(struct rtw89_dev *rtwdev, bool state) rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x0); } +static void rtw8852a_fill_freq_with_ppdu(struct rtw89_dev *rtwdev, + struct rtw89_rx_phy_ppdu *phy_ppdu, + struct ieee80211_rx_status *status) +{ + u16 chan = phy_ppdu->chan_idx; + u8 band; + + if (chan == 0) + return; + + band = chan <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; + status->freq = ieee80211_channel_to_frequency(chan, band); + status->band = band; +} + static void rtw8852a_query_ppdu(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu, struct ieee80211_rx_status *status) @@ -1939,6 +1956,8 @@ static void rtw8852a_query_ppdu(struct rtw89_dev *rtwdev, status->chains |= BIT(path); status->chain_signal[path] = rx_power[path]; } + if (phy_ppdu->valid) + rtw8852a_fill_freq_with_ppdu(rtwdev, phy_ppdu, status); } static const struct rtw89_chip_ops rtw8852a_chip_ops = { @@ -2012,7 +2031,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .limit_efuse_size = 1152, .phycap_addr = 0x580, .phycap_size = 128, - .para_ver = 0x05050764, + .para_ver = 0x05050864, .wlcx_desired = 0x05050000, .btcx_desired = 0x5, .scbd = 0x1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a_table.c b/drivers/net/wireless/realtek/rtw89/rtw8852a_table.c index 3a4fe7207420..253b5f8fc4f9 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a_table.c @@ -43384,5248 +43384,6991 @@ static const u8 _txpwr_track_delta_swingidx_2g_cck_a_p[] = { const s8 rtw89_8852a_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [RTW89_RS_LMT_NUM][RTW89_BF_NUM] [RTW89_REGD_NUM][RTW89_2G_CH_NUM] = { - [0][0][0][0][0][0] = 56, - [0][0][0][0][0][1] = 56, - [0][0][0][0][0][2] = 56, - [0][0][0][0][0][3] = 56, - [0][0][0][0][0][4] = 56, - [0][0][0][0][0][5] = 56, - [0][0][0][0][0][6] = 56, - [0][0][0][0][0][7] = 56, - [0][0][0][0][0][8] = 56, - [0][0][0][0][0][9] = 56, - [0][0][0][0][0][10] = 56, - [0][0][0][0][0][11] = 56, - [0][0][0][0][0][12] = 48, - [0][0][0][0][0][13] = 76, - [0][1][0][0][0][0] = 44, - [0][1][0][0][0][1] = 44, - [0][1][0][0][0][2] = 44, - [0][1][0][0][0][3] = 44, - [0][1][0][0][0][4] = 44, - [0][1][0][0][0][5] = 44, - [0][1][0][0][0][6] = 44, - [0][1][0][0][0][7] = 44, - [0][1][0][0][0][8] = 44, - [0][1][0][0][0][9] = 44, - [0][1][0][0][0][10] = 44, - [0][1][0][0][0][11] = 44, - [0][1][0][0][0][12] = 38, - [0][1][0][0][0][13] = 64, - [1][0][0][0][0][0] = 0, - [1][0][0][0][0][1] = 0, - [1][0][0][0][0][2] = 58, - [1][0][0][0][0][3] = 58, - [1][0][0][0][0][4] = 58, - [1][0][0][0][0][5] = 58, - [1][0][0][0][0][6] = 46, - [1][0][0][0][0][7] = 46, - [1][0][0][0][0][8] = 46, - [1][0][0][0][0][9] = 32, - [1][0][0][0][0][10] = 32, - [1][0][0][0][0][11] = 0, - [1][0][0][0][0][12] = 0, - [1][0][0][0][0][13] = 0, - [1][1][0][0][0][0] = 0, - [1][1][0][0][0][1] = 0, - [1][1][0][0][0][2] = 46, - [1][1][0][0][0][3] = 46, - [1][1][0][0][0][4] = 46, - [1][1][0][0][0][5] = 46, - [1][1][0][0][0][6] = 46, - [1][1][0][0][0][7] = 46, - [1][1][0][0][0][8] = 46, - [1][1][0][0][0][9] = 24, - [1][1][0][0][0][10] = 24, - [1][1][0][0][0][11] = 0, - [1][1][0][0][0][12] = 0, - [1][1][0][0][0][13] = 0, - [0][0][1][0][0][0] = 58, - [0][0][1][0][0][1] = 58, - [0][0][1][0][0][2] = 58, - [0][0][1][0][0][3] = 58, - [0][0][1][0][0][4] = 58, - [0][0][1][0][0][5] = 58, - [0][0][1][0][0][6] = 58, - [0][0][1][0][0][7] = 58, - [0][0][1][0][0][8] = 58, - [0][0][1][0][0][9] = 58, - [0][0][1][0][0][10] = 58, - [0][0][1][0][0][11] = 56, - [0][0][1][0][0][12] = 52, - [0][0][1][0][0][13] = 0, - [0][1][1][0][0][0] = 46, - [0][1][1][0][0][1] = 46, - [0][1][1][0][0][2] = 46, - [0][1][1][0][0][3] = 46, - [0][1][1][0][0][4] = 46, - [0][1][1][0][0][5] = 46, - [0][1][1][0][0][6] = 46, - [0][1][1][0][0][7] = 46, - [0][1][1][0][0][8] = 46, - [0][1][1][0][0][9] = 46, - [0][1][1][0][0][10] = 46, - [0][1][1][0][0][11] = 42, - [0][1][1][0][0][12] = 40, - [0][1][1][0][0][13] = 0, - [0][0][2][0][0][0] = 58, - [0][0][2][0][0][1] = 58, - [0][0][2][0][0][2] = 58, - [0][0][2][0][0][3] = 58, - [0][0][2][0][0][4] = 58, - [0][0][2][0][0][5] = 58, - [0][0][2][0][0][6] = 58, - [0][0][2][0][0][7] = 58, - [0][0][2][0][0][8] = 58, - [0][0][2][0][0][9] = 58, - [0][0][2][0][0][10] = 58, - [0][0][2][0][0][11] = 54, - [0][0][2][0][0][12] = 50, - [0][0][2][0][0][13] = 0, - [0][1][2][0][0][0] = 46, - [0][1][2][0][0][1] = 46, - [0][1][2][0][0][2] = 46, - [0][1][2][0][0][3] = 46, - [0][1][2][0][0][4] = 46, - [0][1][2][0][0][5] = 46, - [0][1][2][0][0][6] = 46, - [0][1][2][0][0][7] = 46, - [0][1][2][0][0][8] = 46, - [0][1][2][0][0][9] = 46, - [0][1][2][0][0][10] = 46, - [0][1][2][0][0][11] = 42, - [0][1][2][0][0][12] = 40, - [0][1][2][0][0][13] = 0, - [0][1][2][1][0][0] = 34, - [0][1][2][1][0][1] = 34, - [0][1][2][1][0][2] = 34, - [0][1][2][1][0][3] = 34, - [0][1][2][1][0][4] = 34, - [0][1][2][1][0][5] = 34, - [0][1][2][1][0][6] = 34, - [0][1][2][1][0][7] = 34, - [0][1][2][1][0][8] = 34, - [0][1][2][1][0][9] = 34, - [0][1][2][1][0][10] = 34, - [0][1][2][1][0][11] = 34, - [0][1][2][1][0][12] = 34, - [0][1][2][1][0][13] = 0, - [1][0][2][0][0][0] = 0, - [1][0][2][0][0][1] = 0, - [1][0][2][0][0][2] = 56, - [1][0][2][0][0][3] = 56, - [1][0][2][0][0][4] = 58, - [1][0][2][0][0][5] = 58, - [1][0][2][0][0][6] = 54, - [1][0][2][0][0][7] = 50, - [1][0][2][0][0][8] = 50, - [1][0][2][0][0][9] = 42, - [1][0][2][0][0][10] = 40, - [1][0][2][0][0][11] = 0, - [1][0][2][0][0][12] = 0, - [1][0][2][0][0][13] = 0, - [1][1][2][0][0][0] = 0, - [1][1][2][0][0][1] = 0, - [1][1][2][0][0][2] = 46, - [1][1][2][0][0][3] = 46, - [1][1][2][0][0][4] = 46, - [1][1][2][0][0][5] = 46, - [1][1][2][0][0][6] = 46, - [1][1][2][0][0][7] = 46, - [1][1][2][0][0][8] = 46, - [1][1][2][0][0][9] = 38, - [1][1][2][0][0][10] = 36, - [1][1][2][0][0][11] = 0, - [1][1][2][0][0][12] = 0, - [1][1][2][0][0][13] = 0, - [1][1][2][1][0][0] = 0, - [1][1][2][1][0][1] = 0, - [1][1][2][1][0][2] = 34, - [1][1][2][1][0][3] = 34, - [1][1][2][1][0][4] = 34, - [1][1][2][1][0][5] = 34, - [1][1][2][1][0][6] = 34, - [1][1][2][1][0][7] = 34, - [1][1][2][1][0][8] = 34, - [1][1][2][1][0][9] = 34, - [1][1][2][1][0][10] = 34, - [1][1][2][1][0][11] = 0, - [1][1][2][1][0][12] = 0, - [1][1][2][1][0][13] = 0, - [0][0][0][0][2][0] = 76, - [0][0][0][0][1][0] = 56, - [0][0][0][0][3][0] = 68, - [0][0][0][0][5][0] = 76, - [0][0][0][0][6][0] = 56, - [0][0][0][0][9][0] = 56, - [0][0][0][0][8][0] = 60, - [0][0][0][0][11][0] = 56, - [0][0][0][0][2][1] = 76, - [0][0][0][0][1][1] = 56, - [0][0][0][0][3][1] = 68, - [0][0][0][0][5][1] = 76, - [0][0][0][0][6][1] = 56, - [0][0][0][0][9][1] = 56, - [0][0][0][0][8][1] = 60, - [0][0][0][0][11][1] = 56, - [0][0][0][0][2][2] = 76, - [0][0][0][0][1][2] = 56, - [0][0][0][0][3][2] = 68, - [0][0][0][0][5][2] = 76, - [0][0][0][0][6][2] = 56, - [0][0][0][0][9][2] = 56, - [0][0][0][0][8][2] = 60, - [0][0][0][0][11][2] = 56, - [0][0][0][0][2][3] = 76, - [0][0][0][0][1][3] = 56, - [0][0][0][0][3][3] = 68, - [0][0][0][0][5][3] = 76, - [0][0][0][0][6][3] = 56, - [0][0][0][0][9][3] = 56, - [0][0][0][0][8][3] = 60, - [0][0][0][0][11][3] = 56, - [0][0][0][0][2][4] = 76, - [0][0][0][0][1][4] = 56, - [0][0][0][0][3][4] = 68, - [0][0][0][0][5][4] = 76, - [0][0][0][0][6][4] = 56, - [0][0][0][0][9][4] = 56, - [0][0][0][0][8][4] = 60, - [0][0][0][0][11][4] = 56, - [0][0][0][0][2][5] = 76, - [0][0][0][0][1][5] = 56, - [0][0][0][0][3][5] = 68, - [0][0][0][0][5][5] = 76, - [0][0][0][0][6][5] = 56, - [0][0][0][0][9][5] = 56, - [0][0][0][0][8][5] = 60, - [0][0][0][0][11][5] = 56, - [0][0][0][0][2][6] = 76, - [0][0][0][0][1][6] = 56, - [0][0][0][0][3][6] = 68, - [0][0][0][0][5][6] = 76, - [0][0][0][0][6][6] = 56, - [0][0][0][0][9][6] = 56, - [0][0][0][0][8][6] = 60, - [0][0][0][0][11][6] = 56, - [0][0][0][0][2][7] = 76, - [0][0][0][0][1][7] = 56, - [0][0][0][0][3][7] = 68, - [0][0][0][0][5][7] = 76, - [0][0][0][0][6][7] = 56, - [0][0][0][0][9][7] = 56, - [0][0][0][0][8][7] = 60, - [0][0][0][0][11][7] = 56, - [0][0][0][0][2][8] = 76, - [0][0][0][0][1][8] = 56, - [0][0][0][0][3][8] = 68, - [0][0][0][0][5][8] = 76, - [0][0][0][0][6][8] = 56, - [0][0][0][0][9][8] = 56, - [0][0][0][0][8][8] = 60, - [0][0][0][0][11][8] = 56, - [0][0][0][0][2][9] = 76, - [0][0][0][0][1][9] = 56, - [0][0][0][0][3][9] = 68, - [0][0][0][0][5][9] = 76, - [0][0][0][0][6][9] = 56, - [0][0][0][0][9][9] = 56, - [0][0][0][0][8][9] = 60, - [0][0][0][0][11][9] = 56, - [0][0][0][0][2][10] = 76, - [0][0][0][0][1][10] = 56, - [0][0][0][0][3][10] = 68, - [0][0][0][0][5][10] = 76, - [0][0][0][0][6][10] = 56, - [0][0][0][0][9][10] = 56, - [0][0][0][0][8][10] = 60, - [0][0][0][0][11][10] = 56, - [0][0][0][0][2][11] = 68, - [0][0][0][0][1][11] = 56, - [0][0][0][0][3][11] = 68, - [0][0][0][0][5][11] = 68, - [0][0][0][0][6][11] = 56, - [0][0][0][0][9][11] = 56, - [0][0][0][0][8][11] = 60, - [0][0][0][0][11][11] = 56, - [0][0][0][0][2][12] = 48, - [0][0][0][0][1][12] = 56, - [0][0][0][0][3][12] = 68, - [0][0][0][0][5][12] = 48, - [0][0][0][0][6][12] = 56, - [0][0][0][0][9][12] = 56, - [0][0][0][0][8][12] = 60, - [0][0][0][0][11][12] = 56, - [0][0][0][0][2][13] = 127, - [0][0][0][0][1][13] = 127, - [0][0][0][0][3][13] = 76, - [0][0][0][0][5][13] = 127, - [0][0][0][0][6][13] = 127, - [0][0][0][0][9][13] = 127, - [0][0][0][0][8][13] = 127, - [0][0][0][0][11][13] = 127, - [0][1][0][0][2][0] = 74, - [0][1][0][0][1][0] = 44, - [0][1][0][0][3][0] = 56, - [0][1][0][0][5][0] = 74, - [0][1][0][0][6][0] = 44, - [0][1][0][0][9][0] = 44, - [0][1][0][0][8][0] = 48, - [0][1][0][0][11][0] = 44, - [0][1][0][0][2][1] = 76, - [0][1][0][0][1][1] = 44, - [0][1][0][0][3][1] = 56, - [0][1][0][0][5][1] = 76, - [0][1][0][0][6][1] = 44, - [0][1][0][0][9][1] = 44, - [0][1][0][0][8][1] = 48, - [0][1][0][0][11][1] = 44, - [0][1][0][0][2][2] = 76, - [0][1][0][0][1][2] = 44, - [0][1][0][0][3][2] = 56, - [0][1][0][0][5][2] = 76, - [0][1][0][0][6][2] = 44, - [0][1][0][0][9][2] = 44, - [0][1][0][0][8][2] = 48, - [0][1][0][0][11][2] = 44, - [0][1][0][0][2][3] = 76, - [0][1][0][0][1][3] = 44, - [0][1][0][0][3][3] = 56, - [0][1][0][0][5][3] = 76, - [0][1][0][0][6][3] = 44, - [0][1][0][0][9][3] = 44, - [0][1][0][0][8][3] = 48, - [0][1][0][0][11][3] = 44, - [0][1][0][0][2][4] = 76, - [0][1][0][0][1][4] = 44, - [0][1][0][0][3][4] = 56, - [0][1][0][0][5][4] = 76, - [0][1][0][0][6][4] = 44, - [0][1][0][0][9][4] = 44, - [0][1][0][0][8][4] = 48, - [0][1][0][0][11][4] = 44, - [0][1][0][0][2][5] = 76, - [0][1][0][0][1][5] = 44, - [0][1][0][0][3][5] = 56, - [0][1][0][0][5][5] = 76, - [0][1][0][0][6][5] = 44, - [0][1][0][0][9][5] = 44, - [0][1][0][0][8][5] = 48, - [0][1][0][0][11][5] = 44, - [0][1][0][0][2][6] = 76, - [0][1][0][0][1][6] = 44, - [0][1][0][0][3][6] = 56, - [0][1][0][0][5][6] = 76, - [0][1][0][0][6][6] = 44, - [0][1][0][0][9][6] = 44, - [0][1][0][0][8][6] = 48, - [0][1][0][0][11][6] = 44, - [0][1][0][0][2][7] = 76, - [0][1][0][0][1][7] = 44, - [0][1][0][0][3][7] = 56, - [0][1][0][0][5][7] = 76, - [0][1][0][0][6][7] = 44, - [0][1][0][0][9][7] = 44, - [0][1][0][0][8][7] = 48, - [0][1][0][0][11][7] = 44, - [0][1][0][0][2][8] = 76, - [0][1][0][0][1][8] = 44, - [0][1][0][0][3][8] = 56, - [0][1][0][0][5][8] = 76, - [0][1][0][0][6][8] = 44, - [0][1][0][0][9][8] = 44, - [0][1][0][0][8][8] = 48, - [0][1][0][0][11][8] = 44, - [0][1][0][0][2][9] = 76, - [0][1][0][0][1][9] = 44, - [0][1][0][0][3][9] = 56, - [0][1][0][0][5][9] = 76, - [0][1][0][0][6][9] = 44, - [0][1][0][0][9][9] = 44, - [0][1][0][0][8][9] = 48, - [0][1][0][0][11][9] = 44, - [0][1][0][0][2][10] = 62, - [0][1][0][0][1][10] = 44, - [0][1][0][0][3][10] = 56, - [0][1][0][0][5][10] = 62, - [0][1][0][0][6][10] = 44, - [0][1][0][0][9][10] = 44, - [0][1][0][0][8][10] = 48, - [0][1][0][0][11][10] = 44, - [0][1][0][0][2][11] = 52, - [0][1][0][0][1][11] = 44, - [0][1][0][0][3][11] = 56, - [0][1][0][0][5][11] = 52, - [0][1][0][0][6][11] = 44, - [0][1][0][0][9][11] = 44, - [0][1][0][0][8][11] = 48, - [0][1][0][0][11][11] = 44, - [0][1][0][0][2][12] = 38, - [0][1][0][0][1][12] = 44, - [0][1][0][0][3][12] = 56, - [0][1][0][0][5][12] = 38, - [0][1][0][0][6][12] = 44, - [0][1][0][0][9][12] = 44, - [0][1][0][0][8][12] = 48, - [0][1][0][0][11][12] = 44, - [0][1][0][0][2][13] = 127, - [0][1][0][0][1][13] = 127, - [0][1][0][0][3][13] = 64, - [0][1][0][0][5][13] = 127, - [0][1][0][0][6][13] = 127, - [0][1][0][0][9][13] = 127, - [0][1][0][0][8][13] = 127, - [0][1][0][0][11][13] = 127, - [1][0][0][0][2][0] = 127, - [1][0][0][0][1][0] = 127, - [1][0][0][0][3][0] = 127, - [1][0][0][0][5][0] = 127, - [1][0][0][0][6][0] = 127, - [1][0][0][0][9][0] = 127, - [1][0][0][0][8][0] = 127, - [1][0][0][0][11][0] = 127, - [1][0][0][0][2][1] = 127, - [1][0][0][0][1][1] = 127, - [1][0][0][0][3][1] = 127, - [1][0][0][0][5][1] = 127, - [1][0][0][0][6][1] = 127, - [1][0][0][0][9][1] = 127, - [1][0][0][0][8][1] = 127, - [1][0][0][0][11][1] = 127, - [1][0][0][0][2][2] = 60, - [1][0][0][0][1][2] = 58, - [1][0][0][0][3][2] = 68, - [1][0][0][0][5][2] = 60, - [1][0][0][0][6][2] = 58, - [1][0][0][0][9][2] = 58, - [1][0][0][0][8][2] = 60, - [1][0][0][0][11][2] = 58, - [1][0][0][0][2][3] = 60, - [1][0][0][0][1][3] = 58, - [1][0][0][0][3][3] = 68, - [1][0][0][0][5][3] = 60, - [1][0][0][0][6][3] = 58, - [1][0][0][0][9][3] = 58, - [1][0][0][0][8][3] = 60, - [1][0][0][0][11][3] = 58, - [1][0][0][0][2][4] = 60, - [1][0][0][0][1][4] = 58, - [1][0][0][0][3][4] = 68, - [1][0][0][0][5][4] = 60, - [1][0][0][0][6][4] = 58, - [1][0][0][0][9][4] = 58, - [1][0][0][0][8][4] = 60, - [1][0][0][0][11][4] = 58, - [1][0][0][0][2][5] = 60, - [1][0][0][0][1][5] = 58, - [1][0][0][0][3][5] = 68, - [1][0][0][0][5][5] = 60, - [1][0][0][0][6][5] = 58, - [1][0][0][0][9][5] = 58, - [1][0][0][0][8][5] = 60, - [1][0][0][0][11][5] = 58, - [1][0][0][0][2][6] = 46, - [1][0][0][0][1][6] = 58, - [1][0][0][0][3][6] = 68, - [1][0][0][0][5][6] = 46, - [1][0][0][0][6][6] = 58, - [1][0][0][0][9][6] = 58, - [1][0][0][0][8][6] = 60, - [1][0][0][0][11][6] = 58, - [1][0][0][0][2][7] = 46, - [1][0][0][0][1][7] = 58, - [1][0][0][0][3][7] = 68, - [1][0][0][0][5][7] = 46, - [1][0][0][0][6][7] = 58, - [1][0][0][0][9][7] = 58, - [1][0][0][0][8][7] = 60, - [1][0][0][0][11][7] = 58, - [1][0][0][0][2][8] = 46, - [1][0][0][0][1][8] = 58, - [1][0][0][0][3][8] = 68, - [1][0][0][0][5][8] = 46, - [1][0][0][0][6][8] = 58, - [1][0][0][0][9][8] = 58, - [1][0][0][0][8][8] = 60, - [1][0][0][0][11][8] = 58, - [1][0][0][0][2][9] = 32, - [1][0][0][0][1][9] = 58, - [1][0][0][0][3][9] = 68, - [1][0][0][0][5][9] = 32, - [1][0][0][0][6][9] = 58, - [1][0][0][0][9][9] = 58, - [1][0][0][0][8][9] = 60, - [1][0][0][0][11][9] = 58, - [1][0][0][0][2][10] = 32, - [1][0][0][0][1][10] = 58, - [1][0][0][0][3][10] = 68, - [1][0][0][0][5][10] = 32, - [1][0][0][0][6][10] = 58, - [1][0][0][0][9][10] = 58, - [1][0][0][0][8][10] = 60, - [1][0][0][0][11][10] = 58, - [1][0][0][0][2][11] = 127, - [1][0][0][0][1][11] = 127, - [1][0][0][0][3][11] = 127, - [1][0][0][0][5][11] = 127, - [1][0][0][0][6][11] = 127, - [1][0][0][0][9][11] = 127, - [1][0][0][0][8][11] = 127, - [1][0][0][0][11][11] = 127, - [1][0][0][0][2][12] = 127, - [1][0][0][0][1][12] = 127, - [1][0][0][0][3][12] = 127, - [1][0][0][0][5][12] = 127, - [1][0][0][0][6][12] = 127, - [1][0][0][0][9][12] = 127, - [1][0][0][0][8][12] = 127, - [1][0][0][0][11][12] = 127, - [1][0][0][0][2][13] = 127, - [1][0][0][0][1][13] = 127, - [1][0][0][0][3][13] = 127, - [1][0][0][0][5][13] = 127, - [1][0][0][0][6][13] = 127, - [1][0][0][0][9][13] = 127, - [1][0][0][0][8][13] = 127, - [1][0][0][0][11][13] = 127, - [1][1][0][0][2][0] = 127, - [1][1][0][0][1][0] = 127, - [1][1][0][0][3][0] = 127, - [1][1][0][0][5][0] = 127, - [1][1][0][0][6][0] = 127, - [1][1][0][0][9][0] = 127, - [1][1][0][0][8][0] = 127, - [1][1][0][0][11][0] = 127, - [1][1][0][0][2][1] = 127, - [1][1][0][0][1][1] = 127, - [1][1][0][0][3][1] = 127, - [1][1][0][0][5][1] = 127, - [1][1][0][0][6][1] = 127, - [1][1][0][0][9][1] = 127, - [1][1][0][0][8][1] = 127, - [1][1][0][0][11][1] = 127, - [1][1][0][0][2][2] = 48, - [1][1][0][0][1][2] = 46, - [1][1][0][0][3][2] = 56, - [1][1][0][0][5][2] = 48, - [1][1][0][0][6][2] = 46, - [1][1][0][0][9][2] = 46, - [1][1][0][0][8][2] = 48, - [1][1][0][0][11][2] = 46, - [1][1][0][0][2][3] = 48, - [1][1][0][0][1][3] = 46, - [1][1][0][0][3][3] = 56, - [1][1][0][0][5][3] = 48, - [1][1][0][0][6][3] = 46, - [1][1][0][0][9][3] = 46, - [1][1][0][0][8][3] = 48, - [1][1][0][0][11][3] = 46, - [1][1][0][0][2][4] = 48, - [1][1][0][0][1][4] = 46, - [1][1][0][0][3][4] = 56, - [1][1][0][0][5][4] = 48, - [1][1][0][0][6][4] = 46, - [1][1][0][0][9][4] = 46, - [1][1][0][0][8][4] = 48, - [1][1][0][0][11][4] = 46, - [1][1][0][0][2][5] = 58, - [1][1][0][0][1][5] = 46, - [1][1][0][0][3][5] = 56, - [1][1][0][0][5][5] = 58, - [1][1][0][0][6][5] = 46, - [1][1][0][0][9][5] = 46, - [1][1][0][0][8][5] = 48, - [1][1][0][0][11][5] = 46, - [1][1][0][0][2][6] = 46, - [1][1][0][0][1][6] = 46, - [1][1][0][0][3][6] = 56, - [1][1][0][0][5][6] = 46, - [1][1][0][0][6][6] = 46, - [1][1][0][0][9][6] = 46, - [1][1][0][0][8][6] = 48, - [1][1][0][0][11][6] = 46, - [1][1][0][0][2][7] = 46, - [1][1][0][0][1][7] = 46, - [1][1][0][0][3][7] = 56, - [1][1][0][0][5][7] = 46, - [1][1][0][0][6][7] = 46, - [1][1][0][0][9][7] = 46, - [1][1][0][0][8][7] = 48, - [1][1][0][0][11][7] = 46, - [1][1][0][0][2][8] = 46, - [1][1][0][0][1][8] = 46, - [1][1][0][0][3][8] = 56, - [1][1][0][0][5][8] = 46, - [1][1][0][0][6][8] = 46, - [1][1][0][0][9][8] = 46, - [1][1][0][0][8][8] = 48, - [1][1][0][0][11][8] = 46, - [1][1][0][0][2][9] = 24, - [1][1][0][0][1][9] = 46, - [1][1][0][0][3][9] = 56, - [1][1][0][0][5][9] = 24, - [1][1][0][0][6][9] = 46, - [1][1][0][0][9][9] = 46, - [1][1][0][0][8][9] = 48, - [1][1][0][0][11][9] = 46, - [1][1][0][0][2][10] = 24, - [1][1][0][0][1][10] = 46, - [1][1][0][0][3][10] = 56, - [1][1][0][0][5][10] = 24, - [1][1][0][0][6][10] = 46, - [1][1][0][0][9][10] = 46, - [1][1][0][0][8][10] = 48, - [1][1][0][0][11][10] = 46, - [1][1][0][0][2][11] = 127, - [1][1][0][0][1][11] = 127, - [1][1][0][0][3][11] = 127, - [1][1][0][0][5][11] = 127, - [1][1][0][0][6][11] = 127, - [1][1][0][0][9][11] = 127, - [1][1][0][0][8][11] = 127, - [1][1][0][0][11][11] = 127, - [1][1][0][0][2][12] = 127, - [1][1][0][0][1][12] = 127, - [1][1][0][0][3][12] = 127, - [1][1][0][0][5][12] = 127, - [1][1][0][0][6][12] = 127, - [1][1][0][0][9][12] = 127, - [1][1][0][0][8][12] = 127, - [1][1][0][0][11][12] = 127, - [1][1][0][0][2][13] = 127, - [1][1][0][0][1][13] = 127, - [1][1][0][0][3][13] = 127, - [1][1][0][0][5][13] = 127, - [1][1][0][0][6][13] = 127, - [1][1][0][0][9][13] = 127, - [1][1][0][0][8][13] = 127, - [1][1][0][0][11][13] = 127, - [0][0][1][0][2][0] = 66, - [0][0][1][0][1][0] = 58, - [0][0][1][0][3][0] = 76, - [0][0][1][0][5][0] = 66, - [0][0][1][0][6][0] = 58, - [0][0][1][0][9][0] = 58, - [0][0][1][0][8][0] = 60, - [0][0][1][0][11][0] = 58, - [0][0][1][0][2][1] = 66, - [0][0][1][0][1][1] = 58, - [0][0][1][0][3][1] = 76, - [0][0][1][0][5][1] = 66, - [0][0][1][0][6][1] = 58, - [0][0][1][0][9][1] = 58, - [0][0][1][0][8][1] = 60, - [0][0][1][0][11][1] = 58, - [0][0][1][0][2][2] = 70, - [0][0][1][0][1][2] = 58, - [0][0][1][0][3][2] = 76, - [0][0][1][0][5][2] = 70, - [0][0][1][0][6][2] = 58, - [0][0][1][0][9][2] = 58, - [0][0][1][0][8][2] = 60, - [0][0][1][0][11][2] = 58, - [0][0][1][0][2][3] = 74, - [0][0][1][0][1][3] = 58, - [0][0][1][0][3][3] = 76, - [0][0][1][0][5][3] = 74, - [0][0][1][0][6][3] = 58, - [0][0][1][0][9][3] = 58, - [0][0][1][0][8][3] = 60, - [0][0][1][0][11][3] = 58, - [0][0][1][0][2][4] = 78, - [0][0][1][0][1][4] = 58, - [0][0][1][0][3][4] = 76, - [0][0][1][0][5][4] = 78, - [0][0][1][0][6][4] = 58, - [0][0][1][0][9][4] = 58, - [0][0][1][0][8][4] = 60, - [0][0][1][0][11][4] = 58, - [0][0][1][0][2][5] = 78, - [0][0][1][0][1][5] = 58, - [0][0][1][0][3][5] = 76, - [0][0][1][0][5][5] = 78, - [0][0][1][0][6][5] = 58, - [0][0][1][0][9][5] = 58, - [0][0][1][0][8][5] = 60, - [0][0][1][0][11][5] = 58, - [0][0][1][0][2][6] = 78, - [0][0][1][0][1][6] = 58, - [0][0][1][0][3][6] = 76, - [0][0][1][0][5][6] = 78, - [0][0][1][0][6][6] = 58, - [0][0][1][0][9][6] = 58, - [0][0][1][0][8][6] = 60, - [0][0][1][0][11][6] = 58, - [0][0][1][0][2][7] = 74, - [0][0][1][0][1][7] = 58, - [0][0][1][0][3][7] = 76, - [0][0][1][0][5][7] = 74, - [0][0][1][0][6][7] = 58, - [0][0][1][0][9][7] = 58, - [0][0][1][0][8][7] = 60, - [0][0][1][0][11][7] = 58, - [0][0][1][0][2][8] = 70, - [0][0][1][0][1][8] = 58, - [0][0][1][0][3][8] = 76, - [0][0][1][0][5][8] = 70, - [0][0][1][0][6][8] = 58, - [0][0][1][0][9][8] = 58, - [0][0][1][0][8][8] = 60, - [0][0][1][0][11][8] = 58, - [0][0][1][0][2][9] = 66, - [0][0][1][0][1][9] = 58, - [0][0][1][0][3][9] = 76, - [0][0][1][0][5][9] = 66, - [0][0][1][0][6][9] = 58, - [0][0][1][0][9][9] = 58, - [0][0][1][0][8][9] = 60, - [0][0][1][0][11][9] = 58, - [0][0][1][0][2][10] = 66, - [0][0][1][0][1][10] = 58, - [0][0][1][0][3][10] = 76, - [0][0][1][0][5][10] = 66, - [0][0][1][0][6][10] = 58, - [0][0][1][0][9][10] = 58, - [0][0][1][0][8][10] = 60, - [0][0][1][0][11][10] = 58, - [0][0][1][0][2][11] = 56, - [0][0][1][0][1][11] = 58, - [0][0][1][0][3][11] = 76, - [0][0][1][0][5][11] = 56, - [0][0][1][0][6][11] = 58, - [0][0][1][0][9][11] = 58, - [0][0][1][0][8][11] = 60, - [0][0][1][0][11][11] = 58, - [0][0][1][0][2][12] = 52, - [0][0][1][0][1][12] = 58, - [0][0][1][0][3][12] = 76, - [0][0][1][0][5][12] = 52, - [0][0][1][0][6][12] = 58, - [0][0][1][0][9][12] = 58, - [0][0][1][0][8][12] = 60, - [0][0][1][0][11][12] = 58, - [0][0][1][0][2][13] = 127, - [0][0][1][0][1][13] = 127, - [0][0][1][0][3][13] = 127, - [0][0][1][0][5][13] = 127, - [0][0][1][0][6][13] = 127, - [0][0][1][0][9][13] = 127, - [0][0][1][0][8][13] = 127, - [0][0][1][0][11][13] = 127, - [0][1][1][0][2][0] = 62, - [0][1][1][0][1][0] = 46, - [0][1][1][0][3][0] = 64, - [0][1][1][0][5][0] = 62, - [0][1][1][0][6][0] = 46, - [0][1][1][0][9][0] = 46, - [0][1][1][0][8][0] = 48, - [0][1][1][0][11][0] = 46, - [0][1][1][0][2][1] = 62, - [0][1][1][0][1][1] = 46, - [0][1][1][0][3][1] = 64, - [0][1][1][0][5][1] = 62, - [0][1][1][0][6][1] = 46, - [0][1][1][0][9][1] = 46, - [0][1][1][0][8][1] = 48, - [0][1][1][0][11][1] = 46, - [0][1][1][0][2][2] = 66, - [0][1][1][0][1][2] = 46, - [0][1][1][0][3][2] = 64, - [0][1][1][0][5][2] = 66, - [0][1][1][0][6][2] = 46, - [0][1][1][0][9][2] = 46, - [0][1][1][0][8][2] = 48, - [0][1][1][0][11][2] = 46, - [0][1][1][0][2][3] = 70, - [0][1][1][0][1][3] = 46, - [0][1][1][0][3][3] = 64, - [0][1][1][0][5][3] = 70, - [0][1][1][0][6][3] = 46, - [0][1][1][0][9][3] = 46, - [0][1][1][0][8][3] = 48, - [0][1][1][0][11][3] = 46, - [0][1][1][0][2][4] = 78, - [0][1][1][0][1][4] = 46, - [0][1][1][0][3][4] = 64, - [0][1][1][0][5][4] = 78, - [0][1][1][0][6][4] = 46, - [0][1][1][0][9][4] = 46, - [0][1][1][0][8][4] = 48, - [0][1][1][0][11][4] = 46, - [0][1][1][0][2][5] = 78, - [0][1][1][0][1][5] = 46, - [0][1][1][0][3][5] = 64, - [0][1][1][0][5][5] = 78, - [0][1][1][0][6][5] = 46, - [0][1][1][0][9][5] = 46, - [0][1][1][0][8][5] = 48, - [0][1][1][0][11][5] = 46, - [0][1][1][0][2][6] = 78, - [0][1][1][0][1][6] = 46, - [0][1][1][0][3][6] = 64, - [0][1][1][0][5][6] = 78, - [0][1][1][0][6][6] = 46, - [0][1][1][0][9][6] = 46, - [0][1][1][0][8][6] = 48, - [0][1][1][0][11][6] = 46, - [0][1][1][0][2][7] = 70, - [0][1][1][0][1][7] = 46, - [0][1][1][0][3][7] = 64, - [0][1][1][0][5][7] = 70, - [0][1][1][0][6][7] = 46, - [0][1][1][0][9][7] = 46, - [0][1][1][0][8][7] = 48, - [0][1][1][0][11][7] = 46, - [0][1][1][0][2][8] = 66, - [0][1][1][0][1][8] = 46, - [0][1][1][0][3][8] = 64, - [0][1][1][0][5][8] = 66, - [0][1][1][0][6][8] = 46, - [0][1][1][0][9][8] = 46, - [0][1][1][0][8][8] = 48, - [0][1][1][0][11][8] = 46, - [0][1][1][0][2][9] = 62, - [0][1][1][0][1][9] = 46, - [0][1][1][0][3][9] = 64, - [0][1][1][0][5][9] = 62, - [0][1][1][0][6][9] = 46, - [0][1][1][0][9][9] = 46, - [0][1][1][0][8][9] = 48, - [0][1][1][0][11][9] = 46, - [0][1][1][0][2][10] = 62, - [0][1][1][0][1][10] = 46, - [0][1][1][0][3][10] = 64, - [0][1][1][0][5][10] = 62, - [0][1][1][0][6][10] = 46, - [0][1][1][0][9][10] = 46, - [0][1][1][0][8][10] = 48, - [0][1][1][0][11][10] = 46, - [0][1][1][0][2][11] = 42, - [0][1][1][0][1][11] = 46, - [0][1][1][0][3][11] = 64, - [0][1][1][0][5][11] = 42, - [0][1][1][0][6][11] = 46, - [0][1][1][0][9][11] = 46, - [0][1][1][0][8][11] = 48, - [0][1][1][0][11][11] = 46, - [0][1][1][0][2][12] = 40, - [0][1][1][0][1][12] = 46, - [0][1][1][0][3][12] = 64, - [0][1][1][0][5][12] = 40, - [0][1][1][0][6][12] = 46, - [0][1][1][0][9][12] = 46, - [0][1][1][0][8][12] = 48, - [0][1][1][0][11][12] = 46, - [0][1][1][0][2][13] = 127, - [0][1][1][0][1][13] = 127, - [0][1][1][0][3][13] = 127, - [0][1][1][0][5][13] = 127, - [0][1][1][0][6][13] = 127, - [0][1][1][0][9][13] = 127, - [0][1][1][0][8][13] = 127, - [0][1][1][0][11][13] = 127, - [0][0][2][0][2][0] = 66, - [0][0][2][0][1][0] = 58, - [0][0][2][0][3][0] = 76, - [0][0][2][0][5][0] = 66, - [0][0][2][0][6][0] = 58, - [0][0][2][0][9][0] = 58, - [0][0][2][0][8][0] = 60, - [0][0][2][0][11][0] = 58, - [0][0][2][0][2][1] = 66, - [0][0][2][0][1][1] = 58, - [0][0][2][0][3][1] = 76, - [0][0][2][0][5][1] = 66, - [0][0][2][0][6][1] = 58, - [0][0][2][0][9][1] = 58, - [0][0][2][0][8][1] = 60, - [0][0][2][0][11][1] = 58, - [0][0][2][0][2][2] = 70, - [0][0][2][0][1][2] = 58, - [0][0][2][0][3][2] = 76, - [0][0][2][0][5][2] = 70, - [0][0][2][0][6][2] = 58, - [0][0][2][0][9][2] = 58, - [0][0][2][0][8][2] = 60, - [0][0][2][0][11][2] = 58, - [0][0][2][0][2][3] = 74, - [0][0][2][0][1][3] = 58, - [0][0][2][0][3][3] = 76, - [0][0][2][0][5][3] = 74, - [0][0][2][0][6][3] = 58, - [0][0][2][0][9][3] = 58, - [0][0][2][0][8][3] = 60, - [0][0][2][0][11][3] = 58, - [0][0][2][0][2][4] = 76, - [0][0][2][0][1][4] = 58, - [0][0][2][0][3][4] = 76, - [0][0][2][0][5][4] = 76, - [0][0][2][0][6][4] = 58, - [0][0][2][0][9][4] = 58, - [0][0][2][0][8][4] = 60, - [0][0][2][0][11][4] = 58, - [0][0][2][0][2][5] = 76, - [0][0][2][0][1][5] = 58, - [0][0][2][0][3][5] = 76, - [0][0][2][0][5][5] = 76, - [0][0][2][0][6][5] = 58, - [0][0][2][0][9][5] = 58, - [0][0][2][0][8][5] = 60, - [0][0][2][0][11][5] = 58, - [0][0][2][0][2][6] = 76, - [0][0][2][0][1][6] = 58, - [0][0][2][0][3][6] = 76, - [0][0][2][0][5][6] = 76, - [0][0][2][0][6][6] = 58, - [0][0][2][0][9][6] = 58, - [0][0][2][0][8][6] = 60, - [0][0][2][0][11][6] = 58, - [0][0][2][0][2][7] = 74, - [0][0][2][0][1][7] = 58, - [0][0][2][0][3][7] = 76, - [0][0][2][0][5][7] = 74, - [0][0][2][0][6][7] = 58, - [0][0][2][0][9][7] = 58, - [0][0][2][0][8][7] = 60, - [0][0][2][0][11][7] = 58, - [0][0][2][0][2][8] = 70, - [0][0][2][0][1][8] = 58, - [0][0][2][0][3][8] = 76, - [0][0][2][0][5][8] = 70, - [0][0][2][0][6][8] = 58, - [0][0][2][0][9][8] = 58, - [0][0][2][0][8][8] = 60, - [0][0][2][0][11][8] = 58, - [0][0][2][0][2][9] = 66, - [0][0][2][0][1][9] = 58, - [0][0][2][0][3][9] = 76, - [0][0][2][0][5][9] = 66, - [0][0][2][0][6][9] = 58, - [0][0][2][0][9][9] = 58, - [0][0][2][0][8][9] = 60, - [0][0][2][0][11][9] = 58, - [0][0][2][0][2][10] = 66, - [0][0][2][0][1][10] = 58, - [0][0][2][0][3][10] = 76, - [0][0][2][0][5][10] = 66, - [0][0][2][0][6][10] = 58, - [0][0][2][0][9][10] = 58, - [0][0][2][0][8][10] = 60, - [0][0][2][0][11][10] = 58, - [0][0][2][0][2][11] = 54, - [0][0][2][0][1][11] = 58, - [0][0][2][0][3][11] = 76, - [0][0][2][0][5][11] = 54, - [0][0][2][0][6][11] = 58, - [0][0][2][0][9][11] = 58, - [0][0][2][0][8][11] = 60, - [0][0][2][0][11][11] = 58, - [0][0][2][0][2][12] = 50, - [0][0][2][0][1][12] = 58, - [0][0][2][0][3][12] = 76, - [0][0][2][0][5][12] = 50, - [0][0][2][0][6][12] = 58, - [0][0][2][0][9][12] = 58, - [0][0][2][0][8][12] = 60, - [0][0][2][0][11][12] = 58, - [0][0][2][0][2][13] = 127, - [0][0][2][0][1][13] = 127, - [0][0][2][0][3][13] = 127, - [0][0][2][0][5][13] = 127, - [0][0][2][0][6][13] = 127, - [0][0][2][0][9][13] = 127, - [0][0][2][0][8][13] = 127, - [0][0][2][0][11][13] = 127, - [0][1][2][0][2][0] = 62, - [0][1][2][0][1][0] = 46, - [0][1][2][0][3][0] = 64, - [0][1][2][0][5][0] = 62, - [0][1][2][0][6][0] = 46, - [0][1][2][0][9][0] = 46, - [0][1][2][0][8][0] = 48, - [0][1][2][0][11][0] = 46, - [0][1][2][0][2][1] = 62, - [0][1][2][0][1][1] = 46, - [0][1][2][0][3][1] = 64, - [0][1][2][0][5][1] = 62, - [0][1][2][0][6][1] = 46, - [0][1][2][0][9][1] = 46, - [0][1][2][0][8][1] = 48, - [0][1][2][0][11][1] = 46, - [0][1][2][0][2][2] = 66, - [0][1][2][0][1][2] = 46, - [0][1][2][0][3][2] = 64, - [0][1][2][0][5][2] = 66, - [0][1][2][0][6][2] = 46, - [0][1][2][0][9][2] = 46, - [0][1][2][0][8][2] = 48, - [0][1][2][0][11][2] = 46, - [0][1][2][0][2][3] = 70, - [0][1][2][0][1][3] = 46, - [0][1][2][0][3][3] = 64, - [0][1][2][0][5][3] = 70, - [0][1][2][0][6][3] = 46, - [0][1][2][0][9][3] = 46, - [0][1][2][0][8][3] = 48, - [0][1][2][0][11][3] = 46, - [0][1][2][0][2][4] = 76, - [0][1][2][0][1][4] = 46, - [0][1][2][0][3][4] = 64, - [0][1][2][0][5][4] = 76, - [0][1][2][0][6][4] = 46, - [0][1][2][0][9][4] = 46, - [0][1][2][0][8][4] = 48, - [0][1][2][0][11][4] = 46, - [0][1][2][0][2][5] = 76, - [0][1][2][0][1][5] = 46, - [0][1][2][0][3][5] = 64, - [0][1][2][0][5][5] = 76, - [0][1][2][0][6][5] = 46, - [0][1][2][0][9][5] = 46, - [0][1][2][0][8][5] = 48, - [0][1][2][0][11][5] = 46, - [0][1][2][0][2][6] = 76, - [0][1][2][0][1][6] = 46, - [0][1][2][0][3][6] = 64, - [0][1][2][0][5][6] = 76, - [0][1][2][0][6][6] = 46, - [0][1][2][0][9][6] = 46, - [0][1][2][0][8][6] = 48, - [0][1][2][0][11][6] = 46, - [0][1][2][0][2][7] = 68, - [0][1][2][0][1][7] = 46, - [0][1][2][0][3][7] = 64, - [0][1][2][0][5][7] = 68, - [0][1][2][0][6][7] = 46, - [0][1][2][0][9][7] = 46, - [0][1][2][0][8][7] = 48, - [0][1][2][0][11][7] = 46, - [0][1][2][0][2][8] = 64, - [0][1][2][0][1][8] = 46, - [0][1][2][0][3][8] = 64, - [0][1][2][0][5][8] = 64, - [0][1][2][0][6][8] = 46, - [0][1][2][0][9][8] = 46, - [0][1][2][0][8][8] = 48, - [0][1][2][0][11][8] = 46, - [0][1][2][0][2][9] = 60, - [0][1][2][0][1][9] = 46, - [0][1][2][0][3][9] = 64, - [0][1][2][0][5][9] = 60, - [0][1][2][0][6][9] = 46, - [0][1][2][0][9][9] = 46, - [0][1][2][0][8][9] = 48, - [0][1][2][0][11][9] = 46, - [0][1][2][0][2][10] = 60, - [0][1][2][0][1][10] = 46, - [0][1][2][0][3][10] = 64, - [0][1][2][0][5][10] = 60, - [0][1][2][0][6][10] = 46, - [0][1][2][0][9][10] = 46, - [0][1][2][0][8][10] = 48, - [0][1][2][0][11][10] = 46, - [0][1][2][0][2][11] = 42, - [0][1][2][0][1][11] = 46, - [0][1][2][0][3][11] = 64, - [0][1][2][0][5][11] = 42, - [0][1][2][0][6][11] = 46, - [0][1][2][0][9][11] = 46, - [0][1][2][0][8][11] = 48, - [0][1][2][0][11][11] = 46, - [0][1][2][0][2][12] = 40, - [0][1][2][0][1][12] = 46, - [0][1][2][0][3][12] = 64, - [0][1][2][0][5][12] = 40, - [0][1][2][0][6][12] = 46, - [0][1][2][0][9][12] = 46, - [0][1][2][0][8][12] = 48, - [0][1][2][0][11][12] = 46, - [0][1][2][0][2][13] = 127, - [0][1][2][0][1][13] = 127, - [0][1][2][0][3][13] = 127, - [0][1][2][0][5][13] = 127, - [0][1][2][0][6][13] = 127, - [0][1][2][0][9][13] = 127, - [0][1][2][0][8][13] = 127, - [0][1][2][0][11][13] = 127, - [0][1][2][1][2][0] = 62, - [0][1][2][1][1][0] = 34, - [0][1][2][1][3][0] = 64, - [0][1][2][1][5][0] = 62, - [0][1][2][1][6][0] = 34, - [0][1][2][1][9][0] = 34, - [0][1][2][1][8][0] = 36, - [0][1][2][1][11][0] = 34, - [0][1][2][1][2][1] = 62, - [0][1][2][1][1][1] = 34, - [0][1][2][1][3][1] = 64, - [0][1][2][1][5][1] = 62, - [0][1][2][1][6][1] = 34, - [0][1][2][1][9][1] = 34, - [0][1][2][1][8][1] = 36, - [0][1][2][1][11][1] = 34, - [0][1][2][1][2][2] = 66, - [0][1][2][1][1][2] = 34, - [0][1][2][1][3][2] = 64, - [0][1][2][1][5][2] = 66, - [0][1][2][1][6][2] = 34, - [0][1][2][1][9][2] = 34, - [0][1][2][1][8][2] = 36, - [0][1][2][1][11][2] = 34, - [0][1][2][1][2][3] = 70, - [0][1][2][1][1][3] = 34, - [0][1][2][1][3][3] = 64, - [0][1][2][1][5][3] = 70, - [0][1][2][1][6][3] = 34, - [0][1][2][1][9][3] = 34, - [0][1][2][1][8][3] = 36, - [0][1][2][1][11][3] = 34, - [0][1][2][1][2][4] = 76, - [0][1][2][1][1][4] = 34, - [0][1][2][1][3][4] = 64, - [0][1][2][1][5][4] = 76, - [0][1][2][1][6][4] = 34, - [0][1][2][1][9][4] = 34, - [0][1][2][1][8][4] = 36, - [0][1][2][1][11][4] = 34, - [0][1][2][1][2][5] = 76, - [0][1][2][1][1][5] = 34, - [0][1][2][1][3][5] = 64, - [0][1][2][1][5][5] = 76, - [0][1][2][1][6][5] = 34, - [0][1][2][1][9][5] = 34, - [0][1][2][1][8][5] = 36, - [0][1][2][1][11][5] = 34, - [0][1][2][1][2][6] = 76, - [0][1][2][1][1][6] = 34, - [0][1][2][1][3][6] = 64, - [0][1][2][1][5][6] = 76, - [0][1][2][1][6][6] = 34, - [0][1][2][1][9][6] = 34, - [0][1][2][1][8][6] = 36, - [0][1][2][1][11][6] = 34, - [0][1][2][1][2][7] = 68, - [0][1][2][1][1][7] = 34, - [0][1][2][1][3][7] = 64, - [0][1][2][1][5][7] = 68, - [0][1][2][1][6][7] = 34, - [0][1][2][1][9][7] = 34, - [0][1][2][1][8][7] = 36, - [0][1][2][1][11][7] = 34, - [0][1][2][1][2][8] = 64, - [0][1][2][1][1][8] = 34, - [0][1][2][1][3][8] = 64, - [0][1][2][1][5][8] = 64, - [0][1][2][1][6][8] = 34, - [0][1][2][1][9][8] = 34, - [0][1][2][1][8][8] = 36, - [0][1][2][1][11][8] = 34, - [0][1][2][1][2][9] = 60, - [0][1][2][1][1][9] = 34, - [0][1][2][1][3][9] = 64, - [0][1][2][1][5][9] = 60, - [0][1][2][1][6][9] = 34, - [0][1][2][1][9][9] = 34, - [0][1][2][1][8][9] = 36, - [0][1][2][1][11][9] = 34, - [0][1][2][1][2][10] = 60, - [0][1][2][1][1][10] = 34, - [0][1][2][1][3][10] = 64, - [0][1][2][1][5][10] = 60, - [0][1][2][1][6][10] = 34, - [0][1][2][1][9][10] = 34, - [0][1][2][1][8][10] = 36, - [0][1][2][1][11][10] = 34, - [0][1][2][1][2][11] = 42, - [0][1][2][1][1][11] = 34, - [0][1][2][1][3][11] = 64, - [0][1][2][1][5][11] = 42, - [0][1][2][1][6][11] = 34, - [0][1][2][1][9][11] = 34, - [0][1][2][1][8][11] = 36, - [0][1][2][1][11][11] = 34, - [0][1][2][1][2][12] = 40, - [0][1][2][1][1][12] = 34, - [0][1][2][1][3][12] = 64, - [0][1][2][1][5][12] = 40, - [0][1][2][1][6][12] = 34, - [0][1][2][1][9][12] = 34, - [0][1][2][1][8][12] = 36, - [0][1][2][1][11][12] = 34, - [0][1][2][1][2][13] = 127, - [0][1][2][1][1][13] = 127, - [0][1][2][1][3][13] = 127, - [0][1][2][1][5][13] = 127, - [0][1][2][1][6][13] = 127, - [0][1][2][1][9][13] = 127, - [0][1][2][1][8][13] = 127, - [0][1][2][1][11][13] = 127, - [1][0][2][0][2][0] = 127, - [1][0][2][0][1][0] = 127, - [1][0][2][0][3][0] = 127, - [1][0][2][0][5][0] = 127, - [1][0][2][0][6][0] = 127, - [1][0][2][0][9][0] = 127, - [1][0][2][0][8][0] = 127, - [1][0][2][0][11][0] = 127, - [1][0][2][0][2][1] = 127, - [1][0][2][0][1][1] = 127, - [1][0][2][0][3][1] = 127, - [1][0][2][0][5][1] = 127, - [1][0][2][0][6][1] = 127, - [1][0][2][0][9][1] = 127, - [1][0][2][0][8][1] = 127, - [1][0][2][0][11][1] = 127, - [1][0][2][0][2][2] = 56, - [1][0][2][0][1][2] = 58, - [1][0][2][0][3][2] = 76, - [1][0][2][0][5][2] = 56, - [1][0][2][0][6][2] = 58, - [1][0][2][0][9][2] = 58, - [1][0][2][0][8][2] = 60, - [1][0][2][0][11][2] = 58, - [1][0][2][0][2][3] = 56, - [1][0][2][0][1][3] = 58, - [1][0][2][0][3][3] = 76, - [1][0][2][0][5][3] = 56, - [1][0][2][0][6][3] = 58, - [1][0][2][0][9][3] = 58, - [1][0][2][0][8][3] = 60, - [1][0][2][0][11][3] = 58, - [1][0][2][0][2][4] = 60, - [1][0][2][0][1][4] = 58, - [1][0][2][0][3][4] = 76, - [1][0][2][0][5][4] = 60, - [1][0][2][0][6][4] = 58, - [1][0][2][0][9][4] = 58, - [1][0][2][0][8][4] = 60, - [1][0][2][0][11][4] = 58, - [1][0][2][0][2][5] = 64, - [1][0][2][0][1][5] = 58, - [1][0][2][0][3][5] = 76, - [1][0][2][0][5][5] = 64, - [1][0][2][0][6][5] = 58, - [1][0][2][0][9][5] = 58, - [1][0][2][0][8][5] = 60, - [1][0][2][0][11][5] = 58, - [1][0][2][0][2][6] = 54, - [1][0][2][0][1][6] = 58, - [1][0][2][0][3][6] = 76, - [1][0][2][0][5][6] = 54, - [1][0][2][0][6][6] = 58, - [1][0][2][0][9][6] = 58, - [1][0][2][0][8][6] = 60, - [1][0][2][0][11][6] = 58, - [1][0][2][0][2][7] = 50, - [1][0][2][0][1][7] = 58, - [1][0][2][0][3][7] = 76, - [1][0][2][0][5][7] = 50, - [1][0][2][0][6][7] = 58, - [1][0][2][0][9][7] = 58, - [1][0][2][0][8][7] = 60, - [1][0][2][0][11][7] = 58, - [1][0][2][0][2][8] = 50, - [1][0][2][0][1][8] = 58, - [1][0][2][0][3][8] = 76, - [1][0][2][0][5][8] = 50, - [1][0][2][0][6][8] = 58, - [1][0][2][0][9][8] = 58, - [1][0][2][0][8][8] = 60, - [1][0][2][0][11][8] = 58, - [1][0][2][0][2][9] = 42, - [1][0][2][0][1][9] = 58, - [1][0][2][0][3][9] = 76, - [1][0][2][0][5][9] = 42, - [1][0][2][0][6][9] = 58, - [1][0][2][0][9][9] = 58, - [1][0][2][0][8][9] = 60, - [1][0][2][0][11][9] = 58, - [1][0][2][0][2][10] = 40, - [1][0][2][0][1][10] = 58, - [1][0][2][0][3][10] = 76, - [1][0][2][0][5][10] = 40, - [1][0][2][0][6][10] = 58, - [1][0][2][0][9][10] = 58, - [1][0][2][0][8][10] = 60, - [1][0][2][0][11][10] = 58, - [1][0][2][0][2][11] = 127, - [1][0][2][0][1][11] = 127, - [1][0][2][0][3][11] = 127, - [1][0][2][0][5][11] = 127, - [1][0][2][0][6][11] = 127, - [1][0][2][0][9][11] = 127, - [1][0][2][0][8][11] = 127, - [1][0][2][0][11][11] = 127, - [1][0][2][0][2][12] = 127, - [1][0][2][0][1][12] = 127, - [1][0][2][0][3][12] = 127, - [1][0][2][0][5][12] = 127, - [1][0][2][0][6][12] = 127, - [1][0][2][0][9][12] = 127, - [1][0][2][0][8][12] = 127, - [1][0][2][0][11][12] = 127, - [1][0][2][0][2][13] = 127, - [1][0][2][0][1][13] = 127, - [1][0][2][0][3][13] = 127, - [1][0][2][0][5][13] = 127, - [1][0][2][0][6][13] = 127, - [1][0][2][0][9][13] = 127, - [1][0][2][0][8][13] = 127, - [1][0][2][0][11][13] = 127, - [1][1][2][0][2][0] = 127, - [1][1][2][0][1][0] = 127, - [1][1][2][0][3][0] = 127, - [1][1][2][0][5][0] = 127, - [1][1][2][0][6][0] = 127, - [1][1][2][0][9][0] = 127, - [1][1][2][0][8][0] = 127, - [1][1][2][0][11][0] = 127, - [1][1][2][0][2][1] = 127, - [1][1][2][0][1][1] = 127, - [1][1][2][0][3][1] = 127, - [1][1][2][0][5][1] = 127, - [1][1][2][0][6][1] = 127, - [1][1][2][0][9][1] = 127, - [1][1][2][0][8][1] = 127, - [1][1][2][0][11][1] = 127, - [1][1][2][0][2][2] = 52, - [1][1][2][0][1][2] = 46, - [1][1][2][0][3][2] = 64, - [1][1][2][0][5][2] = 52, - [1][1][2][0][6][2] = 46, - [1][1][2][0][9][2] = 46, - [1][1][2][0][8][2] = 48, - [1][1][2][0][11][2] = 46, - [1][1][2][0][2][3] = 52, - [1][1][2][0][1][3] = 46, - [1][1][2][0][3][3] = 64, - [1][1][2][0][5][3] = 52, - [1][1][2][0][6][3] = 46, - [1][1][2][0][9][3] = 46, - [1][1][2][0][8][3] = 48, - [1][1][2][0][11][3] = 46, - [1][1][2][0][2][4] = 56, - [1][1][2][0][1][4] = 46, - [1][1][2][0][3][4] = 64, - [1][1][2][0][5][4] = 56, - [1][1][2][0][6][4] = 46, - [1][1][2][0][9][4] = 46, - [1][1][2][0][8][4] = 48, - [1][1][2][0][11][4] = 46, - [1][1][2][0][2][5] = 60, - [1][1][2][0][1][5] = 46, - [1][1][2][0][3][5] = 64, - [1][1][2][0][5][5] = 60, - [1][1][2][0][6][5] = 46, - [1][1][2][0][9][5] = 46, - [1][1][2][0][8][5] = 48, - [1][1][2][0][11][5] = 46, - [1][1][2][0][2][6] = 54, - [1][1][2][0][1][6] = 46, - [1][1][2][0][3][6] = 64, - [1][1][2][0][5][6] = 52, - [1][1][2][0][6][6] = 46, - [1][1][2][0][9][6] = 46, - [1][1][2][0][8][6] = 48, - [1][1][2][0][11][6] = 46, - [1][1][2][0][2][7] = 50, - [1][1][2][0][1][7] = 46, - [1][1][2][0][3][7] = 64, - [1][1][2][0][5][7] = 48, - [1][1][2][0][6][7] = 46, - [1][1][2][0][9][7] = 46, - [1][1][2][0][8][7] = 48, - [1][1][2][0][11][7] = 46, - [1][1][2][0][2][8] = 50, - [1][1][2][0][1][8] = 46, - [1][1][2][0][3][8] = 64, - [1][1][2][0][5][8] = 48, - [1][1][2][0][6][8] = 46, - [1][1][2][0][9][8] = 46, - [1][1][2][0][8][8] = 48, - [1][1][2][0][11][8] = 46, - [1][1][2][0][2][9] = 38, - [1][1][2][0][1][9] = 46, - [1][1][2][0][3][9] = 64, - [1][1][2][0][5][9] = 38, - [1][1][2][0][6][9] = 46, - [1][1][2][0][9][9] = 46, - [1][1][2][0][8][9] = 48, - [1][1][2][0][11][9] = 46, - [1][1][2][0][2][10] = 36, - [1][1][2][0][1][10] = 46, - [1][1][2][0][3][10] = 64, - [1][1][2][0][5][10] = 36, - [1][1][2][0][6][10] = 46, - [1][1][2][0][9][10] = 46, - [1][1][2][0][8][10] = 48, - [1][1][2][0][11][10] = 46, - [1][1][2][0][2][11] = 127, - [1][1][2][0][1][11] = 127, - [1][1][2][0][3][11] = 127, - [1][1][2][0][5][11] = 127, - [1][1][2][0][6][11] = 127, - [1][1][2][0][9][11] = 127, - [1][1][2][0][8][11] = 127, - [1][1][2][0][11][11] = 127, - [1][1][2][0][2][12] = 127, - [1][1][2][0][1][12] = 127, - [1][1][2][0][3][12] = 127, - [1][1][2][0][5][12] = 127, - [1][1][2][0][6][12] = 127, - [1][1][2][0][9][12] = 127, - [1][1][2][0][8][12] = 127, - [1][1][2][0][11][12] = 127, - [1][1][2][0][2][13] = 127, - [1][1][2][0][1][13] = 127, - [1][1][2][0][3][13] = 127, - [1][1][2][0][5][13] = 127, - [1][1][2][0][6][13] = 127, - [1][1][2][0][9][13] = 127, - [1][1][2][0][8][13] = 127, - [1][1][2][0][11][13] = 127, - [1][1][2][1][2][0] = 127, - [1][1][2][1][1][0] = 127, - [1][1][2][1][3][0] = 127, - [1][1][2][1][5][0] = 127, - [1][1][2][1][6][0] = 127, - [1][1][2][1][9][0] = 127, - [1][1][2][1][8][0] = 127, - [1][1][2][1][11][0] = 127, - [1][1][2][1][2][1] = 127, - [1][1][2][1][1][1] = 127, - [1][1][2][1][3][1] = 127, - [1][1][2][1][5][1] = 127, - [1][1][2][1][6][1] = 127, - [1][1][2][1][9][1] = 127, - [1][1][2][1][8][1] = 127, - [1][1][2][1][11][1] = 127, - [1][1][2][1][2][2] = 52, - [1][1][2][1][1][2] = 34, - [1][1][2][1][3][2] = 64, - [1][1][2][1][5][2] = 52, - [1][1][2][1][6][2] = 34, - [1][1][2][1][9][2] = 34, - [1][1][2][1][8][2] = 36, - [1][1][2][1][11][2] = 34, - [1][1][2][1][2][3] = 52, - [1][1][2][1][1][3] = 34, - [1][1][2][1][3][3] = 64, - [1][1][2][1][5][3] = 52, - [1][1][2][1][6][3] = 34, - [1][1][2][1][9][3] = 34, - [1][1][2][1][8][3] = 36, - [1][1][2][1][11][3] = 34, - [1][1][2][1][2][4] = 56, - [1][1][2][1][1][4] = 34, - [1][1][2][1][3][4] = 64, - [1][1][2][1][5][4] = 56, - [1][1][2][1][6][4] = 34, - [1][1][2][1][9][4] = 34, - [1][1][2][1][8][4] = 36, - [1][1][2][1][11][4] = 34, - [1][1][2][1][2][5] = 60, - [1][1][2][1][1][5] = 34, - [1][1][2][1][3][5] = 64, - [1][1][2][1][5][5] = 60, - [1][1][2][1][6][5] = 34, - [1][1][2][1][9][5] = 34, - [1][1][2][1][8][5] = 36, - [1][1][2][1][11][5] = 34, - [1][1][2][1][2][6] = 54, - [1][1][2][1][1][6] = 34, - [1][1][2][1][3][6] = 64, - [1][1][2][1][5][6] = 52, - [1][1][2][1][6][6] = 34, - [1][1][2][1][9][6] = 34, - [1][1][2][1][8][6] = 36, - [1][1][2][1][11][6] = 34, - [1][1][2][1][2][7] = 50, - [1][1][2][1][1][7] = 34, - [1][1][2][1][3][7] = 64, - [1][1][2][1][5][7] = 48, - [1][1][2][1][6][7] = 34, - [1][1][2][1][9][7] = 34, - [1][1][2][1][8][7] = 36, - [1][1][2][1][11][7] = 34, - [1][1][2][1][2][8] = 50, - [1][1][2][1][1][8] = 34, - [1][1][2][1][3][8] = 64, - [1][1][2][1][5][8] = 48, - [1][1][2][1][6][8] = 34, - [1][1][2][1][9][8] = 34, - [1][1][2][1][8][8] = 36, - [1][1][2][1][11][8] = 34, - [1][1][2][1][2][9] = 38, - [1][1][2][1][1][9] = 34, - [1][1][2][1][3][9] = 64, - [1][1][2][1][5][9] = 38, - [1][1][2][1][6][9] = 34, - [1][1][2][1][9][9] = 34, - [1][1][2][1][8][9] = 36, - [1][1][2][1][11][9] = 34, - [1][1][2][1][2][10] = 36, - [1][1][2][1][1][10] = 34, - [1][1][2][1][3][10] = 64, - [1][1][2][1][5][10] = 36, - [1][1][2][1][6][10] = 34, - [1][1][2][1][9][10] = 34, - [1][1][2][1][8][10] = 36, - [1][1][2][1][11][10] = 34, - [1][1][2][1][2][11] = 127, - [1][1][2][1][1][11] = 127, - [1][1][2][1][3][11] = 127, - [1][1][2][1][5][11] = 127, - [1][1][2][1][6][11] = 127, - [1][1][2][1][9][11] = 127, - [1][1][2][1][8][11] = 127, - [1][1][2][1][11][11] = 127, - [1][1][2][1][2][12] = 127, - [1][1][2][1][1][12] = 127, - [1][1][2][1][3][12] = 127, - [1][1][2][1][5][12] = 127, - [1][1][2][1][6][12] = 127, - [1][1][2][1][9][12] = 127, - [1][1][2][1][8][12] = 127, - [1][1][2][1][11][12] = 127, - [1][1][2][1][2][13] = 127, - [1][1][2][1][1][13] = 127, - [1][1][2][1][3][13] = 127, - [1][1][2][1][5][13] = 127, - [1][1][2][1][6][13] = 127, - [1][1][2][1][9][13] = 127, - [1][1][2][1][8][13] = 127, - [1][1][2][1][11][13] = 127, + [0][0][0][0][RTW89_WW][0] = 56, + [0][0][0][0][RTW89_WW][1] = 56, + [0][0][0][0][RTW89_WW][2] = 56, + [0][0][0][0][RTW89_WW][3] = 56, + [0][0][0][0][RTW89_WW][4] = 56, + [0][0][0][0][RTW89_WW][5] = 56, + [0][0][0][0][RTW89_WW][6] = 56, + [0][0][0][0][RTW89_WW][7] = 56, + [0][0][0][0][RTW89_WW][8] = 56, + [0][0][0][0][RTW89_WW][9] = 56, + [0][0][0][0][RTW89_WW][10] = 56, + [0][0][0][0][RTW89_WW][11] = 56, + [0][0][0][0][RTW89_WW][12] = 48, + [0][0][0][0][RTW89_WW][13] = 76, + [0][1][0][0][RTW89_WW][0] = 44, + [0][1][0][0][RTW89_WW][1] = 44, + [0][1][0][0][RTW89_WW][2] = 44, + [0][1][0][0][RTW89_WW][3] = 44, + [0][1][0][0][RTW89_WW][4] = 44, + [0][1][0][0][RTW89_WW][5] = 44, + [0][1][0][0][RTW89_WW][6] = 44, + [0][1][0][0][RTW89_WW][7] = 44, + [0][1][0][0][RTW89_WW][8] = 44, + [0][1][0][0][RTW89_WW][9] = 44, + [0][1][0][0][RTW89_WW][10] = 44, + [0][1][0][0][RTW89_WW][11] = 44, + [0][1][0][0][RTW89_WW][12] = 38, + [0][1][0][0][RTW89_WW][13] = 64, + [1][0][0][0][RTW89_WW][0] = 0, + [1][0][0][0][RTW89_WW][1] = 0, + [1][0][0][0][RTW89_WW][2] = 58, + [1][0][0][0][RTW89_WW][3] = 58, + [1][0][0][0][RTW89_WW][4] = 58, + [1][0][0][0][RTW89_WW][5] = 58, + [1][0][0][0][RTW89_WW][6] = 46, + [1][0][0][0][RTW89_WW][7] = 46, + [1][0][0][0][RTW89_WW][8] = 46, + [1][0][0][0][RTW89_WW][9] = 32, + [1][0][0][0][RTW89_WW][10] = 32, + [1][0][0][0][RTW89_WW][11] = 0, + [1][0][0][0][RTW89_WW][12] = 0, + [1][0][0][0][RTW89_WW][13] = 0, + [1][1][0][0][RTW89_WW][0] = 0, + [1][1][0][0][RTW89_WW][1] = 0, + [1][1][0][0][RTW89_WW][2] = 46, + [1][1][0][0][RTW89_WW][3] = 46, + [1][1][0][0][RTW89_WW][4] = 46, + [1][1][0][0][RTW89_WW][5] = 46, + [1][1][0][0][RTW89_WW][6] = 46, + [1][1][0][0][RTW89_WW][7] = 46, + [1][1][0][0][RTW89_WW][8] = 46, + [1][1][0][0][RTW89_WW][9] = 24, + [1][1][0][0][RTW89_WW][10] = 24, + [1][1][0][0][RTW89_WW][11] = 0, + [1][1][0][0][RTW89_WW][12] = 0, + [1][1][0][0][RTW89_WW][13] = 0, + [0][0][1][0][RTW89_WW][0] = 58, + [0][0][1][0][RTW89_WW][1] = 58, + [0][0][1][0][RTW89_WW][2] = 58, + [0][0][1][0][RTW89_WW][3] = 58, + [0][0][1][0][RTW89_WW][4] = 58, + [0][0][1][0][RTW89_WW][5] = 58, + [0][0][1][0][RTW89_WW][6] = 58, + [0][0][1][0][RTW89_WW][7] = 58, + [0][0][1][0][RTW89_WW][8] = 58, + [0][0][1][0][RTW89_WW][9] = 58, + [0][0][1][0][RTW89_WW][10] = 58, + [0][0][1][0][RTW89_WW][11] = 56, + [0][0][1][0][RTW89_WW][12] = 52, + [0][0][1][0][RTW89_WW][13] = 0, + [0][1][1][0][RTW89_WW][0] = 46, + [0][1][1][0][RTW89_WW][1] = 46, + [0][1][1][0][RTW89_WW][2] = 46, + [0][1][1][0][RTW89_WW][3] = 46, + [0][1][1][0][RTW89_WW][4] = 46, + [0][1][1][0][RTW89_WW][5] = 46, + [0][1][1][0][RTW89_WW][6] = 46, + [0][1][1][0][RTW89_WW][7] = 46, + [0][1][1][0][RTW89_WW][8] = 46, + [0][1][1][0][RTW89_WW][9] = 46, + [0][1][1][0][RTW89_WW][10] = 46, + [0][1][1][0][RTW89_WW][11] = 42, + [0][1][1][0][RTW89_WW][12] = 40, + [0][1][1][0][RTW89_WW][13] = 0, + [0][0][2][0][RTW89_WW][0] = 58, + [0][0][2][0][RTW89_WW][1] = 58, + [0][0][2][0][RTW89_WW][2] = 58, + [0][0][2][0][RTW89_WW][3] = 58, + [0][0][2][0][RTW89_WW][4] = 58, + [0][0][2][0][RTW89_WW][5] = 58, + [0][0][2][0][RTW89_WW][6] = 58, + [0][0][2][0][RTW89_WW][7] = 58, + [0][0][2][0][RTW89_WW][8] = 58, + [0][0][2][0][RTW89_WW][9] = 58, + [0][0][2][0][RTW89_WW][10] = 58, + [0][0][2][0][RTW89_WW][11] = 54, + [0][0][2][0][RTW89_WW][12] = 50, + [0][0][2][0][RTW89_WW][13] = 0, + [0][1][2][0][RTW89_WW][0] = 46, + [0][1][2][0][RTW89_WW][1] = 46, + [0][1][2][0][RTW89_WW][2] = 46, + [0][1][2][0][RTW89_WW][3] = 46, + [0][1][2][0][RTW89_WW][4] = 46, + [0][1][2][0][RTW89_WW][5] = 46, + [0][1][2][0][RTW89_WW][6] = 46, + [0][1][2][0][RTW89_WW][7] = 46, + [0][1][2][0][RTW89_WW][8] = 46, + [0][1][2][0][RTW89_WW][9] = 46, + [0][1][2][0][RTW89_WW][10] = 46, + [0][1][2][0][RTW89_WW][11] = 42, + [0][1][2][0][RTW89_WW][12] = 40, + [0][1][2][0][RTW89_WW][13] = 0, + [0][1][2][1][RTW89_WW][0] = 34, + [0][1][2][1][RTW89_WW][1] = 34, + [0][1][2][1][RTW89_WW][2] = 34, + [0][1][2][1][RTW89_WW][3] = 34, + [0][1][2][1][RTW89_WW][4] = 34, + [0][1][2][1][RTW89_WW][5] = 34, + [0][1][2][1][RTW89_WW][6] = 34, + [0][1][2][1][RTW89_WW][7] = 34, + [0][1][2][1][RTW89_WW][8] = 34, + [0][1][2][1][RTW89_WW][9] = 34, + [0][1][2][1][RTW89_WW][10] = 34, + [0][1][2][1][RTW89_WW][11] = 34, + [0][1][2][1][RTW89_WW][12] = 34, + [0][1][2][1][RTW89_WW][13] = 0, + [1][0][2][0][RTW89_WW][0] = 0, + [1][0][2][0][RTW89_WW][1] = 0, + [1][0][2][0][RTW89_WW][2] = 56, + [1][0][2][0][RTW89_WW][3] = 56, + [1][0][2][0][RTW89_WW][4] = 58, + [1][0][2][0][RTW89_WW][5] = 58, + [1][0][2][0][RTW89_WW][6] = 54, + [1][0][2][0][RTW89_WW][7] = 50, + [1][0][2][0][RTW89_WW][8] = 50, + [1][0][2][0][RTW89_WW][9] = 42, + [1][0][2][0][RTW89_WW][10] = 40, + [1][0][2][0][RTW89_WW][11] = 0, + [1][0][2][0][RTW89_WW][12] = 0, + [1][0][2][0][RTW89_WW][13] = 0, + [1][1][2][0][RTW89_WW][0] = 0, + [1][1][2][0][RTW89_WW][1] = 0, + [1][1][2][0][RTW89_WW][2] = 46, + [1][1][2][0][RTW89_WW][3] = 46, + [1][1][2][0][RTW89_WW][4] = 46, + [1][1][2][0][RTW89_WW][5] = 46, + [1][1][2][0][RTW89_WW][6] = 46, + [1][1][2][0][RTW89_WW][7] = 46, + [1][1][2][0][RTW89_WW][8] = 46, + [1][1][2][0][RTW89_WW][9] = 38, + [1][1][2][0][RTW89_WW][10] = 36, + [1][1][2][0][RTW89_WW][11] = 0, + [1][1][2][0][RTW89_WW][12] = 0, + [1][1][2][0][RTW89_WW][13] = 0, + [1][1][2][1][RTW89_WW][0] = 0, + [1][1][2][1][RTW89_WW][1] = 0, + [1][1][2][1][RTW89_WW][2] = 34, + [1][1][2][1][RTW89_WW][3] = 34, + [1][1][2][1][RTW89_WW][4] = 34, + [1][1][2][1][RTW89_WW][5] = 34, + [1][1][2][1][RTW89_WW][6] = 34, + [1][1][2][1][RTW89_WW][7] = 34, + [1][1][2][1][RTW89_WW][8] = 34, + [1][1][2][1][RTW89_WW][9] = 34, + [1][1][2][1][RTW89_WW][10] = 34, + [1][1][2][1][RTW89_WW][11] = 0, + [1][1][2][1][RTW89_WW][12] = 0, + [1][1][2][1][RTW89_WW][13] = 0, + [0][0][0][0][RTW89_FCC][0] = 76, + [0][0][0][0][RTW89_ETSI][0] = 56, + [0][0][0][0][RTW89_MKK][0] = 68, + [0][0][0][0][RTW89_IC][0] = 76, + [0][0][0][0][RTW89_KCC][0] = 76, + [0][0][0][0][RTW89_ACMA][0] = 56, + [0][0][0][0][RTW89_CHILE][0] = 60, + [0][0][0][0][RTW89_UKRAINE][0] = 56, + [0][0][0][0][RTW89_MEXICO][0] = 76, + [0][0][0][0][RTW89_CN][0] = 56, + [0][0][0][0][RTW89_QATAR][0] = 56, + [0][0][0][0][RTW89_FCC][1] = 76, + [0][0][0][0][RTW89_ETSI][1] = 56, + [0][0][0][0][RTW89_MKK][1] = 68, + [0][0][0][0][RTW89_IC][1] = 76, + [0][0][0][0][RTW89_KCC][1] = 76, + [0][0][0][0][RTW89_ACMA][1] = 56, + [0][0][0][0][RTW89_CHILE][1] = 60, + [0][0][0][0][RTW89_UKRAINE][1] = 56, + [0][0][0][0][RTW89_MEXICO][1] = 76, + [0][0][0][0][RTW89_CN][1] = 56, + [0][0][0][0][RTW89_QATAR][1] = 56, + [0][0][0][0][RTW89_FCC][2] = 76, + [0][0][0][0][RTW89_ETSI][2] = 56, + [0][0][0][0][RTW89_MKK][2] = 68, + [0][0][0][0][RTW89_IC][2] = 76, + [0][0][0][0][RTW89_KCC][2] = 76, + [0][0][0][0][RTW89_ACMA][2] = 56, + [0][0][0][0][RTW89_CHILE][2] = 60, + [0][0][0][0][RTW89_UKRAINE][2] = 56, + [0][0][0][0][RTW89_MEXICO][2] = 76, + [0][0][0][0][RTW89_CN][2] = 56, + [0][0][0][0][RTW89_QATAR][2] = 56, + [0][0][0][0][RTW89_FCC][3] = 76, + [0][0][0][0][RTW89_ETSI][3] = 56, + [0][0][0][0][RTW89_MKK][3] = 68, + [0][0][0][0][RTW89_IC][3] = 76, + [0][0][0][0][RTW89_KCC][3] = 76, + [0][0][0][0][RTW89_ACMA][3] = 56, + [0][0][0][0][RTW89_CHILE][3] = 60, + [0][0][0][0][RTW89_UKRAINE][3] = 56, + [0][0][0][0][RTW89_MEXICO][3] = 76, + [0][0][0][0][RTW89_CN][3] = 56, + [0][0][0][0][RTW89_QATAR][3] = 56, + [0][0][0][0][RTW89_FCC][4] = 76, + [0][0][0][0][RTW89_ETSI][4] = 56, + [0][0][0][0][RTW89_MKK][4] = 68, + [0][0][0][0][RTW89_IC][4] = 76, + [0][0][0][0][RTW89_KCC][4] = 76, + [0][0][0][0][RTW89_ACMA][4] = 56, + [0][0][0][0][RTW89_CHILE][4] = 60, + [0][0][0][0][RTW89_UKRAINE][4] = 56, + [0][0][0][0][RTW89_MEXICO][4] = 76, + [0][0][0][0][RTW89_CN][4] = 56, + [0][0][0][0][RTW89_QATAR][4] = 56, + [0][0][0][0][RTW89_FCC][5] = 76, + [0][0][0][0][RTW89_ETSI][5] = 56, + [0][0][0][0][RTW89_MKK][5] = 68, + [0][0][0][0][RTW89_IC][5] = 76, + [0][0][0][0][RTW89_KCC][5] = 76, + [0][0][0][0][RTW89_ACMA][5] = 56, + [0][0][0][0][RTW89_CHILE][5] = 60, + [0][0][0][0][RTW89_UKRAINE][5] = 56, + [0][0][0][0][RTW89_MEXICO][5] = 76, + [0][0][0][0][RTW89_CN][5] = 56, + [0][0][0][0][RTW89_QATAR][5] = 56, + [0][0][0][0][RTW89_FCC][6] = 76, + [0][0][0][0][RTW89_ETSI][6] = 56, + [0][0][0][0][RTW89_MKK][6] = 68, + [0][0][0][0][RTW89_IC][6] = 76, + [0][0][0][0][RTW89_KCC][6] = 76, + [0][0][0][0][RTW89_ACMA][6] = 56, + [0][0][0][0][RTW89_CHILE][6] = 60, + [0][0][0][0][RTW89_UKRAINE][6] = 56, + [0][0][0][0][RTW89_MEXICO][6] = 76, + [0][0][0][0][RTW89_CN][6] = 56, + [0][0][0][0][RTW89_QATAR][6] = 56, + [0][0][0][0][RTW89_FCC][7] = 76, + [0][0][0][0][RTW89_ETSI][7] = 56, + [0][0][0][0][RTW89_MKK][7] = 68, + [0][0][0][0][RTW89_IC][7] = 76, + [0][0][0][0][RTW89_KCC][7] = 76, + [0][0][0][0][RTW89_ACMA][7] = 56, + [0][0][0][0][RTW89_CHILE][7] = 60, + [0][0][0][0][RTW89_UKRAINE][7] = 56, + [0][0][0][0][RTW89_MEXICO][7] = 76, + [0][0][0][0][RTW89_CN][7] = 56, + [0][0][0][0][RTW89_QATAR][7] = 56, + [0][0][0][0][RTW89_FCC][8] = 76, + [0][0][0][0][RTW89_ETSI][8] = 56, + [0][0][0][0][RTW89_MKK][8] = 68, + [0][0][0][0][RTW89_IC][8] = 76, + [0][0][0][0][RTW89_KCC][8] = 76, + [0][0][0][0][RTW89_ACMA][8] = 56, + [0][0][0][0][RTW89_CHILE][8] = 60, + [0][0][0][0][RTW89_UKRAINE][8] = 56, + [0][0][0][0][RTW89_MEXICO][8] = 76, + [0][0][0][0][RTW89_CN][8] = 56, + [0][0][0][0][RTW89_QATAR][8] = 56, + [0][0][0][0][RTW89_FCC][9] = 76, + [0][0][0][0][RTW89_ETSI][9] = 56, + [0][0][0][0][RTW89_MKK][9] = 68, + [0][0][0][0][RTW89_IC][9] = 76, + [0][0][0][0][RTW89_KCC][9] = 76, + [0][0][0][0][RTW89_ACMA][9] = 56, + [0][0][0][0][RTW89_CHILE][9] = 60, + [0][0][0][0][RTW89_UKRAINE][9] = 56, + [0][0][0][0][RTW89_MEXICO][9] = 76, + [0][0][0][0][RTW89_CN][9] = 56, + [0][0][0][0][RTW89_QATAR][9] = 56, + [0][0][0][0][RTW89_FCC][10] = 76, + [0][0][0][0][RTW89_ETSI][10] = 56, + [0][0][0][0][RTW89_MKK][10] = 68, + [0][0][0][0][RTW89_IC][10] = 76, + [0][0][0][0][RTW89_KCC][10] = 76, + [0][0][0][0][RTW89_ACMA][10] = 56, + [0][0][0][0][RTW89_CHILE][10] = 60, + [0][0][0][0][RTW89_UKRAINE][10] = 56, + [0][0][0][0][RTW89_MEXICO][10] = 76, + [0][0][0][0][RTW89_CN][10] = 56, + [0][0][0][0][RTW89_QATAR][10] = 56, + [0][0][0][0][RTW89_FCC][11] = 68, + [0][0][0][0][RTW89_ETSI][11] = 56, + [0][0][0][0][RTW89_MKK][11] = 68, + [0][0][0][0][RTW89_IC][11] = 68, + [0][0][0][0][RTW89_KCC][11] = 76, + [0][0][0][0][RTW89_ACMA][11] = 56, + [0][0][0][0][RTW89_CHILE][11] = 60, + [0][0][0][0][RTW89_UKRAINE][11] = 56, + [0][0][0][0][RTW89_MEXICO][11] = 68, + [0][0][0][0][RTW89_CN][11] = 56, + [0][0][0][0][RTW89_QATAR][11] = 56, + [0][0][0][0][RTW89_FCC][12] = 48, + [0][0][0][0][RTW89_ETSI][12] = 56, + [0][0][0][0][RTW89_MKK][12] = 68, + [0][0][0][0][RTW89_IC][12] = 48, + [0][0][0][0][RTW89_KCC][12] = 76, + [0][0][0][0][RTW89_ACMA][12] = 56, + [0][0][0][0][RTW89_CHILE][12] = 48, + [0][0][0][0][RTW89_UKRAINE][12] = 56, + [0][0][0][0][RTW89_MEXICO][12] = 48, + [0][0][0][0][RTW89_CN][12] = 56, + [0][0][0][0][RTW89_QATAR][12] = 56, + [0][0][0][0][RTW89_FCC][13] = 127, + [0][0][0][0][RTW89_ETSI][13] = 127, + [0][0][0][0][RTW89_MKK][13] = 76, + [0][0][0][0][RTW89_IC][13] = 127, + [0][0][0][0][RTW89_KCC][13] = 127, + [0][0][0][0][RTW89_ACMA][13] = 127, + [0][0][0][0][RTW89_CHILE][13] = 127, + [0][0][0][0][RTW89_UKRAINE][13] = 127, + [0][0][0][0][RTW89_MEXICO][13] = 127, + [0][0][0][0][RTW89_CN][13] = 127, + [0][0][0][0][RTW89_QATAR][13] = 127, + [0][1][0][0][RTW89_FCC][0] = 74, + [0][1][0][0][RTW89_ETSI][0] = 44, + [0][1][0][0][RTW89_MKK][0] = 56, + [0][1][0][0][RTW89_IC][0] = 74, + [0][1][0][0][RTW89_KCC][0] = 68, + [0][1][0][0][RTW89_ACMA][0] = 44, + [0][1][0][0][RTW89_CHILE][0] = 48, + [0][1][0][0][RTW89_UKRAINE][0] = 44, + [0][1][0][0][RTW89_MEXICO][0] = 74, + [0][1][0][0][RTW89_CN][0] = 44, + [0][1][0][0][RTW89_QATAR][0] = 44, + [0][1][0][0][RTW89_FCC][1] = 76, + [0][1][0][0][RTW89_ETSI][1] = 44, + [0][1][0][0][RTW89_MKK][1] = 56, + [0][1][0][0][RTW89_IC][1] = 76, + [0][1][0][0][RTW89_KCC][1] = 68, + [0][1][0][0][RTW89_ACMA][1] = 44, + [0][1][0][0][RTW89_CHILE][1] = 48, + [0][1][0][0][RTW89_UKRAINE][1] = 44, + [0][1][0][0][RTW89_MEXICO][1] = 76, + [0][1][0][0][RTW89_CN][1] = 44, + [0][1][0][0][RTW89_QATAR][1] = 44, + [0][1][0][0][RTW89_FCC][2] = 76, + [0][1][0][0][RTW89_ETSI][2] = 44, + [0][1][0][0][RTW89_MKK][2] = 56, + [0][1][0][0][RTW89_IC][2] = 76, + [0][1][0][0][RTW89_KCC][2] = 68, + [0][1][0][0][RTW89_ACMA][2] = 44, + [0][1][0][0][RTW89_CHILE][2] = 48, + [0][1][0][0][RTW89_UKRAINE][2] = 44, + [0][1][0][0][RTW89_MEXICO][2] = 76, + [0][1][0][0][RTW89_CN][2] = 44, + [0][1][0][0][RTW89_QATAR][2] = 44, + [0][1][0][0][RTW89_FCC][3] = 76, + [0][1][0][0][RTW89_ETSI][3] = 44, + [0][1][0][0][RTW89_MKK][3] = 56, + [0][1][0][0][RTW89_IC][3] = 76, + [0][1][0][0][RTW89_KCC][3] = 68, + [0][1][0][0][RTW89_ACMA][3] = 44, + [0][1][0][0][RTW89_CHILE][3] = 48, + [0][1][0][0][RTW89_UKRAINE][3] = 44, + [0][1][0][0][RTW89_MEXICO][3] = 76, + [0][1][0][0][RTW89_CN][3] = 44, + [0][1][0][0][RTW89_QATAR][3] = 44, + [0][1][0][0][RTW89_FCC][4] = 76, + [0][1][0][0][RTW89_ETSI][4] = 44, + [0][1][0][0][RTW89_MKK][4] = 56, + [0][1][0][0][RTW89_IC][4] = 76, + [0][1][0][0][RTW89_KCC][4] = 68, + [0][1][0][0][RTW89_ACMA][4] = 44, + [0][1][0][0][RTW89_CHILE][4] = 48, + [0][1][0][0][RTW89_UKRAINE][4] = 44, + [0][1][0][0][RTW89_MEXICO][4] = 76, + [0][1][0][0][RTW89_CN][4] = 44, + [0][1][0][0][RTW89_QATAR][4] = 44, + [0][1][0][0][RTW89_FCC][5] = 76, + [0][1][0][0][RTW89_ETSI][5] = 44, + [0][1][0][0][RTW89_MKK][5] = 56, + [0][1][0][0][RTW89_IC][5] = 76, + [0][1][0][0][RTW89_KCC][5] = 68, + [0][1][0][0][RTW89_ACMA][5] = 44, + [0][1][0][0][RTW89_CHILE][5] = 48, + [0][1][0][0][RTW89_UKRAINE][5] = 44, + [0][1][0][0][RTW89_MEXICO][5] = 76, + [0][1][0][0][RTW89_CN][5] = 44, + [0][1][0][0][RTW89_QATAR][5] = 44, + [0][1][0][0][RTW89_FCC][6] = 76, + [0][1][0][0][RTW89_ETSI][6] = 44, + [0][1][0][0][RTW89_MKK][6] = 56, + [0][1][0][0][RTW89_IC][6] = 76, + [0][1][0][0][RTW89_KCC][6] = 68, + [0][1][0][0][RTW89_ACMA][6] = 44, + [0][1][0][0][RTW89_CHILE][6] = 48, + [0][1][0][0][RTW89_UKRAINE][6] = 44, + [0][1][0][0][RTW89_MEXICO][6] = 76, + [0][1][0][0][RTW89_CN][6] = 44, + [0][1][0][0][RTW89_QATAR][6] = 44, + [0][1][0][0][RTW89_FCC][7] = 76, + [0][1][0][0][RTW89_ETSI][7] = 44, + [0][1][0][0][RTW89_MKK][7] = 56, + [0][1][0][0][RTW89_IC][7] = 76, + [0][1][0][0][RTW89_KCC][7] = 68, + [0][1][0][0][RTW89_ACMA][7] = 44, + [0][1][0][0][RTW89_CHILE][7] = 48, + [0][1][0][0][RTW89_UKRAINE][7] = 44, + [0][1][0][0][RTW89_MEXICO][7] = 76, + [0][1][0][0][RTW89_CN][7] = 44, + [0][1][0][0][RTW89_QATAR][7] = 44, + [0][1][0][0][RTW89_FCC][8] = 76, + [0][1][0][0][RTW89_ETSI][8] = 44, + [0][1][0][0][RTW89_MKK][8] = 56, + [0][1][0][0][RTW89_IC][8] = 76, + [0][1][0][0][RTW89_KCC][8] = 68, + [0][1][0][0][RTW89_ACMA][8] = 44, + [0][1][0][0][RTW89_CHILE][8] = 48, + [0][1][0][0][RTW89_UKRAINE][8] = 44, + [0][1][0][0][RTW89_MEXICO][8] = 76, + [0][1][0][0][RTW89_CN][8] = 44, + [0][1][0][0][RTW89_QATAR][8] = 44, + [0][1][0][0][RTW89_FCC][9] = 76, + [0][1][0][0][RTW89_ETSI][9] = 44, + [0][1][0][0][RTW89_MKK][9] = 56, + [0][1][0][0][RTW89_IC][9] = 76, + [0][1][0][0][RTW89_KCC][9] = 68, + [0][1][0][0][RTW89_ACMA][9] = 44, + [0][1][0][0][RTW89_CHILE][9] = 48, + [0][1][0][0][RTW89_UKRAINE][9] = 44, + [0][1][0][0][RTW89_MEXICO][9] = 76, + [0][1][0][0][RTW89_CN][9] = 44, + [0][1][0][0][RTW89_QATAR][9] = 44, + [0][1][0][0][RTW89_FCC][10] = 62, + [0][1][0][0][RTW89_ETSI][10] = 44, + [0][1][0][0][RTW89_MKK][10] = 56, + [0][1][0][0][RTW89_IC][10] = 62, + [0][1][0][0][RTW89_KCC][10] = 68, + [0][1][0][0][RTW89_ACMA][10] = 44, + [0][1][0][0][RTW89_CHILE][10] = 48, + [0][1][0][0][RTW89_UKRAINE][10] = 44, + [0][1][0][0][RTW89_MEXICO][10] = 62, + [0][1][0][0][RTW89_CN][10] = 44, + [0][1][0][0][RTW89_QATAR][10] = 44, + [0][1][0][0][RTW89_FCC][11] = 52, + [0][1][0][0][RTW89_ETSI][11] = 44, + [0][1][0][0][RTW89_MKK][11] = 56, + [0][1][0][0][RTW89_IC][11] = 52, + [0][1][0][0][RTW89_KCC][11] = 68, + [0][1][0][0][RTW89_ACMA][11] = 44, + [0][1][0][0][RTW89_CHILE][11] = 48, + [0][1][0][0][RTW89_UKRAINE][11] = 44, + [0][1][0][0][RTW89_MEXICO][11] = 52, + [0][1][0][0][RTW89_CN][11] = 44, + [0][1][0][0][RTW89_QATAR][11] = 44, + [0][1][0][0][RTW89_FCC][12] = 38, + [0][1][0][0][RTW89_ETSI][12] = 44, + [0][1][0][0][RTW89_MKK][12] = 56, + [0][1][0][0][RTW89_IC][12] = 38, + [0][1][0][0][RTW89_KCC][12] = 68, + [0][1][0][0][RTW89_ACMA][12] = 44, + [0][1][0][0][RTW89_CHILE][12] = 38, + [0][1][0][0][RTW89_UKRAINE][12] = 44, + [0][1][0][0][RTW89_MEXICO][12] = 38, + [0][1][0][0][RTW89_CN][12] = 44, + [0][1][0][0][RTW89_QATAR][12] = 44, + [0][1][0][0][RTW89_FCC][13] = 127, + [0][1][0][0][RTW89_ETSI][13] = 127, + [0][1][0][0][RTW89_MKK][13] = 64, + [0][1][0][0][RTW89_IC][13] = 127, + [0][1][0][0][RTW89_KCC][13] = 127, + [0][1][0][0][RTW89_ACMA][13] = 127, + [0][1][0][0][RTW89_CHILE][13] = 127, + [0][1][0][0][RTW89_UKRAINE][13] = 127, + [0][1][0][0][RTW89_MEXICO][13] = 127, + [0][1][0][0][RTW89_CN][13] = 127, + [0][1][0][0][RTW89_QATAR][13] = 127, + [1][0][0][0][RTW89_FCC][0] = 127, + [1][0][0][0][RTW89_ETSI][0] = 127, + [1][0][0][0][RTW89_MKK][0] = 127, + [1][0][0][0][RTW89_IC][0] = 127, + [1][0][0][0][RTW89_KCC][0] = 127, + [1][0][0][0][RTW89_ACMA][0] = 127, + [1][0][0][0][RTW89_CHILE][0] = 127, + [1][0][0][0][RTW89_UKRAINE][0] = 127, + [1][0][0][0][RTW89_MEXICO][0] = 127, + [1][0][0][0][RTW89_CN][0] = 127, + [1][0][0][0][RTW89_QATAR][0] = 127, + [1][0][0][0][RTW89_FCC][1] = 127, + [1][0][0][0][RTW89_ETSI][1] = 127, + [1][0][0][0][RTW89_MKK][1] = 127, + [1][0][0][0][RTW89_IC][1] = 127, + [1][0][0][0][RTW89_KCC][1] = 127, + [1][0][0][0][RTW89_ACMA][1] = 127, + [1][0][0][0][RTW89_CHILE][1] = 127, + [1][0][0][0][RTW89_UKRAINE][1] = 127, + [1][0][0][0][RTW89_MEXICO][1] = 127, + [1][0][0][0][RTW89_CN][1] = 127, + [1][0][0][0][RTW89_QATAR][1] = 127, + [1][0][0][0][RTW89_FCC][2] = 60, + [1][0][0][0][RTW89_ETSI][2] = 58, + [1][0][0][0][RTW89_MKK][2] = 68, + [1][0][0][0][RTW89_IC][2] = 60, + [1][0][0][0][RTW89_KCC][2] = 70, + [1][0][0][0][RTW89_ACMA][2] = 58, + [1][0][0][0][RTW89_CHILE][2] = 60, + [1][0][0][0][RTW89_UKRAINE][2] = 58, + [1][0][0][0][RTW89_MEXICO][2] = 60, + [1][0][0][0][RTW89_CN][2] = 58, + [1][0][0][0][RTW89_QATAR][2] = 58, + [1][0][0][0][RTW89_FCC][3] = 60, + [1][0][0][0][RTW89_ETSI][3] = 58, + [1][0][0][0][RTW89_MKK][3] = 68, + [1][0][0][0][RTW89_IC][3] = 60, + [1][0][0][0][RTW89_KCC][3] = 70, + [1][0][0][0][RTW89_ACMA][3] = 58, + [1][0][0][0][RTW89_CHILE][3] = 60, + [1][0][0][0][RTW89_UKRAINE][3] = 58, + [1][0][0][0][RTW89_MEXICO][3] = 60, + [1][0][0][0][RTW89_CN][3] = 58, + [1][0][0][0][RTW89_QATAR][3] = 58, + [1][0][0][0][RTW89_FCC][4] = 60, + [1][0][0][0][RTW89_ETSI][4] = 58, + [1][0][0][0][RTW89_MKK][4] = 68, + [1][0][0][0][RTW89_IC][4] = 60, + [1][0][0][0][RTW89_KCC][4] = 70, + [1][0][0][0][RTW89_ACMA][4] = 58, + [1][0][0][0][RTW89_CHILE][4] = 60, + [1][0][0][0][RTW89_UKRAINE][4] = 58, + [1][0][0][0][RTW89_MEXICO][4] = 60, + [1][0][0][0][RTW89_CN][4] = 58, + [1][0][0][0][RTW89_QATAR][4] = 58, + [1][0][0][0][RTW89_FCC][5] = 60, + [1][0][0][0][RTW89_ETSI][5] = 58, + [1][0][0][0][RTW89_MKK][5] = 68, + [1][0][0][0][RTW89_IC][5] = 60, + [1][0][0][0][RTW89_KCC][5] = 70, + [1][0][0][0][RTW89_ACMA][5] = 58, + [1][0][0][0][RTW89_CHILE][5] = 60, + [1][0][0][0][RTW89_UKRAINE][5] = 58, + [1][0][0][0][RTW89_MEXICO][5] = 60, + [1][0][0][0][RTW89_CN][5] = 58, + [1][0][0][0][RTW89_QATAR][5] = 58, + [1][0][0][0][RTW89_FCC][6] = 46, + [1][0][0][0][RTW89_ETSI][6] = 58, + [1][0][0][0][RTW89_MKK][6] = 68, + [1][0][0][0][RTW89_IC][6] = 46, + [1][0][0][0][RTW89_KCC][6] = 70, + [1][0][0][0][RTW89_ACMA][6] = 58, + [1][0][0][0][RTW89_CHILE][6] = 46, + [1][0][0][0][RTW89_UKRAINE][6] = 58, + [1][0][0][0][RTW89_MEXICO][6] = 46, + [1][0][0][0][RTW89_CN][6] = 58, + [1][0][0][0][RTW89_QATAR][6] = 58, + [1][0][0][0][RTW89_FCC][7] = 46, + [1][0][0][0][RTW89_ETSI][7] = 58, + [1][0][0][0][RTW89_MKK][7] = 68, + [1][0][0][0][RTW89_IC][7] = 46, + [1][0][0][0][RTW89_KCC][7] = 70, + [1][0][0][0][RTW89_ACMA][7] = 58, + [1][0][0][0][RTW89_CHILE][7] = 46, + [1][0][0][0][RTW89_UKRAINE][7] = 58, + [1][0][0][0][RTW89_MEXICO][7] = 46, + [1][0][0][0][RTW89_CN][7] = 58, + [1][0][0][0][RTW89_QATAR][7] = 58, + [1][0][0][0][RTW89_FCC][8] = 46, + [1][0][0][0][RTW89_ETSI][8] = 58, + [1][0][0][0][RTW89_MKK][8] = 68, + [1][0][0][0][RTW89_IC][8] = 46, + [1][0][0][0][RTW89_KCC][8] = 70, + [1][0][0][0][RTW89_ACMA][8] = 58, + [1][0][0][0][RTW89_CHILE][8] = 46, + [1][0][0][0][RTW89_UKRAINE][8] = 58, + [1][0][0][0][RTW89_MEXICO][8] = 46, + [1][0][0][0][RTW89_CN][8] = 58, + [1][0][0][0][RTW89_QATAR][8] = 58, + [1][0][0][0][RTW89_FCC][9] = 32, + [1][0][0][0][RTW89_ETSI][9] = 58, + [1][0][0][0][RTW89_MKK][9] = 68, + [1][0][0][0][RTW89_IC][9] = 32, + [1][0][0][0][RTW89_KCC][9] = 70, + [1][0][0][0][RTW89_ACMA][9] = 58, + [1][0][0][0][RTW89_CHILE][9] = 32, + [1][0][0][0][RTW89_UKRAINE][9] = 58, + [1][0][0][0][RTW89_MEXICO][9] = 32, + [1][0][0][0][RTW89_CN][9] = 58, + [1][0][0][0][RTW89_QATAR][9] = 58, + [1][0][0][0][RTW89_FCC][10] = 32, + [1][0][0][0][RTW89_ETSI][10] = 58, + [1][0][0][0][RTW89_MKK][10] = 68, + [1][0][0][0][RTW89_IC][10] = 32, + [1][0][0][0][RTW89_KCC][10] = 70, + [1][0][0][0][RTW89_ACMA][10] = 58, + [1][0][0][0][RTW89_CHILE][10] = 32, + [1][0][0][0][RTW89_UKRAINE][10] = 58, + [1][0][0][0][RTW89_MEXICO][10] = 32, + [1][0][0][0][RTW89_CN][10] = 58, + [1][0][0][0][RTW89_QATAR][10] = 58, + [1][0][0][0][RTW89_FCC][11] = 127, + [1][0][0][0][RTW89_ETSI][11] = 127, + [1][0][0][0][RTW89_MKK][11] = 127, + [1][0][0][0][RTW89_IC][11] = 127, + [1][0][0][0][RTW89_KCC][11] = 127, + [1][0][0][0][RTW89_ACMA][11] = 127, + [1][0][0][0][RTW89_CHILE][11] = 127, + [1][0][0][0][RTW89_UKRAINE][11] = 127, + [1][0][0][0][RTW89_MEXICO][11] = 127, + [1][0][0][0][RTW89_CN][11] = 127, + [1][0][0][0][RTW89_QATAR][11] = 127, + [1][0][0][0][RTW89_FCC][12] = 127, + [1][0][0][0][RTW89_ETSI][12] = 127, + [1][0][0][0][RTW89_MKK][12] = 127, + [1][0][0][0][RTW89_IC][12] = 127, + [1][0][0][0][RTW89_KCC][12] = 127, + [1][0][0][0][RTW89_ACMA][12] = 127, + [1][0][0][0][RTW89_CHILE][12] = 127, + [1][0][0][0][RTW89_UKRAINE][12] = 127, + [1][0][0][0][RTW89_MEXICO][12] = 127, + [1][0][0][0][RTW89_CN][12] = 127, + [1][0][0][0][RTW89_QATAR][12] = 127, + [1][0][0][0][RTW89_FCC][13] = 127, + [1][0][0][0][RTW89_ETSI][13] = 127, + [1][0][0][0][RTW89_MKK][13] = 127, + [1][0][0][0][RTW89_IC][13] = 127, + [1][0][0][0][RTW89_KCC][13] = 127, + [1][0][0][0][RTW89_ACMA][13] = 127, + [1][0][0][0][RTW89_CHILE][13] = 127, + [1][0][0][0][RTW89_UKRAINE][13] = 127, + [1][0][0][0][RTW89_MEXICO][13] = 127, + [1][0][0][0][RTW89_CN][13] = 127, + [1][0][0][0][RTW89_QATAR][13] = 127, + [1][1][0][0][RTW89_FCC][0] = 127, + [1][1][0][0][RTW89_ETSI][0] = 127, + [1][1][0][0][RTW89_MKK][0] = 127, + [1][1][0][0][RTW89_IC][0] = 127, + [1][1][0][0][RTW89_KCC][0] = 127, + [1][1][0][0][RTW89_ACMA][0] = 127, + [1][1][0][0][RTW89_CHILE][0] = 127, + [1][1][0][0][RTW89_UKRAINE][0] = 127, + [1][1][0][0][RTW89_MEXICO][0] = 127, + [1][1][0][0][RTW89_CN][0] = 127, + [1][1][0][0][RTW89_QATAR][0] = 127, + [1][1][0][0][RTW89_FCC][1] = 127, + [1][1][0][0][RTW89_ETSI][1] = 127, + [1][1][0][0][RTW89_MKK][1] = 127, + [1][1][0][0][RTW89_IC][1] = 127, + [1][1][0][0][RTW89_KCC][1] = 127, + [1][1][0][0][RTW89_ACMA][1] = 127, + [1][1][0][0][RTW89_CHILE][1] = 127, + [1][1][0][0][RTW89_UKRAINE][1] = 127, + [1][1][0][0][RTW89_MEXICO][1] = 127, + [1][1][0][0][RTW89_CN][1] = 127, + [1][1][0][0][RTW89_QATAR][1] = 127, + [1][1][0][0][RTW89_FCC][2] = 48, + [1][1][0][0][RTW89_ETSI][2] = 46, + [1][1][0][0][RTW89_MKK][2] = 56, + [1][1][0][0][RTW89_IC][2] = 48, + [1][1][0][0][RTW89_KCC][2] = 58, + [1][1][0][0][RTW89_ACMA][2] = 46, + [1][1][0][0][RTW89_CHILE][2] = 48, + [1][1][0][0][RTW89_UKRAINE][2] = 46, + [1][1][0][0][RTW89_MEXICO][2] = 48, + [1][1][0][0][RTW89_CN][2] = 46, + [1][1][0][0][RTW89_QATAR][2] = 46, + [1][1][0][0][RTW89_FCC][3] = 48, + [1][1][0][0][RTW89_ETSI][3] = 46, + [1][1][0][0][RTW89_MKK][3] = 56, + [1][1][0][0][RTW89_IC][3] = 48, + [1][1][0][0][RTW89_KCC][3] = 58, + [1][1][0][0][RTW89_ACMA][3] = 46, + [1][1][0][0][RTW89_CHILE][3] = 48, + [1][1][0][0][RTW89_UKRAINE][3] = 46, + [1][1][0][0][RTW89_MEXICO][3] = 48, + [1][1][0][0][RTW89_CN][3] = 46, + [1][1][0][0][RTW89_QATAR][3] = 46, + [1][1][0][0][RTW89_FCC][4] = 48, + [1][1][0][0][RTW89_ETSI][4] = 46, + [1][1][0][0][RTW89_MKK][4] = 56, + [1][1][0][0][RTW89_IC][4] = 48, + [1][1][0][0][RTW89_KCC][4] = 58, + [1][1][0][0][RTW89_ACMA][4] = 46, + [1][1][0][0][RTW89_CHILE][4] = 48, + [1][1][0][0][RTW89_UKRAINE][4] = 46, + [1][1][0][0][RTW89_MEXICO][4] = 48, + [1][1][0][0][RTW89_CN][4] = 46, + [1][1][0][0][RTW89_QATAR][4] = 46, + [1][1][0][0][RTW89_FCC][5] = 58, + [1][1][0][0][RTW89_ETSI][5] = 46, + [1][1][0][0][RTW89_MKK][5] = 56, + [1][1][0][0][RTW89_IC][5] = 58, + [1][1][0][0][RTW89_KCC][5] = 58, + [1][1][0][0][RTW89_ACMA][5] = 46, + [1][1][0][0][RTW89_CHILE][5] = 48, + [1][1][0][0][RTW89_UKRAINE][5] = 46, + [1][1][0][0][RTW89_MEXICO][5] = 58, + [1][1][0][0][RTW89_CN][5] = 46, + [1][1][0][0][RTW89_QATAR][5] = 46, + [1][1][0][0][RTW89_FCC][6] = 46, + [1][1][0][0][RTW89_ETSI][6] = 46, + [1][1][0][0][RTW89_MKK][6] = 56, + [1][1][0][0][RTW89_IC][6] = 46, + [1][1][0][0][RTW89_KCC][6] = 58, + [1][1][0][0][RTW89_ACMA][6] = 46, + [1][1][0][0][RTW89_CHILE][6] = 46, + [1][1][0][0][RTW89_UKRAINE][6] = 46, + [1][1][0][0][RTW89_MEXICO][6] = 46, + [1][1][0][0][RTW89_CN][6] = 46, + [1][1][0][0][RTW89_QATAR][6] = 46, + [1][1][0][0][RTW89_FCC][7] = 46, + [1][1][0][0][RTW89_ETSI][7] = 46, + [1][1][0][0][RTW89_MKK][7] = 56, + [1][1][0][0][RTW89_IC][7] = 46, + [1][1][0][0][RTW89_KCC][7] = 58, + [1][1][0][0][RTW89_ACMA][7] = 46, + [1][1][0][0][RTW89_CHILE][7] = 46, + [1][1][0][0][RTW89_UKRAINE][7] = 46, + [1][1][0][0][RTW89_MEXICO][7] = 46, + [1][1][0][0][RTW89_CN][7] = 46, + [1][1][0][0][RTW89_QATAR][7] = 46, + [1][1][0][0][RTW89_FCC][8] = 46, + [1][1][0][0][RTW89_ETSI][8] = 46, + [1][1][0][0][RTW89_MKK][8] = 56, + [1][1][0][0][RTW89_IC][8] = 46, + [1][1][0][0][RTW89_KCC][8] = 58, + [1][1][0][0][RTW89_ACMA][8] = 46, + [1][1][0][0][RTW89_CHILE][8] = 46, + [1][1][0][0][RTW89_UKRAINE][8] = 46, + [1][1][0][0][RTW89_MEXICO][8] = 46, + [1][1][0][0][RTW89_CN][8] = 46, + [1][1][0][0][RTW89_QATAR][8] = 46, + [1][1][0][0][RTW89_FCC][9] = 24, + [1][1][0][0][RTW89_ETSI][9] = 46, + [1][1][0][0][RTW89_MKK][9] = 56, + [1][1][0][0][RTW89_IC][9] = 24, + [1][1][0][0][RTW89_KCC][9] = 58, + [1][1][0][0][RTW89_ACMA][9] = 46, + [1][1][0][0][RTW89_CHILE][9] = 24, + [1][1][0][0][RTW89_UKRAINE][9] = 46, + [1][1][0][0][RTW89_MEXICO][9] = 24, + [1][1][0][0][RTW89_CN][9] = 46, + [1][1][0][0][RTW89_QATAR][9] = 46, + [1][1][0][0][RTW89_FCC][10] = 24, + [1][1][0][0][RTW89_ETSI][10] = 46, + [1][1][0][0][RTW89_MKK][10] = 56, + [1][1][0][0][RTW89_IC][10] = 24, + [1][1][0][0][RTW89_KCC][10] = 58, + [1][1][0][0][RTW89_ACMA][10] = 46, + [1][1][0][0][RTW89_CHILE][10] = 24, + [1][1][0][0][RTW89_UKRAINE][10] = 46, + [1][1][0][0][RTW89_MEXICO][10] = 24, + [1][1][0][0][RTW89_CN][10] = 46, + [1][1][0][0][RTW89_QATAR][10] = 46, + [1][1][0][0][RTW89_FCC][11] = 127, + [1][1][0][0][RTW89_ETSI][11] = 127, + [1][1][0][0][RTW89_MKK][11] = 127, + [1][1][0][0][RTW89_IC][11] = 127, + [1][1][0][0][RTW89_KCC][11] = 127, + [1][1][0][0][RTW89_ACMA][11] = 127, + [1][1][0][0][RTW89_CHILE][11] = 127, + [1][1][0][0][RTW89_UKRAINE][11] = 127, + [1][1][0][0][RTW89_MEXICO][11] = 127, + [1][1][0][0][RTW89_CN][11] = 127, + [1][1][0][0][RTW89_QATAR][11] = 127, + [1][1][0][0][RTW89_FCC][12] = 127, + [1][1][0][0][RTW89_ETSI][12] = 127, + [1][1][0][0][RTW89_MKK][12] = 127, + [1][1][0][0][RTW89_IC][12] = 127, + [1][1][0][0][RTW89_KCC][12] = 127, + [1][1][0][0][RTW89_ACMA][12] = 127, + [1][1][0][0][RTW89_CHILE][12] = 127, + [1][1][0][0][RTW89_UKRAINE][12] = 127, + [1][1][0][0][RTW89_MEXICO][12] = 127, + [1][1][0][0][RTW89_CN][12] = 127, + [1][1][0][0][RTW89_QATAR][12] = 127, + [1][1][0][0][RTW89_FCC][13] = 127, + [1][1][0][0][RTW89_ETSI][13] = 127, + [1][1][0][0][RTW89_MKK][13] = 127, + [1][1][0][0][RTW89_IC][13] = 127, + [1][1][0][0][RTW89_KCC][13] = 127, + [1][1][0][0][RTW89_ACMA][13] = 127, + [1][1][0][0][RTW89_CHILE][13] = 127, + [1][1][0][0][RTW89_UKRAINE][13] = 127, + [1][1][0][0][RTW89_MEXICO][13] = 127, + [1][1][0][0][RTW89_CN][13] = 127, + [1][1][0][0][RTW89_QATAR][13] = 127, + [0][0][1][0][RTW89_FCC][0] = 66, + [0][0][1][0][RTW89_ETSI][0] = 58, + [0][0][1][0][RTW89_MKK][0] = 76, + [0][0][1][0][RTW89_IC][0] = 66, + [0][0][1][0][RTW89_KCC][0] = 76, + [0][0][1][0][RTW89_ACMA][0] = 58, + [0][0][1][0][RTW89_CHILE][0] = 60, + [0][0][1][0][RTW89_UKRAINE][0] = 58, + [0][0][1][0][RTW89_MEXICO][0] = 66, + [0][0][1][0][RTW89_CN][0] = 58, + [0][0][1][0][RTW89_QATAR][0] = 58, + [0][0][1][0][RTW89_FCC][1] = 66, + [0][0][1][0][RTW89_ETSI][1] = 58, + [0][0][1][0][RTW89_MKK][1] = 76, + [0][0][1][0][RTW89_IC][1] = 66, + [0][0][1][0][RTW89_KCC][1] = 76, + [0][0][1][0][RTW89_ACMA][1] = 58, + [0][0][1][0][RTW89_CHILE][1] = 60, + [0][0][1][0][RTW89_UKRAINE][1] = 58, + [0][0][1][0][RTW89_MEXICO][1] = 66, + [0][0][1][0][RTW89_CN][1] = 58, + [0][0][1][0][RTW89_QATAR][1] = 58, + [0][0][1][0][RTW89_FCC][2] = 70, + [0][0][1][0][RTW89_ETSI][2] = 58, + [0][0][1][0][RTW89_MKK][2] = 76, + [0][0][1][0][RTW89_IC][2] = 70, + [0][0][1][0][RTW89_KCC][2] = 76, + [0][0][1][0][RTW89_ACMA][2] = 58, + [0][0][1][0][RTW89_CHILE][2] = 60, + [0][0][1][0][RTW89_UKRAINE][2] = 58, + [0][0][1][0][RTW89_MEXICO][2] = 70, + [0][0][1][0][RTW89_CN][2] = 58, + [0][0][1][0][RTW89_QATAR][2] = 58, + [0][0][1][0][RTW89_FCC][3] = 74, + [0][0][1][0][RTW89_ETSI][3] = 58, + [0][0][1][0][RTW89_MKK][3] = 76, + [0][0][1][0][RTW89_IC][3] = 74, + [0][0][1][0][RTW89_KCC][3] = 76, + [0][0][1][0][RTW89_ACMA][3] = 58, + [0][0][1][0][RTW89_CHILE][3] = 60, + [0][0][1][0][RTW89_UKRAINE][3] = 58, + [0][0][1][0][RTW89_MEXICO][3] = 74, + [0][0][1][0][RTW89_CN][3] = 58, + [0][0][1][0][RTW89_QATAR][3] = 58, + [0][0][1][0][RTW89_FCC][4] = 78, + [0][0][1][0][RTW89_ETSI][4] = 58, + [0][0][1][0][RTW89_MKK][4] = 76, + [0][0][1][0][RTW89_IC][4] = 78, + [0][0][1][0][RTW89_KCC][4] = 76, + [0][0][1][0][RTW89_ACMA][4] = 58, + [0][0][1][0][RTW89_CHILE][4] = 60, + [0][0][1][0][RTW89_UKRAINE][4] = 58, + [0][0][1][0][RTW89_MEXICO][4] = 78, + [0][0][1][0][RTW89_CN][4] = 58, + [0][0][1][0][RTW89_QATAR][4] = 58, + [0][0][1][0][RTW89_FCC][5] = 78, + [0][0][1][0][RTW89_ETSI][5] = 58, + [0][0][1][0][RTW89_MKK][5] = 76, + [0][0][1][0][RTW89_IC][5] = 78, + [0][0][1][0][RTW89_KCC][5] = 76, + [0][0][1][0][RTW89_ACMA][5] = 58, + [0][0][1][0][RTW89_CHILE][5] = 60, + [0][0][1][0][RTW89_UKRAINE][5] = 58, + [0][0][1][0][RTW89_MEXICO][5] = 78, + [0][0][1][0][RTW89_CN][5] = 58, + [0][0][1][0][RTW89_QATAR][5] = 58, + [0][0][1][0][RTW89_FCC][6] = 78, + [0][0][1][0][RTW89_ETSI][6] = 58, + [0][0][1][0][RTW89_MKK][6] = 76, + [0][0][1][0][RTW89_IC][6] = 78, + [0][0][1][0][RTW89_KCC][6] = 76, + [0][0][1][0][RTW89_ACMA][6] = 58, + [0][0][1][0][RTW89_CHILE][6] = 60, + [0][0][1][0][RTW89_UKRAINE][6] = 58, + [0][0][1][0][RTW89_MEXICO][6] = 78, + [0][0][1][0][RTW89_CN][6] = 58, + [0][0][1][0][RTW89_QATAR][6] = 58, + [0][0][1][0][RTW89_FCC][7] = 74, + [0][0][1][0][RTW89_ETSI][7] = 58, + [0][0][1][0][RTW89_MKK][7] = 76, + [0][0][1][0][RTW89_IC][7] = 74, + [0][0][1][0][RTW89_KCC][7] = 76, + [0][0][1][0][RTW89_ACMA][7] = 58, + [0][0][1][0][RTW89_CHILE][7] = 60, + [0][0][1][0][RTW89_UKRAINE][7] = 58, + [0][0][1][0][RTW89_MEXICO][7] = 74, + [0][0][1][0][RTW89_CN][7] = 58, + [0][0][1][0][RTW89_QATAR][7] = 58, + [0][0][1][0][RTW89_FCC][8] = 70, + [0][0][1][0][RTW89_ETSI][8] = 58, + [0][0][1][0][RTW89_MKK][8] = 76, + [0][0][1][0][RTW89_IC][8] = 70, + [0][0][1][0][RTW89_KCC][8] = 76, + [0][0][1][0][RTW89_ACMA][8] = 58, + [0][0][1][0][RTW89_CHILE][8] = 60, + [0][0][1][0][RTW89_UKRAINE][8] = 58, + [0][0][1][0][RTW89_MEXICO][8] = 70, + [0][0][1][0][RTW89_CN][8] = 58, + [0][0][1][0][RTW89_QATAR][8] = 58, + [0][0][1][0][RTW89_FCC][9] = 66, + [0][0][1][0][RTW89_ETSI][9] = 58, + [0][0][1][0][RTW89_MKK][9] = 76, + [0][0][1][0][RTW89_IC][9] = 66, + [0][0][1][0][RTW89_KCC][9] = 76, + [0][0][1][0][RTW89_ACMA][9] = 58, + [0][0][1][0][RTW89_CHILE][9] = 60, + [0][0][1][0][RTW89_UKRAINE][9] = 58, + [0][0][1][0][RTW89_MEXICO][9] = 66, + [0][0][1][0][RTW89_CN][9] = 58, + [0][0][1][0][RTW89_QATAR][9] = 58, + [0][0][1][0][RTW89_FCC][10] = 66, + [0][0][1][0][RTW89_ETSI][10] = 58, + [0][0][1][0][RTW89_MKK][10] = 76, + [0][0][1][0][RTW89_IC][10] = 66, + [0][0][1][0][RTW89_KCC][10] = 76, + [0][0][1][0][RTW89_ACMA][10] = 58, + [0][0][1][0][RTW89_CHILE][10] = 60, + [0][0][1][0][RTW89_UKRAINE][10] = 58, + [0][0][1][0][RTW89_MEXICO][10] = 66, + [0][0][1][0][RTW89_CN][10] = 58, + [0][0][1][0][RTW89_QATAR][10] = 58, + [0][0][1][0][RTW89_FCC][11] = 56, + [0][0][1][0][RTW89_ETSI][11] = 58, + [0][0][1][0][RTW89_MKK][11] = 76, + [0][0][1][0][RTW89_IC][11] = 56, + [0][0][1][0][RTW89_KCC][11] = 76, + [0][0][1][0][RTW89_ACMA][11] = 58, + [0][0][1][0][RTW89_CHILE][11] = 56, + [0][0][1][0][RTW89_UKRAINE][11] = 58, + [0][0][1][0][RTW89_MEXICO][11] = 56, + [0][0][1][0][RTW89_CN][11] = 58, + [0][0][1][0][RTW89_QATAR][11] = 58, + [0][0][1][0][RTW89_FCC][12] = 52, + [0][0][1][0][RTW89_ETSI][12] = 58, + [0][0][1][0][RTW89_MKK][12] = 76, + [0][0][1][0][RTW89_IC][12] = 52, + [0][0][1][0][RTW89_KCC][12] = 76, + [0][0][1][0][RTW89_ACMA][12] = 58, + [0][0][1][0][RTW89_CHILE][12] = 52, + [0][0][1][0][RTW89_UKRAINE][12] = 58, + [0][0][1][0][RTW89_MEXICO][12] = 52, + [0][0][1][0][RTW89_CN][12] = 58, + [0][0][1][0][RTW89_QATAR][12] = 58, + [0][0][1][0][RTW89_FCC][13] = 127, + [0][0][1][0][RTW89_ETSI][13] = 127, + [0][0][1][0][RTW89_MKK][13] = 127, + [0][0][1][0][RTW89_IC][13] = 127, + [0][0][1][0][RTW89_KCC][13] = 127, + [0][0][1][0][RTW89_ACMA][13] = 127, + [0][0][1][0][RTW89_CHILE][13] = 127, + [0][0][1][0][RTW89_UKRAINE][13] = 127, + [0][0][1][0][RTW89_MEXICO][13] = 127, + [0][0][1][0][RTW89_CN][13] = 127, + [0][0][1][0][RTW89_QATAR][13] = 127, + [0][1][1][0][RTW89_FCC][0] = 62, + [0][1][1][0][RTW89_ETSI][0] = 46, + [0][1][1][0][RTW89_MKK][0] = 64, + [0][1][1][0][RTW89_IC][0] = 62, + [0][1][1][0][RTW89_KCC][0] = 70, + [0][1][1][0][RTW89_ACMA][0] = 46, + [0][1][1][0][RTW89_CHILE][0] = 48, + [0][1][1][0][RTW89_UKRAINE][0] = 46, + [0][1][1][0][RTW89_MEXICO][0] = 62, + [0][1][1][0][RTW89_CN][0] = 46, + [0][1][1][0][RTW89_QATAR][0] = 46, + [0][1][1][0][RTW89_FCC][1] = 62, + [0][1][1][0][RTW89_ETSI][1] = 46, + [0][1][1][0][RTW89_MKK][1] = 64, + [0][1][1][0][RTW89_IC][1] = 62, + [0][1][1][0][RTW89_KCC][1] = 70, + [0][1][1][0][RTW89_ACMA][1] = 46, + [0][1][1][0][RTW89_CHILE][1] = 48, + [0][1][1][0][RTW89_UKRAINE][1] = 46, + [0][1][1][0][RTW89_MEXICO][1] = 62, + [0][1][1][0][RTW89_CN][1] = 46, + [0][1][1][0][RTW89_QATAR][1] = 46, + [0][1][1][0][RTW89_FCC][2] = 66, + [0][1][1][0][RTW89_ETSI][2] = 46, + [0][1][1][0][RTW89_MKK][2] = 64, + [0][1][1][0][RTW89_IC][2] = 66, + [0][1][1][0][RTW89_KCC][2] = 70, + [0][1][1][0][RTW89_ACMA][2] = 46, + [0][1][1][0][RTW89_CHILE][2] = 48, + [0][1][1][0][RTW89_UKRAINE][2] = 46, + [0][1][1][0][RTW89_MEXICO][2] = 66, + [0][1][1][0][RTW89_CN][2] = 46, + [0][1][1][0][RTW89_QATAR][2] = 46, + [0][1][1][0][RTW89_FCC][3] = 70, + [0][1][1][0][RTW89_ETSI][3] = 46, + [0][1][1][0][RTW89_MKK][3] = 64, + [0][1][1][0][RTW89_IC][3] = 70, + [0][1][1][0][RTW89_KCC][3] = 70, + [0][1][1][0][RTW89_ACMA][3] = 46, + [0][1][1][0][RTW89_CHILE][3] = 48, + [0][1][1][0][RTW89_UKRAINE][3] = 46, + [0][1][1][0][RTW89_MEXICO][3] = 70, + [0][1][1][0][RTW89_CN][3] = 46, + [0][1][1][0][RTW89_QATAR][3] = 46, + [0][1][1][0][RTW89_FCC][4] = 78, + [0][1][1][0][RTW89_ETSI][4] = 46, + [0][1][1][0][RTW89_MKK][4] = 64, + [0][1][1][0][RTW89_IC][4] = 78, + [0][1][1][0][RTW89_KCC][4] = 70, + [0][1][1][0][RTW89_ACMA][4] = 46, + [0][1][1][0][RTW89_CHILE][4] = 48, + [0][1][1][0][RTW89_UKRAINE][4] = 46, + [0][1][1][0][RTW89_MEXICO][4] = 78, + [0][1][1][0][RTW89_CN][4] = 46, + [0][1][1][0][RTW89_QATAR][4] = 46, + [0][1][1][0][RTW89_FCC][5] = 78, + [0][1][1][0][RTW89_ETSI][5] = 46, + [0][1][1][0][RTW89_MKK][5] = 64, + [0][1][1][0][RTW89_IC][5] = 78, + [0][1][1][0][RTW89_KCC][5] = 70, + [0][1][1][0][RTW89_ACMA][5] = 46, + [0][1][1][0][RTW89_CHILE][5] = 48, + [0][1][1][0][RTW89_UKRAINE][5] = 46, + [0][1][1][0][RTW89_MEXICO][5] = 78, + [0][1][1][0][RTW89_CN][5] = 46, + [0][1][1][0][RTW89_QATAR][5] = 46, + [0][1][1][0][RTW89_FCC][6] = 78, + [0][1][1][0][RTW89_ETSI][6] = 46, + [0][1][1][0][RTW89_MKK][6] = 64, + [0][1][1][0][RTW89_IC][6] = 78, + [0][1][1][0][RTW89_KCC][6] = 70, + [0][1][1][0][RTW89_ACMA][6] = 46, + [0][1][1][0][RTW89_CHILE][6] = 48, + [0][1][1][0][RTW89_UKRAINE][6] = 46, + [0][1][1][0][RTW89_MEXICO][6] = 78, + [0][1][1][0][RTW89_CN][6] = 46, + [0][1][1][0][RTW89_QATAR][6] = 46, + [0][1][1][0][RTW89_FCC][7] = 70, + [0][1][1][0][RTW89_ETSI][7] = 46, + [0][1][1][0][RTW89_MKK][7] = 64, + [0][1][1][0][RTW89_IC][7] = 70, + [0][1][1][0][RTW89_KCC][7] = 70, + [0][1][1][0][RTW89_ACMA][7] = 46, + [0][1][1][0][RTW89_CHILE][7] = 48, + [0][1][1][0][RTW89_UKRAINE][7] = 46, + [0][1][1][0][RTW89_MEXICO][7] = 70, + [0][1][1][0][RTW89_CN][7] = 46, + [0][1][1][0][RTW89_QATAR][7] = 46, + [0][1][1][0][RTW89_FCC][8] = 66, + [0][1][1][0][RTW89_ETSI][8] = 46, + [0][1][1][0][RTW89_MKK][8] = 64, + [0][1][1][0][RTW89_IC][8] = 66, + [0][1][1][0][RTW89_KCC][8] = 70, + [0][1][1][0][RTW89_ACMA][8] = 46, + [0][1][1][0][RTW89_CHILE][8] = 48, + [0][1][1][0][RTW89_UKRAINE][8] = 46, + [0][1][1][0][RTW89_MEXICO][8] = 66, + [0][1][1][0][RTW89_CN][8] = 46, + [0][1][1][0][RTW89_QATAR][8] = 46, + [0][1][1][0][RTW89_FCC][9] = 62, + [0][1][1][0][RTW89_ETSI][9] = 46, + [0][1][1][0][RTW89_MKK][9] = 64, + [0][1][1][0][RTW89_IC][9] = 62, + [0][1][1][0][RTW89_KCC][9] = 70, + [0][1][1][0][RTW89_ACMA][9] = 46, + [0][1][1][0][RTW89_CHILE][9] = 48, + [0][1][1][0][RTW89_UKRAINE][9] = 46, + [0][1][1][0][RTW89_MEXICO][9] = 62, + [0][1][1][0][RTW89_CN][9] = 46, + [0][1][1][0][RTW89_QATAR][9] = 46, + [0][1][1][0][RTW89_FCC][10] = 62, + [0][1][1][0][RTW89_ETSI][10] = 46, + [0][1][1][0][RTW89_MKK][10] = 64, + [0][1][1][0][RTW89_IC][10] = 62, + [0][1][1][0][RTW89_KCC][10] = 70, + [0][1][1][0][RTW89_ACMA][10] = 46, + [0][1][1][0][RTW89_CHILE][10] = 48, + [0][1][1][0][RTW89_UKRAINE][10] = 46, + [0][1][1][0][RTW89_MEXICO][10] = 62, + [0][1][1][0][RTW89_CN][10] = 46, + [0][1][1][0][RTW89_QATAR][10] = 46, + [0][1][1][0][RTW89_FCC][11] = 42, + [0][1][1][0][RTW89_ETSI][11] = 46, + [0][1][1][0][RTW89_MKK][11] = 64, + [0][1][1][0][RTW89_IC][11] = 42, + [0][1][1][0][RTW89_KCC][11] = 70, + [0][1][1][0][RTW89_ACMA][11] = 46, + [0][1][1][0][RTW89_CHILE][11] = 42, + [0][1][1][0][RTW89_UKRAINE][11] = 46, + [0][1][1][0][RTW89_MEXICO][11] = 42, + [0][1][1][0][RTW89_CN][11] = 46, + [0][1][1][0][RTW89_QATAR][11] = 46, + [0][1][1][0][RTW89_FCC][12] = 40, + [0][1][1][0][RTW89_ETSI][12] = 46, + [0][1][1][0][RTW89_MKK][12] = 64, + [0][1][1][0][RTW89_IC][12] = 40, + [0][1][1][0][RTW89_KCC][12] = 70, + [0][1][1][0][RTW89_ACMA][12] = 46, + [0][1][1][0][RTW89_CHILE][12] = 40, + [0][1][1][0][RTW89_UKRAINE][12] = 46, + [0][1][1][0][RTW89_MEXICO][12] = 40, + [0][1][1][0][RTW89_CN][12] = 46, + [0][1][1][0][RTW89_QATAR][12] = 46, + [0][1][1][0][RTW89_FCC][13] = 127, + [0][1][1][0][RTW89_ETSI][13] = 127, + [0][1][1][0][RTW89_MKK][13] = 127, + [0][1][1][0][RTW89_IC][13] = 127, + [0][1][1][0][RTW89_KCC][13] = 127, + [0][1][1][0][RTW89_ACMA][13] = 127, + [0][1][1][0][RTW89_CHILE][13] = 127, + [0][1][1][0][RTW89_UKRAINE][13] = 127, + [0][1][1][0][RTW89_MEXICO][13] = 127, + [0][1][1][0][RTW89_CN][13] = 127, + [0][1][1][0][RTW89_QATAR][13] = 127, + [0][0][2][0][RTW89_FCC][0] = 66, + [0][0][2][0][RTW89_ETSI][0] = 58, + [0][0][2][0][RTW89_MKK][0] = 76, + [0][0][2][0][RTW89_IC][0] = 66, + [0][0][2][0][RTW89_KCC][0] = 76, + [0][0][2][0][RTW89_ACMA][0] = 58, + [0][0][2][0][RTW89_CHILE][0] = 60, + [0][0][2][0][RTW89_UKRAINE][0] = 58, + [0][0][2][0][RTW89_MEXICO][0] = 66, + [0][0][2][0][RTW89_CN][0] = 58, + [0][0][2][0][RTW89_QATAR][0] = 58, + [0][0][2][0][RTW89_FCC][1] = 66, + [0][0][2][0][RTW89_ETSI][1] = 58, + [0][0][2][0][RTW89_MKK][1] = 76, + [0][0][2][0][RTW89_IC][1] = 66, + [0][0][2][0][RTW89_KCC][1] = 76, + [0][0][2][0][RTW89_ACMA][1] = 58, + [0][0][2][0][RTW89_CHILE][1] = 60, + [0][0][2][0][RTW89_UKRAINE][1] = 58, + [0][0][2][0][RTW89_MEXICO][1] = 66, + [0][0][2][0][RTW89_CN][1] = 58, + [0][0][2][0][RTW89_QATAR][1] = 58, + [0][0][2][0][RTW89_FCC][2] = 70, + [0][0][2][0][RTW89_ETSI][2] = 58, + [0][0][2][0][RTW89_MKK][2] = 76, + [0][0][2][0][RTW89_IC][2] = 70, + [0][0][2][0][RTW89_KCC][2] = 76, + [0][0][2][0][RTW89_ACMA][2] = 58, + [0][0][2][0][RTW89_CHILE][2] = 60, + [0][0][2][0][RTW89_UKRAINE][2] = 58, + [0][0][2][0][RTW89_MEXICO][2] = 70, + [0][0][2][0][RTW89_CN][2] = 58, + [0][0][2][0][RTW89_QATAR][2] = 58, + [0][0][2][0][RTW89_FCC][3] = 74, + [0][0][2][0][RTW89_ETSI][3] = 58, + [0][0][2][0][RTW89_MKK][3] = 76, + [0][0][2][0][RTW89_IC][3] = 74, + [0][0][2][0][RTW89_KCC][3] = 76, + [0][0][2][0][RTW89_ACMA][3] = 58, + [0][0][2][0][RTW89_CHILE][3] = 60, + [0][0][2][0][RTW89_UKRAINE][3] = 58, + [0][0][2][0][RTW89_MEXICO][3] = 74, + [0][0][2][0][RTW89_CN][3] = 58, + [0][0][2][0][RTW89_QATAR][3] = 58, + [0][0][2][0][RTW89_FCC][4] = 76, + [0][0][2][0][RTW89_ETSI][4] = 58, + [0][0][2][0][RTW89_MKK][4] = 76, + [0][0][2][0][RTW89_IC][4] = 76, + [0][0][2][0][RTW89_KCC][4] = 76, + [0][0][2][0][RTW89_ACMA][4] = 58, + [0][0][2][0][RTW89_CHILE][4] = 60, + [0][0][2][0][RTW89_UKRAINE][4] = 58, + [0][0][2][0][RTW89_MEXICO][4] = 76, + [0][0][2][0][RTW89_CN][4] = 58, + [0][0][2][0][RTW89_QATAR][4] = 58, + [0][0][2][0][RTW89_FCC][5] = 76, + [0][0][2][0][RTW89_ETSI][5] = 58, + [0][0][2][0][RTW89_MKK][5] = 76, + [0][0][2][0][RTW89_IC][5] = 76, + [0][0][2][0][RTW89_KCC][5] = 76, + [0][0][2][0][RTW89_ACMA][5] = 58, + [0][0][2][0][RTW89_CHILE][5] = 60, + [0][0][2][0][RTW89_UKRAINE][5] = 58, + [0][0][2][0][RTW89_MEXICO][5] = 76, + [0][0][2][0][RTW89_CN][5] = 58, + [0][0][2][0][RTW89_QATAR][5] = 58, + [0][0][2][0][RTW89_FCC][6] = 76, + [0][0][2][0][RTW89_ETSI][6] = 58, + [0][0][2][0][RTW89_MKK][6] = 76, + [0][0][2][0][RTW89_IC][6] = 76, + [0][0][2][0][RTW89_KCC][6] = 76, + [0][0][2][0][RTW89_ACMA][6] = 58, + [0][0][2][0][RTW89_CHILE][6] = 60, + [0][0][2][0][RTW89_UKRAINE][6] = 58, + [0][0][2][0][RTW89_MEXICO][6] = 76, + [0][0][2][0][RTW89_CN][6] = 58, + [0][0][2][0][RTW89_QATAR][6] = 58, + [0][0][2][0][RTW89_FCC][7] = 74, + [0][0][2][0][RTW89_ETSI][7] = 58, + [0][0][2][0][RTW89_MKK][7] = 76, + [0][0][2][0][RTW89_IC][7] = 74, + [0][0][2][0][RTW89_KCC][7] = 76, + [0][0][2][0][RTW89_ACMA][7] = 58, + [0][0][2][0][RTW89_CHILE][7] = 60, + [0][0][2][0][RTW89_UKRAINE][7] = 58, + [0][0][2][0][RTW89_MEXICO][7] = 74, + [0][0][2][0][RTW89_CN][7] = 58, + [0][0][2][0][RTW89_QATAR][7] = 58, + [0][0][2][0][RTW89_FCC][8] = 70, + [0][0][2][0][RTW89_ETSI][8] = 58, + [0][0][2][0][RTW89_MKK][8] = 76, + [0][0][2][0][RTW89_IC][8] = 70, + [0][0][2][0][RTW89_KCC][8] = 76, + [0][0][2][0][RTW89_ACMA][8] = 58, + [0][0][2][0][RTW89_CHILE][8] = 60, + [0][0][2][0][RTW89_UKRAINE][8] = 58, + [0][0][2][0][RTW89_MEXICO][8] = 70, + [0][0][2][0][RTW89_CN][8] = 58, + [0][0][2][0][RTW89_QATAR][8] = 58, + [0][0][2][0][RTW89_FCC][9] = 66, + [0][0][2][0][RTW89_ETSI][9] = 58, + [0][0][2][0][RTW89_MKK][9] = 76, + [0][0][2][0][RTW89_IC][9] = 66, + [0][0][2][0][RTW89_KCC][9] = 76, + [0][0][2][0][RTW89_ACMA][9] = 58, + [0][0][2][0][RTW89_CHILE][9] = 60, + [0][0][2][0][RTW89_UKRAINE][9] = 58, + [0][0][2][0][RTW89_MEXICO][9] = 66, + [0][0][2][0][RTW89_CN][9] = 58, + [0][0][2][0][RTW89_QATAR][9] = 58, + [0][0][2][0][RTW89_FCC][10] = 66, + [0][0][2][0][RTW89_ETSI][10] = 58, + [0][0][2][0][RTW89_MKK][10] = 76, + [0][0][2][0][RTW89_IC][10] = 66, + [0][0][2][0][RTW89_KCC][10] = 76, + [0][0][2][0][RTW89_ACMA][10] = 58, + [0][0][2][0][RTW89_CHILE][10] = 60, + [0][0][2][0][RTW89_UKRAINE][10] = 58, + [0][0][2][0][RTW89_MEXICO][10] = 66, + [0][0][2][0][RTW89_CN][10] = 58, + [0][0][2][0][RTW89_QATAR][10] = 58, + [0][0][2][0][RTW89_FCC][11] = 54, + [0][0][2][0][RTW89_ETSI][11] = 58, + [0][0][2][0][RTW89_MKK][11] = 76, + [0][0][2][0][RTW89_IC][11] = 54, + [0][0][2][0][RTW89_KCC][11] = 76, + [0][0][2][0][RTW89_ACMA][11] = 58, + [0][0][2][0][RTW89_CHILE][11] = 54, + [0][0][2][0][RTW89_UKRAINE][11] = 58, + [0][0][2][0][RTW89_MEXICO][11] = 54, + [0][0][2][0][RTW89_CN][11] = 58, + [0][0][2][0][RTW89_QATAR][11] = 58, + [0][0][2][0][RTW89_FCC][12] = 50, + [0][0][2][0][RTW89_ETSI][12] = 58, + [0][0][2][0][RTW89_MKK][12] = 76, + [0][0][2][0][RTW89_IC][12] = 50, + [0][0][2][0][RTW89_KCC][12] = 74, + [0][0][2][0][RTW89_ACMA][12] = 58, + [0][0][2][0][RTW89_CHILE][12] = 50, + [0][0][2][0][RTW89_UKRAINE][12] = 58, + [0][0][2][0][RTW89_MEXICO][12] = 50, + [0][0][2][0][RTW89_CN][12] = 58, + [0][0][2][0][RTW89_QATAR][12] = 58, + [0][0][2][0][RTW89_FCC][13] = 127, + [0][0][2][0][RTW89_ETSI][13] = 127, + [0][0][2][0][RTW89_MKK][13] = 127, + [0][0][2][0][RTW89_IC][13] = 127, + [0][0][2][0][RTW89_KCC][13] = 127, + [0][0][2][0][RTW89_ACMA][13] = 127, + [0][0][2][0][RTW89_CHILE][13] = 127, + [0][0][2][0][RTW89_UKRAINE][13] = 127, + [0][0][2][0][RTW89_MEXICO][13] = 127, + [0][0][2][0][RTW89_CN][13] = 127, + [0][0][2][0][RTW89_QATAR][13] = 127, + [0][1][2][0][RTW89_FCC][0] = 62, + [0][1][2][0][RTW89_ETSI][0] = 46, + [0][1][2][0][RTW89_MKK][0] = 64, + [0][1][2][0][RTW89_IC][0] = 62, + [0][1][2][0][RTW89_KCC][0] = 68, + [0][1][2][0][RTW89_ACMA][0] = 46, + [0][1][2][0][RTW89_CHILE][0] = 48, + [0][1][2][0][RTW89_UKRAINE][0] = 46, + [0][1][2][0][RTW89_MEXICO][0] = 62, + [0][1][2][0][RTW89_CN][0] = 46, + [0][1][2][0][RTW89_QATAR][0] = 46, + [0][1][2][0][RTW89_FCC][1] = 62, + [0][1][2][0][RTW89_ETSI][1] = 46, + [0][1][2][0][RTW89_MKK][1] = 64, + [0][1][2][0][RTW89_IC][1] = 62, + [0][1][2][0][RTW89_KCC][1] = 70, + [0][1][2][0][RTW89_ACMA][1] = 46, + [0][1][2][0][RTW89_CHILE][1] = 48, + [0][1][2][0][RTW89_UKRAINE][1] = 46, + [0][1][2][0][RTW89_MEXICO][1] = 62, + [0][1][2][0][RTW89_CN][1] = 46, + [0][1][2][0][RTW89_QATAR][1] = 46, + [0][1][2][0][RTW89_FCC][2] = 66, + [0][1][2][0][RTW89_ETSI][2] = 46, + [0][1][2][0][RTW89_MKK][2] = 64, + [0][1][2][0][RTW89_IC][2] = 66, + [0][1][2][0][RTW89_KCC][2] = 70, + [0][1][2][0][RTW89_ACMA][2] = 46, + [0][1][2][0][RTW89_CHILE][2] = 48, + [0][1][2][0][RTW89_UKRAINE][2] = 46, + [0][1][2][0][RTW89_MEXICO][2] = 66, + [0][1][2][0][RTW89_CN][2] = 46, + [0][1][2][0][RTW89_QATAR][2] = 46, + [0][1][2][0][RTW89_FCC][3] = 70, + [0][1][2][0][RTW89_ETSI][3] = 46, + [0][1][2][0][RTW89_MKK][3] = 64, + [0][1][2][0][RTW89_IC][3] = 70, + [0][1][2][0][RTW89_KCC][3] = 70, + [0][1][2][0][RTW89_ACMA][3] = 46, + [0][1][2][0][RTW89_CHILE][3] = 48, + [0][1][2][0][RTW89_UKRAINE][3] = 46, + [0][1][2][0][RTW89_MEXICO][3] = 70, + [0][1][2][0][RTW89_CN][3] = 46, + [0][1][2][0][RTW89_QATAR][3] = 46, + [0][1][2][0][RTW89_FCC][4] = 76, + [0][1][2][0][RTW89_ETSI][4] = 46, + [0][1][2][0][RTW89_MKK][4] = 64, + [0][1][2][0][RTW89_IC][4] = 76, + [0][1][2][0][RTW89_KCC][4] = 70, + [0][1][2][0][RTW89_ACMA][4] = 46, + [0][1][2][0][RTW89_CHILE][4] = 48, + [0][1][2][0][RTW89_UKRAINE][4] = 46, + [0][1][2][0][RTW89_MEXICO][4] = 76, + [0][1][2][0][RTW89_CN][4] = 46, + [0][1][2][0][RTW89_QATAR][4] = 46, + [0][1][2][0][RTW89_FCC][5] = 76, + [0][1][2][0][RTW89_ETSI][5] = 46, + [0][1][2][0][RTW89_MKK][5] = 64, + [0][1][2][0][RTW89_IC][5] = 76, + [0][1][2][0][RTW89_KCC][5] = 70, + [0][1][2][0][RTW89_ACMA][5] = 46, + [0][1][2][0][RTW89_CHILE][5] = 48, + [0][1][2][0][RTW89_UKRAINE][5] = 46, + [0][1][2][0][RTW89_MEXICO][5] = 76, + [0][1][2][0][RTW89_CN][5] = 46, + [0][1][2][0][RTW89_QATAR][5] = 46, + [0][1][2][0][RTW89_FCC][6] = 76, + [0][1][2][0][RTW89_ETSI][6] = 46, + [0][1][2][0][RTW89_MKK][6] = 64, + [0][1][2][0][RTW89_IC][6] = 76, + [0][1][2][0][RTW89_KCC][6] = 70, + [0][1][2][0][RTW89_ACMA][6] = 46, + [0][1][2][0][RTW89_CHILE][6] = 48, + [0][1][2][0][RTW89_UKRAINE][6] = 46, + [0][1][2][0][RTW89_MEXICO][6] = 76, + [0][1][2][0][RTW89_CN][6] = 46, + [0][1][2][0][RTW89_QATAR][6] = 46, + [0][1][2][0][RTW89_FCC][7] = 68, + [0][1][2][0][RTW89_ETSI][7] = 46, + [0][1][2][0][RTW89_MKK][7] = 64, + [0][1][2][0][RTW89_IC][7] = 68, + [0][1][2][0][RTW89_KCC][7] = 70, + [0][1][2][0][RTW89_ACMA][7] = 46, + [0][1][2][0][RTW89_CHILE][7] = 48, + [0][1][2][0][RTW89_UKRAINE][7] = 46, + [0][1][2][0][RTW89_MEXICO][7] = 68, + [0][1][2][0][RTW89_CN][7] = 46, + [0][1][2][0][RTW89_QATAR][7] = 46, + [0][1][2][0][RTW89_FCC][8] = 64, + [0][1][2][0][RTW89_ETSI][8] = 46, + [0][1][2][0][RTW89_MKK][8] = 64, + [0][1][2][0][RTW89_IC][8] = 64, + [0][1][2][0][RTW89_KCC][8] = 70, + [0][1][2][0][RTW89_ACMA][8] = 46, + [0][1][2][0][RTW89_CHILE][8] = 48, + [0][1][2][0][RTW89_UKRAINE][8] = 46, + [0][1][2][0][RTW89_MEXICO][8] = 64, + [0][1][2][0][RTW89_CN][8] = 46, + [0][1][2][0][RTW89_QATAR][8] = 46, + [0][1][2][0][RTW89_FCC][9] = 60, + [0][1][2][0][RTW89_ETSI][9] = 46, + [0][1][2][0][RTW89_MKK][9] = 64, + [0][1][2][0][RTW89_IC][9] = 60, + [0][1][2][0][RTW89_KCC][9] = 70, + [0][1][2][0][RTW89_ACMA][9] = 46, + [0][1][2][0][RTW89_CHILE][9] = 48, + [0][1][2][0][RTW89_UKRAINE][9] = 46, + [0][1][2][0][RTW89_MEXICO][9] = 60, + [0][1][2][0][RTW89_CN][9] = 46, + [0][1][2][0][RTW89_QATAR][9] = 46, + [0][1][2][0][RTW89_FCC][10] = 60, + [0][1][2][0][RTW89_ETSI][10] = 46, + [0][1][2][0][RTW89_MKK][10] = 64, + [0][1][2][0][RTW89_IC][10] = 60, + [0][1][2][0][RTW89_KCC][10] = 70, + [0][1][2][0][RTW89_ACMA][10] = 46, + [0][1][2][0][RTW89_CHILE][10] = 48, + [0][1][2][0][RTW89_UKRAINE][10] = 46, + [0][1][2][0][RTW89_MEXICO][10] = 60, + [0][1][2][0][RTW89_CN][10] = 46, + [0][1][2][0][RTW89_QATAR][10] = 46, + [0][1][2][0][RTW89_FCC][11] = 42, + [0][1][2][0][RTW89_ETSI][11] = 46, + [0][1][2][0][RTW89_MKK][11] = 64, + [0][1][2][0][RTW89_IC][11] = 42, + [0][1][2][0][RTW89_KCC][11] = 70, + [0][1][2][0][RTW89_ACMA][11] = 46, + [0][1][2][0][RTW89_CHILE][11] = 42, + [0][1][2][0][RTW89_UKRAINE][11] = 46, + [0][1][2][0][RTW89_MEXICO][11] = 42, + [0][1][2][0][RTW89_CN][11] = 46, + [0][1][2][0][RTW89_QATAR][11] = 46, + [0][1][2][0][RTW89_FCC][12] = 40, + [0][1][2][0][RTW89_ETSI][12] = 46, + [0][1][2][0][RTW89_MKK][12] = 64, + [0][1][2][0][RTW89_IC][12] = 40, + [0][1][2][0][RTW89_KCC][12] = 68, + [0][1][2][0][RTW89_ACMA][12] = 46, + [0][1][2][0][RTW89_CHILE][12] = 40, + [0][1][2][0][RTW89_UKRAINE][12] = 46, + [0][1][2][0][RTW89_MEXICO][12] = 40, + [0][1][2][0][RTW89_CN][12] = 46, + [0][1][2][0][RTW89_QATAR][12] = 46, + [0][1][2][0][RTW89_FCC][13] = 127, + [0][1][2][0][RTW89_ETSI][13] = 127, + [0][1][2][0][RTW89_MKK][13] = 127, + [0][1][2][0][RTW89_IC][13] = 127, + [0][1][2][0][RTW89_KCC][13] = 127, + [0][1][2][0][RTW89_ACMA][13] = 127, + [0][1][2][0][RTW89_CHILE][13] = 127, + [0][1][2][0][RTW89_UKRAINE][13] = 127, + [0][1][2][0][RTW89_MEXICO][13] = 127, + [0][1][2][0][RTW89_CN][13] = 127, + [0][1][2][0][RTW89_QATAR][13] = 127, + [0][1][2][1][RTW89_FCC][0] = 62, + [0][1][2][1][RTW89_ETSI][0] = 34, + [0][1][2][1][RTW89_MKK][0] = 64, + [0][1][2][1][RTW89_IC][0] = 62, + [0][1][2][1][RTW89_KCC][0] = 68, + [0][1][2][1][RTW89_ACMA][0] = 34, + [0][1][2][1][RTW89_CHILE][0] = 36, + [0][1][2][1][RTW89_UKRAINE][0] = 34, + [0][1][2][1][RTW89_MEXICO][0] = 62, + [0][1][2][1][RTW89_CN][0] = 34, + [0][1][2][1][RTW89_QATAR][0] = 34, + [0][1][2][1][RTW89_FCC][1] = 62, + [0][1][2][1][RTW89_ETSI][1] = 34, + [0][1][2][1][RTW89_MKK][1] = 64, + [0][1][2][1][RTW89_IC][1] = 62, + [0][1][2][1][RTW89_KCC][1] = 70, + [0][1][2][1][RTW89_ACMA][1] = 34, + [0][1][2][1][RTW89_CHILE][1] = 36, + [0][1][2][1][RTW89_UKRAINE][1] = 34, + [0][1][2][1][RTW89_MEXICO][1] = 62, + [0][1][2][1][RTW89_CN][1] = 34, + [0][1][2][1][RTW89_QATAR][1] = 34, + [0][1][2][1][RTW89_FCC][2] = 66, + [0][1][2][1][RTW89_ETSI][2] = 34, + [0][1][2][1][RTW89_MKK][2] = 64, + [0][1][2][1][RTW89_IC][2] = 66, + [0][1][2][1][RTW89_KCC][2] = 70, + [0][1][2][1][RTW89_ACMA][2] = 34, + [0][1][2][1][RTW89_CHILE][2] = 36, + [0][1][2][1][RTW89_UKRAINE][2] = 34, + [0][1][2][1][RTW89_MEXICO][2] = 66, + [0][1][2][1][RTW89_CN][2] = 34, + [0][1][2][1][RTW89_QATAR][2] = 34, + [0][1][2][1][RTW89_FCC][3] = 70, + [0][1][2][1][RTW89_ETSI][3] = 34, + [0][1][2][1][RTW89_MKK][3] = 64, + [0][1][2][1][RTW89_IC][3] = 70, + [0][1][2][1][RTW89_KCC][3] = 70, + [0][1][2][1][RTW89_ACMA][3] = 34, + [0][1][2][1][RTW89_CHILE][3] = 36, + [0][1][2][1][RTW89_UKRAINE][3] = 34, + [0][1][2][1][RTW89_MEXICO][3] = 70, + [0][1][2][1][RTW89_CN][3] = 34, + [0][1][2][1][RTW89_QATAR][3] = 34, + [0][1][2][1][RTW89_FCC][4] = 76, + [0][1][2][1][RTW89_ETSI][4] = 34, + [0][1][2][1][RTW89_MKK][4] = 64, + [0][1][2][1][RTW89_IC][4] = 76, + [0][1][2][1][RTW89_KCC][4] = 70, + [0][1][2][1][RTW89_ACMA][4] = 34, + [0][1][2][1][RTW89_CHILE][4] = 36, + [0][1][2][1][RTW89_UKRAINE][4] = 34, + [0][1][2][1][RTW89_MEXICO][4] = 76, + [0][1][2][1][RTW89_CN][4] = 34, + [0][1][2][1][RTW89_QATAR][4] = 34, + [0][1][2][1][RTW89_FCC][5] = 76, + [0][1][2][1][RTW89_ETSI][5] = 34, + [0][1][2][1][RTW89_MKK][5] = 64, + [0][1][2][1][RTW89_IC][5] = 76, + [0][1][2][1][RTW89_KCC][5] = 70, + [0][1][2][1][RTW89_ACMA][5] = 34, + [0][1][2][1][RTW89_CHILE][5] = 36, + [0][1][2][1][RTW89_UKRAINE][5] = 34, + [0][1][2][1][RTW89_MEXICO][5] = 76, + [0][1][2][1][RTW89_CN][5] = 34, + [0][1][2][1][RTW89_QATAR][5] = 34, + [0][1][2][1][RTW89_FCC][6] = 76, + [0][1][2][1][RTW89_ETSI][6] = 34, + [0][1][2][1][RTW89_MKK][6] = 64, + [0][1][2][1][RTW89_IC][6] = 76, + [0][1][2][1][RTW89_KCC][6] = 70, + [0][1][2][1][RTW89_ACMA][6] = 34, + [0][1][2][1][RTW89_CHILE][6] = 36, + [0][1][2][1][RTW89_UKRAINE][6] = 34, + [0][1][2][1][RTW89_MEXICO][6] = 76, + [0][1][2][1][RTW89_CN][6] = 34, + [0][1][2][1][RTW89_QATAR][6] = 34, + [0][1][2][1][RTW89_FCC][7] = 68, + [0][1][2][1][RTW89_ETSI][7] = 34, + [0][1][2][1][RTW89_MKK][7] = 64, + [0][1][2][1][RTW89_IC][7] = 68, + [0][1][2][1][RTW89_KCC][7] = 70, + [0][1][2][1][RTW89_ACMA][7] = 34, + [0][1][2][1][RTW89_CHILE][7] = 36, + [0][1][2][1][RTW89_UKRAINE][7] = 34, + [0][1][2][1][RTW89_MEXICO][7] = 68, + [0][1][2][1][RTW89_CN][7] = 34, + [0][1][2][1][RTW89_QATAR][7] = 34, + [0][1][2][1][RTW89_FCC][8] = 64, + [0][1][2][1][RTW89_ETSI][8] = 34, + [0][1][2][1][RTW89_MKK][8] = 64, + [0][1][2][1][RTW89_IC][8] = 64, + [0][1][2][1][RTW89_KCC][8] = 70, + [0][1][2][1][RTW89_ACMA][8] = 34, + [0][1][2][1][RTW89_CHILE][8] = 36, + [0][1][2][1][RTW89_UKRAINE][8] = 34, + [0][1][2][1][RTW89_MEXICO][8] = 64, + [0][1][2][1][RTW89_CN][8] = 34, + [0][1][2][1][RTW89_QATAR][8] = 34, + [0][1][2][1][RTW89_FCC][9] = 60, + [0][1][2][1][RTW89_ETSI][9] = 34, + [0][1][2][1][RTW89_MKK][9] = 64, + [0][1][2][1][RTW89_IC][9] = 60, + [0][1][2][1][RTW89_KCC][9] = 70, + [0][1][2][1][RTW89_ACMA][9] = 34, + [0][1][2][1][RTW89_CHILE][9] = 36, + [0][1][2][1][RTW89_UKRAINE][9] = 34, + [0][1][2][1][RTW89_MEXICO][9] = 60, + [0][1][2][1][RTW89_CN][9] = 34, + [0][1][2][1][RTW89_QATAR][9] = 34, + [0][1][2][1][RTW89_FCC][10] = 60, + [0][1][2][1][RTW89_ETSI][10] = 34, + [0][1][2][1][RTW89_MKK][10] = 64, + [0][1][2][1][RTW89_IC][10] = 60, + [0][1][2][1][RTW89_KCC][10] = 70, + [0][1][2][1][RTW89_ACMA][10] = 34, + [0][1][2][1][RTW89_CHILE][10] = 36, + [0][1][2][1][RTW89_UKRAINE][10] = 34, + [0][1][2][1][RTW89_MEXICO][10] = 60, + [0][1][2][1][RTW89_CN][10] = 34, + [0][1][2][1][RTW89_QATAR][10] = 34, + [0][1][2][1][RTW89_FCC][11] = 42, + [0][1][2][1][RTW89_ETSI][11] = 34, + [0][1][2][1][RTW89_MKK][11] = 64, + [0][1][2][1][RTW89_IC][11] = 42, + [0][1][2][1][RTW89_KCC][11] = 70, + [0][1][2][1][RTW89_ACMA][11] = 34, + [0][1][2][1][RTW89_CHILE][11] = 36, + [0][1][2][1][RTW89_UKRAINE][11] = 34, + [0][1][2][1][RTW89_MEXICO][11] = 42, + [0][1][2][1][RTW89_CN][11] = 34, + [0][1][2][1][RTW89_QATAR][11] = 34, + [0][1][2][1][RTW89_FCC][12] = 40, + [0][1][2][1][RTW89_ETSI][12] = 34, + [0][1][2][1][RTW89_MKK][12] = 64, + [0][1][2][1][RTW89_IC][12] = 40, + [0][1][2][1][RTW89_KCC][12] = 68, + [0][1][2][1][RTW89_ACMA][12] = 34, + [0][1][2][1][RTW89_CHILE][12] = 36, + [0][1][2][1][RTW89_UKRAINE][12] = 34, + [0][1][2][1][RTW89_MEXICO][12] = 40, + [0][1][2][1][RTW89_CN][12] = 34, + [0][1][2][1][RTW89_QATAR][12] = 34, + [0][1][2][1][RTW89_FCC][13] = 127, + [0][1][2][1][RTW89_ETSI][13] = 127, + [0][1][2][1][RTW89_MKK][13] = 127, + [0][1][2][1][RTW89_IC][13] = 127, + [0][1][2][1][RTW89_KCC][13] = 127, + [0][1][2][1][RTW89_ACMA][13] = 127, + [0][1][2][1][RTW89_CHILE][13] = 127, + [0][1][2][1][RTW89_UKRAINE][13] = 127, + [0][1][2][1][RTW89_MEXICO][13] = 127, + [0][1][2][1][RTW89_CN][13] = 127, + [0][1][2][1][RTW89_QATAR][13] = 127, + [1][0][2][0][RTW89_FCC][0] = 127, + [1][0][2][0][RTW89_ETSI][0] = 127, + [1][0][2][0][RTW89_MKK][0] = 127, + [1][0][2][0][RTW89_IC][0] = 127, + [1][0][2][0][RTW89_KCC][0] = 127, + [1][0][2][0][RTW89_ACMA][0] = 127, + [1][0][2][0][RTW89_CHILE][0] = 127, + [1][0][2][0][RTW89_UKRAINE][0] = 127, + [1][0][2][0][RTW89_MEXICO][0] = 127, + [1][0][2][0][RTW89_CN][0] = 127, + [1][0][2][0][RTW89_QATAR][0] = 127, + [1][0][2][0][RTW89_FCC][1] = 127, + [1][0][2][0][RTW89_ETSI][1] = 127, + [1][0][2][0][RTW89_MKK][1] = 127, + [1][0][2][0][RTW89_IC][1] = 127, + [1][0][2][0][RTW89_KCC][1] = 127, + [1][0][2][0][RTW89_ACMA][1] = 127, + [1][0][2][0][RTW89_CHILE][1] = 127, + [1][0][2][0][RTW89_UKRAINE][1] = 127, + [1][0][2][0][RTW89_MEXICO][1] = 127, + [1][0][2][0][RTW89_CN][1] = 127, + [1][0][2][0][RTW89_QATAR][1] = 127, + [1][0][2][0][RTW89_FCC][2] = 56, + [1][0][2][0][RTW89_ETSI][2] = 58, + [1][0][2][0][RTW89_MKK][2] = 68, + [1][0][2][0][RTW89_IC][2] = 56, + [1][0][2][0][RTW89_KCC][2] = 68, + [1][0][2][0][RTW89_ACMA][2] = 58, + [1][0][2][0][RTW89_CHILE][2] = 56, + [1][0][2][0][RTW89_UKRAINE][2] = 58, + [1][0][2][0][RTW89_MEXICO][2] = 56, + [1][0][2][0][RTW89_CN][2] = 58, + [1][0][2][0][RTW89_QATAR][2] = 58, + [1][0][2][0][RTW89_FCC][3] = 56, + [1][0][2][0][RTW89_ETSI][3] = 58, + [1][0][2][0][RTW89_MKK][3] = 68, + [1][0][2][0][RTW89_IC][3] = 56, + [1][0][2][0][RTW89_KCC][3] = 68, + [1][0][2][0][RTW89_ACMA][3] = 58, + [1][0][2][0][RTW89_CHILE][3] = 56, + [1][0][2][0][RTW89_UKRAINE][3] = 58, + [1][0][2][0][RTW89_MEXICO][3] = 56, + [1][0][2][0][RTW89_CN][3] = 58, + [1][0][2][0][RTW89_QATAR][3] = 58, + [1][0][2][0][RTW89_FCC][4] = 60, + [1][0][2][0][RTW89_ETSI][4] = 58, + [1][0][2][0][RTW89_MKK][4] = 68, + [1][0][2][0][RTW89_IC][4] = 60, + [1][0][2][0][RTW89_KCC][4] = 68, + [1][0][2][0][RTW89_ACMA][4] = 58, + [1][0][2][0][RTW89_CHILE][4] = 60, + [1][0][2][0][RTW89_UKRAINE][4] = 58, + [1][0][2][0][RTW89_MEXICO][4] = 60, + [1][0][2][0][RTW89_CN][4] = 58, + [1][0][2][0][RTW89_QATAR][4] = 58, + [1][0][2][0][RTW89_FCC][5] = 64, + [1][0][2][0][RTW89_ETSI][5] = 58, + [1][0][2][0][RTW89_MKK][5] = 68, + [1][0][2][0][RTW89_IC][5] = 64, + [1][0][2][0][RTW89_KCC][5] = 68, + [1][0][2][0][RTW89_ACMA][5] = 58, + [1][0][2][0][RTW89_CHILE][5] = 60, + [1][0][2][0][RTW89_UKRAINE][5] = 58, + [1][0][2][0][RTW89_MEXICO][5] = 64, + [1][0][2][0][RTW89_CN][5] = 58, + [1][0][2][0][RTW89_QATAR][5] = 58, + [1][0][2][0][RTW89_FCC][6] = 54, + [1][0][2][0][RTW89_ETSI][6] = 58, + [1][0][2][0][RTW89_MKK][6] = 68, + [1][0][2][0][RTW89_IC][6] = 54, + [1][0][2][0][RTW89_KCC][6] = 68, + [1][0][2][0][RTW89_ACMA][6] = 58, + [1][0][2][0][RTW89_CHILE][6] = 54, + [1][0][2][0][RTW89_UKRAINE][6] = 58, + [1][0][2][0][RTW89_MEXICO][6] = 54, + [1][0][2][0][RTW89_CN][6] = 58, + [1][0][2][0][RTW89_QATAR][6] = 58, + [1][0][2][0][RTW89_FCC][7] = 50, + [1][0][2][0][RTW89_ETSI][7] = 58, + [1][0][2][0][RTW89_MKK][7] = 68, + [1][0][2][0][RTW89_IC][7] = 50, + [1][0][2][0][RTW89_KCC][7] = 68, + [1][0][2][0][RTW89_ACMA][7] = 58, + [1][0][2][0][RTW89_CHILE][7] = 50, + [1][0][2][0][RTW89_UKRAINE][7] = 58, + [1][0][2][0][RTW89_MEXICO][7] = 50, + [1][0][2][0][RTW89_CN][7] = 58, + [1][0][2][0][RTW89_QATAR][7] = 58, + [1][0][2][0][RTW89_FCC][8] = 50, + [1][0][2][0][RTW89_ETSI][8] = 58, + [1][0][2][0][RTW89_MKK][8] = 68, + [1][0][2][0][RTW89_IC][8] = 50, + [1][0][2][0][RTW89_KCC][8] = 68, + [1][0][2][0][RTW89_ACMA][8] = 58, + [1][0][2][0][RTW89_CHILE][8] = 50, + [1][0][2][0][RTW89_UKRAINE][8] = 58, + [1][0][2][0][RTW89_MEXICO][8] = 50, + [1][0][2][0][RTW89_CN][8] = 58, + [1][0][2][0][RTW89_QATAR][8] = 58, + [1][0][2][0][RTW89_FCC][9] = 42, + [1][0][2][0][RTW89_ETSI][9] = 58, + [1][0][2][0][RTW89_MKK][9] = 68, + [1][0][2][0][RTW89_IC][9] = 42, + [1][0][2][0][RTW89_KCC][9] = 68, + [1][0][2][0][RTW89_ACMA][9] = 58, + [1][0][2][0][RTW89_CHILE][9] = 42, + [1][0][2][0][RTW89_UKRAINE][9] = 58, + [1][0][2][0][RTW89_MEXICO][9] = 42, + [1][0][2][0][RTW89_CN][9] = 58, + [1][0][2][0][RTW89_QATAR][9] = 58, + [1][0][2][0][RTW89_FCC][10] = 40, + [1][0][2][0][RTW89_ETSI][10] = 58, + [1][0][2][0][RTW89_MKK][10] = 68, + [1][0][2][0][RTW89_IC][10] = 40, + [1][0][2][0][RTW89_KCC][10] = 68, + [1][0][2][0][RTW89_ACMA][10] = 58, + [1][0][2][0][RTW89_CHILE][10] = 40, + [1][0][2][0][RTW89_UKRAINE][10] = 58, + [1][0][2][0][RTW89_MEXICO][10] = 40, + [1][0][2][0][RTW89_CN][10] = 58, + [1][0][2][0][RTW89_QATAR][10] = 58, + [1][0][2][0][RTW89_FCC][11] = 127, + [1][0][2][0][RTW89_ETSI][11] = 127, + [1][0][2][0][RTW89_MKK][11] = 127, + [1][0][2][0][RTW89_IC][11] = 127, + [1][0][2][0][RTW89_KCC][11] = 127, + [1][0][2][0][RTW89_ACMA][11] = 127, + [1][0][2][0][RTW89_CHILE][11] = 127, + [1][0][2][0][RTW89_UKRAINE][11] = 127, + [1][0][2][0][RTW89_MEXICO][11] = 127, + [1][0][2][0][RTW89_CN][11] = 127, + [1][0][2][0][RTW89_QATAR][11] = 127, + [1][0][2][0][RTW89_FCC][12] = 127, + [1][0][2][0][RTW89_ETSI][12] = 127, + [1][0][2][0][RTW89_MKK][12] = 127, + [1][0][2][0][RTW89_IC][12] = 127, + [1][0][2][0][RTW89_KCC][12] = 127, + [1][0][2][0][RTW89_ACMA][12] = 127, + [1][0][2][0][RTW89_CHILE][12] = 127, + [1][0][2][0][RTW89_UKRAINE][12] = 127, + [1][0][2][0][RTW89_MEXICO][12] = 127, + [1][0][2][0][RTW89_CN][12] = 127, + [1][0][2][0][RTW89_QATAR][12] = 127, + [1][0][2][0][RTW89_FCC][13] = 127, + [1][0][2][0][RTW89_ETSI][13] = 127, + [1][0][2][0][RTW89_MKK][13] = 127, + [1][0][2][0][RTW89_IC][13] = 127, + [1][0][2][0][RTW89_KCC][13] = 127, + [1][0][2][0][RTW89_ACMA][13] = 127, + [1][0][2][0][RTW89_CHILE][13] = 127, + [1][0][2][0][RTW89_UKRAINE][13] = 127, + [1][0][2][0][RTW89_MEXICO][13] = 127, + [1][0][2][0][RTW89_CN][13] = 127, + [1][0][2][0][RTW89_QATAR][13] = 127, + [1][1][2][0][RTW89_FCC][0] = 127, + [1][1][2][0][RTW89_ETSI][0] = 127, + [1][1][2][0][RTW89_MKK][0] = 127, + [1][1][2][0][RTW89_IC][0] = 127, + [1][1][2][0][RTW89_KCC][0] = 127, + [1][1][2][0][RTW89_ACMA][0] = 127, + [1][1][2][0][RTW89_CHILE][0] = 127, + [1][1][2][0][RTW89_UKRAINE][0] = 127, + [1][1][2][0][RTW89_MEXICO][0] = 127, + [1][1][2][0][RTW89_CN][0] = 127, + [1][1][2][0][RTW89_QATAR][0] = 127, + [1][1][2][0][RTW89_FCC][1] = 127, + [1][1][2][0][RTW89_ETSI][1] = 127, + [1][1][2][0][RTW89_MKK][1] = 127, + [1][1][2][0][RTW89_IC][1] = 127, + [1][1][2][0][RTW89_KCC][1] = 127, + [1][1][2][0][RTW89_ACMA][1] = 127, + [1][1][2][0][RTW89_CHILE][1] = 127, + [1][1][2][0][RTW89_UKRAINE][1] = 127, + [1][1][2][0][RTW89_MEXICO][1] = 127, + [1][1][2][0][RTW89_CN][1] = 127, + [1][1][2][0][RTW89_QATAR][1] = 127, + [1][1][2][0][RTW89_FCC][2] = 52, + [1][1][2][0][RTW89_ETSI][2] = 46, + [1][1][2][0][RTW89_MKK][2] = 64, + [1][1][2][0][RTW89_IC][2] = 52, + [1][1][2][0][RTW89_KCC][2] = 66, + [1][1][2][0][RTW89_ACMA][2] = 46, + [1][1][2][0][RTW89_CHILE][2] = 48, + [1][1][2][0][RTW89_UKRAINE][2] = 46, + [1][1][2][0][RTW89_MEXICO][2] = 52, + [1][1][2][0][RTW89_CN][2] = 46, + [1][1][2][0][RTW89_QATAR][2] = 46, + [1][1][2][0][RTW89_FCC][3] = 52, + [1][1][2][0][RTW89_ETSI][3] = 46, + [1][1][2][0][RTW89_MKK][3] = 64, + [1][1][2][0][RTW89_IC][3] = 52, + [1][1][2][0][RTW89_KCC][3] = 68, + [1][1][2][0][RTW89_ACMA][3] = 46, + [1][1][2][0][RTW89_CHILE][3] = 48, + [1][1][2][0][RTW89_UKRAINE][3] = 46, + [1][1][2][0][RTW89_MEXICO][3] = 52, + [1][1][2][0][RTW89_CN][3] = 46, + [1][1][2][0][RTW89_QATAR][3] = 46, + [1][1][2][0][RTW89_FCC][4] = 56, + [1][1][2][0][RTW89_ETSI][4] = 46, + [1][1][2][0][RTW89_MKK][4] = 64, + [1][1][2][0][RTW89_IC][4] = 56, + [1][1][2][0][RTW89_KCC][4] = 68, + [1][1][2][0][RTW89_ACMA][4] = 46, + [1][1][2][0][RTW89_CHILE][4] = 48, + [1][1][2][0][RTW89_UKRAINE][4] = 46, + [1][1][2][0][RTW89_MEXICO][4] = 56, + [1][1][2][0][RTW89_CN][4] = 46, + [1][1][2][0][RTW89_QATAR][4] = 46, + [1][1][2][0][RTW89_FCC][5] = 60, + [1][1][2][0][RTW89_ETSI][5] = 46, + [1][1][2][0][RTW89_MKK][5] = 64, + [1][1][2][0][RTW89_IC][5] = 60, + [1][1][2][0][RTW89_KCC][5] = 68, + [1][1][2][0][RTW89_ACMA][5] = 46, + [1][1][2][0][RTW89_CHILE][5] = 48, + [1][1][2][0][RTW89_UKRAINE][5] = 46, + [1][1][2][0][RTW89_MEXICO][5] = 60, + [1][1][2][0][RTW89_CN][5] = 46, + [1][1][2][0][RTW89_QATAR][5] = 46, + [1][1][2][0][RTW89_FCC][6] = 54, + [1][1][2][0][RTW89_ETSI][6] = 46, + [1][1][2][0][RTW89_MKK][6] = 64, + [1][1][2][0][RTW89_IC][6] = 52, + [1][1][2][0][RTW89_KCC][6] = 68, + [1][1][2][0][RTW89_ACMA][6] = 46, + [1][1][2][0][RTW89_CHILE][6] = 48, + [1][1][2][0][RTW89_UKRAINE][6] = 46, + [1][1][2][0][RTW89_MEXICO][6] = 54, + [1][1][2][0][RTW89_CN][6] = 46, + [1][1][2][0][RTW89_QATAR][6] = 46, + [1][1][2][0][RTW89_FCC][7] = 50, + [1][1][2][0][RTW89_ETSI][7] = 46, + [1][1][2][0][RTW89_MKK][7] = 64, + [1][1][2][0][RTW89_IC][7] = 48, + [1][1][2][0][RTW89_KCC][7] = 68, + [1][1][2][0][RTW89_ACMA][7] = 46, + [1][1][2][0][RTW89_CHILE][7] = 48, + [1][1][2][0][RTW89_UKRAINE][7] = 46, + [1][1][2][0][RTW89_MEXICO][7] = 50, + [1][1][2][0][RTW89_CN][7] = 46, + [1][1][2][0][RTW89_QATAR][7] = 46, + [1][1][2][0][RTW89_FCC][8] = 50, + [1][1][2][0][RTW89_ETSI][8] = 46, + [1][1][2][0][RTW89_MKK][8] = 64, + [1][1][2][0][RTW89_IC][8] = 48, + [1][1][2][0][RTW89_KCC][8] = 68, + [1][1][2][0][RTW89_ACMA][8] = 46, + [1][1][2][0][RTW89_CHILE][8] = 48, + [1][1][2][0][RTW89_UKRAINE][8] = 46, + [1][1][2][0][RTW89_MEXICO][8] = 50, + [1][1][2][0][RTW89_CN][8] = 46, + [1][1][2][0][RTW89_QATAR][8] = 46, + [1][1][2][0][RTW89_FCC][9] = 38, + [1][1][2][0][RTW89_ETSI][9] = 46, + [1][1][2][0][RTW89_MKK][9] = 64, + [1][1][2][0][RTW89_IC][9] = 38, + [1][1][2][0][RTW89_KCC][9] = 68, + [1][1][2][0][RTW89_ACMA][9] = 46, + [1][1][2][0][RTW89_CHILE][9] = 38, + [1][1][2][0][RTW89_UKRAINE][9] = 46, + [1][1][2][0][RTW89_MEXICO][9] = 38, + [1][1][2][0][RTW89_CN][9] = 46, + [1][1][2][0][RTW89_QATAR][9] = 46, + [1][1][2][0][RTW89_FCC][10] = 36, + [1][1][2][0][RTW89_ETSI][10] = 46, + [1][1][2][0][RTW89_MKK][10] = 64, + [1][1][2][0][RTW89_IC][10] = 36, + [1][1][2][0][RTW89_KCC][10] = 66, + [1][1][2][0][RTW89_ACMA][10] = 46, + [1][1][2][0][RTW89_CHILE][10] = 36, + [1][1][2][0][RTW89_UKRAINE][10] = 46, + [1][1][2][0][RTW89_MEXICO][10] = 36, + [1][1][2][0][RTW89_CN][10] = 46, + [1][1][2][0][RTW89_QATAR][10] = 46, + [1][1][2][0][RTW89_FCC][11] = 127, + [1][1][2][0][RTW89_ETSI][11] = 127, + [1][1][2][0][RTW89_MKK][11] = 127, + [1][1][2][0][RTW89_IC][11] = 127, + [1][1][2][0][RTW89_KCC][11] = 127, + [1][1][2][0][RTW89_ACMA][11] = 127, + [1][1][2][0][RTW89_CHILE][11] = 127, + [1][1][2][0][RTW89_UKRAINE][11] = 127, + [1][1][2][0][RTW89_MEXICO][11] = 127, + [1][1][2][0][RTW89_CN][11] = 127, + [1][1][2][0][RTW89_QATAR][11] = 127, + [1][1][2][0][RTW89_FCC][12] = 127, + [1][1][2][0][RTW89_ETSI][12] = 127, + [1][1][2][0][RTW89_MKK][12] = 127, + [1][1][2][0][RTW89_IC][12] = 127, + [1][1][2][0][RTW89_KCC][12] = 127, + [1][1][2][0][RTW89_ACMA][12] = 127, + [1][1][2][0][RTW89_CHILE][12] = 127, + [1][1][2][0][RTW89_UKRAINE][12] = 127, + [1][1][2][0][RTW89_MEXICO][12] = 127, + [1][1][2][0][RTW89_CN][12] = 127, + [1][1][2][0][RTW89_QATAR][12] = 127, + [1][1][2][0][RTW89_FCC][13] = 127, + [1][1][2][0][RTW89_ETSI][13] = 127, + [1][1][2][0][RTW89_MKK][13] = 127, + [1][1][2][0][RTW89_IC][13] = 127, + [1][1][2][0][RTW89_KCC][13] = 127, + [1][1][2][0][RTW89_ACMA][13] = 127, + [1][1][2][0][RTW89_CHILE][13] = 127, + [1][1][2][0][RTW89_UKRAINE][13] = 127, + [1][1][2][0][RTW89_MEXICO][13] = 127, + [1][1][2][0][RTW89_CN][13] = 127, + [1][1][2][0][RTW89_QATAR][13] = 127, + [1][1][2][1][RTW89_FCC][0] = 127, + [1][1][2][1][RTW89_ETSI][0] = 127, + [1][1][2][1][RTW89_MKK][0] = 127, + [1][1][2][1][RTW89_IC][0] = 127, + [1][1][2][1][RTW89_KCC][0] = 127, + [1][1][2][1][RTW89_ACMA][0] = 127, + [1][1][2][1][RTW89_CHILE][0] = 127, + [1][1][2][1][RTW89_UKRAINE][0] = 127, + [1][1][2][1][RTW89_MEXICO][0] = 127, + [1][1][2][1][RTW89_CN][0] = 127, + [1][1][2][1][RTW89_QATAR][0] = 127, + [1][1][2][1][RTW89_FCC][1] = 127, + [1][1][2][1][RTW89_ETSI][1] = 127, + [1][1][2][1][RTW89_MKK][1] = 127, + [1][1][2][1][RTW89_IC][1] = 127, + [1][1][2][1][RTW89_KCC][1] = 127, + [1][1][2][1][RTW89_ACMA][1] = 127, + [1][1][2][1][RTW89_CHILE][1] = 127, + [1][1][2][1][RTW89_UKRAINE][1] = 127, + [1][1][2][1][RTW89_MEXICO][1] = 127, + [1][1][2][1][RTW89_CN][1] = 127, + [1][1][2][1][RTW89_QATAR][1] = 127, + [1][1][2][1][RTW89_FCC][2] = 52, + [1][1][2][1][RTW89_ETSI][2] = 34, + [1][1][2][1][RTW89_MKK][2] = 64, + [1][1][2][1][RTW89_IC][2] = 52, + [1][1][2][1][RTW89_KCC][2] = 66, + [1][1][2][1][RTW89_ACMA][2] = 34, + [1][1][2][1][RTW89_CHILE][2] = 36, + [1][1][2][1][RTW89_UKRAINE][2] = 34, + [1][1][2][1][RTW89_MEXICO][2] = 52, + [1][1][2][1][RTW89_CN][2] = 34, + [1][1][2][1][RTW89_QATAR][2] = 34, + [1][1][2][1][RTW89_FCC][3] = 52, + [1][1][2][1][RTW89_ETSI][3] = 34, + [1][1][2][1][RTW89_MKK][3] = 64, + [1][1][2][1][RTW89_IC][3] = 52, + [1][1][2][1][RTW89_KCC][3] = 68, + [1][1][2][1][RTW89_ACMA][3] = 34, + [1][1][2][1][RTW89_CHILE][3] = 36, + [1][1][2][1][RTW89_UKRAINE][3] = 34, + [1][1][2][1][RTW89_MEXICO][3] = 52, + [1][1][2][1][RTW89_CN][3] = 34, + [1][1][2][1][RTW89_QATAR][3] = 34, + [1][1][2][1][RTW89_FCC][4] = 56, + [1][1][2][1][RTW89_ETSI][4] = 34, + [1][1][2][1][RTW89_MKK][4] = 64, + [1][1][2][1][RTW89_IC][4] = 56, + [1][1][2][1][RTW89_KCC][4] = 68, + [1][1][2][1][RTW89_ACMA][4] = 34, + [1][1][2][1][RTW89_CHILE][4] = 36, + [1][1][2][1][RTW89_UKRAINE][4] = 34, + [1][1][2][1][RTW89_MEXICO][4] = 56, + [1][1][2][1][RTW89_CN][4] = 34, + [1][1][2][1][RTW89_QATAR][4] = 34, + [1][1][2][1][RTW89_FCC][5] = 60, + [1][1][2][1][RTW89_ETSI][5] = 34, + [1][1][2][1][RTW89_MKK][5] = 64, + [1][1][2][1][RTW89_IC][5] = 60, + [1][1][2][1][RTW89_KCC][5] = 68, + [1][1][2][1][RTW89_ACMA][5] = 34, + [1][1][2][1][RTW89_CHILE][5] = 36, + [1][1][2][1][RTW89_UKRAINE][5] = 34, + [1][1][2][1][RTW89_MEXICO][5] = 60, + [1][1][2][1][RTW89_CN][5] = 34, + [1][1][2][1][RTW89_QATAR][5] = 34, + [1][1][2][1][RTW89_FCC][6] = 54, + [1][1][2][1][RTW89_ETSI][6] = 34, + [1][1][2][1][RTW89_MKK][6] = 64, + [1][1][2][1][RTW89_IC][6] = 52, + [1][1][2][1][RTW89_KCC][6] = 68, + [1][1][2][1][RTW89_ACMA][6] = 34, + [1][1][2][1][RTW89_CHILE][6] = 36, + [1][1][2][1][RTW89_UKRAINE][6] = 34, + [1][1][2][1][RTW89_MEXICO][6] = 54, + [1][1][2][1][RTW89_CN][6] = 34, + [1][1][2][1][RTW89_QATAR][6] = 34, + [1][1][2][1][RTW89_FCC][7] = 50, + [1][1][2][1][RTW89_ETSI][7] = 34, + [1][1][2][1][RTW89_MKK][7] = 64, + [1][1][2][1][RTW89_IC][7] = 48, + [1][1][2][1][RTW89_KCC][7] = 68, + [1][1][2][1][RTW89_ACMA][7] = 34, + [1][1][2][1][RTW89_CHILE][7] = 36, + [1][1][2][1][RTW89_UKRAINE][7] = 34, + [1][1][2][1][RTW89_MEXICO][7] = 50, + [1][1][2][1][RTW89_CN][7] = 34, + [1][1][2][1][RTW89_QATAR][7] = 34, + [1][1][2][1][RTW89_FCC][8] = 50, + [1][1][2][1][RTW89_ETSI][8] = 34, + [1][1][2][1][RTW89_MKK][8] = 64, + [1][1][2][1][RTW89_IC][8] = 48, + [1][1][2][1][RTW89_KCC][8] = 68, + [1][1][2][1][RTW89_ACMA][8] = 34, + [1][1][2][1][RTW89_CHILE][8] = 36, + [1][1][2][1][RTW89_UKRAINE][8] = 34, + [1][1][2][1][RTW89_MEXICO][8] = 50, + [1][1][2][1][RTW89_CN][8] = 34, + [1][1][2][1][RTW89_QATAR][8] = 34, + [1][1][2][1][RTW89_FCC][9] = 38, + [1][1][2][1][RTW89_ETSI][9] = 34, + [1][1][2][1][RTW89_MKK][9] = 64, + [1][1][2][1][RTW89_IC][9] = 38, + [1][1][2][1][RTW89_KCC][9] = 68, + [1][1][2][1][RTW89_ACMA][9] = 34, + [1][1][2][1][RTW89_CHILE][9] = 36, + [1][1][2][1][RTW89_UKRAINE][9] = 34, + [1][1][2][1][RTW89_MEXICO][9] = 38, + [1][1][2][1][RTW89_CN][9] = 34, + [1][1][2][1][RTW89_QATAR][9] = 34, + [1][1][2][1][RTW89_FCC][10] = 36, + [1][1][2][1][RTW89_ETSI][10] = 34, + [1][1][2][1][RTW89_MKK][10] = 64, + [1][1][2][1][RTW89_IC][10] = 36, + [1][1][2][1][RTW89_KCC][10] = 66, + [1][1][2][1][RTW89_ACMA][10] = 34, + [1][1][2][1][RTW89_CHILE][10] = 36, + [1][1][2][1][RTW89_UKRAINE][10] = 34, + [1][1][2][1][RTW89_MEXICO][10] = 36, + [1][1][2][1][RTW89_CN][10] = 34, + [1][1][2][1][RTW89_QATAR][10] = 34, + [1][1][2][1][RTW89_FCC][11] = 127, + [1][1][2][1][RTW89_ETSI][11] = 127, + [1][1][2][1][RTW89_MKK][11] = 127, + [1][1][2][1][RTW89_IC][11] = 127, + [1][1][2][1][RTW89_KCC][11] = 127, + [1][1][2][1][RTW89_ACMA][11] = 127, + [1][1][2][1][RTW89_CHILE][11] = 127, + [1][1][2][1][RTW89_UKRAINE][11] = 127, + [1][1][2][1][RTW89_MEXICO][11] = 127, + [1][1][2][1][RTW89_CN][11] = 127, + [1][1][2][1][RTW89_QATAR][11] = 127, + [1][1][2][1][RTW89_FCC][12] = 127, + [1][1][2][1][RTW89_ETSI][12] = 127, + [1][1][2][1][RTW89_MKK][12] = 127, + [1][1][2][1][RTW89_IC][12] = 127, + [1][1][2][1][RTW89_KCC][12] = 127, + [1][1][2][1][RTW89_ACMA][12] = 127, + [1][1][2][1][RTW89_CHILE][12] = 127, + [1][1][2][1][RTW89_UKRAINE][12] = 127, + [1][1][2][1][RTW89_MEXICO][12] = 127, + [1][1][2][1][RTW89_CN][12] = 127, + [1][1][2][1][RTW89_QATAR][12] = 127, + [1][1][2][1][RTW89_FCC][13] = 127, + [1][1][2][1][RTW89_ETSI][13] = 127, + [1][1][2][1][RTW89_MKK][13] = 127, + [1][1][2][1][RTW89_IC][13] = 127, + [1][1][2][1][RTW89_KCC][13] = 127, + [1][1][2][1][RTW89_ACMA][13] = 127, + [1][1][2][1][RTW89_CHILE][13] = 127, + [1][1][2][1][RTW89_UKRAINE][13] = 127, + [1][1][2][1][RTW89_MEXICO][13] = 127, + [1][1][2][1][RTW89_CN][13] = 127, + [1][1][2][1][RTW89_QATAR][13] = 127, }; const s8 rtw89_8852a_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [RTW89_RS_LMT_NUM][RTW89_BF_NUM] [RTW89_REGD_NUM][RTW89_5G_CH_NUM] = { - [0][0][1][0][0][0] = 30, - [0][0][1][0][0][2] = 30, - [0][0][1][0][0][4] = 30, - [0][0][1][0][0][6] = 30, - [0][0][1][0][0][8] = 52, - [0][0][1][0][0][10] = 52, - [0][0][1][0][0][12] = 52, - [0][0][1][0][0][14] = 52, - [0][0][1][0][0][15] = 52, - [0][0][1][0][0][17] = 52, - [0][0][1][0][0][19] = 52, - [0][0][1][0][0][21] = 52, - [0][0][1][0][0][23] = 52, - [0][0][1][0][0][25] = 52, - [0][0][1][0][0][27] = 52, - [0][0][1][0][0][29] = 52, - [0][0][1][0][0][31] = 52, - [0][0][1][0][0][33] = 52, - [0][0][1][0][0][35] = 52, - [0][0][1][0][0][37] = 54, - [0][0][1][0][0][38] = 28, - [0][0][1][0][0][40] = 28, - [0][0][1][0][0][42] = 28, - [0][0][1][0][0][44] = 28, - [0][0][1][0][0][46] = 28, - [0][1][1][0][0][0] = 18, - [0][1][1][0][0][2] = 18, - [0][1][1][0][0][4] = 18, - [0][1][1][0][0][6] = 18, - [0][1][1][0][0][8] = 40, - [0][1][1][0][0][10] = 40, - [0][1][1][0][0][12] = 40, - [0][1][1][0][0][14] = 40, - [0][1][1][0][0][15] = 40, - [0][1][1][0][0][17] = 40, - [0][1][1][0][0][19] = 40, - [0][1][1][0][0][21] = 40, - [0][1][1][0][0][23] = 40, - [0][1][1][0][0][25] = 40, - [0][1][1][0][0][27] = 40, - [0][1][1][0][0][29] = 40, - [0][1][1][0][0][31] = 40, - [0][1][1][0][0][33] = 40, - [0][1][1][0][0][35] = 40, - [0][1][1][0][0][37] = 42, - [0][1][1][0][0][38] = 16, - [0][1][1][0][0][40] = 16, - [0][1][1][0][0][42] = 16, - [0][1][1][0][0][44] = 16, - [0][1][1][0][0][46] = 16, - [0][0][2][0][0][0] = 30, - [0][0][2][0][0][2] = 30, - [0][0][2][0][0][4] = 30, - [0][0][2][0][0][6] = 30, - [0][0][2][0][0][8] = 52, - [0][0][2][0][0][10] = 52, - [0][0][2][0][0][12] = 52, - [0][0][2][0][0][14] = 52, - [0][0][2][0][0][15] = 52, - [0][0][2][0][0][17] = 52, - [0][0][2][0][0][19] = 52, - [0][0][2][0][0][21] = 52, - [0][0][2][0][0][23] = 52, - [0][0][2][0][0][25] = 52, - [0][0][2][0][0][27] = 52, - [0][0][2][0][0][29] = 52, - [0][0][2][0][0][31] = 52, - [0][0][2][0][0][33] = 52, - [0][0][2][0][0][35] = 52, - [0][0][2][0][0][37] = 54, - [0][0][2][0][0][38] = 28, - [0][0][2][0][0][40] = 28, - [0][0][2][0][0][42] = 28, - [0][0][2][0][0][44] = 28, - [0][0][2][0][0][46] = 28, - [0][1][2][0][0][0] = 18, - [0][1][2][0][0][2] = 18, - [0][1][2][0][0][4] = 18, - [0][1][2][0][0][6] = 18, - [0][1][2][0][0][8] = 40, - [0][1][2][0][0][10] = 40, - [0][1][2][0][0][12] = 40, - [0][1][2][0][0][14] = 40, - [0][1][2][0][0][15] = 40, - [0][1][2][0][0][17] = 40, - [0][1][2][0][0][19] = 40, - [0][1][2][0][0][21] = 40, - [0][1][2][0][0][23] = 40, - [0][1][2][0][0][25] = 40, - [0][1][2][0][0][27] = 40, - [0][1][2][0][0][29] = 40, - [0][1][2][0][0][31] = 40, - [0][1][2][0][0][33] = 40, - [0][1][2][0][0][35] = 40, - [0][1][2][0][0][37] = 42, - [0][1][2][0][0][38] = 16, - [0][1][2][0][0][40] = 16, - [0][1][2][0][0][42] = 16, - [0][1][2][0][0][44] = 16, - [0][1][2][0][0][46] = 16, - [0][1][2][1][0][0] = 6, - [0][1][2][1][0][2] = 6, - [0][1][2][1][0][4] = 6, - [0][1][2][1][0][6] = 6, - [0][1][2][1][0][8] = 28, - [0][1][2][1][0][10] = 28, - [0][1][2][1][0][12] = 28, - [0][1][2][1][0][14] = 28, - [0][1][2][1][0][15] = 28, - [0][1][2][1][0][17] = 28, - [0][1][2][1][0][19] = 28, - [0][1][2][1][0][21] = 28, - [0][1][2][1][0][23] = 28, - [0][1][2][1][0][25] = 28, - [0][1][2][1][0][27] = 28, - [0][1][2][1][0][29] = 28, - [0][1][2][1][0][31] = 28, - [0][1][2][1][0][33] = 28, - [0][1][2][1][0][35] = 28, - [0][1][2][1][0][37] = 30, - [0][1][2][1][0][38] = 4, - [0][1][2][1][0][40] = 4, - [0][1][2][1][0][42] = 4, - [0][1][2][1][0][44] = 4, - [0][1][2][1][0][46] = 4, - [1][0][2][0][0][1] = 30, - [1][0][2][0][0][5] = 30, - [1][0][2][0][0][9] = 52, - [1][0][2][0][0][13] = 52, - [1][0][2][0][0][16] = 52, - [1][0][2][0][0][20] = 52, - [1][0][2][0][0][24] = 52, - [1][0][2][0][0][28] = 52, - [1][0][2][0][0][32] = 52, - [1][0][2][0][0][36] = 54, - [1][0][2][0][0][39] = 28, - [1][0][2][0][0][43] = 28, - [1][1][2][0][0][1] = 18, - [1][1][2][0][0][5] = 18, - [1][1][2][0][0][9] = 40, - [1][1][2][0][0][13] = 40, - [1][1][2][0][0][16] = 40, - [1][1][2][0][0][20] = 40, - [1][1][2][0][0][24] = 40, - [1][1][2][0][0][28] = 40, - [1][1][2][0][0][32] = 40, - [1][1][2][0][0][36] = 42, - [1][1][2][0][0][39] = 16, - [1][1][2][0][0][43] = 16, - [1][1][2][1][0][1] = 6, - [1][1][2][1][0][5] = 6, - [1][1][2][1][0][9] = 28, - [1][1][2][1][0][13] = 28, - [1][1][2][1][0][16] = 28, - [1][1][2][1][0][20] = 28, - [1][1][2][1][0][24] = 28, - [1][1][2][1][0][28] = 28, - [1][1][2][1][0][32] = 28, - [1][1][2][1][0][36] = 30, - [1][1][2][1][0][39] = 4, - [1][1][2][1][0][43] = 4, - [2][0][2][0][0][3] = 30, - [2][0][2][0][0][11] = 52, - [2][0][2][0][0][18] = 52, - [2][0][2][0][0][26] = 52, - [2][0][2][0][0][34] = 54, - [2][0][2][0][0][41] = 28, - [2][1][2][0][0][3] = 18, - [2][1][2][0][0][11] = 40, - [2][1][2][0][0][18] = 40, - [2][1][2][0][0][26] = 40, - [2][1][2][0][0][34] = 42, - [2][1][2][0][0][41] = 16, - [2][1][2][1][0][3] = 6, - [2][1][2][1][0][11] = 28, - [2][1][2][1][0][18] = 28, - [2][1][2][1][0][26] = 28, - [2][1][2][1][0][34] = 30, - [2][1][2][1][0][41] = 4, - [0][0][1][0][2][0] = 76, - [0][0][1][0][1][0] = 58, - [0][0][1][0][3][0] = 62, - [0][0][1][0][5][0] = 62, - [0][0][1][0][6][0] = 58, - [0][0][1][0][9][0] = 58, - [0][0][1][0][8][0] = 30, - [0][0][1][0][11][0] = 52, - [0][0][1][0][2][2] = 76, - [0][0][1][0][1][2] = 58, - [0][0][1][0][3][2] = 62, - [0][0][1][0][5][2] = 62, - [0][0][1][0][6][2] = 58, - [0][0][1][0][9][2] = 58, - [0][0][1][0][8][2] = 30, - [0][0][1][0][11][2] = 52, - [0][0][1][0][2][4] = 76, - [0][0][1][0][1][4] = 58, - [0][0][1][0][3][4] = 62, - [0][0][1][0][5][4] = 62, - [0][0][1][0][6][4] = 58, - [0][0][1][0][9][4] = 58, - [0][0][1][0][8][4] = 30, - [0][0][1][0][11][4] = 52, - [0][0][1][0][2][6] = 76, - [0][0][1][0][1][6] = 58, - [0][0][1][0][3][6] = 62, - [0][0][1][0][5][6] = 62, - [0][0][1][0][6][6] = 54, - [0][0][1][0][9][6] = 58, - [0][0][1][0][8][6] = 30, - [0][0][1][0][11][6] = 52, - [0][0][1][0][2][8] = 76, - [0][0][1][0][1][8] = 58, - [0][0][1][0][3][8] = 62, - [0][0][1][0][5][8] = 64, - [0][0][1][0][6][8] = 58, - [0][0][1][0][9][8] = 58, - [0][0][1][0][8][8] = 54, - [0][0][1][0][11][8] = 52, - [0][0][1][0][2][10] = 76, - [0][0][1][0][1][10] = 58, - [0][0][1][0][3][10] = 62, - [0][0][1][0][5][10] = 64, - [0][0][1][0][6][10] = 58, - [0][0][1][0][9][10] = 58, - [0][0][1][0][8][10] = 54, - [0][0][1][0][11][10] = 52, - [0][0][1][0][2][12] = 76, - [0][0][1][0][1][12] = 58, - [0][0][1][0][3][12] = 62, - [0][0][1][0][5][12] = 64, - [0][0][1][0][6][12] = 58, - [0][0][1][0][9][12] = 58, - [0][0][1][0][8][12] = 54, - [0][0][1][0][11][12] = 52, - [0][0][1][0][2][14] = 76, - [0][0][1][0][1][14] = 58, - [0][0][1][0][3][14] = 62, - [0][0][1][0][5][14] = 64, - [0][0][1][0][6][14] = 58, - [0][0][1][0][9][14] = 58, - [0][0][1][0][8][14] = 54, - [0][0][1][0][11][14] = 52, - [0][0][1][0][2][15] = 76, - [0][0][1][0][1][15] = 58, - [0][0][1][0][3][15] = 76, - [0][0][1][0][5][15] = 76, - [0][0][1][0][6][15] = 58, - [0][0][1][0][9][15] = 58, - [0][0][1][0][8][15] = 54, - [0][0][1][0][11][15] = 52, - [0][0][1][0][2][17] = 76, - [0][0][1][0][1][17] = 58, - [0][0][1][0][3][17] = 76, - [0][0][1][0][5][17] = 76, - [0][0][1][0][6][17] = 58, - [0][0][1][0][9][17] = 58, - [0][0][1][0][8][17] = 54, - [0][0][1][0][11][17] = 52, - [0][0][1][0][2][19] = 76, - [0][0][1][0][1][19] = 58, - [0][0][1][0][3][19] = 76, - [0][0][1][0][5][19] = 76, - [0][0][1][0][6][19] = 58, - [0][0][1][0][9][19] = 58, - [0][0][1][0][8][19] = 54, - [0][0][1][0][11][19] = 52, - [0][0][1][0][2][21] = 76, - [0][0][1][0][1][21] = 58, - [0][0][1][0][3][21] = 76, - [0][0][1][0][5][21] = 76, - [0][0][1][0][6][21] = 58, - [0][0][1][0][9][21] = 58, - [0][0][1][0][8][21] = 54, - [0][0][1][0][11][21] = 52, - [0][0][1][0][2][23] = 76, - [0][0][1][0][1][23] = 58, - [0][0][1][0][3][23] = 76, - [0][0][1][0][5][23] = 76, - [0][0][1][0][6][23] = 58, - [0][0][1][0][9][23] = 58, - [0][0][1][0][8][23] = 54, - [0][0][1][0][11][23] = 52, - [0][0][1][0][2][25] = 76, - [0][0][1][0][1][25] = 58, - [0][0][1][0][3][25] = 76, - [0][0][1][0][5][25] = 127, - [0][0][1][0][6][25] = 58, - [0][0][1][0][9][25] = 127, - [0][0][1][0][8][25] = 54, - [0][0][1][0][11][25] = 52, - [0][0][1][0][2][27] = 76, - [0][0][1][0][1][27] = 58, - [0][0][1][0][3][27] = 76, - [0][0][1][0][5][27] = 127, - [0][0][1][0][6][27] = 58, - [0][0][1][0][9][27] = 127, - [0][0][1][0][8][27] = 54, - [0][0][1][0][11][27] = 52, - [0][0][1][0][2][29] = 76, - [0][0][1][0][1][29] = 58, - [0][0][1][0][3][29] = 76, - [0][0][1][0][5][29] = 127, - [0][0][1][0][6][29] = 58, - [0][0][1][0][9][29] = 127, - [0][0][1][0][8][29] = 54, - [0][0][1][0][11][29] = 52, - [0][0][1][0][2][31] = 76, - [0][0][1][0][1][31] = 58, - [0][0][1][0][3][31] = 76, - [0][0][1][0][5][31] = 76, - [0][0][1][0][6][31] = 58, - [0][0][1][0][9][31] = 58, - [0][0][1][0][8][31] = 54, - [0][0][1][0][11][31] = 52, - [0][0][1][0][2][33] = 76, - [0][0][1][0][1][33] = 58, - [0][0][1][0][3][33] = 76, - [0][0][1][0][5][33] = 76, - [0][0][1][0][6][33] = 58, - [0][0][1][0][9][33] = 58, - [0][0][1][0][8][33] = 54, - [0][0][1][0][11][33] = 52, - [0][0][1][0][2][35] = 74, - [0][0][1][0][1][35] = 58, - [0][0][1][0][3][35] = 76, - [0][0][1][0][5][35] = 74, - [0][0][1][0][6][35] = 58, - [0][0][1][0][9][35] = 58, - [0][0][1][0][8][35] = 54, - [0][0][1][0][11][35] = 52, - [0][0][1][0][2][37] = 76, - [0][0][1][0][1][37] = 127, - [0][0][1][0][3][37] = 76, - [0][0][1][0][5][37] = 76, - [0][0][1][0][6][37] = 58, - [0][0][1][0][9][37] = 76, - [0][0][1][0][8][37] = 54, - [0][0][1][0][11][37] = 127, - [0][0][1][0][2][38] = 76, - [0][0][1][0][1][38] = 28, - [0][0][1][0][3][38] = 127, - [0][0][1][0][5][38] = 76, - [0][0][1][0][6][38] = 28, - [0][0][1][0][9][38] = 76, - [0][0][1][0][8][38] = 54, - [0][0][1][0][11][38] = 52, - [0][0][1][0][2][40] = 76, - [0][0][1][0][1][40] = 28, - [0][0][1][0][3][40] = 127, - [0][0][1][0][5][40] = 76, - [0][0][1][0][6][40] = 28, - [0][0][1][0][9][40] = 76, - [0][0][1][0][8][40] = 54, - [0][0][1][0][11][40] = 52, - [0][0][1][0][2][42] = 76, - [0][0][1][0][1][42] = 28, - [0][0][1][0][3][42] = 127, - [0][0][1][0][5][42] = 76, - [0][0][1][0][6][42] = 28, - [0][0][1][0][9][42] = 76, - [0][0][1][0][8][42] = 54, - [0][0][1][0][11][42] = 52, - [0][0][1][0][2][44] = 76, - [0][0][1][0][1][44] = 28, - [0][0][1][0][3][44] = 127, - [0][0][1][0][5][44] = 76, - [0][0][1][0][6][44] = 28, - [0][0][1][0][9][44] = 76, - [0][0][1][0][8][44] = 54, - [0][0][1][0][11][44] = 52, - [0][0][1][0][2][46] = 76, - [0][0][1][0][1][46] = 28, - [0][0][1][0][3][46] = 127, - [0][0][1][0][5][46] = 76, - [0][0][1][0][6][46] = 28, - [0][0][1][0][9][46] = 76, - [0][0][1][0][8][46] = 54, - [0][0][1][0][11][46] = 52, - [0][1][1][0][2][0] = 68, - [0][1][1][0][1][0] = 46, - [0][1][1][0][3][0] = 50, - [0][1][1][0][5][0] = 40, - [0][1][1][0][6][0] = 46, - [0][1][1][0][9][0] = 46, - [0][1][1][0][8][0] = 18, - [0][1][1][0][11][0] = 40, - [0][1][1][0][2][2] = 68, - [0][1][1][0][1][2] = 46, - [0][1][1][0][3][2] = 50, - [0][1][1][0][5][2] = 40, - [0][1][1][0][6][2] = 46, - [0][1][1][0][9][2] = 46, - [0][1][1][0][8][2] = 18, - [0][1][1][0][11][2] = 40, - [0][1][1][0][2][4] = 68, - [0][1][1][0][1][4] = 46, - [0][1][1][0][3][4] = 50, - [0][1][1][0][5][4] = 40, - [0][1][1][0][6][4] = 46, - [0][1][1][0][9][4] = 46, - [0][1][1][0][8][4] = 18, - [0][1][1][0][11][4] = 40, - [0][1][1][0][2][6] = 68, - [0][1][1][0][1][6] = 46, - [0][1][1][0][3][6] = 50, - [0][1][1][0][5][6] = 40, - [0][1][1][0][6][6] = 36, - [0][1][1][0][9][6] = 46, - [0][1][1][0][8][6] = 18, - [0][1][1][0][11][6] = 40, - [0][1][1][0][2][8] = 68, - [0][1][1][0][1][8] = 46, - [0][1][1][0][3][8] = 50, - [0][1][1][0][5][8] = 52, - [0][1][1][0][6][8] = 46, - [0][1][1][0][9][8] = 46, - [0][1][1][0][8][8] = 42, - [0][1][1][0][11][8] = 40, - [0][1][1][0][2][10] = 68, - [0][1][1][0][1][10] = 46, - [0][1][1][0][3][10] = 50, - [0][1][1][0][5][10] = 52, - [0][1][1][0][6][10] = 46, - [0][1][1][0][9][10] = 46, - [0][1][1][0][8][10] = 42, - [0][1][1][0][11][10] = 40, - [0][1][1][0][2][12] = 68, - [0][1][1][0][1][12] = 46, - [0][1][1][0][3][12] = 50, - [0][1][1][0][5][12] = 52, - [0][1][1][0][6][12] = 46, - [0][1][1][0][9][12] = 46, - [0][1][1][0][8][12] = 42, - [0][1][1][0][11][12] = 40, - [0][1][1][0][2][14] = 68, - [0][1][1][0][1][14] = 46, - [0][1][1][0][3][14] = 50, - [0][1][1][0][5][14] = 52, - [0][1][1][0][6][14] = 46, - [0][1][1][0][9][14] = 46, - [0][1][1][0][8][14] = 42, - [0][1][1][0][11][14] = 40, - [0][1][1][0][2][15] = 68, - [0][1][1][0][1][15] = 46, - [0][1][1][0][3][15] = 70, - [0][1][1][0][5][15] = 68, - [0][1][1][0][6][15] = 46, - [0][1][1][0][9][15] = 46, - [0][1][1][0][8][15] = 42, - [0][1][1][0][11][15] = 40, - [0][1][1][0][2][17] = 68, - [0][1][1][0][1][17] = 46, - [0][1][1][0][3][17] = 70, - [0][1][1][0][5][17] = 68, - [0][1][1][0][6][17] = 46, - [0][1][1][0][9][17] = 46, - [0][1][1][0][8][17] = 42, - [0][1][1][0][11][17] = 40, - [0][1][1][0][2][19] = 68, - [0][1][1][0][1][19] = 46, - [0][1][1][0][3][19] = 70, - [0][1][1][0][5][19] = 68, - [0][1][1][0][6][19] = 46, - [0][1][1][0][9][19] = 46, - [0][1][1][0][8][19] = 42, - [0][1][1][0][11][19] = 40, - [0][1][1][0][2][21] = 68, - [0][1][1][0][1][21] = 46, - [0][1][1][0][3][21] = 70, - [0][1][1][0][5][21] = 68, - [0][1][1][0][6][21] = 46, - [0][1][1][0][9][21] = 46, - [0][1][1][0][8][21] = 42, - [0][1][1][0][11][21] = 40, - [0][1][1][0][2][23] = 68, - [0][1][1][0][1][23] = 46, - [0][1][1][0][3][23] = 70, - [0][1][1][0][5][23] = 68, - [0][1][1][0][6][23] = 46, - [0][1][1][0][9][23] = 46, - [0][1][1][0][8][23] = 42, - [0][1][1][0][11][23] = 40, - [0][1][1][0][2][25] = 68, - [0][1][1][0][1][25] = 46, - [0][1][1][0][3][25] = 70, - [0][1][1][0][5][25] = 127, - [0][1][1][0][6][25] = 46, - [0][1][1][0][9][25] = 127, - [0][1][1][0][8][25] = 42, - [0][1][1][0][11][25] = 40, - [0][1][1][0][2][27] = 68, - [0][1][1][0][1][27] = 46, - [0][1][1][0][3][27] = 70, - [0][1][1][0][5][27] = 127, - [0][1][1][0][6][27] = 46, - [0][1][1][0][9][27] = 127, - [0][1][1][0][8][27] = 42, - [0][1][1][0][11][27] = 40, - [0][1][1][0][2][29] = 68, - [0][1][1][0][1][29] = 46, - [0][1][1][0][3][29] = 70, - [0][1][1][0][5][29] = 127, - [0][1][1][0][6][29] = 46, - [0][1][1][0][9][29] = 127, - [0][1][1][0][8][29] = 42, - [0][1][1][0][11][29] = 40, - [0][1][1][0][2][31] = 68, - [0][1][1][0][1][31] = 46, - [0][1][1][0][3][31] = 70, - [0][1][1][0][5][31] = 68, - [0][1][1][0][6][31] = 46, - [0][1][1][0][9][31] = 46, - [0][1][1][0][8][31] = 42, - [0][1][1][0][11][31] = 40, - [0][1][1][0][2][33] = 68, - [0][1][1][0][1][33] = 46, - [0][1][1][0][3][33] = 70, - [0][1][1][0][5][33] = 68, - [0][1][1][0][6][33] = 46, - [0][1][1][0][9][33] = 46, - [0][1][1][0][8][33] = 42, - [0][1][1][0][11][33] = 40, - [0][1][1][0][2][35] = 66, - [0][1][1][0][1][35] = 46, - [0][1][1][0][3][35] = 70, - [0][1][1][0][5][35] = 66, - [0][1][1][0][6][35] = 46, - [0][1][1][0][9][35] = 46, - [0][1][1][0][8][35] = 42, - [0][1][1][0][11][35] = 40, - [0][1][1][0][2][37] = 68, - [0][1][1][0][1][37] = 127, - [0][1][1][0][3][37] = 70, - [0][1][1][0][5][37] = 68, - [0][1][1][0][6][37] = 46, - [0][1][1][0][9][37] = 68, - [0][1][1][0][8][37] = 42, - [0][1][1][0][11][37] = 127, - [0][1][1][0][2][38] = 76, - [0][1][1][0][1][38] = 16, - [0][1][1][0][3][38] = 127, - [0][1][1][0][5][38] = 76, - [0][1][1][0][6][38] = 16, - [0][1][1][0][9][38] = 76, - [0][1][1][0][8][38] = 42, - [0][1][1][0][11][38] = 40, - [0][1][1][0][2][40] = 76, - [0][1][1][0][1][40] = 16, - [0][1][1][0][3][40] = 127, - [0][1][1][0][5][40] = 76, - [0][1][1][0][6][40] = 16, - [0][1][1][0][9][40] = 76, - [0][1][1][0][8][40] = 42, - [0][1][1][0][11][40] = 40, - [0][1][1][0][2][42] = 76, - [0][1][1][0][1][42] = 16, - [0][1][1][0][3][42] = 127, - [0][1][1][0][5][42] = 76, - [0][1][1][0][6][42] = 16, - [0][1][1][0][9][42] = 76, - [0][1][1][0][8][42] = 42, - [0][1][1][0][11][42] = 40, - [0][1][1][0][2][44] = 76, - [0][1][1][0][1][44] = 16, - [0][1][1][0][3][44] = 127, - [0][1][1][0][5][44] = 76, - [0][1][1][0][6][44] = 16, - [0][1][1][0][9][44] = 76, - [0][1][1][0][8][44] = 42, - [0][1][1][0][11][44] = 40, - [0][1][1][0][2][46] = 76, - [0][1][1][0][1][46] = 16, - [0][1][1][0][3][46] = 127, - [0][1][1][0][5][46] = 76, - [0][1][1][0][6][46] = 16, - [0][1][1][0][9][46] = 76, - [0][1][1][0][8][46] = 42, - [0][1][1][0][11][46] = 40, - [0][0][2][0][2][0] = 76, - [0][0][2][0][1][0] = 58, - [0][0][2][0][3][0] = 62, - [0][0][2][0][5][0] = 62, - [0][0][2][0][6][0] = 58, - [0][0][2][0][9][0] = 58, - [0][0][2][0][8][0] = 30, - [0][0][2][0][11][0] = 52, - [0][0][2][0][2][2] = 76, - [0][0][2][0][1][2] = 58, - [0][0][2][0][3][2] = 62, - [0][0][2][0][5][2] = 62, - [0][0][2][0][6][2] = 58, - [0][0][2][0][9][2] = 58, - [0][0][2][0][8][2] = 30, - [0][0][2][0][11][2] = 52, - [0][0][2][0][2][4] = 76, - [0][0][2][0][1][4] = 58, - [0][0][2][0][3][4] = 62, - [0][0][2][0][5][4] = 62, - [0][0][2][0][6][4] = 58, - [0][0][2][0][9][4] = 58, - [0][0][2][0][8][4] = 30, - [0][0][2][0][11][4] = 52, - [0][0][2][0][2][6] = 76, - [0][0][2][0][1][6] = 58, - [0][0][2][0][3][6] = 62, - [0][0][2][0][5][6] = 62, - [0][0][2][0][6][6] = 54, - [0][0][2][0][9][6] = 58, - [0][0][2][0][8][6] = 30, - [0][0][2][0][11][6] = 52, - [0][0][2][0][2][8] = 76, - [0][0][2][0][1][8] = 58, - [0][0][2][0][3][8] = 62, - [0][0][2][0][5][8] = 64, - [0][0][2][0][6][8] = 58, - [0][0][2][0][9][8] = 58, - [0][0][2][0][8][8] = 54, - [0][0][2][0][11][8] = 52, - [0][0][2][0][2][10] = 76, - [0][0][2][0][1][10] = 58, - [0][0][2][0][3][10] = 62, - [0][0][2][0][5][10] = 64, - [0][0][2][0][6][10] = 58, - [0][0][2][0][9][10] = 58, - [0][0][2][0][8][10] = 54, - [0][0][2][0][11][10] = 52, - [0][0][2][0][2][12] = 76, - [0][0][2][0][1][12] = 58, - [0][0][2][0][3][12] = 62, - [0][0][2][0][5][12] = 64, - [0][0][2][0][6][12] = 58, - [0][0][2][0][9][12] = 58, - [0][0][2][0][8][12] = 54, - [0][0][2][0][11][12] = 52, - [0][0][2][0][2][14] = 76, - [0][0][2][0][1][14] = 58, - [0][0][2][0][3][14] = 62, - [0][0][2][0][5][14] = 64, - [0][0][2][0][6][14] = 58, - [0][0][2][0][9][14] = 58, - [0][0][2][0][8][14] = 54, - [0][0][2][0][11][14] = 52, - [0][0][2][0][2][15] = 74, - [0][0][2][0][1][15] = 58, - [0][0][2][0][3][15] = 76, - [0][0][2][0][5][15] = 74, - [0][0][2][0][6][15] = 58, - [0][0][2][0][9][15] = 58, - [0][0][2][0][8][15] = 54, - [0][0][2][0][11][15] = 52, - [0][0][2][0][2][17] = 76, - [0][0][2][0][1][17] = 58, - [0][0][2][0][3][17] = 76, - [0][0][2][0][5][17] = 76, - [0][0][2][0][6][17] = 58, - [0][0][2][0][9][17] = 58, - [0][0][2][0][8][17] = 54, - [0][0][2][0][11][17] = 52, - [0][0][2][0][2][19] = 76, - [0][0][2][0][1][19] = 58, - [0][0][2][0][3][19] = 76, - [0][0][2][0][5][19] = 76, - [0][0][2][0][6][19] = 58, - [0][0][2][0][9][19] = 58, - [0][0][2][0][8][19] = 54, - [0][0][2][0][11][19] = 52, - [0][0][2][0][2][21] = 76, - [0][0][2][0][1][21] = 58, - [0][0][2][0][3][21] = 76, - [0][0][2][0][5][21] = 76, - [0][0][2][0][6][21] = 58, - [0][0][2][0][9][21] = 58, - [0][0][2][0][8][21] = 54, - [0][0][2][0][11][21] = 52, - [0][0][2][0][2][23] = 76, - [0][0][2][0][1][23] = 58, - [0][0][2][0][3][23] = 76, - [0][0][2][0][5][23] = 76, - [0][0][2][0][6][23] = 58, - [0][0][2][0][9][23] = 58, - [0][0][2][0][8][23] = 54, - [0][0][2][0][11][23] = 52, - [0][0][2][0][2][25] = 76, - [0][0][2][0][1][25] = 58, - [0][0][2][0][3][25] = 76, - [0][0][2][0][5][25] = 127, - [0][0][2][0][6][25] = 58, - [0][0][2][0][9][25] = 127, - [0][0][2][0][8][25] = 54, - [0][0][2][0][11][25] = 52, - [0][0][2][0][2][27] = 76, - [0][0][2][0][1][27] = 58, - [0][0][2][0][3][27] = 76, - [0][0][2][0][5][27] = 127, - [0][0][2][0][6][27] = 58, - [0][0][2][0][9][27] = 127, - [0][0][2][0][8][27] = 54, - [0][0][2][0][11][27] = 52, - [0][0][2][0][2][29] = 76, - [0][0][2][0][1][29] = 58, - [0][0][2][0][3][29] = 76, - [0][0][2][0][5][29] = 127, - [0][0][2][0][6][29] = 58, - [0][0][2][0][9][29] = 127, - [0][0][2][0][8][29] = 54, - [0][0][2][0][11][29] = 52, - [0][0][2][0][2][31] = 76, - [0][0][2][0][1][31] = 58, - [0][0][2][0][3][31] = 76, - [0][0][2][0][5][31] = 76, - [0][0][2][0][6][31] = 58, - [0][0][2][0][9][31] = 58, - [0][0][2][0][8][31] = 54, - [0][0][2][0][11][31] = 52, - [0][0][2][0][2][33] = 76, - [0][0][2][0][1][33] = 58, - [0][0][2][0][3][33] = 76, - [0][0][2][0][5][33] = 76, - [0][0][2][0][6][33] = 58, - [0][0][2][0][9][33] = 58, - [0][0][2][0][8][33] = 54, - [0][0][2][0][11][33] = 52, - [0][0][2][0][2][35] = 70, - [0][0][2][0][1][35] = 58, - [0][0][2][0][3][35] = 76, - [0][0][2][0][5][35] = 70, - [0][0][2][0][6][35] = 58, - [0][0][2][0][9][35] = 58, - [0][0][2][0][8][35] = 54, - [0][0][2][0][11][35] = 52, - [0][0][2][0][2][37] = 76, - [0][0][2][0][1][37] = 127, - [0][0][2][0][3][37] = 76, - [0][0][2][0][5][37] = 76, - [0][0][2][0][6][37] = 58, - [0][0][2][0][9][37] = 76, - [0][0][2][0][8][37] = 54, - [0][0][2][0][11][37] = 127, - [0][0][2][0][2][38] = 76, - [0][0][2][0][1][38] = 28, - [0][0][2][0][3][38] = 127, - [0][0][2][0][5][38] = 76, - [0][0][2][0][6][38] = 28, - [0][0][2][0][9][38] = 76, - [0][0][2][0][8][38] = 54, - [0][0][2][0][11][38] = 52, - [0][0][2][0][2][40] = 76, - [0][0][2][0][1][40] = 28, - [0][0][2][0][3][40] = 127, - [0][0][2][0][5][40] = 76, - [0][0][2][0][6][40] = 28, - [0][0][2][0][9][40] = 76, - [0][0][2][0][8][40] = 54, - [0][0][2][0][11][40] = 52, - [0][0][2][0][2][42] = 76, - [0][0][2][0][1][42] = 28, - [0][0][2][0][3][42] = 127, - [0][0][2][0][5][42] = 76, - [0][0][2][0][6][42] = 28, - [0][0][2][0][9][42] = 76, - [0][0][2][0][8][42] = 54, - [0][0][2][0][11][42] = 52, - [0][0][2][0][2][44] = 76, - [0][0][2][0][1][44] = 28, - [0][0][2][0][3][44] = 127, - [0][0][2][0][5][44] = 76, - [0][0][2][0][6][44] = 28, - [0][0][2][0][9][44] = 76, - [0][0][2][0][8][44] = 54, - [0][0][2][0][11][44] = 52, - [0][0][2][0][2][46] = 76, - [0][0][2][0][1][46] = 28, - [0][0][2][0][3][46] = 127, - [0][0][2][0][5][46] = 76, - [0][0][2][0][6][46] = 28, - [0][0][2][0][9][46] = 76, - [0][0][2][0][8][46] = 54, - [0][0][2][0][11][46] = 52, - [0][1][2][0][2][0] = 68, - [0][1][2][0][1][0] = 46, - [0][1][2][0][3][0] = 50, - [0][1][2][0][5][0] = 40, - [0][1][2][0][6][0] = 46, - [0][1][2][0][9][0] = 46, - [0][1][2][0][8][0] = 18, - [0][1][2][0][11][0] = 40, - [0][1][2][0][2][2] = 68, - [0][1][2][0][1][2] = 46, - [0][1][2][0][3][2] = 50, - [0][1][2][0][5][2] = 40, - [0][1][2][0][6][2] = 46, - [0][1][2][0][9][2] = 46, - [0][1][2][0][8][2] = 18, - [0][1][2][0][11][2] = 40, - [0][1][2][0][2][4] = 68, - [0][1][2][0][1][4] = 46, - [0][1][2][0][3][4] = 50, - [0][1][2][0][5][4] = 40, - [0][1][2][0][6][4] = 46, - [0][1][2][0][9][4] = 46, - [0][1][2][0][8][4] = 18, - [0][1][2][0][11][4] = 40, - [0][1][2][0][2][6] = 68, - [0][1][2][0][1][6] = 46, - [0][1][2][0][3][6] = 50, - [0][1][2][0][5][6] = 40, - [0][1][2][0][6][6] = 36, - [0][1][2][0][9][6] = 46, - [0][1][2][0][8][6] = 18, - [0][1][2][0][11][6] = 40, - [0][1][2][0][2][8] = 68, - [0][1][2][0][1][8] = 46, - [0][1][2][0][3][8] = 50, - [0][1][2][0][5][8] = 52, - [0][1][2][0][6][8] = 46, - [0][1][2][0][9][8] = 46, - [0][1][2][0][8][8] = 42, - [0][1][2][0][11][8] = 40, - [0][1][2][0][2][10] = 68, - [0][1][2][0][1][10] = 46, - [0][1][2][0][3][10] = 50, - [0][1][2][0][5][10] = 52, - [0][1][2][0][6][10] = 46, - [0][1][2][0][9][10] = 46, - [0][1][2][0][8][10] = 42, - [0][1][2][0][11][10] = 40, - [0][1][2][0][2][12] = 68, - [0][1][2][0][1][12] = 46, - [0][1][2][0][3][12] = 50, - [0][1][2][0][5][12] = 52, - [0][1][2][0][6][12] = 46, - [0][1][2][0][9][12] = 46, - [0][1][2][0][8][12] = 42, - [0][1][2][0][11][12] = 40, - [0][1][2][0][2][14] = 68, - [0][1][2][0][1][14] = 46, - [0][1][2][0][3][14] = 50, - [0][1][2][0][5][14] = 52, - [0][1][2][0][6][14] = 46, - [0][1][2][0][9][14] = 46, - [0][1][2][0][8][14] = 42, - [0][1][2][0][11][14] = 40, - [0][1][2][0][2][15] = 68, - [0][1][2][0][1][15] = 46, - [0][1][2][0][3][15] = 70, - [0][1][2][0][5][15] = 68, - [0][1][2][0][6][15] = 46, - [0][1][2][0][9][15] = 46, - [0][1][2][0][8][15] = 42, - [0][1][2][0][11][15] = 40, - [0][1][2][0][2][17] = 68, - [0][1][2][0][1][17] = 46, - [0][1][2][0][3][17] = 70, - [0][1][2][0][5][17] = 68, - [0][1][2][0][6][17] = 46, - [0][1][2][0][9][17] = 46, - [0][1][2][0][8][17] = 42, - [0][1][2][0][11][17] = 40, - [0][1][2][0][2][19] = 68, - [0][1][2][0][1][19] = 46, - [0][1][2][0][3][19] = 70, - [0][1][2][0][5][19] = 68, - [0][1][2][0][6][19] = 46, - [0][1][2][0][9][19] = 46, - [0][1][2][0][8][19] = 42, - [0][1][2][0][11][19] = 40, - [0][1][2][0][2][21] = 68, - [0][1][2][0][1][21] = 46, - [0][1][2][0][3][21] = 70, - [0][1][2][0][5][21] = 68, - [0][1][2][0][6][21] = 46, - [0][1][2][0][9][21] = 46, - [0][1][2][0][8][21] = 42, - [0][1][2][0][11][21] = 40, - [0][1][2][0][2][23] = 68, - [0][1][2][0][1][23] = 46, - [0][1][2][0][3][23] = 70, - [0][1][2][0][5][23] = 68, - [0][1][2][0][6][23] = 46, - [0][1][2][0][9][23] = 46, - [0][1][2][0][8][23] = 42, - [0][1][2][0][11][23] = 40, - [0][1][2][0][2][25] = 68, - [0][1][2][0][1][25] = 46, - [0][1][2][0][3][25] = 70, - [0][1][2][0][5][25] = 127, - [0][1][2][0][6][25] = 46, - [0][1][2][0][9][25] = 127, - [0][1][2][0][8][25] = 42, - [0][1][2][0][11][25] = 40, - [0][1][2][0][2][27] = 68, - [0][1][2][0][1][27] = 46, - [0][1][2][0][3][27] = 70, - [0][1][2][0][5][27] = 127, - [0][1][2][0][6][27] = 46, - [0][1][2][0][9][27] = 127, - [0][1][2][0][8][27] = 42, - [0][1][2][0][11][27] = 40, - [0][1][2][0][2][29] = 68, - [0][1][2][0][1][29] = 46, - [0][1][2][0][3][29] = 70, - [0][1][2][0][5][29] = 127, - [0][1][2][0][6][29] = 46, - [0][1][2][0][9][29] = 127, - [0][1][2][0][8][29] = 42, - [0][1][2][0][11][29] = 40, - [0][1][2][0][2][31] = 68, - [0][1][2][0][1][31] = 46, - [0][1][2][0][3][31] = 70, - [0][1][2][0][5][31] = 68, - [0][1][2][0][6][31] = 46, - [0][1][2][0][9][31] = 46, - [0][1][2][0][8][31] = 42, - [0][1][2][0][11][31] = 40, - [0][1][2][0][2][33] = 68, - [0][1][2][0][1][33] = 46, - [0][1][2][0][3][33] = 70, - [0][1][2][0][5][33] = 68, - [0][1][2][0][6][33] = 46, - [0][1][2][0][9][33] = 46, - [0][1][2][0][8][33] = 42, - [0][1][2][0][11][33] = 40, - [0][1][2][0][2][35] = 64, - [0][1][2][0][1][35] = 46, - [0][1][2][0][3][35] = 70, - [0][1][2][0][5][35] = 64, - [0][1][2][0][6][35] = 46, - [0][1][2][0][9][35] = 46, - [0][1][2][0][8][35] = 42, - [0][1][2][0][11][35] = 40, - [0][1][2][0][2][37] = 68, - [0][1][2][0][1][37] = 127, - [0][1][2][0][3][37] = 70, - [0][1][2][0][5][37] = 68, - [0][1][2][0][6][37] = 46, - [0][1][2][0][9][37] = 68, - [0][1][2][0][8][37] = 42, - [0][1][2][0][11][37] = 127, - [0][1][2][0][2][38] = 76, - [0][1][2][0][1][38] = 16, - [0][1][2][0][3][38] = 127, - [0][1][2][0][5][38] = 76, - [0][1][2][0][6][38] = 16, - [0][1][2][0][9][38] = 76, - [0][1][2][0][8][38] = 42, - [0][1][2][0][11][38] = 40, - [0][1][2][0][2][40] = 76, - [0][1][2][0][1][40] = 16, - [0][1][2][0][3][40] = 127, - [0][1][2][0][5][40] = 76, - [0][1][2][0][6][40] = 16, - [0][1][2][0][9][40] = 76, - [0][1][2][0][8][40] = 42, - [0][1][2][0][11][40] = 40, - [0][1][2][0][2][42] = 76, - [0][1][2][0][1][42] = 16, - [0][1][2][0][3][42] = 127, - [0][1][2][0][5][42] = 76, - [0][1][2][0][6][42] = 16, - [0][1][2][0][9][42] = 76, - [0][1][2][0][8][42] = 42, - [0][1][2][0][11][42] = 40, - [0][1][2][0][2][44] = 76, - [0][1][2][0][1][44] = 16, - [0][1][2][0][3][44] = 127, - [0][1][2][0][5][44] = 76, - [0][1][2][0][6][44] = 16, - [0][1][2][0][9][44] = 76, - [0][1][2][0][8][44] = 42, - [0][1][2][0][11][44] = 40, - [0][1][2][0][2][46] = 76, - [0][1][2][0][1][46] = 16, - [0][1][2][0][3][46] = 127, - [0][1][2][0][5][46] = 76, - [0][1][2][0][6][46] = 16, - [0][1][2][0][9][46] = 76, - [0][1][2][0][8][46] = 42, - [0][1][2][0][11][46] = 40, - [0][1][2][1][2][0] = 68, - [0][1][2][1][1][0] = 34, - [0][1][2][1][3][0] = 50, - [0][1][2][1][5][0] = 38, - [0][1][2][1][6][0] = 34, - [0][1][2][1][9][0] = 34, - [0][1][2][1][8][0] = 6, - [0][1][2][1][11][0] = 28, - [0][1][2][1][2][2] = 68, - [0][1][2][1][1][2] = 34, - [0][1][2][1][3][2] = 50, - [0][1][2][1][5][2] = 38, - [0][1][2][1][6][2] = 34, - [0][1][2][1][9][2] = 34, - [0][1][2][1][8][2] = 6, - [0][1][2][1][11][2] = 28, - [0][1][2][1][2][4] = 68, - [0][1][2][1][1][4] = 34, - [0][1][2][1][3][4] = 50, - [0][1][2][1][5][4] = 38, - [0][1][2][1][6][4] = 34, - [0][1][2][1][9][4] = 34, - [0][1][2][1][8][4] = 6, - [0][1][2][1][11][4] = 28, - [0][1][2][1][2][6] = 68, - [0][1][2][1][1][6] = 34, - [0][1][2][1][3][6] = 50, - [0][1][2][1][5][6] = 38, - [0][1][2][1][6][6] = 34, - [0][1][2][1][9][6] = 34, - [0][1][2][1][8][6] = 6, - [0][1][2][1][11][6] = 28, - [0][1][2][1][2][8] = 68, - [0][1][2][1][1][8] = 34, - [0][1][2][1][3][8] = 50, - [0][1][2][1][5][8] = 38, - [0][1][2][1][6][8] = 34, - [0][1][2][1][9][8] = 34, - [0][1][2][1][8][8] = 30, - [0][1][2][1][11][8] = 28, - [0][1][2][1][2][10] = 68, - [0][1][2][1][1][10] = 34, - [0][1][2][1][3][10] = 50, - [0][1][2][1][5][10] = 38, - [0][1][2][1][6][10] = 34, - [0][1][2][1][9][10] = 34, - [0][1][2][1][8][10] = 30, - [0][1][2][1][11][10] = 28, - [0][1][2][1][2][12] = 68, - [0][1][2][1][1][12] = 34, - [0][1][2][1][3][12] = 50, - [0][1][2][1][5][12] = 38, - [0][1][2][1][6][12] = 34, - [0][1][2][1][9][12] = 34, - [0][1][2][1][8][12] = 30, - [0][1][2][1][11][12] = 28, - [0][1][2][1][2][14] = 68, - [0][1][2][1][1][14] = 34, - [0][1][2][1][3][14] = 50, - [0][1][2][1][5][14] = 38, - [0][1][2][1][6][14] = 34, - [0][1][2][1][9][14] = 34, - [0][1][2][1][8][14] = 30, - [0][1][2][1][11][14] = 28, - [0][1][2][1][2][15] = 68, - [0][1][2][1][1][15] = 34, - [0][1][2][1][3][15] = 70, - [0][1][2][1][5][15] = 62, - [0][1][2][1][6][15] = 34, - [0][1][2][1][9][15] = 34, - [0][1][2][1][8][15] = 30, - [0][1][2][1][11][15] = 28, - [0][1][2][1][2][17] = 68, - [0][1][2][1][1][17] = 34, - [0][1][2][1][3][17] = 70, - [0][1][2][1][5][17] = 62, - [0][1][2][1][6][17] = 34, - [0][1][2][1][9][17] = 34, - [0][1][2][1][8][17] = 30, - [0][1][2][1][11][17] = 28, - [0][1][2][1][2][19] = 68, - [0][1][2][1][1][19] = 34, - [0][1][2][1][3][19] = 70, - [0][1][2][1][5][19] = 62, - [0][1][2][1][6][19] = 34, - [0][1][2][1][9][19] = 34, - [0][1][2][1][8][19] = 30, - [0][1][2][1][11][19] = 28, - [0][1][2][1][2][21] = 68, - [0][1][2][1][1][21] = 34, - [0][1][2][1][3][21] = 70, - [0][1][2][1][5][21] = 62, - [0][1][2][1][6][21] = 34, - [0][1][2][1][9][21] = 34, - [0][1][2][1][8][21] = 30, - [0][1][2][1][11][21] = 28, - [0][1][2][1][2][23] = 68, - [0][1][2][1][1][23] = 34, - [0][1][2][1][3][23] = 70, - [0][1][2][1][5][23] = 62, - [0][1][2][1][6][23] = 34, - [0][1][2][1][9][23] = 34, - [0][1][2][1][8][23] = 30, - [0][1][2][1][11][23] = 28, - [0][1][2][1][2][25] = 68, - [0][1][2][1][1][25] = 34, - [0][1][2][1][3][25] = 70, - [0][1][2][1][5][25] = 127, - [0][1][2][1][6][25] = 34, - [0][1][2][1][9][25] = 127, - [0][1][2][1][8][25] = 30, - [0][1][2][1][11][25] = 28, - [0][1][2][1][2][27] = 68, - [0][1][2][1][1][27] = 34, - [0][1][2][1][3][27] = 70, - [0][1][2][1][5][27] = 127, - [0][1][2][1][6][27] = 34, - [0][1][2][1][9][27] = 127, - [0][1][2][1][8][27] = 30, - [0][1][2][1][11][27] = 28, - [0][1][2][1][2][29] = 68, - [0][1][2][1][1][29] = 34, - [0][1][2][1][3][29] = 70, - [0][1][2][1][5][29] = 127, - [0][1][2][1][6][29] = 34, - [0][1][2][1][9][29] = 127, - [0][1][2][1][8][29] = 30, - [0][1][2][1][11][29] = 28, - [0][1][2][1][2][31] = 68, - [0][1][2][1][1][31] = 34, - [0][1][2][1][3][31] = 70, - [0][1][2][1][5][31] = 62, - [0][1][2][1][6][31] = 34, - [0][1][2][1][9][31] = 34, - [0][1][2][1][8][31] = 30, - [0][1][2][1][11][31] = 28, - [0][1][2][1][2][33] = 68, - [0][1][2][1][1][33] = 34, - [0][1][2][1][3][33] = 70, - [0][1][2][1][5][33] = 62, - [0][1][2][1][6][33] = 34, - [0][1][2][1][9][33] = 34, - [0][1][2][1][8][33] = 30, - [0][1][2][1][11][33] = 28, - [0][1][2][1][2][35] = 64, - [0][1][2][1][1][35] = 34, - [0][1][2][1][3][35] = 70, - [0][1][2][1][5][35] = 62, - [0][1][2][1][6][35] = 34, - [0][1][2][1][9][35] = 34, - [0][1][2][1][8][35] = 30, - [0][1][2][1][11][35] = 28, - [0][1][2][1][2][37] = 68, - [0][1][2][1][1][37] = 127, - [0][1][2][1][3][37] = 70, - [0][1][2][1][5][37] = 62, - [0][1][2][1][6][37] = 34, - [0][1][2][1][9][37] = 68, - [0][1][2][1][8][37] = 30, - [0][1][2][1][11][37] = 127, - [0][1][2][1][2][38] = 76, - [0][1][2][1][1][38] = 4, - [0][1][2][1][3][38] = 127, - [0][1][2][1][5][38] = 76, - [0][1][2][1][6][38] = 4, - [0][1][2][1][9][38] = 76, - [0][1][2][1][8][38] = 30, - [0][1][2][1][11][38] = 28, - [0][1][2][1][2][40] = 76, - [0][1][2][1][1][40] = 4, - [0][1][2][1][3][40] = 127, - [0][1][2][1][5][40] = 76, - [0][1][2][1][6][40] = 4, - [0][1][2][1][9][40] = 76, - [0][1][2][1][8][40] = 30, - [0][1][2][1][11][40] = 28, - [0][1][2][1][2][42] = 76, - [0][1][2][1][1][42] = 4, - [0][1][2][1][3][42] = 127, - [0][1][2][1][5][42] = 76, - [0][1][2][1][6][42] = 4, - [0][1][2][1][9][42] = 76, - [0][1][2][1][8][42] = 30, - [0][1][2][1][11][42] = 28, - [0][1][2][1][2][44] = 76, - [0][1][2][1][1][44] = 4, - [0][1][2][1][3][44] = 127, - [0][1][2][1][5][44] = 76, - [0][1][2][1][6][44] = 4, - [0][1][2][1][9][44] = 76, - [0][1][2][1][8][44] = 30, - [0][1][2][1][11][44] = 28, - [0][1][2][1][2][46] = 76, - [0][1][2][1][1][46] = 4, - [0][1][2][1][3][46] = 127, - [0][1][2][1][5][46] = 76, - [0][1][2][1][6][46] = 4, - [0][1][2][1][9][46] = 76, - [0][1][2][1][8][46] = 30, - [0][1][2][1][11][46] = 28, - [1][0][2][0][2][1] = 68, - [1][0][2][0][1][1] = 64, - [1][0][2][0][3][1] = 62, - [1][0][2][0][5][1] = 64, - [1][0][2][0][6][1] = 64, - [1][0][2][0][9][1] = 64, - [1][0][2][0][8][1] = 30, - [1][0][2][0][11][1] = 52, - [1][0][2][0][2][5] = 72, - [1][0][2][0][1][5] = 64, - [1][0][2][0][3][5] = 62, - [1][0][2][0][5][5] = 64, - [1][0][2][0][6][5] = 60, - [1][0][2][0][9][5] = 64, - [1][0][2][0][8][5] = 30, - [1][0][2][0][11][5] = 52, - [1][0][2][0][2][9] = 72, - [1][0][2][0][1][9] = 64, - [1][0][2][0][3][9] = 62, - [1][0][2][0][5][9] = 64, - [1][0][2][0][6][9] = 64, - [1][0][2][0][9][9] = 64, - [1][0][2][0][8][9] = 54, - [1][0][2][0][11][9] = 52, - [1][0][2][0][2][13] = 66, - [1][0][2][0][1][13] = 64, - [1][0][2][0][3][13] = 62, - [1][0][2][0][5][13] = 64, - [1][0][2][0][6][13] = 64, - [1][0][2][0][9][13] = 64, - [1][0][2][0][8][13] = 54, - [1][0][2][0][11][13] = 52, - [1][0][2][0][2][16] = 62, - [1][0][2][0][1][16] = 64, - [1][0][2][0][3][16] = 72, - [1][0][2][0][5][16] = 62, - [1][0][2][0][6][16] = 64, - [1][0][2][0][9][16] = 64, - [1][0][2][0][8][16] = 54, - [1][0][2][0][11][16] = 52, - [1][0][2][0][2][20] = 72, - [1][0][2][0][1][20] = 64, - [1][0][2][0][3][20] = 72, - [1][0][2][0][5][20] = 72, - [1][0][2][0][6][20] = 64, - [1][0][2][0][9][20] = 64, - [1][0][2][0][8][20] = 54, - [1][0][2][0][11][20] = 52, - [1][0][2][0][2][24] = 72, - [1][0][2][0][1][24] = 64, - [1][0][2][0][3][24] = 72, - [1][0][2][0][5][24] = 127, - [1][0][2][0][6][24] = 64, - [1][0][2][0][9][24] = 127, - [1][0][2][0][8][24] = 54, - [1][0][2][0][11][24] = 52, - [1][0][2][0][2][28] = 72, - [1][0][2][0][1][28] = 64, - [1][0][2][0][3][28] = 72, - [1][0][2][0][5][28] = 127, - [1][0][2][0][6][28] = 64, - [1][0][2][0][9][28] = 127, - [1][0][2][0][8][28] = 54, - [1][0][2][0][11][28] = 52, - [1][0][2][0][2][32] = 72, - [1][0][2][0][1][32] = 64, - [1][0][2][0][3][32] = 72, - [1][0][2][0][5][32] = 72, - [1][0][2][0][6][32] = 64, - [1][0][2][0][9][32] = 64, - [1][0][2][0][8][32] = 54, - [1][0][2][0][11][32] = 52, - [1][0][2][0][2][36] = 72, - [1][0][2][0][1][36] = 127, - [1][0][2][0][3][36] = 72, - [1][0][2][0][5][36] = 72, - [1][0][2][0][6][36] = 64, - [1][0][2][0][9][36] = 72, - [1][0][2][0][8][36] = 54, - [1][0][2][0][11][36] = 127, - [1][0][2][0][2][39] = 72, - [1][0][2][0][1][39] = 28, - [1][0][2][0][3][39] = 127, - [1][0][2][0][5][39] = 72, - [1][0][2][0][6][39] = 28, - [1][0][2][0][9][39] = 72, - [1][0][2][0][8][39] = 54, - [1][0][2][0][11][39] = 52, - [1][0][2][0][2][43] = 72, - [1][0][2][0][1][43] = 28, - [1][0][2][0][3][43] = 127, - [1][0][2][0][5][43] = 72, - [1][0][2][0][6][43] = 28, - [1][0][2][0][9][43] = 72, - [1][0][2][0][8][43] = 54, - [1][0][2][0][11][43] = 52, - [1][1][2][0][2][1] = 58, - [1][1][2][0][1][1] = 52, - [1][1][2][0][3][1] = 50, - [1][1][2][0][5][1] = 52, - [1][1][2][0][6][1] = 52, - [1][1][2][0][9][1] = 52, - [1][1][2][0][8][1] = 18, - [1][1][2][0][11][1] = 40, - [1][1][2][0][2][5] = 72, - [1][1][2][0][1][5] = 52, - [1][1][2][0][3][5] = 50, - [1][1][2][0][5][5] = 52, - [1][1][2][0][6][5] = 46, - [1][1][2][0][9][5] = 52, - [1][1][2][0][8][5] = 18, - [1][1][2][0][11][5] = 40, - [1][1][2][0][2][9] = 72, - [1][1][2][0][1][9] = 52, - [1][1][2][0][3][9] = 50, - [1][1][2][0][5][9] = 52, - [1][1][2][0][6][9] = 52, - [1][1][2][0][9][9] = 52, - [1][1][2][0][8][9] = 42, - [1][1][2][0][11][9] = 40, - [1][1][2][0][2][13] = 58, - [1][1][2][0][1][13] = 52, - [1][1][2][0][3][13] = 50, - [1][1][2][0][5][13] = 52, - [1][1][2][0][6][13] = 52, - [1][1][2][0][9][13] = 52, - [1][1][2][0][8][13] = 42, - [1][1][2][0][11][13] = 40, - [1][1][2][0][2][16] = 56, - [1][1][2][0][1][16] = 52, - [1][1][2][0][3][16] = 72, - [1][1][2][0][5][16] = 56, - [1][1][2][0][6][16] = 52, - [1][1][2][0][9][16] = 52, - [1][1][2][0][8][16] = 42, - [1][1][2][0][11][16] = 40, - [1][1][2][0][2][20] = 72, - [1][1][2][0][1][20] = 52, - [1][1][2][0][3][20] = 72, - [1][1][2][0][5][20] = 72, - [1][1][2][0][6][20] = 52, - [1][1][2][0][9][20] = 52, - [1][1][2][0][8][20] = 42, - [1][1][2][0][11][20] = 40, - [1][1][2][0][2][24] = 72, - [1][1][2][0][1][24] = 52, - [1][1][2][0][3][24] = 72, - [1][1][2][0][5][24] = 127, - [1][1][2][0][6][24] = 52, - [1][1][2][0][9][24] = 127, - [1][1][2][0][8][24] = 42, - [1][1][2][0][11][24] = 40, - [1][1][2][0][2][28] = 72, - [1][1][2][0][1][28] = 52, - [1][1][2][0][3][28] = 72, - [1][1][2][0][5][28] = 127, - [1][1][2][0][6][28] = 52, - [1][1][2][0][9][28] = 127, - [1][1][2][0][8][28] = 42, - [1][1][2][0][11][28] = 40, - [1][1][2][0][2][32] = 68, - [1][1][2][0][1][32] = 52, - [1][1][2][0][3][32] = 72, - [1][1][2][0][5][32] = 68, - [1][1][2][0][6][32] = 52, - [1][1][2][0][9][32] = 52, - [1][1][2][0][8][32] = 42, - [1][1][2][0][11][32] = 40, - [1][1][2][0][2][36] = 72, - [1][1][2][0][1][36] = 127, - [1][1][2][0][3][36] = 72, - [1][1][2][0][5][36] = 72, - [1][1][2][0][6][36] = 52, - [1][1][2][0][9][36] = 72, - [1][1][2][0][8][36] = 42, - [1][1][2][0][11][36] = 127, - [1][1][2][0][2][39] = 72, - [1][1][2][0][1][39] = 16, - [1][1][2][0][3][39] = 127, - [1][1][2][0][5][39] = 72, - [1][1][2][0][6][39] = 16, - [1][1][2][0][9][39] = 72, - [1][1][2][0][8][39] = 42, - [1][1][2][0][11][39] = 40, - [1][1][2][0][2][43] = 72, - [1][1][2][0][1][43] = 16, - [1][1][2][0][3][43] = 127, - [1][1][2][0][5][43] = 72, - [1][1][2][0][6][43] = 16, - [1][1][2][0][9][43] = 72, - [1][1][2][0][8][43] = 42, - [1][1][2][0][11][43] = 40, - [1][1][2][1][2][1] = 58, - [1][1][2][1][1][1] = 40, - [1][1][2][1][3][1] = 50, - [1][1][2][1][5][1] = 40, - [1][1][2][1][6][1] = 40, - [1][1][2][1][9][1] = 40, - [1][1][2][1][8][1] = 6, - [1][1][2][1][11][1] = 28, - [1][1][2][1][2][5] = 68, - [1][1][2][1][1][5] = 40, - [1][1][2][1][3][5] = 50, - [1][1][2][1][5][5] = 40, - [1][1][2][1][6][5] = 40, - [1][1][2][1][9][5] = 40, - [1][1][2][1][8][5] = 6, - [1][1][2][1][11][5] = 28, - [1][1][2][1][2][9] = 68, - [1][1][2][1][1][9] = 40, - [1][1][2][1][3][9] = 50, - [1][1][2][1][5][9] = 40, - [1][1][2][1][6][9] = 40, - [1][1][2][1][9][9] = 40, - [1][1][2][1][8][9] = 30, - [1][1][2][1][11][9] = 28, - [1][1][2][1][2][13] = 58, - [1][1][2][1][1][13] = 40, - [1][1][2][1][3][13] = 50, - [1][1][2][1][5][13] = 40, - [1][1][2][1][6][13] = 40, - [1][1][2][1][9][13] = 40, - [1][1][2][1][8][13] = 30, - [1][1][2][1][11][13] = 28, - [1][1][2][1][2][16] = 56, - [1][1][2][1][1][16] = 40, - [1][1][2][1][3][16] = 72, - [1][1][2][1][5][16] = 56, - [1][1][2][1][6][16] = 40, - [1][1][2][1][9][16] = 40, - [1][1][2][1][8][16] = 30, - [1][1][2][1][11][16] = 28, - [1][1][2][1][2][20] = 68, - [1][1][2][1][1][20] = 40, - [1][1][2][1][3][20] = 72, - [1][1][2][1][5][20] = 68, - [1][1][2][1][6][20] = 40, - [1][1][2][1][9][20] = 40, - [1][1][2][1][8][20] = 30, - [1][1][2][1][11][20] = 28, - [1][1][2][1][2][24] = 68, - [1][1][2][1][1][24] = 40, - [1][1][2][1][3][24] = 72, - [1][1][2][1][5][24] = 127, - [1][1][2][1][6][24] = 40, - [1][1][2][1][9][24] = 127, - [1][1][2][1][8][24] = 30, - [1][1][2][1][11][24] = 28, - [1][1][2][1][2][28] = 68, - [1][1][2][1][1][28] = 40, - [1][1][2][1][3][28] = 72, - [1][1][2][1][5][28] = 127, - [1][1][2][1][6][28] = 40, - [1][1][2][1][9][28] = 127, - [1][1][2][1][8][28] = 30, - [1][1][2][1][11][28] = 28, - [1][1][2][1][2][32] = 68, - [1][1][2][1][1][32] = 40, - [1][1][2][1][3][32] = 72, - [1][1][2][1][5][32] = 68, - [1][1][2][1][6][32] = 40, - [1][1][2][1][9][32] = 40, - [1][1][2][1][8][32] = 30, - [1][1][2][1][11][32] = 28, - [1][1][2][1][2][36] = 68, - [1][1][2][1][1][36] = 127, - [1][1][2][1][3][36] = 72, - [1][1][2][1][5][36] = 68, - [1][1][2][1][6][36] = 40, - [1][1][2][1][9][36] = 68, - [1][1][2][1][8][36] = 30, - [1][1][2][1][11][36] = 127, - [1][1][2][1][2][39] = 72, - [1][1][2][1][1][39] = 4, - [1][1][2][1][3][39] = 127, - [1][1][2][1][5][39] = 72, - [1][1][2][1][6][39] = 4, - [1][1][2][1][9][39] = 72, - [1][1][2][1][8][39] = 30, - [1][1][2][1][11][39] = 28, - [1][1][2][1][2][43] = 72, - [1][1][2][1][1][43] = 4, - [1][1][2][1][3][43] = 127, - [1][1][2][1][5][43] = 72, - [1][1][2][1][6][43] = 4, - [1][1][2][1][9][43] = 72, - [1][1][2][1][8][43] = 30, - [1][1][2][1][11][43] = 28, - [2][0][2][0][2][3] = 64, - [2][0][2][0][1][3] = 64, - [2][0][2][0][3][3] = 64, - [2][0][2][0][5][3] = 62, - [2][0][2][0][6][3] = 64, - [2][0][2][0][9][3] = 64, - [2][0][2][0][8][3] = 30, - [2][0][2][0][11][3] = 52, - [2][0][2][0][2][11] = 64, - [2][0][2][0][1][11] = 64, - [2][0][2][0][3][11] = 64, - [2][0][2][0][5][11] = 62, - [2][0][2][0][6][11] = 64, - [2][0][2][0][9][11] = 64, - [2][0][2][0][8][11] = 54, - [2][0][2][0][11][11] = 52, - [2][0][2][0][2][18] = 62, - [2][0][2][0][1][18] = 64, - [2][0][2][0][3][18] = 72, - [2][0][2][0][5][18] = 66, - [2][0][2][0][6][18] = 64, - [2][0][2][0][9][18] = 64, - [2][0][2][0][8][18] = 54, - [2][0][2][0][11][18] = 52, - [2][0][2][0][2][26] = 72, - [2][0][2][0][1][26] = 64, - [2][0][2][0][3][26] = 72, - [2][0][2][0][5][26] = 127, - [2][0][2][0][6][26] = 64, - [2][0][2][0][9][26] = 127, - [2][0][2][0][8][26] = 54, - [2][0][2][0][11][26] = 52, - [2][0][2][0][2][34] = 72, - [2][0][2][0][1][34] = 127, - [2][0][2][0][3][34] = 72, - [2][0][2][0][5][34] = 72, - [2][0][2][0][6][34] = 64, - [2][0][2][0][9][34] = 72, - [2][0][2][0][8][34] = 54, - [2][0][2][0][11][34] = 127, - [2][0][2][0][2][41] = 72, - [2][0][2][0][1][41] = 28, - [2][0][2][0][3][41] = 127, - [2][0][2][0][5][41] = 72, - [2][0][2][0][6][41] = 28, - [2][0][2][0][9][41] = 72, - [2][0][2][0][8][41] = 54, - [2][0][2][0][11][41] = 52, - [2][1][2][0][2][3] = 56, - [2][1][2][0][1][3] = 52, - [2][1][2][0][3][3] = 52, - [2][1][2][0][5][3] = 52, - [2][1][2][0][6][3] = 52, - [2][1][2][0][9][3] = 52, - [2][1][2][0][8][3] = 18, - [2][1][2][0][11][3] = 40, - [2][1][2][0][2][11] = 56, - [2][1][2][0][1][11] = 52, - [2][1][2][0][3][11] = 52, - [2][1][2][0][5][11] = 52, - [2][1][2][0][6][11] = 52, - [2][1][2][0][9][11] = 52, - [2][1][2][0][8][11] = 42, - [2][1][2][0][11][11] = 40, - [2][1][2][0][2][18] = 56, - [2][1][2][0][1][18] = 52, - [2][1][2][0][3][18] = 72, - [2][1][2][0][5][18] = 56, - [2][1][2][0][6][18] = 52, - [2][1][2][0][9][18] = 52, - [2][1][2][0][8][18] = 42, - [2][1][2][0][11][18] = 40, - [2][1][2][0][2][26] = 72, - [2][1][2][0][1][26] = 52, - [2][1][2][0][3][26] = 72, - [2][1][2][0][5][26] = 127, - [2][1][2][0][6][26] = 52, - [2][1][2][0][9][26] = 127, - [2][1][2][0][8][26] = 42, - [2][1][2][0][11][26] = 40, - [2][1][2][0][2][34] = 72, - [2][1][2][0][1][34] = 127, - [2][1][2][0][3][34] = 72, - [2][1][2][0][5][34] = 72, - [2][1][2][0][6][34] = 52, - [2][1][2][0][9][34] = 72, - [2][1][2][0][8][34] = 42, - [2][1][2][0][11][34] = 127, - [2][1][2][0][2][41] = 72, - [2][1][2][0][1][41] = 16, - [2][1][2][0][3][41] = 127, - [2][1][2][0][5][41] = 72, - [2][1][2][0][6][41] = 16, - [2][1][2][0][9][41] = 72, - [2][1][2][0][8][41] = 42, - [2][1][2][0][11][41] = 40, - [2][1][2][1][2][3] = 56, - [2][1][2][1][1][3] = 40, - [2][1][2][1][3][3] = 52, - [2][1][2][1][5][3] = 40, - [2][1][2][1][6][3] = 40, - [2][1][2][1][9][3] = 40, - [2][1][2][1][8][3] = 6, - [2][1][2][1][11][3] = 28, - [2][1][2][1][2][11] = 56, - [2][1][2][1][1][11] = 40, - [2][1][2][1][3][11] = 52, - [2][1][2][1][5][11] = 40, - [2][1][2][1][6][11] = 40, - [2][1][2][1][9][11] = 40, - [2][1][2][1][8][11] = 30, - [2][1][2][1][11][11] = 28, - [2][1][2][1][2][18] = 56, - [2][1][2][1][1][18] = 40, - [2][1][2][1][3][18] = 72, - [2][1][2][1][5][18] = 56, - [2][1][2][1][6][18] = 40, - [2][1][2][1][9][18] = 40, - [2][1][2][1][8][18] = 30, - [2][1][2][1][11][18] = 28, - [2][1][2][1][2][26] = 68, - [2][1][2][1][1][26] = 40, - [2][1][2][1][3][26] = 72, - [2][1][2][1][5][26] = 127, - [2][1][2][1][6][26] = 40, - [2][1][2][1][9][26] = 127, - [2][1][2][1][8][26] = 30, - [2][1][2][1][11][26] = 28, - [2][1][2][1][2][34] = 68, - [2][1][2][1][1][34] = 127, - [2][1][2][1][3][34] = 72, - [2][1][2][1][5][34] = 68, - [2][1][2][1][6][34] = 40, - [2][1][2][1][9][34] = 68, - [2][1][2][1][8][34] = 30, - [2][1][2][1][11][34] = 127, - [2][1][2][1][2][41] = 72, - [2][1][2][1][1][41] = 4, - [2][1][2][1][3][41] = 127, - [2][1][2][1][5][41] = 72, - [2][1][2][1][6][41] = 4, - [2][1][2][1][9][41] = 72, - [2][1][2][1][8][41] = 30, - [2][1][2][1][11][41] = 28, + [0][0][1][0][RTW89_WW][0] = 30, + [0][0][1][0][RTW89_WW][2] = 30, + [0][0][1][0][RTW89_WW][4] = 30, + [0][0][1][0][RTW89_WW][6] = 30, + [0][0][1][0][RTW89_WW][8] = 52, + [0][0][1][0][RTW89_WW][10] = 52, + [0][0][1][0][RTW89_WW][12] = 52, + [0][0][1][0][RTW89_WW][14] = 52, + [0][0][1][0][RTW89_WW][15] = 52, + [0][0][1][0][RTW89_WW][17] = 52, + [0][0][1][0][RTW89_WW][19] = 52, + [0][0][1][0][RTW89_WW][21] = 52, + [0][0][1][0][RTW89_WW][23] = 52, + [0][0][1][0][RTW89_WW][25] = 52, + [0][0][1][0][RTW89_WW][27] = 52, + [0][0][1][0][RTW89_WW][29] = 52, + [0][0][1][0][RTW89_WW][31] = 52, + [0][0][1][0][RTW89_WW][33] = 52, + [0][0][1][0][RTW89_WW][35] = 52, + [0][0][1][0][RTW89_WW][37] = 54, + [0][0][1][0][RTW89_WW][38] = 28, + [0][0][1][0][RTW89_WW][40] = 28, + [0][0][1][0][RTW89_WW][42] = 28, + [0][0][1][0][RTW89_WW][44] = 28, + [0][0][1][0][RTW89_WW][46] = 28, + [0][1][1][0][RTW89_WW][0] = 18, + [0][1][1][0][RTW89_WW][2] = 18, + [0][1][1][0][RTW89_WW][4] = 18, + [0][1][1][0][RTW89_WW][6] = 18, + [0][1][1][0][RTW89_WW][8] = 40, + [0][1][1][0][RTW89_WW][10] = 40, + [0][1][1][0][RTW89_WW][12] = 40, + [0][1][1][0][RTW89_WW][14] = 40, + [0][1][1][0][RTW89_WW][15] = 40, + [0][1][1][0][RTW89_WW][17] = 40, + [0][1][1][0][RTW89_WW][19] = 40, + [0][1][1][0][RTW89_WW][21] = 40, + [0][1][1][0][RTW89_WW][23] = 40, + [0][1][1][0][RTW89_WW][25] = 40, + [0][1][1][0][RTW89_WW][27] = 40, + [0][1][1][0][RTW89_WW][29] = 40, + [0][1][1][0][RTW89_WW][31] = 40, + [0][1][1][0][RTW89_WW][33] = 40, + [0][1][1][0][RTW89_WW][35] = 40, + [0][1][1][0][RTW89_WW][37] = 42, + [0][1][1][0][RTW89_WW][38] = 16, + [0][1][1][0][RTW89_WW][40] = 16, + [0][1][1][0][RTW89_WW][42] = 16, + [0][1][1][0][RTW89_WW][44] = 16, + [0][1][1][0][RTW89_WW][46] = 16, + [0][0][2][0][RTW89_WW][0] = 30, + [0][0][2][0][RTW89_WW][2] = 30, + [0][0][2][0][RTW89_WW][4] = 30, + [0][0][2][0][RTW89_WW][6] = 30, + [0][0][2][0][RTW89_WW][8] = 52, + [0][0][2][0][RTW89_WW][10] = 52, + [0][0][2][0][RTW89_WW][12] = 52, + [0][0][2][0][RTW89_WW][14] = 52, + [0][0][2][0][RTW89_WW][15] = 52, + [0][0][2][0][RTW89_WW][17] = 52, + [0][0][2][0][RTW89_WW][19] = 52, + [0][0][2][0][RTW89_WW][21] = 52, + [0][0][2][0][RTW89_WW][23] = 52, + [0][0][2][0][RTW89_WW][25] = 52, + [0][0][2][0][RTW89_WW][27] = 52, + [0][0][2][0][RTW89_WW][29] = 52, + [0][0][2][0][RTW89_WW][31] = 52, + [0][0][2][0][RTW89_WW][33] = 52, + [0][0][2][0][RTW89_WW][35] = 52, + [0][0][2][0][RTW89_WW][37] = 54, + [0][0][2][0][RTW89_WW][38] = 28, + [0][0][2][0][RTW89_WW][40] = 28, + [0][0][2][0][RTW89_WW][42] = 28, + [0][0][2][0][RTW89_WW][44] = 28, + [0][0][2][0][RTW89_WW][46] = 28, + [0][1][2][0][RTW89_WW][0] = 18, + [0][1][2][0][RTW89_WW][2] = 18, + [0][1][2][0][RTW89_WW][4] = 18, + [0][1][2][0][RTW89_WW][6] = 18, + [0][1][2][0][RTW89_WW][8] = 40, + [0][1][2][0][RTW89_WW][10] = 40, + [0][1][2][0][RTW89_WW][12] = 40, + [0][1][2][0][RTW89_WW][14] = 40, + [0][1][2][0][RTW89_WW][15] = 40, + [0][1][2][0][RTW89_WW][17] = 40, + [0][1][2][0][RTW89_WW][19] = 40, + [0][1][2][0][RTW89_WW][21] = 40, + [0][1][2][0][RTW89_WW][23] = 40, + [0][1][2][0][RTW89_WW][25] = 40, + [0][1][2][0][RTW89_WW][27] = 40, + [0][1][2][0][RTW89_WW][29] = 40, + [0][1][2][0][RTW89_WW][31] = 40, + [0][1][2][0][RTW89_WW][33] = 40, + [0][1][2][0][RTW89_WW][35] = 40, + [0][1][2][0][RTW89_WW][37] = 42, + [0][1][2][0][RTW89_WW][38] = 16, + [0][1][2][0][RTW89_WW][40] = 16, + [0][1][2][0][RTW89_WW][42] = 16, + [0][1][2][0][RTW89_WW][44] = 16, + [0][1][2][0][RTW89_WW][46] = 16, + [0][1][2][1][RTW89_WW][0] = 6, + [0][1][2][1][RTW89_WW][2] = 6, + [0][1][2][1][RTW89_WW][4] = 6, + [0][1][2][1][RTW89_WW][6] = 6, + [0][1][2][1][RTW89_WW][8] = 28, + [0][1][2][1][RTW89_WW][10] = 28, + [0][1][2][1][RTW89_WW][12] = 28, + [0][1][2][1][RTW89_WW][14] = 28, + [0][1][2][1][RTW89_WW][15] = 28, + [0][1][2][1][RTW89_WW][17] = 28, + [0][1][2][1][RTW89_WW][19] = 28, + [0][1][2][1][RTW89_WW][21] = 28, + [0][1][2][1][RTW89_WW][23] = 28, + [0][1][2][1][RTW89_WW][25] = 28, + [0][1][2][1][RTW89_WW][27] = 28, + [0][1][2][1][RTW89_WW][29] = 28, + [0][1][2][1][RTW89_WW][31] = 28, + [0][1][2][1][RTW89_WW][33] = 28, + [0][1][2][1][RTW89_WW][35] = 28, + [0][1][2][1][RTW89_WW][37] = 30, + [0][1][2][1][RTW89_WW][38] = 4, + [0][1][2][1][RTW89_WW][40] = 4, + [0][1][2][1][RTW89_WW][42] = 4, + [0][1][2][1][RTW89_WW][44] = 4, + [0][1][2][1][RTW89_WW][46] = 4, + [1][0][2][0][RTW89_WW][1] = 30, + [1][0][2][0][RTW89_WW][5] = 30, + [1][0][2][0][RTW89_WW][9] = 52, + [1][0][2][0][RTW89_WW][13] = 52, + [1][0][2][0][RTW89_WW][16] = 52, + [1][0][2][0][RTW89_WW][20] = 52, + [1][0][2][0][RTW89_WW][24] = 52, + [1][0][2][0][RTW89_WW][28] = 52, + [1][0][2][0][RTW89_WW][32] = 52, + [1][0][2][0][RTW89_WW][36] = 54, + [1][0][2][0][RTW89_WW][39] = 28, + [1][0][2][0][RTW89_WW][43] = 28, + [1][1][2][0][RTW89_WW][1] = 18, + [1][1][2][0][RTW89_WW][5] = 18, + [1][1][2][0][RTW89_WW][9] = 40, + [1][1][2][0][RTW89_WW][13] = 40, + [1][1][2][0][RTW89_WW][16] = 40, + [1][1][2][0][RTW89_WW][20] = 40, + [1][1][2][0][RTW89_WW][24] = 40, + [1][1][2][0][RTW89_WW][28] = 40, + [1][1][2][0][RTW89_WW][32] = 40, + [1][1][2][0][RTW89_WW][36] = 42, + [1][1][2][0][RTW89_WW][39] = 16, + [1][1][2][0][RTW89_WW][43] = 16, + [1][1][2][1][RTW89_WW][1] = 6, + [1][1][2][1][RTW89_WW][5] = 6, + [1][1][2][1][RTW89_WW][9] = 28, + [1][1][2][1][RTW89_WW][13] = 28, + [1][1][2][1][RTW89_WW][16] = 28, + [1][1][2][1][RTW89_WW][20] = 28, + [1][1][2][1][RTW89_WW][24] = 28, + [1][1][2][1][RTW89_WW][28] = 28, + [1][1][2][1][RTW89_WW][32] = 28, + [1][1][2][1][RTW89_WW][36] = 30, + [1][1][2][1][RTW89_WW][39] = 4, + [1][1][2][1][RTW89_WW][43] = 4, + [2][0][2][0][RTW89_WW][3] = 30, + [2][0][2][0][RTW89_WW][11] = 52, + [2][0][2][0][RTW89_WW][18] = 52, + [2][0][2][0][RTW89_WW][26] = 52, + [2][0][2][0][RTW89_WW][34] = 54, + [2][0][2][0][RTW89_WW][41] = 28, + [2][1][2][0][RTW89_WW][3] = 18, + [2][1][2][0][RTW89_WW][11] = 40, + [2][1][2][0][RTW89_WW][18] = 40, + [2][1][2][0][RTW89_WW][26] = 40, + [2][1][2][0][RTW89_WW][34] = 42, + [2][1][2][0][RTW89_WW][41] = 16, + [2][1][2][1][RTW89_WW][3] = 6, + [2][1][2][1][RTW89_WW][11] = 28, + [2][1][2][1][RTW89_WW][18] = 28, + [2][1][2][1][RTW89_WW][26] = 28, + [2][1][2][1][RTW89_WW][34] = 30, + [2][1][2][1][RTW89_WW][41] = 4, + [0][0][1][0][RTW89_FCC][0] = 76, + [0][0][1][0][RTW89_ETSI][0] = 58, + [0][0][1][0][RTW89_MKK][0] = 62, + [0][0][1][0][RTW89_IC][0] = 62, + [0][0][1][0][RTW89_KCC][0] = 76, + [0][0][1][0][RTW89_ACMA][0] = 58, + [0][0][1][0][RTW89_CHILE][0] = 30, + [0][0][1][0][RTW89_UKRAINE][0] = 52, + [0][0][1][0][RTW89_MEXICO][0] = 62, + [0][0][1][0][RTW89_CN][0] = 58, + [0][0][1][0][RTW89_QATAR][0] = 58, + [0][0][1][0][RTW89_FCC][2] = 76, + [0][0][1][0][RTW89_ETSI][2] = 58, + [0][0][1][0][RTW89_MKK][2] = 62, + [0][0][1][0][RTW89_IC][2] = 62, + [0][0][1][0][RTW89_KCC][2] = 76, + [0][0][1][0][RTW89_ACMA][2] = 58, + [0][0][1][0][RTW89_CHILE][2] = 30, + [0][0][1][0][RTW89_UKRAINE][2] = 52, + [0][0][1][0][RTW89_MEXICO][2] = 62, + [0][0][1][0][RTW89_CN][2] = 58, + [0][0][1][0][RTW89_QATAR][2] = 58, + [0][0][1][0][RTW89_FCC][4] = 76, + [0][0][1][0][RTW89_ETSI][4] = 58, + [0][0][1][0][RTW89_MKK][4] = 62, + [0][0][1][0][RTW89_IC][4] = 62, + [0][0][1][0][RTW89_KCC][4] = 76, + [0][0][1][0][RTW89_ACMA][4] = 58, + [0][0][1][0][RTW89_CHILE][4] = 30, + [0][0][1][0][RTW89_UKRAINE][4] = 52, + [0][0][1][0][RTW89_MEXICO][4] = 62, + [0][0][1][0][RTW89_CN][4] = 58, + [0][0][1][0][RTW89_QATAR][4] = 58, + [0][0][1][0][RTW89_FCC][6] = 76, + [0][0][1][0][RTW89_ETSI][6] = 58, + [0][0][1][0][RTW89_MKK][6] = 62, + [0][0][1][0][RTW89_IC][6] = 62, + [0][0][1][0][RTW89_KCC][6] = 58, + [0][0][1][0][RTW89_ACMA][6] = 58, + [0][0][1][0][RTW89_CHILE][6] = 30, + [0][0][1][0][RTW89_UKRAINE][6] = 52, + [0][0][1][0][RTW89_MEXICO][6] = 62, + [0][0][1][0][RTW89_CN][6] = 58, + [0][0][1][0][RTW89_QATAR][6] = 58, + [0][0][1][0][RTW89_FCC][8] = 76, + [0][0][1][0][RTW89_ETSI][8] = 58, + [0][0][1][0][RTW89_MKK][8] = 62, + [0][0][1][0][RTW89_IC][8] = 64, + [0][0][1][0][RTW89_KCC][8] = 76, + [0][0][1][0][RTW89_ACMA][8] = 58, + [0][0][1][0][RTW89_CHILE][8] = 54, + [0][0][1][0][RTW89_UKRAINE][8] = 52, + [0][0][1][0][RTW89_MEXICO][8] = 76, + [0][0][1][0][RTW89_CN][8] = 58, + [0][0][1][0][RTW89_QATAR][8] = 58, + [0][0][1][0][RTW89_FCC][10] = 76, + [0][0][1][0][RTW89_ETSI][10] = 58, + [0][0][1][0][RTW89_MKK][10] = 62, + [0][0][1][0][RTW89_IC][10] = 64, + [0][0][1][0][RTW89_KCC][10] = 76, + [0][0][1][0][RTW89_ACMA][10] = 58, + [0][0][1][0][RTW89_CHILE][10] = 54, + [0][0][1][0][RTW89_UKRAINE][10] = 52, + [0][0][1][0][RTW89_MEXICO][10] = 76, + [0][0][1][0][RTW89_CN][10] = 58, + [0][0][1][0][RTW89_QATAR][10] = 58, + [0][0][1][0][RTW89_FCC][12] = 76, + [0][0][1][0][RTW89_ETSI][12] = 58, + [0][0][1][0][RTW89_MKK][12] = 62, + [0][0][1][0][RTW89_IC][12] = 64, + [0][0][1][0][RTW89_KCC][12] = 76, + [0][0][1][0][RTW89_ACMA][12] = 58, + [0][0][1][0][RTW89_CHILE][12] = 54, + [0][0][1][0][RTW89_UKRAINE][12] = 52, + [0][0][1][0][RTW89_MEXICO][12] = 76, + [0][0][1][0][RTW89_CN][12] = 58, + [0][0][1][0][RTW89_QATAR][12] = 58, + [0][0][1][0][RTW89_FCC][14] = 76, + [0][0][1][0][RTW89_ETSI][14] = 58, + [0][0][1][0][RTW89_MKK][14] = 62, + [0][0][1][0][RTW89_IC][14] = 64, + [0][0][1][0][RTW89_KCC][14] = 76, + [0][0][1][0][RTW89_ACMA][14] = 58, + [0][0][1][0][RTW89_CHILE][14] = 54, + [0][0][1][0][RTW89_UKRAINE][14] = 52, + [0][0][1][0][RTW89_MEXICO][14] = 76, + [0][0][1][0][RTW89_CN][14] = 58, + [0][0][1][0][RTW89_QATAR][14] = 58, + [0][0][1][0][RTW89_FCC][15] = 76, + [0][0][1][0][RTW89_ETSI][15] = 58, + [0][0][1][0][RTW89_MKK][15] = 76, + [0][0][1][0][RTW89_IC][15] = 76, + [0][0][1][0][RTW89_KCC][15] = 76, + [0][0][1][0][RTW89_ACMA][15] = 58, + [0][0][1][0][RTW89_CHILE][15] = 54, + [0][0][1][0][RTW89_UKRAINE][15] = 52, + [0][0][1][0][RTW89_MEXICO][15] = 76, + [0][0][1][0][RTW89_CN][15] = 127, + [0][0][1][0][RTW89_QATAR][15] = 52, + [0][0][1][0][RTW89_FCC][17] = 76, + [0][0][1][0][RTW89_ETSI][17] = 58, + [0][0][1][0][RTW89_MKK][17] = 76, + [0][0][1][0][RTW89_IC][17] = 76, + [0][0][1][0][RTW89_KCC][17] = 76, + [0][0][1][0][RTW89_ACMA][17] = 58, + [0][0][1][0][RTW89_CHILE][17] = 54, + [0][0][1][0][RTW89_UKRAINE][17] = 52, + [0][0][1][0][RTW89_MEXICO][17] = 76, + [0][0][1][0][RTW89_CN][17] = 127, + [0][0][1][0][RTW89_QATAR][17] = 52, + [0][0][1][0][RTW89_FCC][19] = 76, + [0][0][1][0][RTW89_ETSI][19] = 58, + [0][0][1][0][RTW89_MKK][19] = 76, + [0][0][1][0][RTW89_IC][19] = 76, + [0][0][1][0][RTW89_KCC][19] = 76, + [0][0][1][0][RTW89_ACMA][19] = 58, + [0][0][1][0][RTW89_CHILE][19] = 54, + [0][0][1][0][RTW89_UKRAINE][19] = 52, + [0][0][1][0][RTW89_MEXICO][19] = 76, + [0][0][1][0][RTW89_CN][19] = 127, + [0][0][1][0][RTW89_QATAR][19] = 52, + [0][0][1][0][RTW89_FCC][21] = 76, + [0][0][1][0][RTW89_ETSI][21] = 58, + [0][0][1][0][RTW89_MKK][21] = 76, + [0][0][1][0][RTW89_IC][21] = 76, + [0][0][1][0][RTW89_KCC][21] = 76, + [0][0][1][0][RTW89_ACMA][21] = 58, + [0][0][1][0][RTW89_CHILE][21] = 54, + [0][0][1][0][RTW89_UKRAINE][21] = 52, + [0][0][1][0][RTW89_MEXICO][21] = 76, + [0][0][1][0][RTW89_CN][21] = 127, + [0][0][1][0][RTW89_QATAR][21] = 52, + [0][0][1][0][RTW89_FCC][23] = 76, + [0][0][1][0][RTW89_ETSI][23] = 58, + [0][0][1][0][RTW89_MKK][23] = 76, + [0][0][1][0][RTW89_IC][23] = 76, + [0][0][1][0][RTW89_KCC][23] = 76, + [0][0][1][0][RTW89_ACMA][23] = 58, + [0][0][1][0][RTW89_CHILE][23] = 54, + [0][0][1][0][RTW89_UKRAINE][23] = 52, + [0][0][1][0][RTW89_MEXICO][23] = 76, + [0][0][1][0][RTW89_CN][23] = 127, + [0][0][1][0][RTW89_QATAR][23] = 52, + [0][0][1][0][RTW89_FCC][25] = 76, + [0][0][1][0][RTW89_ETSI][25] = 58, + [0][0][1][0][RTW89_MKK][25] = 76, + [0][0][1][0][RTW89_IC][25] = 127, + [0][0][1][0][RTW89_KCC][25] = 76, + [0][0][1][0][RTW89_ACMA][25] = 127, + [0][0][1][0][RTW89_CHILE][25] = 54, + [0][0][1][0][RTW89_UKRAINE][25] = 52, + [0][0][1][0][RTW89_MEXICO][25] = 76, + [0][0][1][0][RTW89_CN][25] = 127, + [0][0][1][0][RTW89_QATAR][25] = 52, + [0][0][1][0][RTW89_FCC][27] = 76, + [0][0][1][0][RTW89_ETSI][27] = 58, + [0][0][1][0][RTW89_MKK][27] = 76, + [0][0][1][0][RTW89_IC][27] = 127, + [0][0][1][0][RTW89_KCC][27] = 76, + [0][0][1][0][RTW89_ACMA][27] = 127, + [0][0][1][0][RTW89_CHILE][27] = 54, + [0][0][1][0][RTW89_UKRAINE][27] = 52, + [0][0][1][0][RTW89_MEXICO][27] = 76, + [0][0][1][0][RTW89_CN][27] = 127, + [0][0][1][0][RTW89_QATAR][27] = 52, + [0][0][1][0][RTW89_FCC][29] = 76, + [0][0][1][0][RTW89_ETSI][29] = 58, + [0][0][1][0][RTW89_MKK][29] = 76, + [0][0][1][0][RTW89_IC][29] = 127, + [0][0][1][0][RTW89_KCC][29] = 76, + [0][0][1][0][RTW89_ACMA][29] = 127, + [0][0][1][0][RTW89_CHILE][29] = 54, + [0][0][1][0][RTW89_UKRAINE][29] = 52, + [0][0][1][0][RTW89_MEXICO][29] = 76, + [0][0][1][0][RTW89_CN][29] = 127, + [0][0][1][0][RTW89_QATAR][29] = 52, + [0][0][1][0][RTW89_FCC][31] = 76, + [0][0][1][0][RTW89_ETSI][31] = 58, + [0][0][1][0][RTW89_MKK][31] = 76, + [0][0][1][0][RTW89_IC][31] = 76, + [0][0][1][0][RTW89_KCC][31] = 76, + [0][0][1][0][RTW89_ACMA][31] = 58, + [0][0][1][0][RTW89_CHILE][31] = 54, + [0][0][1][0][RTW89_UKRAINE][31] = 52, + [0][0][1][0][RTW89_MEXICO][31] = 76, + [0][0][1][0][RTW89_CN][31] = 127, + [0][0][1][0][RTW89_QATAR][31] = 52, + [0][0][1][0][RTW89_FCC][33] = 76, + [0][0][1][0][RTW89_ETSI][33] = 58, + [0][0][1][0][RTW89_MKK][33] = 76, + [0][0][1][0][RTW89_IC][33] = 76, + [0][0][1][0][RTW89_KCC][33] = 76, + [0][0][1][0][RTW89_ACMA][33] = 58, + [0][0][1][0][RTW89_CHILE][33] = 54, + [0][0][1][0][RTW89_UKRAINE][33] = 52, + [0][0][1][0][RTW89_MEXICO][33] = 76, + [0][0][1][0][RTW89_CN][33] = 127, + [0][0][1][0][RTW89_QATAR][33] = 52, + [0][0][1][0][RTW89_FCC][35] = 74, + [0][0][1][0][RTW89_ETSI][35] = 58, + [0][0][1][0][RTW89_MKK][35] = 76, + [0][0][1][0][RTW89_IC][35] = 74, + [0][0][1][0][RTW89_KCC][35] = 76, + [0][0][1][0][RTW89_ACMA][35] = 58, + [0][0][1][0][RTW89_CHILE][35] = 54, + [0][0][1][0][RTW89_UKRAINE][35] = 52, + [0][0][1][0][RTW89_MEXICO][35] = 74, + [0][0][1][0][RTW89_CN][35] = 127, + [0][0][1][0][RTW89_QATAR][35] = 52, + [0][0][1][0][RTW89_FCC][37] = 76, + [0][0][1][0][RTW89_ETSI][37] = 127, + [0][0][1][0][RTW89_MKK][37] = 76, + [0][0][1][0][RTW89_IC][37] = 76, + [0][0][1][0][RTW89_KCC][37] = 76, + [0][0][1][0][RTW89_ACMA][37] = 76, + [0][0][1][0][RTW89_CHILE][37] = 54, + [0][0][1][0][RTW89_UKRAINE][37] = 127, + [0][0][1][0][RTW89_MEXICO][37] = 76, + [0][0][1][0][RTW89_CN][37] = 127, + [0][0][1][0][RTW89_QATAR][37] = 127, + [0][0][1][0][RTW89_FCC][38] = 76, + [0][0][1][0][RTW89_ETSI][38] = 28, + [0][0][1][0][RTW89_MKK][38] = 127, + [0][0][1][0][RTW89_IC][38] = 76, + [0][0][1][0][RTW89_KCC][38] = 76, + [0][0][1][0][RTW89_ACMA][38] = 76, + [0][0][1][0][RTW89_CHILE][38] = 54, + [0][0][1][0][RTW89_UKRAINE][38] = 28, + [0][0][1][0][RTW89_MEXICO][38] = 76, + [0][0][1][0][RTW89_CN][38] = 72, + [0][0][1][0][RTW89_QATAR][38] = 28, + [0][0][1][0][RTW89_FCC][40] = 76, + [0][0][1][0][RTW89_ETSI][40] = 28, + [0][0][1][0][RTW89_MKK][40] = 127, + [0][0][1][0][RTW89_IC][40] = 76, + [0][0][1][0][RTW89_KCC][40] = 76, + [0][0][1][0][RTW89_ACMA][40] = 76, + [0][0][1][0][RTW89_CHILE][40] = 54, + [0][0][1][0][RTW89_UKRAINE][40] = 28, + [0][0][1][0][RTW89_MEXICO][40] = 76, + [0][0][1][0][RTW89_CN][40] = 76, + [0][0][1][0][RTW89_QATAR][40] = 28, + [0][0][1][0][RTW89_FCC][42] = 76, + [0][0][1][0][RTW89_ETSI][42] = 28, + [0][0][1][0][RTW89_MKK][42] = 127, + [0][0][1][0][RTW89_IC][42] = 76, + [0][0][1][0][RTW89_KCC][42] = 76, + [0][0][1][0][RTW89_ACMA][42] = 76, + [0][0][1][0][RTW89_CHILE][42] = 54, + [0][0][1][0][RTW89_UKRAINE][42] = 28, + [0][0][1][0][RTW89_MEXICO][42] = 76, + [0][0][1][0][RTW89_CN][42] = 76, + [0][0][1][0][RTW89_QATAR][42] = 28, + [0][0][1][0][RTW89_FCC][44] = 76, + [0][0][1][0][RTW89_ETSI][44] = 28, + [0][0][1][0][RTW89_MKK][44] = 127, + [0][0][1][0][RTW89_IC][44] = 76, + [0][0][1][0][RTW89_KCC][44] = 76, + [0][0][1][0][RTW89_ACMA][44] = 76, + [0][0][1][0][RTW89_CHILE][44] = 54, + [0][0][1][0][RTW89_UKRAINE][44] = 28, + [0][0][1][0][RTW89_MEXICO][44] = 76, + [0][0][1][0][RTW89_CN][44] = 76, + [0][0][1][0][RTW89_QATAR][44] = 28, + [0][0][1][0][RTW89_FCC][46] = 76, + [0][0][1][0][RTW89_ETSI][46] = 28, + [0][0][1][0][RTW89_MKK][46] = 127, + [0][0][1][0][RTW89_IC][46] = 76, + [0][0][1][0][RTW89_KCC][46] = 76, + [0][0][1][0][RTW89_ACMA][46] = 76, + [0][0][1][0][RTW89_CHILE][46] = 54, + [0][0][1][0][RTW89_UKRAINE][46] = 28, + [0][0][1][0][RTW89_MEXICO][46] = 76, + [0][0][1][0][RTW89_CN][46] = 76, + [0][0][1][0][RTW89_QATAR][46] = 28, + [0][1][1][0][RTW89_FCC][0] = 68, + [0][1][1][0][RTW89_ETSI][0] = 46, + [0][1][1][0][RTW89_MKK][0] = 50, + [0][1][1][0][RTW89_IC][0] = 40, + [0][1][1][0][RTW89_KCC][0] = 72, + [0][1][1][0][RTW89_ACMA][0] = 46, + [0][1][1][0][RTW89_CHILE][0] = 18, + [0][1][1][0][RTW89_UKRAINE][0] = 40, + [0][1][1][0][RTW89_MEXICO][0] = 50, + [0][1][1][0][RTW89_CN][0] = 46, + [0][1][1][0][RTW89_QATAR][0] = 46, + [0][1][1][0][RTW89_FCC][2] = 68, + [0][1][1][0][RTW89_ETSI][2] = 46, + [0][1][1][0][RTW89_MKK][2] = 50, + [0][1][1][0][RTW89_IC][2] = 40, + [0][1][1][0][RTW89_KCC][2] = 72, + [0][1][1][0][RTW89_ACMA][2] = 46, + [0][1][1][0][RTW89_CHILE][2] = 18, + [0][1][1][0][RTW89_UKRAINE][2] = 40, + [0][1][1][0][RTW89_MEXICO][2] = 50, + [0][1][1][0][RTW89_CN][2] = 46, + [0][1][1][0][RTW89_QATAR][2] = 46, + [0][1][1][0][RTW89_FCC][4] = 68, + [0][1][1][0][RTW89_ETSI][4] = 46, + [0][1][1][0][RTW89_MKK][4] = 50, + [0][1][1][0][RTW89_IC][4] = 40, + [0][1][1][0][RTW89_KCC][4] = 72, + [0][1][1][0][RTW89_ACMA][4] = 46, + [0][1][1][0][RTW89_CHILE][4] = 18, + [0][1][1][0][RTW89_UKRAINE][4] = 40, + [0][1][1][0][RTW89_MEXICO][4] = 50, + [0][1][1][0][RTW89_CN][4] = 46, + [0][1][1][0][RTW89_QATAR][4] = 46, + [0][1][1][0][RTW89_FCC][6] = 68, + [0][1][1][0][RTW89_ETSI][6] = 46, + [0][1][1][0][RTW89_MKK][6] = 50, + [0][1][1][0][RTW89_IC][6] = 40, + [0][1][1][0][RTW89_KCC][6] = 44, + [0][1][1][0][RTW89_ACMA][6] = 46, + [0][1][1][0][RTW89_CHILE][6] = 18, + [0][1][1][0][RTW89_UKRAINE][6] = 40, + [0][1][1][0][RTW89_MEXICO][6] = 50, + [0][1][1][0][RTW89_CN][6] = 46, + [0][1][1][0][RTW89_QATAR][6] = 46, + [0][1][1][0][RTW89_FCC][8] = 68, + [0][1][1][0][RTW89_ETSI][8] = 46, + [0][1][1][0][RTW89_MKK][8] = 50, + [0][1][1][0][RTW89_IC][8] = 52, + [0][1][1][0][RTW89_KCC][8] = 72, + [0][1][1][0][RTW89_ACMA][8] = 46, + [0][1][1][0][RTW89_CHILE][8] = 42, + [0][1][1][0][RTW89_UKRAINE][8] = 40, + [0][1][1][0][RTW89_MEXICO][8] = 68, + [0][1][1][0][RTW89_CN][8] = 46, + [0][1][1][0][RTW89_QATAR][8] = 46, + [0][1][1][0][RTW89_FCC][10] = 68, + [0][1][1][0][RTW89_ETSI][10] = 46, + [0][1][1][0][RTW89_MKK][10] = 50, + [0][1][1][0][RTW89_IC][10] = 52, + [0][1][1][0][RTW89_KCC][10] = 72, + [0][1][1][0][RTW89_ACMA][10] = 46, + [0][1][1][0][RTW89_CHILE][10] = 42, + [0][1][1][0][RTW89_UKRAINE][10] = 40, + [0][1][1][0][RTW89_MEXICO][10] = 68, + [0][1][1][0][RTW89_CN][10] = 46, + [0][1][1][0][RTW89_QATAR][10] = 46, + [0][1][1][0][RTW89_FCC][12] = 68, + [0][1][1][0][RTW89_ETSI][12] = 46, + [0][1][1][0][RTW89_MKK][12] = 50, + [0][1][1][0][RTW89_IC][12] = 52, + [0][1][1][0][RTW89_KCC][12] = 72, + [0][1][1][0][RTW89_ACMA][12] = 46, + [0][1][1][0][RTW89_CHILE][12] = 42, + [0][1][1][0][RTW89_UKRAINE][12] = 40, + [0][1][1][0][RTW89_MEXICO][12] = 68, + [0][1][1][0][RTW89_CN][12] = 46, + [0][1][1][0][RTW89_QATAR][12] = 46, + [0][1][1][0][RTW89_FCC][14] = 68, + [0][1][1][0][RTW89_ETSI][14] = 46, + [0][1][1][0][RTW89_MKK][14] = 50, + [0][1][1][0][RTW89_IC][14] = 52, + [0][1][1][0][RTW89_KCC][14] = 72, + [0][1][1][0][RTW89_ACMA][14] = 46, + [0][1][1][0][RTW89_CHILE][14] = 42, + [0][1][1][0][RTW89_UKRAINE][14] = 40, + [0][1][1][0][RTW89_MEXICO][14] = 68, + [0][1][1][0][RTW89_CN][14] = 46, + [0][1][1][0][RTW89_QATAR][14] = 46, + [0][1][1][0][RTW89_FCC][15] = 68, + [0][1][1][0][RTW89_ETSI][15] = 46, + [0][1][1][0][RTW89_MKK][15] = 70, + [0][1][1][0][RTW89_IC][15] = 68, + [0][1][1][0][RTW89_KCC][15] = 72, + [0][1][1][0][RTW89_ACMA][15] = 46, + [0][1][1][0][RTW89_CHILE][15] = 42, + [0][1][1][0][RTW89_UKRAINE][15] = 40, + [0][1][1][0][RTW89_MEXICO][15] = 68, + [0][1][1][0][RTW89_CN][15] = 127, + [0][1][1][0][RTW89_QATAR][15] = 40, + [0][1][1][0][RTW89_FCC][17] = 68, + [0][1][1][0][RTW89_ETSI][17] = 46, + [0][1][1][0][RTW89_MKK][17] = 70, + [0][1][1][0][RTW89_IC][17] = 68, + [0][1][1][0][RTW89_KCC][17] = 72, + [0][1][1][0][RTW89_ACMA][17] = 46, + [0][1][1][0][RTW89_CHILE][17] = 42, + [0][1][1][0][RTW89_UKRAINE][17] = 40, + [0][1][1][0][RTW89_MEXICO][17] = 68, + [0][1][1][0][RTW89_CN][17] = 127, + [0][1][1][0][RTW89_QATAR][17] = 40, + [0][1][1][0][RTW89_FCC][19] = 68, + [0][1][1][0][RTW89_ETSI][19] = 46, + [0][1][1][0][RTW89_MKK][19] = 70, + [0][1][1][0][RTW89_IC][19] = 68, + [0][1][1][0][RTW89_KCC][19] = 72, + [0][1][1][0][RTW89_ACMA][19] = 46, + [0][1][1][0][RTW89_CHILE][19] = 42, + [0][1][1][0][RTW89_UKRAINE][19] = 40, + [0][1][1][0][RTW89_MEXICO][19] = 68, + [0][1][1][0][RTW89_CN][19] = 127, + [0][1][1][0][RTW89_QATAR][19] = 40, + [0][1][1][0][RTW89_FCC][21] = 68, + [0][1][1][0][RTW89_ETSI][21] = 46, + [0][1][1][0][RTW89_MKK][21] = 70, + [0][1][1][0][RTW89_IC][21] = 68, + [0][1][1][0][RTW89_KCC][21] = 72, + [0][1][1][0][RTW89_ACMA][21] = 46, + [0][1][1][0][RTW89_CHILE][21] = 42, + [0][1][1][0][RTW89_UKRAINE][21] = 40, + [0][1][1][0][RTW89_MEXICO][21] = 68, + [0][1][1][0][RTW89_CN][21] = 127, + [0][1][1][0][RTW89_QATAR][21] = 40, + [0][1][1][0][RTW89_FCC][23] = 68, + [0][1][1][0][RTW89_ETSI][23] = 46, + [0][1][1][0][RTW89_MKK][23] = 70, + [0][1][1][0][RTW89_IC][23] = 68, + [0][1][1][0][RTW89_KCC][23] = 72, + [0][1][1][0][RTW89_ACMA][23] = 46, + [0][1][1][0][RTW89_CHILE][23] = 42, + [0][1][1][0][RTW89_UKRAINE][23] = 40, + [0][1][1][0][RTW89_MEXICO][23] = 68, + [0][1][1][0][RTW89_CN][23] = 127, + [0][1][1][0][RTW89_QATAR][23] = 40, + [0][1][1][0][RTW89_FCC][25] = 68, + [0][1][1][0][RTW89_ETSI][25] = 46, + [0][1][1][0][RTW89_MKK][25] = 70, + [0][1][1][0][RTW89_IC][25] = 127, + [0][1][1][0][RTW89_KCC][25] = 72, + [0][1][1][0][RTW89_ACMA][25] = 127, + [0][1][1][0][RTW89_CHILE][25] = 42, + [0][1][1][0][RTW89_UKRAINE][25] = 40, + [0][1][1][0][RTW89_MEXICO][25] = 68, + [0][1][1][0][RTW89_CN][25] = 127, + [0][1][1][0][RTW89_QATAR][25] = 40, + [0][1][1][0][RTW89_FCC][27] = 68, + [0][1][1][0][RTW89_ETSI][27] = 46, + [0][1][1][0][RTW89_MKK][27] = 70, + [0][1][1][0][RTW89_IC][27] = 127, + [0][1][1][0][RTW89_KCC][27] = 72, + [0][1][1][0][RTW89_ACMA][27] = 127, + [0][1][1][0][RTW89_CHILE][27] = 42, + [0][1][1][0][RTW89_UKRAINE][27] = 40, + [0][1][1][0][RTW89_MEXICO][27] = 68, + [0][1][1][0][RTW89_CN][27] = 127, + [0][1][1][0][RTW89_QATAR][27] = 40, + [0][1][1][0][RTW89_FCC][29] = 68, + [0][1][1][0][RTW89_ETSI][29] = 46, + [0][1][1][0][RTW89_MKK][29] = 70, + [0][1][1][0][RTW89_IC][29] = 127, + [0][1][1][0][RTW89_KCC][29] = 72, + [0][1][1][0][RTW89_ACMA][29] = 127, + [0][1][1][0][RTW89_CHILE][29] = 42, + [0][1][1][0][RTW89_UKRAINE][29] = 40, + [0][1][1][0][RTW89_MEXICO][29] = 68, + [0][1][1][0][RTW89_CN][29] = 127, + [0][1][1][0][RTW89_QATAR][29] = 40, + [0][1][1][0][RTW89_FCC][31] = 68, + [0][1][1][0][RTW89_ETSI][31] = 46, + [0][1][1][0][RTW89_MKK][31] = 70, + [0][1][1][0][RTW89_IC][31] = 68, + [0][1][1][0][RTW89_KCC][31] = 72, + [0][1][1][0][RTW89_ACMA][31] = 46, + [0][1][1][0][RTW89_CHILE][31] = 42, + [0][1][1][0][RTW89_UKRAINE][31] = 40, + [0][1][1][0][RTW89_MEXICO][31] = 68, + [0][1][1][0][RTW89_CN][31] = 127, + [0][1][1][0][RTW89_QATAR][31] = 40, + [0][1][1][0][RTW89_FCC][33] = 68, + [0][1][1][0][RTW89_ETSI][33] = 46, + [0][1][1][0][RTW89_MKK][33] = 70, + [0][1][1][0][RTW89_IC][33] = 68, + [0][1][1][0][RTW89_KCC][33] = 72, + [0][1][1][0][RTW89_ACMA][33] = 46, + [0][1][1][0][RTW89_CHILE][33] = 42, + [0][1][1][0][RTW89_UKRAINE][33] = 40, + [0][1][1][0][RTW89_MEXICO][33] = 68, + [0][1][1][0][RTW89_CN][33] = 127, + [0][1][1][0][RTW89_QATAR][33] = 40, + [0][1][1][0][RTW89_FCC][35] = 66, + [0][1][1][0][RTW89_ETSI][35] = 46, + [0][1][1][0][RTW89_MKK][35] = 70, + [0][1][1][0][RTW89_IC][35] = 66, + [0][1][1][0][RTW89_KCC][35] = 72, + [0][1][1][0][RTW89_ACMA][35] = 46, + [0][1][1][0][RTW89_CHILE][35] = 42, + [0][1][1][0][RTW89_UKRAINE][35] = 40, + [0][1][1][0][RTW89_MEXICO][35] = 66, + [0][1][1][0][RTW89_CN][35] = 127, + [0][1][1][0][RTW89_QATAR][35] = 40, + [0][1][1][0][RTW89_FCC][37] = 68, + [0][1][1][0][RTW89_ETSI][37] = 127, + [0][1][1][0][RTW89_MKK][37] = 70, + [0][1][1][0][RTW89_IC][37] = 68, + [0][1][1][0][RTW89_KCC][37] = 72, + [0][1][1][0][RTW89_ACMA][37] = 68, + [0][1][1][0][RTW89_CHILE][37] = 42, + [0][1][1][0][RTW89_UKRAINE][37] = 127, + [0][1][1][0][RTW89_MEXICO][37] = 68, + [0][1][1][0][RTW89_CN][37] = 127, + [0][1][1][0][RTW89_QATAR][37] = 127, + [0][1][1][0][RTW89_FCC][38] = 76, + [0][1][1][0][RTW89_ETSI][38] = 16, + [0][1][1][0][RTW89_MKK][38] = 127, + [0][1][1][0][RTW89_IC][38] = 76, + [0][1][1][0][RTW89_KCC][38] = 72, + [0][1][1][0][RTW89_ACMA][38] = 76, + [0][1][1][0][RTW89_CHILE][38] = 42, + [0][1][1][0][RTW89_UKRAINE][38] = 16, + [0][1][1][0][RTW89_MEXICO][38] = 76, + [0][1][1][0][RTW89_CN][38] = 72, + [0][1][1][0][RTW89_QATAR][38] = 16, + [0][1][1][0][RTW89_FCC][40] = 76, + [0][1][1][0][RTW89_ETSI][40] = 16, + [0][1][1][0][RTW89_MKK][40] = 127, + [0][1][1][0][RTW89_IC][40] = 76, + [0][1][1][0][RTW89_KCC][40] = 72, + [0][1][1][0][RTW89_ACMA][40] = 76, + [0][1][1][0][RTW89_CHILE][40] = 42, + [0][1][1][0][RTW89_UKRAINE][40] = 16, + [0][1][1][0][RTW89_MEXICO][40] = 76, + [0][1][1][0][RTW89_CN][40] = 76, + [0][1][1][0][RTW89_QATAR][40] = 16, + [0][1][1][0][RTW89_FCC][42] = 76, + [0][1][1][0][RTW89_ETSI][42] = 16, + [0][1][1][0][RTW89_MKK][42] = 127, + [0][1][1][0][RTW89_IC][42] = 76, + [0][1][1][0][RTW89_KCC][42] = 72, + [0][1][1][0][RTW89_ACMA][42] = 76, + [0][1][1][0][RTW89_CHILE][42] = 42, + [0][1][1][0][RTW89_UKRAINE][42] = 16, + [0][1][1][0][RTW89_MEXICO][42] = 76, + [0][1][1][0][RTW89_CN][42] = 76, + [0][1][1][0][RTW89_QATAR][42] = 16, + [0][1][1][0][RTW89_FCC][44] = 76, + [0][1][1][0][RTW89_ETSI][44] = 16, + [0][1][1][0][RTW89_MKK][44] = 127, + [0][1][1][0][RTW89_IC][44] = 76, + [0][1][1][0][RTW89_KCC][44] = 72, + [0][1][1][0][RTW89_ACMA][44] = 76, + [0][1][1][0][RTW89_CHILE][44] = 42, + [0][1][1][0][RTW89_UKRAINE][44] = 16, + [0][1][1][0][RTW89_MEXICO][44] = 76, + [0][1][1][0][RTW89_CN][44] = 76, + [0][1][1][0][RTW89_QATAR][44] = 16, + [0][1][1][0][RTW89_FCC][46] = 76, + [0][1][1][0][RTW89_ETSI][46] = 16, + [0][1][1][0][RTW89_MKK][46] = 127, + [0][1][1][0][RTW89_IC][46] = 76, + [0][1][1][0][RTW89_KCC][46] = 72, + [0][1][1][0][RTW89_ACMA][46] = 76, + [0][1][1][0][RTW89_CHILE][46] = 42, + [0][1][1][0][RTW89_UKRAINE][46] = 16, + [0][1][1][0][RTW89_MEXICO][46] = 76, + [0][1][1][0][RTW89_CN][46] = 76, + [0][1][1][0][RTW89_QATAR][46] = 16, + [0][0][2][0][RTW89_FCC][0] = 76, + [0][0][2][0][RTW89_ETSI][0] = 58, + [0][0][2][0][RTW89_MKK][0] = 62, + [0][0][2][0][RTW89_IC][0] = 62, + [0][0][2][0][RTW89_KCC][0] = 76, + [0][0][2][0][RTW89_ACMA][0] = 58, + [0][0][2][0][RTW89_CHILE][0] = 30, + [0][0][2][0][RTW89_UKRAINE][0] = 52, + [0][0][2][0][RTW89_MEXICO][0] = 62, + [0][0][2][0][RTW89_CN][0] = 58, + [0][0][2][0][RTW89_QATAR][0] = 58, + [0][0][2][0][RTW89_FCC][2] = 76, + [0][0][2][0][RTW89_ETSI][2] = 58, + [0][0][2][0][RTW89_MKK][2] = 62, + [0][0][2][0][RTW89_IC][2] = 62, + [0][0][2][0][RTW89_KCC][2] = 76, + [0][0][2][0][RTW89_ACMA][2] = 58, + [0][0][2][0][RTW89_CHILE][2] = 30, + [0][0][2][0][RTW89_UKRAINE][2] = 52, + [0][0][2][0][RTW89_MEXICO][2] = 62, + [0][0][2][0][RTW89_CN][2] = 58, + [0][0][2][0][RTW89_QATAR][2] = 58, + [0][0][2][0][RTW89_FCC][4] = 76, + [0][0][2][0][RTW89_ETSI][4] = 58, + [0][0][2][0][RTW89_MKK][4] = 62, + [0][0][2][0][RTW89_IC][4] = 62, + [0][0][2][0][RTW89_KCC][4] = 76, + [0][0][2][0][RTW89_ACMA][4] = 58, + [0][0][2][0][RTW89_CHILE][4] = 30, + [0][0][2][0][RTW89_UKRAINE][4] = 52, + [0][0][2][0][RTW89_MEXICO][4] = 62, + [0][0][2][0][RTW89_CN][4] = 58, + [0][0][2][0][RTW89_QATAR][4] = 58, + [0][0][2][0][RTW89_FCC][6] = 76, + [0][0][2][0][RTW89_ETSI][6] = 58, + [0][0][2][0][RTW89_MKK][6] = 62, + [0][0][2][0][RTW89_IC][6] = 62, + [0][0][2][0][RTW89_KCC][6] = 58, + [0][0][2][0][RTW89_ACMA][6] = 58, + [0][0][2][0][RTW89_CHILE][6] = 30, + [0][0][2][0][RTW89_UKRAINE][6] = 52, + [0][0][2][0][RTW89_MEXICO][6] = 62, + [0][0][2][0][RTW89_CN][6] = 58, + [0][0][2][0][RTW89_QATAR][6] = 58, + [0][0][2][0][RTW89_FCC][8] = 76, + [0][0][2][0][RTW89_ETSI][8] = 58, + [0][0][2][0][RTW89_MKK][8] = 62, + [0][0][2][0][RTW89_IC][8] = 64, + [0][0][2][0][RTW89_KCC][8] = 76, + [0][0][2][0][RTW89_ACMA][8] = 58, + [0][0][2][0][RTW89_CHILE][8] = 54, + [0][0][2][0][RTW89_UKRAINE][8] = 52, + [0][0][2][0][RTW89_MEXICO][8] = 76, + [0][0][2][0][RTW89_CN][8] = 58, + [0][0][2][0][RTW89_QATAR][8] = 58, + [0][0][2][0][RTW89_FCC][10] = 76, + [0][0][2][0][RTW89_ETSI][10] = 58, + [0][0][2][0][RTW89_MKK][10] = 62, + [0][0][2][0][RTW89_IC][10] = 64, + [0][0][2][0][RTW89_KCC][10] = 76, + [0][0][2][0][RTW89_ACMA][10] = 58, + [0][0][2][0][RTW89_CHILE][10] = 54, + [0][0][2][0][RTW89_UKRAINE][10] = 52, + [0][0][2][0][RTW89_MEXICO][10] = 76, + [0][0][2][0][RTW89_CN][10] = 58, + [0][0][2][0][RTW89_QATAR][10] = 58, + [0][0][2][0][RTW89_FCC][12] = 76, + [0][0][2][0][RTW89_ETSI][12] = 58, + [0][0][2][0][RTW89_MKK][12] = 62, + [0][0][2][0][RTW89_IC][12] = 64, + [0][0][2][0][RTW89_KCC][12] = 76, + [0][0][2][0][RTW89_ACMA][12] = 58, + [0][0][2][0][RTW89_CHILE][12] = 54, + [0][0][2][0][RTW89_UKRAINE][12] = 52, + [0][0][2][0][RTW89_MEXICO][12] = 76, + [0][0][2][0][RTW89_CN][12] = 58, + [0][0][2][0][RTW89_QATAR][12] = 58, + [0][0][2][0][RTW89_FCC][14] = 76, + [0][0][2][0][RTW89_ETSI][14] = 58, + [0][0][2][0][RTW89_MKK][14] = 62, + [0][0][2][0][RTW89_IC][14] = 64, + [0][0][2][0][RTW89_KCC][14] = 76, + [0][0][2][0][RTW89_ACMA][14] = 58, + [0][0][2][0][RTW89_CHILE][14] = 54, + [0][0][2][0][RTW89_UKRAINE][14] = 52, + [0][0][2][0][RTW89_MEXICO][14] = 76, + [0][0][2][0][RTW89_CN][14] = 58, + [0][0][2][0][RTW89_QATAR][14] = 58, + [0][0][2][0][RTW89_FCC][15] = 74, + [0][0][2][0][RTW89_ETSI][15] = 58, + [0][0][2][0][RTW89_MKK][15] = 76, + [0][0][2][0][RTW89_IC][15] = 74, + [0][0][2][0][RTW89_KCC][15] = 76, + [0][0][2][0][RTW89_ACMA][15] = 58, + [0][0][2][0][RTW89_CHILE][15] = 54, + [0][0][2][0][RTW89_UKRAINE][15] = 52, + [0][0][2][0][RTW89_MEXICO][15] = 74, + [0][0][2][0][RTW89_CN][15] = 127, + [0][0][2][0][RTW89_QATAR][15] = 52, + [0][0][2][0][RTW89_FCC][17] = 76, + [0][0][2][0][RTW89_ETSI][17] = 58, + [0][0][2][0][RTW89_MKK][17] = 76, + [0][0][2][0][RTW89_IC][17] = 76, + [0][0][2][0][RTW89_KCC][17] = 76, + [0][0][2][0][RTW89_ACMA][17] = 58, + [0][0][2][0][RTW89_CHILE][17] = 54, + [0][0][2][0][RTW89_UKRAINE][17] = 52, + [0][0][2][0][RTW89_MEXICO][17] = 76, + [0][0][2][0][RTW89_CN][17] = 127, + [0][0][2][0][RTW89_QATAR][17] = 52, + [0][0][2][0][RTW89_FCC][19] = 76, + [0][0][2][0][RTW89_ETSI][19] = 58, + [0][0][2][0][RTW89_MKK][19] = 76, + [0][0][2][0][RTW89_IC][19] = 76, + [0][0][2][0][RTW89_KCC][19] = 76, + [0][0][2][0][RTW89_ACMA][19] = 58, + [0][0][2][0][RTW89_CHILE][19] = 54, + [0][0][2][0][RTW89_UKRAINE][19] = 52, + [0][0][2][0][RTW89_MEXICO][19] = 76, + [0][0][2][0][RTW89_CN][19] = 127, + [0][0][2][0][RTW89_QATAR][19] = 52, + [0][0][2][0][RTW89_FCC][21] = 76, + [0][0][2][0][RTW89_ETSI][21] = 58, + [0][0][2][0][RTW89_MKK][21] = 76, + [0][0][2][0][RTW89_IC][21] = 76, + [0][0][2][0][RTW89_KCC][21] = 76, + [0][0][2][0][RTW89_ACMA][21] = 58, + [0][0][2][0][RTW89_CHILE][21] = 54, + [0][0][2][0][RTW89_UKRAINE][21] = 52, + [0][0][2][0][RTW89_MEXICO][21] = 76, + [0][0][2][0][RTW89_CN][21] = 127, + [0][0][2][0][RTW89_QATAR][21] = 52, + [0][0][2][0][RTW89_FCC][23] = 76, + [0][0][2][0][RTW89_ETSI][23] = 58, + [0][0][2][0][RTW89_MKK][23] = 76, + [0][0][2][0][RTW89_IC][23] = 76, + [0][0][2][0][RTW89_KCC][23] = 76, + [0][0][2][0][RTW89_ACMA][23] = 58, + [0][0][2][0][RTW89_CHILE][23] = 54, + [0][0][2][0][RTW89_UKRAINE][23] = 52, + [0][0][2][0][RTW89_MEXICO][23] = 76, + [0][0][2][0][RTW89_CN][23] = 127, + [0][0][2][0][RTW89_QATAR][23] = 52, + [0][0][2][0][RTW89_FCC][25] = 76, + [0][0][2][0][RTW89_ETSI][25] = 58, + [0][0][2][0][RTW89_MKK][25] = 76, + [0][0][2][0][RTW89_IC][25] = 127, + [0][0][2][0][RTW89_KCC][25] = 76, + [0][0][2][0][RTW89_ACMA][25] = 127, + [0][0][2][0][RTW89_CHILE][25] = 54, + [0][0][2][0][RTW89_UKRAINE][25] = 52, + [0][0][2][0][RTW89_MEXICO][25] = 76, + [0][0][2][0][RTW89_CN][25] = 127, + [0][0][2][0][RTW89_QATAR][25] = 52, + [0][0][2][0][RTW89_FCC][27] = 76, + [0][0][2][0][RTW89_ETSI][27] = 58, + [0][0][2][0][RTW89_MKK][27] = 76, + [0][0][2][0][RTW89_IC][27] = 127, + [0][0][2][0][RTW89_KCC][27] = 76, + [0][0][2][0][RTW89_ACMA][27] = 127, + [0][0][2][0][RTW89_CHILE][27] = 54, + [0][0][2][0][RTW89_UKRAINE][27] = 52, + [0][0][2][0][RTW89_MEXICO][27] = 76, + [0][0][2][0][RTW89_CN][27] = 127, + [0][0][2][0][RTW89_QATAR][27] = 52, + [0][0][2][0][RTW89_FCC][29] = 76, + [0][0][2][0][RTW89_ETSI][29] = 58, + [0][0][2][0][RTW89_MKK][29] = 76, + [0][0][2][0][RTW89_IC][29] = 127, + [0][0][2][0][RTW89_KCC][29] = 76, + [0][0][2][0][RTW89_ACMA][29] = 127, + [0][0][2][0][RTW89_CHILE][29] = 54, + [0][0][2][0][RTW89_UKRAINE][29] = 52, + [0][0][2][0][RTW89_MEXICO][29] = 76, + [0][0][2][0][RTW89_CN][29] = 127, + [0][0][2][0][RTW89_QATAR][29] = 52, + [0][0][2][0][RTW89_FCC][31] = 76, + [0][0][2][0][RTW89_ETSI][31] = 58, + [0][0][2][0][RTW89_MKK][31] = 76, + [0][0][2][0][RTW89_IC][31] = 76, + [0][0][2][0][RTW89_KCC][31] = 76, + [0][0][2][0][RTW89_ACMA][31] = 58, + [0][0][2][0][RTW89_CHILE][31] = 54, + [0][0][2][0][RTW89_UKRAINE][31] = 52, + [0][0][2][0][RTW89_MEXICO][31] = 76, + [0][0][2][0][RTW89_CN][31] = 127, + [0][0][2][0][RTW89_QATAR][31] = 52, + [0][0][2][0][RTW89_FCC][33] = 76, + [0][0][2][0][RTW89_ETSI][33] = 58, + [0][0][2][0][RTW89_MKK][33] = 76, + [0][0][2][0][RTW89_IC][33] = 76, + [0][0][2][0][RTW89_KCC][33] = 76, + [0][0][2][0][RTW89_ACMA][33] = 58, + [0][0][2][0][RTW89_CHILE][33] = 54, + [0][0][2][0][RTW89_UKRAINE][33] = 52, + [0][0][2][0][RTW89_MEXICO][33] = 76, + [0][0][2][0][RTW89_CN][33] = 127, + [0][0][2][0][RTW89_QATAR][33] = 52, + [0][0][2][0][RTW89_FCC][35] = 70, + [0][0][2][0][RTW89_ETSI][35] = 58, + [0][0][2][0][RTW89_MKK][35] = 76, + [0][0][2][0][RTW89_IC][35] = 70, + [0][0][2][0][RTW89_KCC][35] = 76, + [0][0][2][0][RTW89_ACMA][35] = 58, + [0][0][2][0][RTW89_CHILE][35] = 54, + [0][0][2][0][RTW89_UKRAINE][35] = 52, + [0][0][2][0][RTW89_MEXICO][35] = 70, + [0][0][2][0][RTW89_CN][35] = 127, + [0][0][2][0][RTW89_QATAR][35] = 52, + [0][0][2][0][RTW89_FCC][37] = 76, + [0][0][2][0][RTW89_ETSI][37] = 127, + [0][0][2][0][RTW89_MKK][37] = 76, + [0][0][2][0][RTW89_IC][37] = 76, + [0][0][2][0][RTW89_KCC][37] = 76, + [0][0][2][0][RTW89_ACMA][37] = 76, + [0][0][2][0][RTW89_CHILE][37] = 54, + [0][0][2][0][RTW89_UKRAINE][37] = 127, + [0][0][2][0][RTW89_MEXICO][37] = 76, + [0][0][2][0][RTW89_CN][37] = 127, + [0][0][2][0][RTW89_QATAR][37] = 127, + [0][0][2][0][RTW89_FCC][38] = 76, + [0][0][2][0][RTW89_ETSI][38] = 28, + [0][0][2][0][RTW89_MKK][38] = 127, + [0][0][2][0][RTW89_IC][38] = 76, + [0][0][2][0][RTW89_KCC][38] = 76, + [0][0][2][0][RTW89_ACMA][38] = 76, + [0][0][2][0][RTW89_CHILE][38] = 54, + [0][0][2][0][RTW89_UKRAINE][38] = 28, + [0][0][2][0][RTW89_MEXICO][38] = 76, + [0][0][2][0][RTW89_CN][38] = 68, + [0][0][2][0][RTW89_QATAR][38] = 28, + [0][0][2][0][RTW89_FCC][40] = 76, + [0][0][2][0][RTW89_ETSI][40] = 28, + [0][0][2][0][RTW89_MKK][40] = 127, + [0][0][2][0][RTW89_IC][40] = 76, + [0][0][2][0][RTW89_KCC][40] = 76, + [0][0][2][0][RTW89_ACMA][40] = 76, + [0][0][2][0][RTW89_CHILE][40] = 54, + [0][0][2][0][RTW89_UKRAINE][40] = 28, + [0][0][2][0][RTW89_MEXICO][40] = 76, + [0][0][2][0][RTW89_CN][40] = 76, + [0][0][2][0][RTW89_QATAR][40] = 28, + [0][0][2][0][RTW89_FCC][42] = 76, + [0][0][2][0][RTW89_ETSI][42] = 28, + [0][0][2][0][RTW89_MKK][42] = 127, + [0][0][2][0][RTW89_IC][42] = 76, + [0][0][2][0][RTW89_KCC][42] = 76, + [0][0][2][0][RTW89_ACMA][42] = 76, + [0][0][2][0][RTW89_CHILE][42] = 54, + [0][0][2][0][RTW89_UKRAINE][42] = 28, + [0][0][2][0][RTW89_MEXICO][42] = 76, + [0][0][2][0][RTW89_CN][42] = 76, + [0][0][2][0][RTW89_QATAR][42] = 28, + [0][0][2][0][RTW89_FCC][44] = 76, + [0][0][2][0][RTW89_ETSI][44] = 28, + [0][0][2][0][RTW89_MKK][44] = 127, + [0][0][2][0][RTW89_IC][44] = 76, + [0][0][2][0][RTW89_KCC][44] = 76, + [0][0][2][0][RTW89_ACMA][44] = 76, + [0][0][2][0][RTW89_CHILE][44] = 54, + [0][0][2][0][RTW89_UKRAINE][44] = 28, + [0][0][2][0][RTW89_MEXICO][44] = 76, + [0][0][2][0][RTW89_CN][44] = 76, + [0][0][2][0][RTW89_QATAR][44] = 28, + [0][0][2][0][RTW89_FCC][46] = 76, + [0][0][2][0][RTW89_ETSI][46] = 28, + [0][0][2][0][RTW89_MKK][46] = 127, + [0][0][2][0][RTW89_IC][46] = 76, + [0][0][2][0][RTW89_KCC][46] = 76, + [0][0][2][0][RTW89_ACMA][46] = 76, + [0][0][2][0][RTW89_CHILE][46] = 54, + [0][0][2][0][RTW89_UKRAINE][46] = 28, + [0][0][2][0][RTW89_MEXICO][46] = 76, + [0][0][2][0][RTW89_CN][46] = 76, + [0][0][2][0][RTW89_QATAR][46] = 28, + [0][1][2][0][RTW89_FCC][0] = 68, + [0][1][2][0][RTW89_ETSI][0] = 46, + [0][1][2][0][RTW89_MKK][0] = 50, + [0][1][2][0][RTW89_IC][0] = 40, + [0][1][2][0][RTW89_KCC][0] = 68, + [0][1][2][0][RTW89_ACMA][0] = 46, + [0][1][2][0][RTW89_CHILE][0] = 18, + [0][1][2][0][RTW89_UKRAINE][0] = 40, + [0][1][2][0][RTW89_MEXICO][0] = 50, + [0][1][2][0][RTW89_CN][0] = 46, + [0][1][2][0][RTW89_QATAR][0] = 46, + [0][1][2][0][RTW89_FCC][2] = 68, + [0][1][2][0][RTW89_ETSI][2] = 46, + [0][1][2][0][RTW89_MKK][2] = 50, + [0][1][2][0][RTW89_IC][2] = 40, + [0][1][2][0][RTW89_KCC][2] = 68, + [0][1][2][0][RTW89_ACMA][2] = 46, + [0][1][2][0][RTW89_CHILE][2] = 18, + [0][1][2][0][RTW89_UKRAINE][2] = 40, + [0][1][2][0][RTW89_MEXICO][2] = 50, + [0][1][2][0][RTW89_CN][2] = 46, + [0][1][2][0][RTW89_QATAR][2] = 46, + [0][1][2][0][RTW89_FCC][4] = 68, + [0][1][2][0][RTW89_ETSI][4] = 46, + [0][1][2][0][RTW89_MKK][4] = 50, + [0][1][2][0][RTW89_IC][4] = 40, + [0][1][2][0][RTW89_KCC][4] = 68, + [0][1][2][0][RTW89_ACMA][4] = 46, + [0][1][2][0][RTW89_CHILE][4] = 18, + [0][1][2][0][RTW89_UKRAINE][4] = 40, + [0][1][2][0][RTW89_MEXICO][4] = 50, + [0][1][2][0][RTW89_CN][4] = 46, + [0][1][2][0][RTW89_QATAR][4] = 46, + [0][1][2][0][RTW89_FCC][6] = 68, + [0][1][2][0][RTW89_ETSI][6] = 46, + [0][1][2][0][RTW89_MKK][6] = 50, + [0][1][2][0][RTW89_IC][6] = 40, + [0][1][2][0][RTW89_KCC][6] = 38, + [0][1][2][0][RTW89_ACMA][6] = 46, + [0][1][2][0][RTW89_CHILE][6] = 18, + [0][1][2][0][RTW89_UKRAINE][6] = 40, + [0][1][2][0][RTW89_MEXICO][6] = 50, + [0][1][2][0][RTW89_CN][6] = 46, + [0][1][2][0][RTW89_QATAR][6] = 46, + [0][1][2][0][RTW89_FCC][8] = 68, + [0][1][2][0][RTW89_ETSI][8] = 46, + [0][1][2][0][RTW89_MKK][8] = 50, + [0][1][2][0][RTW89_IC][8] = 52, + [0][1][2][0][RTW89_KCC][8] = 68, + [0][1][2][0][RTW89_ACMA][8] = 46, + [0][1][2][0][RTW89_CHILE][8] = 42, + [0][1][2][0][RTW89_UKRAINE][8] = 40, + [0][1][2][0][RTW89_MEXICO][8] = 68, + [0][1][2][0][RTW89_CN][8] = 46, + [0][1][2][0][RTW89_QATAR][8] = 46, + [0][1][2][0][RTW89_FCC][10] = 68, + [0][1][2][0][RTW89_ETSI][10] = 46, + [0][1][2][0][RTW89_MKK][10] = 50, + [0][1][2][0][RTW89_IC][10] = 52, + [0][1][2][0][RTW89_KCC][10] = 68, + [0][1][2][0][RTW89_ACMA][10] = 46, + [0][1][2][0][RTW89_CHILE][10] = 42, + [0][1][2][0][RTW89_UKRAINE][10] = 40, + [0][1][2][0][RTW89_MEXICO][10] = 68, + [0][1][2][0][RTW89_CN][10] = 46, + [0][1][2][0][RTW89_QATAR][10] = 46, + [0][1][2][0][RTW89_FCC][12] = 68, + [0][1][2][0][RTW89_ETSI][12] = 46, + [0][1][2][0][RTW89_MKK][12] = 50, + [0][1][2][0][RTW89_IC][12] = 52, + [0][1][2][0][RTW89_KCC][12] = 68, + [0][1][2][0][RTW89_ACMA][12] = 46, + [0][1][2][0][RTW89_CHILE][12] = 42, + [0][1][2][0][RTW89_UKRAINE][12] = 40, + [0][1][2][0][RTW89_MEXICO][12] = 68, + [0][1][2][0][RTW89_CN][12] = 46, + [0][1][2][0][RTW89_QATAR][12] = 46, + [0][1][2][0][RTW89_FCC][14] = 68, + [0][1][2][0][RTW89_ETSI][14] = 46, + [0][1][2][0][RTW89_MKK][14] = 50, + [0][1][2][0][RTW89_IC][14] = 52, + [0][1][2][0][RTW89_KCC][14] = 68, + [0][1][2][0][RTW89_ACMA][14] = 46, + [0][1][2][0][RTW89_CHILE][14] = 42, + [0][1][2][0][RTW89_UKRAINE][14] = 40, + [0][1][2][0][RTW89_MEXICO][14] = 68, + [0][1][2][0][RTW89_CN][14] = 46, + [0][1][2][0][RTW89_QATAR][14] = 46, + [0][1][2][0][RTW89_FCC][15] = 68, + [0][1][2][0][RTW89_ETSI][15] = 46, + [0][1][2][0][RTW89_MKK][15] = 70, + [0][1][2][0][RTW89_IC][15] = 68, + [0][1][2][0][RTW89_KCC][15] = 66, + [0][1][2][0][RTW89_ACMA][15] = 46, + [0][1][2][0][RTW89_CHILE][15] = 42, + [0][1][2][0][RTW89_UKRAINE][15] = 40, + [0][1][2][0][RTW89_MEXICO][15] = 68, + [0][1][2][0][RTW89_CN][15] = 127, + [0][1][2][0][RTW89_QATAR][15] = 40, + [0][1][2][0][RTW89_FCC][17] = 68, + [0][1][2][0][RTW89_ETSI][17] = 46, + [0][1][2][0][RTW89_MKK][17] = 70, + [0][1][2][0][RTW89_IC][17] = 68, + [0][1][2][0][RTW89_KCC][17] = 66, + [0][1][2][0][RTW89_ACMA][17] = 46, + [0][1][2][0][RTW89_CHILE][17] = 42, + [0][1][2][0][RTW89_UKRAINE][17] = 40, + [0][1][2][0][RTW89_MEXICO][17] = 68, + [0][1][2][0][RTW89_CN][17] = 127, + [0][1][2][0][RTW89_QATAR][17] = 40, + [0][1][2][0][RTW89_FCC][19] = 68, + [0][1][2][0][RTW89_ETSI][19] = 46, + [0][1][2][0][RTW89_MKK][19] = 70, + [0][1][2][0][RTW89_IC][19] = 68, + [0][1][2][0][RTW89_KCC][19] = 66, + [0][1][2][0][RTW89_ACMA][19] = 46, + [0][1][2][0][RTW89_CHILE][19] = 42, + [0][1][2][0][RTW89_UKRAINE][19] = 40, + [0][1][2][0][RTW89_MEXICO][19] = 68, + [0][1][2][0][RTW89_CN][19] = 127, + [0][1][2][0][RTW89_QATAR][19] = 40, + [0][1][2][0][RTW89_FCC][21] = 68, + [0][1][2][0][RTW89_ETSI][21] = 46, + [0][1][2][0][RTW89_MKK][21] = 70, + [0][1][2][0][RTW89_IC][21] = 68, + [0][1][2][0][RTW89_KCC][21] = 66, + [0][1][2][0][RTW89_ACMA][21] = 46, + [0][1][2][0][RTW89_CHILE][21] = 42, + [0][1][2][0][RTW89_UKRAINE][21] = 40, + [0][1][2][0][RTW89_MEXICO][21] = 68, + [0][1][2][0][RTW89_CN][21] = 127, + [0][1][2][0][RTW89_QATAR][21] = 40, + [0][1][2][0][RTW89_FCC][23] = 68, + [0][1][2][0][RTW89_ETSI][23] = 46, + [0][1][2][0][RTW89_MKK][23] = 70, + [0][1][2][0][RTW89_IC][23] = 68, + [0][1][2][0][RTW89_KCC][23] = 66, + [0][1][2][0][RTW89_ACMA][23] = 46, + [0][1][2][0][RTW89_CHILE][23] = 42, + [0][1][2][0][RTW89_UKRAINE][23] = 40, + [0][1][2][0][RTW89_MEXICO][23] = 68, + [0][1][2][0][RTW89_CN][23] = 127, + [0][1][2][0][RTW89_QATAR][23] = 40, + [0][1][2][0][RTW89_FCC][25] = 68, + [0][1][2][0][RTW89_ETSI][25] = 46, + [0][1][2][0][RTW89_MKK][25] = 70, + [0][1][2][0][RTW89_IC][25] = 127, + [0][1][2][0][RTW89_KCC][25] = 66, + [0][1][2][0][RTW89_ACMA][25] = 127, + [0][1][2][0][RTW89_CHILE][25] = 42, + [0][1][2][0][RTW89_UKRAINE][25] = 40, + [0][1][2][0][RTW89_MEXICO][25] = 68, + [0][1][2][0][RTW89_CN][25] = 127, + [0][1][2][0][RTW89_QATAR][25] = 40, + [0][1][2][0][RTW89_FCC][27] = 68, + [0][1][2][0][RTW89_ETSI][27] = 46, + [0][1][2][0][RTW89_MKK][27] = 70, + [0][1][2][0][RTW89_IC][27] = 127, + [0][1][2][0][RTW89_KCC][27] = 66, + [0][1][2][0][RTW89_ACMA][27] = 127, + [0][1][2][0][RTW89_CHILE][27] = 42, + [0][1][2][0][RTW89_UKRAINE][27] = 40, + [0][1][2][0][RTW89_MEXICO][27] = 68, + [0][1][2][0][RTW89_CN][27] = 127, + [0][1][2][0][RTW89_QATAR][27] = 40, + [0][1][2][0][RTW89_FCC][29] = 68, + [0][1][2][0][RTW89_ETSI][29] = 46, + [0][1][2][0][RTW89_MKK][29] = 70, + [0][1][2][0][RTW89_IC][29] = 127, + [0][1][2][0][RTW89_KCC][29] = 66, + [0][1][2][0][RTW89_ACMA][29] = 127, + [0][1][2][0][RTW89_CHILE][29] = 42, + [0][1][2][0][RTW89_UKRAINE][29] = 40, + [0][1][2][0][RTW89_MEXICO][29] = 68, + [0][1][2][0][RTW89_CN][29] = 127, + [0][1][2][0][RTW89_QATAR][29] = 40, + [0][1][2][0][RTW89_FCC][31] = 68, + [0][1][2][0][RTW89_ETSI][31] = 46, + [0][1][2][0][RTW89_MKK][31] = 70, + [0][1][2][0][RTW89_IC][31] = 68, + [0][1][2][0][RTW89_KCC][31] = 66, + [0][1][2][0][RTW89_ACMA][31] = 46, + [0][1][2][0][RTW89_CHILE][31] = 42, + [0][1][2][0][RTW89_UKRAINE][31] = 40, + [0][1][2][0][RTW89_MEXICO][31] = 68, + [0][1][2][0][RTW89_CN][31] = 127, + [0][1][2][0][RTW89_QATAR][31] = 40, + [0][1][2][0][RTW89_FCC][33] = 68, + [0][1][2][0][RTW89_ETSI][33] = 46, + [0][1][2][0][RTW89_MKK][33] = 70, + [0][1][2][0][RTW89_IC][33] = 68, + [0][1][2][0][RTW89_KCC][33] = 66, + [0][1][2][0][RTW89_ACMA][33] = 46, + [0][1][2][0][RTW89_CHILE][33] = 42, + [0][1][2][0][RTW89_UKRAINE][33] = 40, + [0][1][2][0][RTW89_MEXICO][33] = 68, + [0][1][2][0][RTW89_CN][33] = 127, + [0][1][2][0][RTW89_QATAR][33] = 40, + [0][1][2][0][RTW89_FCC][35] = 64, + [0][1][2][0][RTW89_ETSI][35] = 46, + [0][1][2][0][RTW89_MKK][35] = 70, + [0][1][2][0][RTW89_IC][35] = 64, + [0][1][2][0][RTW89_KCC][35] = 66, + [0][1][2][0][RTW89_ACMA][35] = 46, + [0][1][2][0][RTW89_CHILE][35] = 42, + [0][1][2][0][RTW89_UKRAINE][35] = 40, + [0][1][2][0][RTW89_MEXICO][35] = 64, + [0][1][2][0][RTW89_CN][35] = 127, + [0][1][2][0][RTW89_QATAR][35] = 40, + [0][1][2][0][RTW89_FCC][37] = 68, + [0][1][2][0][RTW89_ETSI][37] = 127, + [0][1][2][0][RTW89_MKK][37] = 70, + [0][1][2][0][RTW89_IC][37] = 68, + [0][1][2][0][RTW89_KCC][37] = 66, + [0][1][2][0][RTW89_ACMA][37] = 68, + [0][1][2][0][RTW89_CHILE][37] = 42, + [0][1][2][0][RTW89_UKRAINE][37] = 127, + [0][1][2][0][RTW89_MEXICO][37] = 68, + [0][1][2][0][RTW89_CN][37] = 127, + [0][1][2][0][RTW89_QATAR][37] = 127, + [0][1][2][0][RTW89_FCC][38] = 76, + [0][1][2][0][RTW89_ETSI][38] = 16, + [0][1][2][0][RTW89_MKK][38] = 127, + [0][1][2][0][RTW89_IC][38] = 76, + [0][1][2][0][RTW89_KCC][38] = 66, + [0][1][2][0][RTW89_ACMA][38] = 76, + [0][1][2][0][RTW89_CHILE][38] = 42, + [0][1][2][0][RTW89_UKRAINE][38] = 16, + [0][1][2][0][RTW89_MEXICO][38] = 76, + [0][1][2][0][RTW89_CN][38] = 68, + [0][1][2][0][RTW89_QATAR][38] = 16, + [0][1][2][0][RTW89_FCC][40] = 76, + [0][1][2][0][RTW89_ETSI][40] = 16, + [0][1][2][0][RTW89_MKK][40] = 127, + [0][1][2][0][RTW89_IC][40] = 76, + [0][1][2][0][RTW89_KCC][40] = 66, + [0][1][2][0][RTW89_ACMA][40] = 76, + [0][1][2][0][RTW89_CHILE][40] = 42, + [0][1][2][0][RTW89_UKRAINE][40] = 16, + [0][1][2][0][RTW89_MEXICO][40] = 76, + [0][1][2][0][RTW89_CN][40] = 76, + [0][1][2][0][RTW89_QATAR][40] = 16, + [0][1][2][0][RTW89_FCC][42] = 76, + [0][1][2][0][RTW89_ETSI][42] = 16, + [0][1][2][0][RTW89_MKK][42] = 127, + [0][1][2][0][RTW89_IC][42] = 76, + [0][1][2][0][RTW89_KCC][42] = 66, + [0][1][2][0][RTW89_ACMA][42] = 76, + [0][1][2][0][RTW89_CHILE][42] = 42, + [0][1][2][0][RTW89_UKRAINE][42] = 16, + [0][1][2][0][RTW89_MEXICO][42] = 76, + [0][1][2][0][RTW89_CN][42] = 76, + [0][1][2][0][RTW89_QATAR][42] = 16, + [0][1][2][0][RTW89_FCC][44] = 76, + [0][1][2][0][RTW89_ETSI][44] = 16, + [0][1][2][0][RTW89_MKK][44] = 127, + [0][1][2][0][RTW89_IC][44] = 76, + [0][1][2][0][RTW89_KCC][44] = 66, + [0][1][2][0][RTW89_ACMA][44] = 76, + [0][1][2][0][RTW89_CHILE][44] = 42, + [0][1][2][0][RTW89_UKRAINE][44] = 16, + [0][1][2][0][RTW89_MEXICO][44] = 76, + [0][1][2][0][RTW89_CN][44] = 76, + [0][1][2][0][RTW89_QATAR][44] = 16, + [0][1][2][0][RTW89_FCC][46] = 76, + [0][1][2][0][RTW89_ETSI][46] = 16, + [0][1][2][0][RTW89_MKK][46] = 127, + [0][1][2][0][RTW89_IC][46] = 76, + [0][1][2][0][RTW89_KCC][46] = 66, + [0][1][2][0][RTW89_ACMA][46] = 76, + [0][1][2][0][RTW89_CHILE][46] = 42, + [0][1][2][0][RTW89_UKRAINE][46] = 16, + [0][1][2][0][RTW89_MEXICO][46] = 76, + [0][1][2][0][RTW89_CN][46] = 76, + [0][1][2][0][RTW89_QATAR][46] = 16, + [0][1][2][1][RTW89_FCC][0] = 68, + [0][1][2][1][RTW89_ETSI][0] = 34, + [0][1][2][1][RTW89_MKK][0] = 50, + [0][1][2][1][RTW89_IC][0] = 38, + [0][1][2][1][RTW89_KCC][0] = 68, + [0][1][2][1][RTW89_ACMA][0] = 34, + [0][1][2][1][RTW89_CHILE][0] = 6, + [0][1][2][1][RTW89_UKRAINE][0] = 28, + [0][1][2][1][RTW89_MEXICO][0] = 50, + [0][1][2][1][RTW89_CN][0] = 34, + [0][1][2][1][RTW89_QATAR][0] = 34, + [0][1][2][1][RTW89_FCC][2] = 68, + [0][1][2][1][RTW89_ETSI][2] = 34, + [0][1][2][1][RTW89_MKK][2] = 50, + [0][1][2][1][RTW89_IC][2] = 38, + [0][1][2][1][RTW89_KCC][2] = 68, + [0][1][2][1][RTW89_ACMA][2] = 34, + [0][1][2][1][RTW89_CHILE][2] = 6, + [0][1][2][1][RTW89_UKRAINE][2] = 28, + [0][1][2][1][RTW89_MEXICO][2] = 50, + [0][1][2][1][RTW89_CN][2] = 34, + [0][1][2][1][RTW89_QATAR][2] = 34, + [0][1][2][1][RTW89_FCC][4] = 68, + [0][1][2][1][RTW89_ETSI][4] = 34, + [0][1][2][1][RTW89_MKK][4] = 50, + [0][1][2][1][RTW89_IC][4] = 38, + [0][1][2][1][RTW89_KCC][4] = 68, + [0][1][2][1][RTW89_ACMA][4] = 34, + [0][1][2][1][RTW89_CHILE][4] = 6, + [0][1][2][1][RTW89_UKRAINE][4] = 28, + [0][1][2][1][RTW89_MEXICO][4] = 50, + [0][1][2][1][RTW89_CN][4] = 34, + [0][1][2][1][RTW89_QATAR][4] = 34, + [0][1][2][1][RTW89_FCC][6] = 68, + [0][1][2][1][RTW89_ETSI][6] = 34, + [0][1][2][1][RTW89_MKK][6] = 50, + [0][1][2][1][RTW89_IC][6] = 38, + [0][1][2][1][RTW89_KCC][6] = 38, + [0][1][2][1][RTW89_ACMA][6] = 34, + [0][1][2][1][RTW89_CHILE][6] = 6, + [0][1][2][1][RTW89_UKRAINE][6] = 28, + [0][1][2][1][RTW89_MEXICO][6] = 50, + [0][1][2][1][RTW89_CN][6] = 34, + [0][1][2][1][RTW89_QATAR][6] = 34, + [0][1][2][1][RTW89_FCC][8] = 68, + [0][1][2][1][RTW89_ETSI][8] = 34, + [0][1][2][1][RTW89_MKK][8] = 50, + [0][1][2][1][RTW89_IC][8] = 38, + [0][1][2][1][RTW89_KCC][8] = 68, + [0][1][2][1][RTW89_ACMA][8] = 34, + [0][1][2][1][RTW89_CHILE][8] = 30, + [0][1][2][1][RTW89_UKRAINE][8] = 28, + [0][1][2][1][RTW89_MEXICO][8] = 68, + [0][1][2][1][RTW89_CN][8] = 34, + [0][1][2][1][RTW89_QATAR][8] = 34, + [0][1][2][1][RTW89_FCC][10] = 68, + [0][1][2][1][RTW89_ETSI][10] = 34, + [0][1][2][1][RTW89_MKK][10] = 50, + [0][1][2][1][RTW89_IC][10] = 38, + [0][1][2][1][RTW89_KCC][10] = 68, + [0][1][2][1][RTW89_ACMA][10] = 34, + [0][1][2][1][RTW89_CHILE][10] = 30, + [0][1][2][1][RTW89_UKRAINE][10] = 28, + [0][1][2][1][RTW89_MEXICO][10] = 68, + [0][1][2][1][RTW89_CN][10] = 34, + [0][1][2][1][RTW89_QATAR][10] = 34, + [0][1][2][1][RTW89_FCC][12] = 68, + [0][1][2][1][RTW89_ETSI][12] = 34, + [0][1][2][1][RTW89_MKK][12] = 50, + [0][1][2][1][RTW89_IC][12] = 38, + [0][1][2][1][RTW89_KCC][12] = 68, + [0][1][2][1][RTW89_ACMA][12] = 34, + [0][1][2][1][RTW89_CHILE][12] = 30, + [0][1][2][1][RTW89_UKRAINE][12] = 28, + [0][1][2][1][RTW89_MEXICO][12] = 68, + [0][1][2][1][RTW89_CN][12] = 34, + [0][1][2][1][RTW89_QATAR][12] = 34, + [0][1][2][1][RTW89_FCC][14] = 68, + [0][1][2][1][RTW89_ETSI][14] = 34, + [0][1][2][1][RTW89_MKK][14] = 50, + [0][1][2][1][RTW89_IC][14] = 38, + [0][1][2][1][RTW89_KCC][14] = 68, + [0][1][2][1][RTW89_ACMA][14] = 34, + [0][1][2][1][RTW89_CHILE][14] = 30, + [0][1][2][1][RTW89_UKRAINE][14] = 28, + [0][1][2][1][RTW89_MEXICO][14] = 68, + [0][1][2][1][RTW89_CN][14] = 34, + [0][1][2][1][RTW89_QATAR][14] = 34, + [0][1][2][1][RTW89_FCC][15] = 68, + [0][1][2][1][RTW89_ETSI][15] = 34, + [0][1][2][1][RTW89_MKK][15] = 70, + [0][1][2][1][RTW89_IC][15] = 62, + [0][1][2][1][RTW89_KCC][15] = 66, + [0][1][2][1][RTW89_ACMA][15] = 34, + [0][1][2][1][RTW89_CHILE][15] = 30, + [0][1][2][1][RTW89_UKRAINE][15] = 28, + [0][1][2][1][RTW89_MEXICO][15] = 68, + [0][1][2][1][RTW89_CN][15] = 127, + [0][1][2][1][RTW89_QATAR][15] = 28, + [0][1][2][1][RTW89_FCC][17] = 68, + [0][1][2][1][RTW89_ETSI][17] = 34, + [0][1][2][1][RTW89_MKK][17] = 70, + [0][1][2][1][RTW89_IC][17] = 62, + [0][1][2][1][RTW89_KCC][17] = 66, + [0][1][2][1][RTW89_ACMA][17] = 34, + [0][1][2][1][RTW89_CHILE][17] = 30, + [0][1][2][1][RTW89_UKRAINE][17] = 28, + [0][1][2][1][RTW89_MEXICO][17] = 68, + [0][1][2][1][RTW89_CN][17] = 127, + [0][1][2][1][RTW89_QATAR][17] = 28, + [0][1][2][1][RTW89_FCC][19] = 68, + [0][1][2][1][RTW89_ETSI][19] = 34, + [0][1][2][1][RTW89_MKK][19] = 70, + [0][1][2][1][RTW89_IC][19] = 62, + [0][1][2][1][RTW89_KCC][19] = 66, + [0][1][2][1][RTW89_ACMA][19] = 34, + [0][1][2][1][RTW89_CHILE][19] = 30, + [0][1][2][1][RTW89_UKRAINE][19] = 28, + [0][1][2][1][RTW89_MEXICO][19] = 68, + [0][1][2][1][RTW89_CN][19] = 127, + [0][1][2][1][RTW89_QATAR][19] = 28, + [0][1][2][1][RTW89_FCC][21] = 68, + [0][1][2][1][RTW89_ETSI][21] = 34, + [0][1][2][1][RTW89_MKK][21] = 70, + [0][1][2][1][RTW89_IC][21] = 62, + [0][1][2][1][RTW89_KCC][21] = 66, + [0][1][2][1][RTW89_ACMA][21] = 34, + [0][1][2][1][RTW89_CHILE][21] = 30, + [0][1][2][1][RTW89_UKRAINE][21] = 28, + [0][1][2][1][RTW89_MEXICO][21] = 68, + [0][1][2][1][RTW89_CN][21] = 127, + [0][1][2][1][RTW89_QATAR][21] = 28, + [0][1][2][1][RTW89_FCC][23] = 68, + [0][1][2][1][RTW89_ETSI][23] = 34, + [0][1][2][1][RTW89_MKK][23] = 70, + [0][1][2][1][RTW89_IC][23] = 62, + [0][1][2][1][RTW89_KCC][23] = 66, + [0][1][2][1][RTW89_ACMA][23] = 34, + [0][1][2][1][RTW89_CHILE][23] = 30, + [0][1][2][1][RTW89_UKRAINE][23] = 28, + [0][1][2][1][RTW89_MEXICO][23] = 68, + [0][1][2][1][RTW89_CN][23] = 127, + [0][1][2][1][RTW89_QATAR][23] = 28, + [0][1][2][1][RTW89_FCC][25] = 68, + [0][1][2][1][RTW89_ETSI][25] = 34, + [0][1][2][1][RTW89_MKK][25] = 70, + [0][1][2][1][RTW89_IC][25] = 127, + [0][1][2][1][RTW89_KCC][25] = 66, + [0][1][2][1][RTW89_ACMA][25] = 127, + [0][1][2][1][RTW89_CHILE][25] = 30, + [0][1][2][1][RTW89_UKRAINE][25] = 28, + [0][1][2][1][RTW89_MEXICO][25] = 68, + [0][1][2][1][RTW89_CN][25] = 127, + [0][1][2][1][RTW89_QATAR][25] = 28, + [0][1][2][1][RTW89_FCC][27] = 68, + [0][1][2][1][RTW89_ETSI][27] = 34, + [0][1][2][1][RTW89_MKK][27] = 70, + [0][1][2][1][RTW89_IC][27] = 127, + [0][1][2][1][RTW89_KCC][27] = 66, + [0][1][2][1][RTW89_ACMA][27] = 127, + [0][1][2][1][RTW89_CHILE][27] = 30, + [0][1][2][1][RTW89_UKRAINE][27] = 28, + [0][1][2][1][RTW89_MEXICO][27] = 68, + [0][1][2][1][RTW89_CN][27] = 127, + [0][1][2][1][RTW89_QATAR][27] = 28, + [0][1][2][1][RTW89_FCC][29] = 68, + [0][1][2][1][RTW89_ETSI][29] = 34, + [0][1][2][1][RTW89_MKK][29] = 70, + [0][1][2][1][RTW89_IC][29] = 127, + [0][1][2][1][RTW89_KCC][29] = 66, + [0][1][2][1][RTW89_ACMA][29] = 127, + [0][1][2][1][RTW89_CHILE][29] = 30, + [0][1][2][1][RTW89_UKRAINE][29] = 28, + [0][1][2][1][RTW89_MEXICO][29] = 68, + [0][1][2][1][RTW89_CN][29] = 127, + [0][1][2][1][RTW89_QATAR][29] = 28, + [0][1][2][1][RTW89_FCC][31] = 68, + [0][1][2][1][RTW89_ETSI][31] = 34, + [0][1][2][1][RTW89_MKK][31] = 70, + [0][1][2][1][RTW89_IC][31] = 62, + [0][1][2][1][RTW89_KCC][31] = 66, + [0][1][2][1][RTW89_ACMA][31] = 34, + [0][1][2][1][RTW89_CHILE][31] = 30, + [0][1][2][1][RTW89_UKRAINE][31] = 28, + [0][1][2][1][RTW89_MEXICO][31] = 68, + [0][1][2][1][RTW89_CN][31] = 127, + [0][1][2][1][RTW89_QATAR][31] = 28, + [0][1][2][1][RTW89_FCC][33] = 68, + [0][1][2][1][RTW89_ETSI][33] = 34, + [0][1][2][1][RTW89_MKK][33] = 70, + [0][1][2][1][RTW89_IC][33] = 62, + [0][1][2][1][RTW89_KCC][33] = 66, + [0][1][2][1][RTW89_ACMA][33] = 34, + [0][1][2][1][RTW89_CHILE][33] = 30, + [0][1][2][1][RTW89_UKRAINE][33] = 28, + [0][1][2][1][RTW89_MEXICO][33] = 68, + [0][1][2][1][RTW89_CN][33] = 127, + [0][1][2][1][RTW89_QATAR][33] = 28, + [0][1][2][1][RTW89_FCC][35] = 64, + [0][1][2][1][RTW89_ETSI][35] = 34, + [0][1][2][1][RTW89_MKK][35] = 70, + [0][1][2][1][RTW89_IC][35] = 62, + [0][1][2][1][RTW89_KCC][35] = 66, + [0][1][2][1][RTW89_ACMA][35] = 34, + [0][1][2][1][RTW89_CHILE][35] = 30, + [0][1][2][1][RTW89_UKRAINE][35] = 28, + [0][1][2][1][RTW89_MEXICO][35] = 64, + [0][1][2][1][RTW89_CN][35] = 127, + [0][1][2][1][RTW89_QATAR][35] = 28, + [0][1][2][1][RTW89_FCC][37] = 68, + [0][1][2][1][RTW89_ETSI][37] = 127, + [0][1][2][1][RTW89_MKK][37] = 70, + [0][1][2][1][RTW89_IC][37] = 62, + [0][1][2][1][RTW89_KCC][37] = 66, + [0][1][2][1][RTW89_ACMA][37] = 68, + [0][1][2][1][RTW89_CHILE][37] = 30, + [0][1][2][1][RTW89_UKRAINE][37] = 127, + [0][1][2][1][RTW89_MEXICO][37] = 68, + [0][1][2][1][RTW89_CN][37] = 127, + [0][1][2][1][RTW89_QATAR][37] = 127, + [0][1][2][1][RTW89_FCC][38] = 76, + [0][1][2][1][RTW89_ETSI][38] = 4, + [0][1][2][1][RTW89_MKK][38] = 127, + [0][1][2][1][RTW89_IC][38] = 76, + [0][1][2][1][RTW89_KCC][38] = 66, + [0][1][2][1][RTW89_ACMA][38] = 76, + [0][1][2][1][RTW89_CHILE][38] = 30, + [0][1][2][1][RTW89_UKRAINE][38] = 4, + [0][1][2][1][RTW89_MEXICO][38] = 76, + [0][1][2][1][RTW89_CN][38] = 68, + [0][1][2][1][RTW89_QATAR][38] = 4, + [0][1][2][1][RTW89_FCC][40] = 76, + [0][1][2][1][RTW89_ETSI][40] = 4, + [0][1][2][1][RTW89_MKK][40] = 127, + [0][1][2][1][RTW89_IC][40] = 76, + [0][1][2][1][RTW89_KCC][40] = 66, + [0][1][2][1][RTW89_ACMA][40] = 76, + [0][1][2][1][RTW89_CHILE][40] = 30, + [0][1][2][1][RTW89_UKRAINE][40] = 4, + [0][1][2][1][RTW89_MEXICO][40] = 76, + [0][1][2][1][RTW89_CN][40] = 70, + [0][1][2][1][RTW89_QATAR][40] = 4, + [0][1][2][1][RTW89_FCC][42] = 76, + [0][1][2][1][RTW89_ETSI][42] = 4, + [0][1][2][1][RTW89_MKK][42] = 127, + [0][1][2][1][RTW89_IC][42] = 76, + [0][1][2][1][RTW89_KCC][42] = 66, + [0][1][2][1][RTW89_ACMA][42] = 76, + [0][1][2][1][RTW89_CHILE][42] = 30, + [0][1][2][1][RTW89_UKRAINE][42] = 4, + [0][1][2][1][RTW89_MEXICO][42] = 76, + [0][1][2][1][RTW89_CN][42] = 70, + [0][1][2][1][RTW89_QATAR][42] = 4, + [0][1][2][1][RTW89_FCC][44] = 76, + [0][1][2][1][RTW89_ETSI][44] = 4, + [0][1][2][1][RTW89_MKK][44] = 127, + [0][1][2][1][RTW89_IC][44] = 76, + [0][1][2][1][RTW89_KCC][44] = 66, + [0][1][2][1][RTW89_ACMA][44] = 76, + [0][1][2][1][RTW89_CHILE][44] = 30, + [0][1][2][1][RTW89_UKRAINE][44] = 4, + [0][1][2][1][RTW89_MEXICO][44] = 76, + [0][1][2][1][RTW89_CN][44] = 70, + [0][1][2][1][RTW89_QATAR][44] = 4, + [0][1][2][1][RTW89_FCC][46] = 76, + [0][1][2][1][RTW89_ETSI][46] = 4, + [0][1][2][1][RTW89_MKK][46] = 127, + [0][1][2][1][RTW89_IC][46] = 76, + [0][1][2][1][RTW89_KCC][46] = 66, + [0][1][2][1][RTW89_ACMA][46] = 76, + [0][1][2][1][RTW89_CHILE][46] = 30, + [0][1][2][1][RTW89_UKRAINE][46] = 4, + [0][1][2][1][RTW89_MEXICO][46] = 76, + [0][1][2][1][RTW89_CN][46] = 70, + [0][1][2][1][RTW89_QATAR][46] = 4, + [1][0][2][0][RTW89_FCC][1] = 68, + [1][0][2][0][RTW89_ETSI][1] = 64, + [1][0][2][0][RTW89_MKK][1] = 62, + [1][0][2][0][RTW89_IC][1] = 64, + [1][0][2][0][RTW89_KCC][1] = 72, + [1][0][2][0][RTW89_ACMA][1] = 64, + [1][0][2][0][RTW89_CHILE][1] = 30, + [1][0][2][0][RTW89_UKRAINE][1] = 52, + [1][0][2][0][RTW89_MEXICO][1] = 62, + [1][0][2][0][RTW89_CN][1] = 64, + [1][0][2][0][RTW89_QATAR][1] = 64, + [1][0][2][0][RTW89_FCC][5] = 72, + [1][0][2][0][RTW89_ETSI][5] = 64, + [1][0][2][0][RTW89_MKK][5] = 62, + [1][0][2][0][RTW89_IC][5] = 64, + [1][0][2][0][RTW89_KCC][5] = 72, + [1][0][2][0][RTW89_ACMA][5] = 64, + [1][0][2][0][RTW89_CHILE][5] = 30, + [1][0][2][0][RTW89_UKRAINE][5] = 52, + [1][0][2][0][RTW89_MEXICO][5] = 62, + [1][0][2][0][RTW89_CN][5] = 64, + [1][0][2][0][RTW89_QATAR][5] = 64, + [1][0][2][0][RTW89_FCC][9] = 72, + [1][0][2][0][RTW89_ETSI][9] = 64, + [1][0][2][0][RTW89_MKK][9] = 62, + [1][0][2][0][RTW89_IC][9] = 64, + [1][0][2][0][RTW89_KCC][9] = 72, + [1][0][2][0][RTW89_ACMA][9] = 64, + [1][0][2][0][RTW89_CHILE][9] = 54, + [1][0][2][0][RTW89_UKRAINE][9] = 52, + [1][0][2][0][RTW89_MEXICO][9] = 72, + [1][0][2][0][RTW89_CN][9] = 64, + [1][0][2][0][RTW89_QATAR][9] = 64, + [1][0][2][0][RTW89_FCC][13] = 66, + [1][0][2][0][RTW89_ETSI][13] = 64, + [1][0][2][0][RTW89_MKK][13] = 62, + [1][0][2][0][RTW89_IC][13] = 64, + [1][0][2][0][RTW89_KCC][13] = 68, + [1][0][2][0][RTW89_ACMA][13] = 64, + [1][0][2][0][RTW89_CHILE][13] = 54, + [1][0][2][0][RTW89_UKRAINE][13] = 52, + [1][0][2][0][RTW89_MEXICO][13] = 66, + [1][0][2][0][RTW89_CN][13] = 64, + [1][0][2][0][RTW89_QATAR][13] = 64, + [1][0][2][0][RTW89_FCC][16] = 62, + [1][0][2][0][RTW89_ETSI][16] = 64, + [1][0][2][0][RTW89_MKK][16] = 72, + [1][0][2][0][RTW89_IC][16] = 62, + [1][0][2][0][RTW89_KCC][16] = 72, + [1][0][2][0][RTW89_ACMA][16] = 64, + [1][0][2][0][RTW89_CHILE][16] = 54, + [1][0][2][0][RTW89_UKRAINE][16] = 52, + [1][0][2][0][RTW89_MEXICO][16] = 62, + [1][0][2][0][RTW89_CN][16] = 127, + [1][0][2][0][RTW89_QATAR][16] = 52, + [1][0][2][0][RTW89_FCC][20] = 72, + [1][0][2][0][RTW89_ETSI][20] = 64, + [1][0][2][0][RTW89_MKK][20] = 72, + [1][0][2][0][RTW89_IC][20] = 72, + [1][0][2][0][RTW89_KCC][20] = 72, + [1][0][2][0][RTW89_ACMA][20] = 64, + [1][0][2][0][RTW89_CHILE][20] = 54, + [1][0][2][0][RTW89_UKRAINE][20] = 52, + [1][0][2][0][RTW89_MEXICO][20] = 72, + [1][0][2][0][RTW89_CN][20] = 127, + [1][0][2][0][RTW89_QATAR][20] = 52, + [1][0][2][0][RTW89_FCC][24] = 72, + [1][0][2][0][RTW89_ETSI][24] = 64, + [1][0][2][0][RTW89_MKK][24] = 72, + [1][0][2][0][RTW89_IC][24] = 127, + [1][0][2][0][RTW89_KCC][24] = 72, + [1][0][2][0][RTW89_ACMA][24] = 127, + [1][0][2][0][RTW89_CHILE][24] = 54, + [1][0][2][0][RTW89_UKRAINE][24] = 52, + [1][0][2][0][RTW89_MEXICO][24] = 72, + [1][0][2][0][RTW89_CN][24] = 127, + [1][0][2][0][RTW89_QATAR][24] = 52, + [1][0][2][0][RTW89_FCC][28] = 72, + [1][0][2][0][RTW89_ETSI][28] = 64, + [1][0][2][0][RTW89_MKK][28] = 72, + [1][0][2][0][RTW89_IC][28] = 127, + [1][0][2][0][RTW89_KCC][28] = 72, + [1][0][2][0][RTW89_ACMA][28] = 127, + [1][0][2][0][RTW89_CHILE][28] = 54, + [1][0][2][0][RTW89_UKRAINE][28] = 52, + [1][0][2][0][RTW89_MEXICO][28] = 72, + [1][0][2][0][RTW89_CN][28] = 127, + [1][0][2][0][RTW89_QATAR][28] = 52, + [1][0][2][0][RTW89_FCC][32] = 72, + [1][0][2][0][RTW89_ETSI][32] = 64, + [1][0][2][0][RTW89_MKK][32] = 72, + [1][0][2][0][RTW89_IC][32] = 72, + [1][0][2][0][RTW89_KCC][32] = 72, + [1][0][2][0][RTW89_ACMA][32] = 64, + [1][0][2][0][RTW89_CHILE][32] = 54, + [1][0][2][0][RTW89_UKRAINE][32] = 52, + [1][0][2][0][RTW89_MEXICO][32] = 72, + [1][0][2][0][RTW89_CN][32] = 127, + [1][0][2][0][RTW89_QATAR][32] = 52, + [1][0][2][0][RTW89_FCC][36] = 72, + [1][0][2][0][RTW89_ETSI][36] = 127, + [1][0][2][0][RTW89_MKK][36] = 72, + [1][0][2][0][RTW89_IC][36] = 72, + [1][0][2][0][RTW89_KCC][36] = 72, + [1][0][2][0][RTW89_ACMA][36] = 72, + [1][0][2][0][RTW89_CHILE][36] = 54, + [1][0][2][0][RTW89_UKRAINE][36] = 127, + [1][0][2][0][RTW89_MEXICO][36] = 72, + [1][0][2][0][RTW89_CN][36] = 127, + [1][0][2][0][RTW89_QATAR][36] = 127, + [1][0][2][0][RTW89_FCC][39] = 72, + [1][0][2][0][RTW89_ETSI][39] = 28, + [1][0][2][0][RTW89_MKK][39] = 127, + [1][0][2][0][RTW89_IC][39] = 72, + [1][0][2][0][RTW89_KCC][39] = 72, + [1][0][2][0][RTW89_ACMA][39] = 72, + [1][0][2][0][RTW89_CHILE][39] = 54, + [1][0][2][0][RTW89_UKRAINE][39] = 28, + [1][0][2][0][RTW89_MEXICO][39] = 72, + [1][0][2][0][RTW89_CN][39] = 68, + [1][0][2][0][RTW89_QATAR][39] = 28, + [1][0][2][0][RTW89_FCC][43] = 72, + [1][0][2][0][RTW89_ETSI][43] = 28, + [1][0][2][0][RTW89_MKK][43] = 127, + [1][0][2][0][RTW89_IC][43] = 72, + [1][0][2][0][RTW89_KCC][43] = 72, + [1][0][2][0][RTW89_ACMA][43] = 72, + [1][0][2][0][RTW89_CHILE][43] = 54, + [1][0][2][0][RTW89_UKRAINE][43] = 28, + [1][0][2][0][RTW89_MEXICO][43] = 72, + [1][0][2][0][RTW89_CN][43] = 72, + [1][0][2][0][RTW89_QATAR][43] = 28, + [1][1][2][0][RTW89_FCC][1] = 58, + [1][1][2][0][RTW89_ETSI][1] = 52, + [1][1][2][0][RTW89_MKK][1] = 50, + [1][1][2][0][RTW89_IC][1] = 52, + [1][1][2][0][RTW89_KCC][1] = 66, + [1][1][2][0][RTW89_ACMA][1] = 52, + [1][1][2][0][RTW89_CHILE][1] = 18, + [1][1][2][0][RTW89_UKRAINE][1] = 40, + [1][1][2][0][RTW89_MEXICO][1] = 50, + [1][1][2][0][RTW89_CN][1] = 52, + [1][1][2][0][RTW89_QATAR][1] = 52, + [1][1][2][0][RTW89_FCC][5] = 72, + [1][1][2][0][RTW89_ETSI][5] = 52, + [1][1][2][0][RTW89_MKK][5] = 50, + [1][1][2][0][RTW89_IC][5] = 52, + [1][1][2][0][RTW89_KCC][5] = 50, + [1][1][2][0][RTW89_ACMA][5] = 52, + [1][1][2][0][RTW89_CHILE][5] = 18, + [1][1][2][0][RTW89_UKRAINE][5] = 40, + [1][1][2][0][RTW89_MEXICO][5] = 50, + [1][1][2][0][RTW89_CN][5] = 52, + [1][1][2][0][RTW89_QATAR][5] = 52, + [1][1][2][0][RTW89_FCC][9] = 72, + [1][1][2][0][RTW89_ETSI][9] = 52, + [1][1][2][0][RTW89_MKK][9] = 50, + [1][1][2][0][RTW89_IC][9] = 52, + [1][1][2][0][RTW89_KCC][9] = 66, + [1][1][2][0][RTW89_ACMA][9] = 52, + [1][1][2][0][RTW89_CHILE][9] = 42, + [1][1][2][0][RTW89_UKRAINE][9] = 40, + [1][1][2][0][RTW89_MEXICO][9] = 72, + [1][1][2][0][RTW89_CN][9] = 52, + [1][1][2][0][RTW89_QATAR][9] = 52, + [1][1][2][0][RTW89_FCC][13] = 58, + [1][1][2][0][RTW89_ETSI][13] = 52, + [1][1][2][0][RTW89_MKK][13] = 50, + [1][1][2][0][RTW89_IC][13] = 52, + [1][1][2][0][RTW89_KCC][13] = 66, + [1][1][2][0][RTW89_ACMA][13] = 52, + [1][1][2][0][RTW89_CHILE][13] = 42, + [1][1][2][0][RTW89_UKRAINE][13] = 40, + [1][1][2][0][RTW89_MEXICO][13] = 58, + [1][1][2][0][RTW89_CN][13] = 52, + [1][1][2][0][RTW89_QATAR][13] = 52, + [1][1][2][0][RTW89_FCC][16] = 56, + [1][1][2][0][RTW89_ETSI][16] = 52, + [1][1][2][0][RTW89_MKK][16] = 72, + [1][1][2][0][RTW89_IC][16] = 56, + [1][1][2][0][RTW89_KCC][16] = 64, + [1][1][2][0][RTW89_ACMA][16] = 52, + [1][1][2][0][RTW89_CHILE][16] = 42, + [1][1][2][0][RTW89_UKRAINE][16] = 40, + [1][1][2][0][RTW89_MEXICO][16] = 56, + [1][1][2][0][RTW89_CN][16] = 127, + [1][1][2][0][RTW89_QATAR][16] = 40, + [1][1][2][0][RTW89_FCC][20] = 72, + [1][1][2][0][RTW89_ETSI][20] = 52, + [1][1][2][0][RTW89_MKK][20] = 72, + [1][1][2][0][RTW89_IC][20] = 72, + [1][1][2][0][RTW89_KCC][20] = 66, + [1][1][2][0][RTW89_ACMA][20] = 52, + [1][1][2][0][RTW89_CHILE][20] = 42, + [1][1][2][0][RTW89_UKRAINE][20] = 40, + [1][1][2][0][RTW89_MEXICO][20] = 72, + [1][1][2][0][RTW89_CN][20] = 127, + [1][1][2][0][RTW89_QATAR][20] = 40, + [1][1][2][0][RTW89_FCC][24] = 72, + [1][1][2][0][RTW89_ETSI][24] = 52, + [1][1][2][0][RTW89_MKK][24] = 72, + [1][1][2][0][RTW89_IC][24] = 127, + [1][1][2][0][RTW89_KCC][24] = 66, + [1][1][2][0][RTW89_ACMA][24] = 127, + [1][1][2][0][RTW89_CHILE][24] = 42, + [1][1][2][0][RTW89_UKRAINE][24] = 40, + [1][1][2][0][RTW89_MEXICO][24] = 72, + [1][1][2][0][RTW89_CN][24] = 127, + [1][1][2][0][RTW89_QATAR][24] = 40, + [1][1][2][0][RTW89_FCC][28] = 72, + [1][1][2][0][RTW89_ETSI][28] = 52, + [1][1][2][0][RTW89_MKK][28] = 72, + [1][1][2][0][RTW89_IC][28] = 127, + [1][1][2][0][RTW89_KCC][28] = 66, + [1][1][2][0][RTW89_ACMA][28] = 127, + [1][1][2][0][RTW89_CHILE][28] = 42, + [1][1][2][0][RTW89_UKRAINE][28] = 40, + [1][1][2][0][RTW89_MEXICO][28] = 72, + [1][1][2][0][RTW89_CN][28] = 127, + [1][1][2][0][RTW89_QATAR][28] = 40, + [1][1][2][0][RTW89_FCC][32] = 68, + [1][1][2][0][RTW89_ETSI][32] = 52, + [1][1][2][0][RTW89_MKK][32] = 72, + [1][1][2][0][RTW89_IC][32] = 68, + [1][1][2][0][RTW89_KCC][32] = 66, + [1][1][2][0][RTW89_ACMA][32] = 52, + [1][1][2][0][RTW89_CHILE][32] = 42, + [1][1][2][0][RTW89_UKRAINE][32] = 40, + [1][1][2][0][RTW89_MEXICO][32] = 68, + [1][1][2][0][RTW89_CN][32] = 127, + [1][1][2][0][RTW89_QATAR][32] = 40, + [1][1][2][0][RTW89_FCC][36] = 72, + [1][1][2][0][RTW89_ETSI][36] = 127, + [1][1][2][0][RTW89_MKK][36] = 72, + [1][1][2][0][RTW89_IC][36] = 72, + [1][1][2][0][RTW89_KCC][36] = 66, + [1][1][2][0][RTW89_ACMA][36] = 72, + [1][1][2][0][RTW89_CHILE][36] = 42, + [1][1][2][0][RTW89_UKRAINE][36] = 127, + [1][1][2][0][RTW89_MEXICO][36] = 72, + [1][1][2][0][RTW89_CN][36] = 127, + [1][1][2][0][RTW89_QATAR][36] = 127, + [1][1][2][0][RTW89_FCC][39] = 72, + [1][1][2][0][RTW89_ETSI][39] = 16, + [1][1][2][0][RTW89_MKK][39] = 127, + [1][1][2][0][RTW89_IC][39] = 72, + [1][1][2][0][RTW89_KCC][39] = 66, + [1][1][2][0][RTW89_ACMA][39] = 72, + [1][1][2][0][RTW89_CHILE][39] = 42, + [1][1][2][0][RTW89_UKRAINE][39] = 16, + [1][1][2][0][RTW89_MEXICO][39] = 72, + [1][1][2][0][RTW89_CN][39] = 68, + [1][1][2][0][RTW89_QATAR][39] = 16, + [1][1][2][0][RTW89_FCC][43] = 72, + [1][1][2][0][RTW89_ETSI][43] = 16, + [1][1][2][0][RTW89_MKK][43] = 127, + [1][1][2][0][RTW89_IC][43] = 72, + [1][1][2][0][RTW89_KCC][43] = 66, + [1][1][2][0][RTW89_ACMA][43] = 72, + [1][1][2][0][RTW89_CHILE][43] = 42, + [1][1][2][0][RTW89_UKRAINE][43] = 16, + [1][1][2][0][RTW89_MEXICO][43] = 72, + [1][1][2][0][RTW89_CN][43] = 72, + [1][1][2][0][RTW89_QATAR][43] = 16, + [1][1][2][1][RTW89_FCC][1] = 58, + [1][1][2][1][RTW89_ETSI][1] = 40, + [1][1][2][1][RTW89_MKK][1] = 50, + [1][1][2][1][RTW89_IC][1] = 40, + [1][1][2][1][RTW89_KCC][1] = 66, + [1][1][2][1][RTW89_ACMA][1] = 40, + [1][1][2][1][RTW89_CHILE][1] = 6, + [1][1][2][1][RTW89_UKRAINE][1] = 28, + [1][1][2][1][RTW89_MEXICO][1] = 50, + [1][1][2][1][RTW89_CN][1] = 40, + [1][1][2][1][RTW89_QATAR][1] = 40, + [1][1][2][1][RTW89_FCC][5] = 68, + [1][1][2][1][RTW89_ETSI][5] = 40, + [1][1][2][1][RTW89_MKK][5] = 50, + [1][1][2][1][RTW89_IC][5] = 40, + [1][1][2][1][RTW89_KCC][5] = 50, + [1][1][2][1][RTW89_ACMA][5] = 40, + [1][1][2][1][RTW89_CHILE][5] = 6, + [1][1][2][1][RTW89_UKRAINE][5] = 28, + [1][1][2][1][RTW89_MEXICO][5] = 50, + [1][1][2][1][RTW89_CN][5] = 40, + [1][1][2][1][RTW89_QATAR][5] = 40, + [1][1][2][1][RTW89_FCC][9] = 68, + [1][1][2][1][RTW89_ETSI][9] = 40, + [1][1][2][1][RTW89_MKK][9] = 50, + [1][1][2][1][RTW89_IC][9] = 40, + [1][1][2][1][RTW89_KCC][9] = 66, + [1][1][2][1][RTW89_ACMA][9] = 40, + [1][1][2][1][RTW89_CHILE][9] = 30, + [1][1][2][1][RTW89_UKRAINE][9] = 28, + [1][1][2][1][RTW89_MEXICO][9] = 68, + [1][1][2][1][RTW89_CN][9] = 40, + [1][1][2][1][RTW89_QATAR][9] = 40, + [1][1][2][1][RTW89_FCC][13] = 58, + [1][1][2][1][RTW89_ETSI][13] = 40, + [1][1][2][1][RTW89_MKK][13] = 50, + [1][1][2][1][RTW89_IC][13] = 40, + [1][1][2][1][RTW89_KCC][13] = 66, + [1][1][2][1][RTW89_ACMA][13] = 40, + [1][1][2][1][RTW89_CHILE][13] = 30, + [1][1][2][1][RTW89_UKRAINE][13] = 28, + [1][1][2][1][RTW89_MEXICO][13] = 58, + [1][1][2][1][RTW89_CN][13] = 40, + [1][1][2][1][RTW89_QATAR][13] = 40, + [1][1][2][1][RTW89_FCC][16] = 56, + [1][1][2][1][RTW89_ETSI][16] = 40, + [1][1][2][1][RTW89_MKK][16] = 72, + [1][1][2][1][RTW89_IC][16] = 56, + [1][1][2][1][RTW89_KCC][16] = 64, + [1][1][2][1][RTW89_ACMA][16] = 40, + [1][1][2][1][RTW89_CHILE][16] = 30, + [1][1][2][1][RTW89_UKRAINE][16] = 28, + [1][1][2][1][RTW89_MEXICO][16] = 56, + [1][1][2][1][RTW89_CN][16] = 127, + [1][1][2][1][RTW89_QATAR][16] = 28, + [1][1][2][1][RTW89_FCC][20] = 68, + [1][1][2][1][RTW89_ETSI][20] = 40, + [1][1][2][1][RTW89_MKK][20] = 72, + [1][1][2][1][RTW89_IC][20] = 68, + [1][1][2][1][RTW89_KCC][20] = 66, + [1][1][2][1][RTW89_ACMA][20] = 40, + [1][1][2][1][RTW89_CHILE][20] = 30, + [1][1][2][1][RTW89_UKRAINE][20] = 28, + [1][1][2][1][RTW89_MEXICO][20] = 68, + [1][1][2][1][RTW89_CN][20] = 127, + [1][1][2][1][RTW89_QATAR][20] = 28, + [1][1][2][1][RTW89_FCC][24] = 68, + [1][1][2][1][RTW89_ETSI][24] = 40, + [1][1][2][1][RTW89_MKK][24] = 72, + [1][1][2][1][RTW89_IC][24] = 127, + [1][1][2][1][RTW89_KCC][24] = 66, + [1][1][2][1][RTW89_ACMA][24] = 127, + [1][1][2][1][RTW89_CHILE][24] = 30, + [1][1][2][1][RTW89_UKRAINE][24] = 28, + [1][1][2][1][RTW89_MEXICO][24] = 68, + [1][1][2][1][RTW89_CN][24] = 127, + [1][1][2][1][RTW89_QATAR][24] = 28, + [1][1][2][1][RTW89_FCC][28] = 68, + [1][1][2][1][RTW89_ETSI][28] = 40, + [1][1][2][1][RTW89_MKK][28] = 72, + [1][1][2][1][RTW89_IC][28] = 127, + [1][1][2][1][RTW89_KCC][28] = 66, + [1][1][2][1][RTW89_ACMA][28] = 127, + [1][1][2][1][RTW89_CHILE][28] = 30, + [1][1][2][1][RTW89_UKRAINE][28] = 28, + [1][1][2][1][RTW89_MEXICO][28] = 68, + [1][1][2][1][RTW89_CN][28] = 127, + [1][1][2][1][RTW89_QATAR][28] = 28, + [1][1][2][1][RTW89_FCC][32] = 68, + [1][1][2][1][RTW89_ETSI][32] = 40, + [1][1][2][1][RTW89_MKK][32] = 72, + [1][1][2][1][RTW89_IC][32] = 68, + [1][1][2][1][RTW89_KCC][32] = 66, + [1][1][2][1][RTW89_ACMA][32] = 40, + [1][1][2][1][RTW89_CHILE][32] = 30, + [1][1][2][1][RTW89_UKRAINE][32] = 28, + [1][1][2][1][RTW89_MEXICO][32] = 68, + [1][1][2][1][RTW89_CN][32] = 127, + [1][1][2][1][RTW89_QATAR][32] = 28, + [1][1][2][1][RTW89_FCC][36] = 68, + [1][1][2][1][RTW89_ETSI][36] = 127, + [1][1][2][1][RTW89_MKK][36] = 72, + [1][1][2][1][RTW89_IC][36] = 68, + [1][1][2][1][RTW89_KCC][36] = 66, + [1][1][2][1][RTW89_ACMA][36] = 68, + [1][1][2][1][RTW89_CHILE][36] = 30, + [1][1][2][1][RTW89_UKRAINE][36] = 127, + [1][1][2][1][RTW89_MEXICO][36] = 68, + [1][1][2][1][RTW89_CN][36] = 127, + [1][1][2][1][RTW89_QATAR][36] = 127, + [1][1][2][1][RTW89_FCC][39] = 72, + [1][1][2][1][RTW89_ETSI][39] = 4, + [1][1][2][1][RTW89_MKK][39] = 127, + [1][1][2][1][RTW89_IC][39] = 72, + [1][1][2][1][RTW89_KCC][39] = 66, + [1][1][2][1][RTW89_ACMA][39] = 72, + [1][1][2][1][RTW89_CHILE][39] = 30, + [1][1][2][1][RTW89_UKRAINE][39] = 4, + [1][1][2][1][RTW89_MEXICO][39] = 72, + [1][1][2][1][RTW89_CN][39] = 62, + [1][1][2][1][RTW89_QATAR][39] = 4, + [1][1][2][1][RTW89_FCC][43] = 72, + [1][1][2][1][RTW89_ETSI][43] = 4, + [1][1][2][1][RTW89_MKK][43] = 127, + [1][1][2][1][RTW89_IC][43] = 72, + [1][1][2][1][RTW89_KCC][43] = 66, + [1][1][2][1][RTW89_ACMA][43] = 72, + [1][1][2][1][RTW89_CHILE][43] = 30, + [1][1][2][1][RTW89_UKRAINE][43] = 4, + [1][1][2][1][RTW89_MEXICO][43] = 72, + [1][1][2][1][RTW89_CN][43] = 72, + [1][1][2][1][RTW89_QATAR][43] = 4, + [2][0][2][0][RTW89_FCC][3] = 64, + [2][0][2][0][RTW89_ETSI][3] = 64, + [2][0][2][0][RTW89_MKK][3] = 64, + [2][0][2][0][RTW89_IC][3] = 62, + [2][0][2][0][RTW89_KCC][3] = 72, + [2][0][2][0][RTW89_ACMA][3] = 64, + [2][0][2][0][RTW89_CHILE][3] = 30, + [2][0][2][0][RTW89_UKRAINE][3] = 52, + [2][0][2][0][RTW89_MEXICO][3] = 62, + [2][0][2][0][RTW89_CN][3] = 64, + [2][0][2][0][RTW89_QATAR][3] = 64, + [2][0][2][0][RTW89_FCC][11] = 64, + [2][0][2][0][RTW89_ETSI][11] = 64, + [2][0][2][0][RTW89_MKK][11] = 64, + [2][0][2][0][RTW89_IC][11] = 62, + [2][0][2][0][RTW89_KCC][11] = 72, + [2][0][2][0][RTW89_ACMA][11] = 64, + [2][0][2][0][RTW89_CHILE][11] = 54, + [2][0][2][0][RTW89_UKRAINE][11] = 52, + [2][0][2][0][RTW89_MEXICO][11] = 64, + [2][0][2][0][RTW89_CN][11] = 64, + [2][0][2][0][RTW89_QATAR][11] = 64, + [2][0][2][0][RTW89_FCC][18] = 62, + [2][0][2][0][RTW89_ETSI][18] = 64, + [2][0][2][0][RTW89_MKK][18] = 72, + [2][0][2][0][RTW89_IC][18] = 66, + [2][0][2][0][RTW89_KCC][18] = 70, + [2][0][2][0][RTW89_ACMA][18] = 64, + [2][0][2][0][RTW89_CHILE][18] = 54, + [2][0][2][0][RTW89_UKRAINE][18] = 52, + [2][0][2][0][RTW89_MEXICO][18] = 62, + [2][0][2][0][RTW89_CN][18] = 127, + [2][0][2][0][RTW89_QATAR][18] = 52, + [2][0][2][0][RTW89_FCC][26] = 72, + [2][0][2][0][RTW89_ETSI][26] = 64, + [2][0][2][0][RTW89_MKK][26] = 72, + [2][0][2][0][RTW89_IC][26] = 127, + [2][0][2][0][RTW89_KCC][26] = 72, + [2][0][2][0][RTW89_ACMA][26] = 127, + [2][0][2][0][RTW89_CHILE][26] = 54, + [2][0][2][0][RTW89_UKRAINE][26] = 52, + [2][0][2][0][RTW89_MEXICO][26] = 72, + [2][0][2][0][RTW89_CN][26] = 127, + [2][0][2][0][RTW89_QATAR][26] = 52, + [2][0][2][0][RTW89_FCC][34] = 72, + [2][0][2][0][RTW89_ETSI][34] = 127, + [2][0][2][0][RTW89_MKK][34] = 72, + [2][0][2][0][RTW89_IC][34] = 72, + [2][0][2][0][RTW89_KCC][34] = 72, + [2][0][2][0][RTW89_ACMA][34] = 72, + [2][0][2][0][RTW89_CHILE][34] = 54, + [2][0][2][0][RTW89_UKRAINE][34] = 127, + [2][0][2][0][RTW89_MEXICO][34] = 72, + [2][0][2][0][RTW89_CN][34] = 127, + [2][0][2][0][RTW89_QATAR][34] = 127, + [2][0][2][0][RTW89_FCC][41] = 72, + [2][0][2][0][RTW89_ETSI][41] = 28, + [2][0][2][0][RTW89_MKK][41] = 127, + [2][0][2][0][RTW89_IC][41] = 72, + [2][0][2][0][RTW89_KCC][41] = 68, + [2][0][2][0][RTW89_ACMA][41] = 72, + [2][0][2][0][RTW89_CHILE][41] = 54, + [2][0][2][0][RTW89_UKRAINE][41] = 28, + [2][0][2][0][RTW89_MEXICO][41] = 72, + [2][0][2][0][RTW89_CN][41] = 68, + [2][0][2][0][RTW89_QATAR][41] = 28, + [2][1][2][0][RTW89_FCC][3] = 56, + [2][1][2][0][RTW89_ETSI][3] = 52, + [2][1][2][0][RTW89_MKK][3] = 52, + [2][1][2][0][RTW89_IC][3] = 52, + [2][1][2][0][RTW89_KCC][3] = 66, + [2][1][2][0][RTW89_ACMA][3] = 52, + [2][1][2][0][RTW89_CHILE][3] = 18, + [2][1][2][0][RTW89_UKRAINE][3] = 40, + [2][1][2][0][RTW89_MEXICO][3] = 50, + [2][1][2][0][RTW89_CN][3] = 52, + [2][1][2][0][RTW89_QATAR][3] = 52, + [2][1][2][0][RTW89_FCC][11] = 56, + [2][1][2][0][RTW89_ETSI][11] = 52, + [2][1][2][0][RTW89_MKK][11] = 52, + [2][1][2][0][RTW89_IC][11] = 52, + [2][1][2][0][RTW89_KCC][11] = 64, + [2][1][2][0][RTW89_ACMA][11] = 52, + [2][1][2][0][RTW89_CHILE][11] = 42, + [2][1][2][0][RTW89_UKRAINE][11] = 40, + [2][1][2][0][RTW89_MEXICO][11] = 56, + [2][1][2][0][RTW89_CN][11] = 52, + [2][1][2][0][RTW89_QATAR][11] = 52, + [2][1][2][0][RTW89_FCC][18] = 56, + [2][1][2][0][RTW89_ETSI][18] = 52, + [2][1][2][0][RTW89_MKK][18] = 72, + [2][1][2][0][RTW89_IC][18] = 56, + [2][1][2][0][RTW89_KCC][18] = 58, + [2][1][2][0][RTW89_ACMA][18] = 52, + [2][1][2][0][RTW89_CHILE][18] = 42, + [2][1][2][0][RTW89_UKRAINE][18] = 40, + [2][1][2][0][RTW89_MEXICO][18] = 56, + [2][1][2][0][RTW89_CN][18] = 127, + [2][1][2][0][RTW89_QATAR][18] = 40, + [2][1][2][0][RTW89_FCC][26] = 72, + [2][1][2][0][RTW89_ETSI][26] = 52, + [2][1][2][0][RTW89_MKK][26] = 72, + [2][1][2][0][RTW89_IC][26] = 127, + [2][1][2][0][RTW89_KCC][26] = 64, + [2][1][2][0][RTW89_ACMA][26] = 127, + [2][1][2][0][RTW89_CHILE][26] = 42, + [2][1][2][0][RTW89_UKRAINE][26] = 40, + [2][1][2][0][RTW89_MEXICO][26] = 72, + [2][1][2][0][RTW89_CN][26] = 127, + [2][1][2][0][RTW89_QATAR][26] = 40, + [2][1][2][0][RTW89_FCC][34] = 72, + [2][1][2][0][RTW89_ETSI][34] = 127, + [2][1][2][0][RTW89_MKK][34] = 72, + [2][1][2][0][RTW89_IC][34] = 72, + [2][1][2][0][RTW89_KCC][34] = 64, + [2][1][2][0][RTW89_ACMA][34] = 72, + [2][1][2][0][RTW89_CHILE][34] = 42, + [2][1][2][0][RTW89_UKRAINE][34] = 127, + [2][1][2][0][RTW89_MEXICO][34] = 72, + [2][1][2][0][RTW89_CN][34] = 127, + [2][1][2][0][RTW89_QATAR][34] = 127, + [2][1][2][0][RTW89_FCC][41] = 72, + [2][1][2][0][RTW89_ETSI][41] = 16, + [2][1][2][0][RTW89_MKK][41] = 127, + [2][1][2][0][RTW89_IC][41] = 72, + [2][1][2][0][RTW89_KCC][41] = 58, + [2][1][2][0][RTW89_ACMA][41] = 72, + [2][1][2][0][RTW89_CHILE][41] = 42, + [2][1][2][0][RTW89_UKRAINE][41] = 16, + [2][1][2][0][RTW89_MEXICO][41] = 72, + [2][1][2][0][RTW89_CN][41] = 68, + [2][1][2][0][RTW89_QATAR][41] = 16, + [2][1][2][1][RTW89_FCC][3] = 56, + [2][1][2][1][RTW89_ETSI][3] = 40, + [2][1][2][1][RTW89_MKK][3] = 52, + [2][1][2][1][RTW89_IC][3] = 40, + [2][1][2][1][RTW89_KCC][3] = 66, + [2][1][2][1][RTW89_ACMA][3] = 40, + [2][1][2][1][RTW89_CHILE][3] = 6, + [2][1][2][1][RTW89_UKRAINE][3] = 28, + [2][1][2][1][RTW89_MEXICO][3] = 50, + [2][1][2][1][RTW89_CN][3] = 40, + [2][1][2][1][RTW89_QATAR][3] = 40, + [2][1][2][1][RTW89_FCC][11] = 56, + [2][1][2][1][RTW89_ETSI][11] = 40, + [2][1][2][1][RTW89_MKK][11] = 52, + [2][1][2][1][RTW89_IC][11] = 40, + [2][1][2][1][RTW89_KCC][11] = 64, + [2][1][2][1][RTW89_ACMA][11] = 40, + [2][1][2][1][RTW89_CHILE][11] = 30, + [2][1][2][1][RTW89_UKRAINE][11] = 28, + [2][1][2][1][RTW89_MEXICO][11] = 56, + [2][1][2][1][RTW89_CN][11] = 40, + [2][1][2][1][RTW89_QATAR][11] = 40, + [2][1][2][1][RTW89_FCC][18] = 56, + [2][1][2][1][RTW89_ETSI][18] = 40, + [2][1][2][1][RTW89_MKK][18] = 72, + [2][1][2][1][RTW89_IC][18] = 56, + [2][1][2][1][RTW89_KCC][18] = 58, + [2][1][2][1][RTW89_ACMA][18] = 40, + [2][1][2][1][RTW89_CHILE][18] = 30, + [2][1][2][1][RTW89_UKRAINE][18] = 28, + [2][1][2][1][RTW89_MEXICO][18] = 56, + [2][1][2][1][RTW89_CN][18] = 127, + [2][1][2][1][RTW89_QATAR][18] = 28, + [2][1][2][1][RTW89_FCC][26] = 68, + [2][1][2][1][RTW89_ETSI][26] = 40, + [2][1][2][1][RTW89_MKK][26] = 72, + [2][1][2][1][RTW89_IC][26] = 127, + [2][1][2][1][RTW89_KCC][26] = 64, + [2][1][2][1][RTW89_ACMA][26] = 127, + [2][1][2][1][RTW89_CHILE][26] = 30, + [2][1][2][1][RTW89_UKRAINE][26] = 28, + [2][1][2][1][RTW89_MEXICO][26] = 68, + [2][1][2][1][RTW89_CN][26] = 127, + [2][1][2][1][RTW89_QATAR][26] = 28, + [2][1][2][1][RTW89_FCC][34] = 68, + [2][1][2][1][RTW89_ETSI][34] = 127, + [2][1][2][1][RTW89_MKK][34] = 72, + [2][1][2][1][RTW89_IC][34] = 68, + [2][1][2][1][RTW89_KCC][34] = 64, + [2][1][2][1][RTW89_ACMA][34] = 68, + [2][1][2][1][RTW89_CHILE][34] = 30, + [2][1][2][1][RTW89_UKRAINE][34] = 127, + [2][1][2][1][RTW89_MEXICO][34] = 68, + [2][1][2][1][RTW89_CN][34] = 127, + [2][1][2][1][RTW89_QATAR][34] = 127, + [2][1][2][1][RTW89_FCC][41] = 72, + [2][1][2][1][RTW89_ETSI][41] = 4, + [2][1][2][1][RTW89_MKK][41] = 127, + [2][1][2][1][RTW89_IC][41] = 72, + [2][1][2][1][RTW89_KCC][41] = 58, + [2][1][2][1][RTW89_ACMA][41] = 72, + [2][1][2][1][RTW89_CHILE][41] = 30, + [2][1][2][1][RTW89_UKRAINE][41] = 4, + [2][1][2][1][RTW89_MEXICO][41] = 72, + [2][1][2][1][RTW89_CN][41] = 64, + [2][1][2][1][RTW89_QATAR][41] = 4, }; const s8 rtw89_8852a_txpwr_lmt_ru_2g[RTW89_RU_NUM][RTW89_NTX_NUM] [RTW89_REGD_NUM][RTW89_2G_CH_NUM] = { - [0][0][0][0] = 32, - [0][0][0][1] = 32, - [0][0][0][2] = 32, - [0][0][0][3] = 32, - [0][0][0][4] = 32, - [0][0][0][5] = 32, - [0][0][0][6] = 32, - [0][0][0][7] = 32, - [0][0][0][8] = 32, - [0][0][0][9] = 32, - [0][0][0][10] = 32, - [0][0][0][11] = 32, - [0][0][0][12] = 32, - [0][0][0][13] = 0, - [0][1][0][0] = 20, - [0][1][0][1] = 20, - [0][1][0][2] = 20, - [0][1][0][3] = 20, - [0][1][0][4] = 20, - [0][1][0][5] = 20, - [0][1][0][6] = 20, - [0][1][0][7] = 20, - [0][1][0][8] = 20, - [0][1][0][9] = 20, - [0][1][0][10] = 20, - [0][1][0][11] = 20, - [0][1][0][12] = 20, - [0][1][0][13] = 0, - [1][0][0][0] = 42, - [1][0][0][1] = 42, - [1][0][0][2] = 42, - [1][0][0][3] = 42, - [1][0][0][4] = 42, - [1][0][0][5] = 42, - [1][0][0][6] = 42, - [1][0][0][7] = 42, - [1][0][0][8] = 42, - [1][0][0][9] = 42, - [1][0][0][10] = 42, - [1][0][0][11] = 42, - [1][0][0][12] = 36, - [1][0][0][13] = 0, - [1][1][0][0] = 30, - [1][1][0][1] = 30, - [1][1][0][2] = 30, - [1][1][0][3] = 30, - [1][1][0][4] = 30, - [1][1][0][5] = 30, - [1][1][0][6] = 30, - [1][1][0][7] = 30, - [1][1][0][8] = 30, - [1][1][0][9] = 30, - [1][1][0][10] = 30, - [1][1][0][11] = 30, - [1][1][0][12] = 30, - [1][1][0][13] = 0, - [2][0][0][0] = 52, - [2][0][0][1] = 52, - [2][0][0][2] = 52, - [2][0][0][3] = 52, - [2][0][0][4] = 52, - [2][0][0][5] = 52, - [2][0][0][6] = 52, - [2][0][0][7] = 52, - [2][0][0][8] = 52, - [2][0][0][9] = 52, - [2][0][0][10] = 52, - [2][0][0][11] = 52, - [2][0][0][12] = 40, - [2][0][0][13] = 0, - [2][1][0][0] = 40, - [2][1][0][1] = 40, - [2][1][0][2] = 40, - [2][1][0][3] = 40, - [2][1][0][4] = 40, - [2][1][0][5] = 40, - [2][1][0][6] = 40, - [2][1][0][7] = 40, - [2][1][0][8] = 40, - [2][1][0][9] = 40, - [2][1][0][10] = 40, - [2][1][0][11] = 40, - [2][1][0][12] = 26, - [2][1][0][13] = 0, - [0][0][2][0] = 70, - [0][0][1][0] = 32, - [0][0][3][0] = 40, - [0][0][5][0] = 70, - [0][0][6][0] = 32, - [0][0][9][0] = 32, - [0][0][8][0] = 60, - [0][0][11][0] = 32, - [0][0][2][1] = 70, - [0][0][1][1] = 32, - [0][0][3][1] = 40, - [0][0][5][1] = 70, - [0][0][6][1] = 32, - [0][0][9][1] = 32, - [0][0][8][1] = 60, - [0][0][11][1] = 32, - [0][0][2][2] = 74, - [0][0][1][2] = 32, - [0][0][3][2] = 40, - [0][0][5][2] = 74, - [0][0][6][2] = 32, - [0][0][9][2] = 32, - [0][0][8][2] = 60, - [0][0][11][2] = 32, - [0][0][2][3] = 78, - [0][0][1][3] = 32, - [0][0][3][3] = 40, - [0][0][5][3] = 78, - [0][0][6][3] = 32, - [0][0][9][3] = 32, - [0][0][8][3] = 60, - [0][0][11][3] = 32, - [0][0][2][4] = 78, - [0][0][1][4] = 32, - [0][0][3][4] = 40, - [0][0][5][4] = 78, - [0][0][6][4] = 32, - [0][0][9][4] = 32, - [0][0][8][4] = 60, - [0][0][11][4] = 32, - [0][0][2][5] = 78, - [0][0][1][5] = 32, - [0][0][3][5] = 40, - [0][0][5][5] = 78, - [0][0][6][5] = 32, - [0][0][9][5] = 32, - [0][0][8][5] = 60, - [0][0][11][5] = 32, - [0][0][2][6] = 78, - [0][0][1][6] = 32, - [0][0][3][6] = 40, - [0][0][5][6] = 78, - [0][0][6][6] = 32, - [0][0][9][6] = 32, - [0][0][8][6] = 60, - [0][0][11][6] = 32, - [0][0][2][7] = 78, - [0][0][1][7] = 32, - [0][0][3][7] = 40, - [0][0][5][7] = 78, - [0][0][6][7] = 32, - [0][0][9][7] = 32, - [0][0][8][7] = 60, - [0][0][11][7] = 32, - [0][0][2][8] = 74, - [0][0][1][8] = 32, - [0][0][3][8] = 40, - [0][0][5][8] = 74, - [0][0][6][8] = 32, - [0][0][9][8] = 32, - [0][0][8][8] = 60, - [0][0][11][8] = 32, - [0][0][2][9] = 70, - [0][0][1][9] = 32, - [0][0][3][9] = 40, - [0][0][5][9] = 70, - [0][0][6][9] = 32, - [0][0][9][9] = 32, - [0][0][8][9] = 60, - [0][0][11][9] = 32, - [0][0][2][10] = 70, - [0][0][1][10] = 32, - [0][0][3][10] = 40, - [0][0][5][10] = 70, - [0][0][6][10] = 32, - [0][0][9][10] = 32, - [0][0][8][10] = 60, - [0][0][11][10] = 32, - [0][0][2][11] = 58, - [0][0][1][11] = 32, - [0][0][3][11] = 40, - [0][0][5][11] = 58, - [0][0][6][11] = 32, - [0][0][9][11] = 32, - [0][0][8][11] = 60, - [0][0][11][11] = 32, - [0][0][2][12] = 34, - [0][0][1][12] = 32, - [0][0][3][12] = 40, - [0][0][5][12] = 34, - [0][0][6][12] = 32, - [0][0][9][12] = 32, - [0][0][8][12] = 60, - [0][0][11][12] = 32, - [0][0][2][13] = 127, - [0][0][1][13] = 127, - [0][0][3][13] = 127, - [0][0][5][13] = 127, - [0][0][6][13] = 127, - [0][0][9][13] = 127, - [0][0][8][13] = 127, - [0][0][11][13] = 127, - [0][1][2][0] = 64, - [0][1][1][0] = 20, - [0][1][3][0] = 28, - [0][1][5][0] = 64, - [0][1][6][0] = 20, - [0][1][9][0] = 20, - [0][1][8][0] = 48, - [0][1][11][0] = 20, - [0][1][2][1] = 64, - [0][1][1][1] = 20, - [0][1][3][1] = 28, - [0][1][5][1] = 64, - [0][1][6][1] = 20, - [0][1][9][1] = 20, - [0][1][8][1] = 48, - [0][1][11][1] = 20, - [0][1][2][2] = 68, - [0][1][1][2] = 20, - [0][1][3][2] = 28, - [0][1][5][2] = 68, - [0][1][6][2] = 20, - [0][1][9][2] = 20, - [0][1][8][2] = 48, - [0][1][11][2] = 20, - [0][1][2][3] = 72, - [0][1][1][3] = 20, - [0][1][3][3] = 28, - [0][1][5][3] = 72, - [0][1][6][3] = 20, - [0][1][9][3] = 20, - [0][1][8][3] = 48, - [0][1][11][3] = 20, - [0][1][2][4] = 76, - [0][1][1][4] = 20, - [0][1][3][4] = 28, - [0][1][5][4] = 76, - [0][1][6][4] = 20, - [0][1][9][4] = 20, - [0][1][8][4] = 48, - [0][1][11][4] = 20, - [0][1][2][5] = 78, - [0][1][1][5] = 20, - [0][1][3][5] = 28, - [0][1][5][5] = 78, - [0][1][6][5] = 20, - [0][1][9][5] = 20, - [0][1][8][5] = 48, - [0][1][11][5] = 20, - [0][1][2][6] = 76, - [0][1][1][6] = 20, - [0][1][3][6] = 28, - [0][1][5][6] = 76, - [0][1][6][6] = 20, - [0][1][9][6] = 20, - [0][1][8][6] = 48, - [0][1][11][6] = 20, - [0][1][2][7] = 72, - [0][1][1][7] = 20, - [0][1][3][7] = 28, - [0][1][5][7] = 72, - [0][1][6][7] = 20, - [0][1][9][7] = 20, - [0][1][8][7] = 48, - [0][1][11][7] = 20, - [0][1][2][8] = 68, - [0][1][1][8] = 20, - [0][1][3][8] = 28, - [0][1][5][8] = 68, - [0][1][6][8] = 20, - [0][1][9][8] = 20, - [0][1][8][8] = 48, - [0][1][11][8] = 20, - [0][1][2][9] = 64, - [0][1][1][9] = 20, - [0][1][3][9] = 28, - [0][1][5][9] = 64, - [0][1][6][9] = 20, - [0][1][9][9] = 20, - [0][1][8][9] = 48, - [0][1][11][9] = 20, - [0][1][2][10] = 64, - [0][1][1][10] = 20, - [0][1][3][10] = 28, - [0][1][5][10] = 64, - [0][1][6][10] = 20, - [0][1][9][10] = 20, - [0][1][8][10] = 48, - [0][1][11][10] = 20, - [0][1][2][11] = 54, - [0][1][1][11] = 20, - [0][1][3][11] = 28, - [0][1][5][11] = 54, - [0][1][6][11] = 20, - [0][1][9][11] = 20, - [0][1][8][11] = 48, - [0][1][11][11] = 20, - [0][1][2][12] = 32, - [0][1][1][12] = 20, - [0][1][3][12] = 28, - [0][1][5][12] = 32, - [0][1][6][12] = 20, - [0][1][9][12] = 20, - [0][1][8][12] = 48, - [0][1][11][12] = 20, - [0][1][2][13] = 127, - [0][1][1][13] = 127, - [0][1][3][13] = 127, - [0][1][5][13] = 127, - [0][1][6][13] = 127, - [0][1][9][13] = 127, - [0][1][8][13] = 127, - [0][1][11][13] = 127, - [1][0][2][0] = 72, - [1][0][1][0] = 42, - [1][0][3][0] = 50, - [1][0][5][0] = 72, - [1][0][6][0] = 42, - [1][0][9][0] = 42, - [1][0][8][0] = 60, - [1][0][11][0] = 42, - [1][0][2][1] = 72, - [1][0][1][1] = 42, - [1][0][3][1] = 50, - [1][0][5][1] = 72, - [1][0][6][1] = 42, - [1][0][9][1] = 42, - [1][0][8][1] = 60, - [1][0][11][1] = 42, - [1][0][2][2] = 76, - [1][0][1][2] = 42, - [1][0][3][2] = 50, - [1][0][5][2] = 76, - [1][0][6][2] = 42, - [1][0][9][2] = 42, - [1][0][8][2] = 60, - [1][0][11][2] = 42, - [1][0][2][3] = 78, - [1][0][1][3] = 42, - [1][0][3][3] = 50, - [1][0][5][3] = 78, - [1][0][6][3] = 42, - [1][0][9][3] = 42, - [1][0][8][3] = 60, - [1][0][11][3] = 42, - [1][0][2][4] = 78, - [1][0][1][4] = 42, - [1][0][3][4] = 50, - [1][0][5][4] = 78, - [1][0][6][4] = 42, - [1][0][9][4] = 42, - [1][0][8][4] = 60, - [1][0][11][4] = 42, - [1][0][2][5] = 78, - [1][0][1][5] = 42, - [1][0][3][5] = 50, - [1][0][5][5] = 78, - [1][0][6][5] = 42, - [1][0][9][5] = 42, - [1][0][8][5] = 60, - [1][0][11][5] = 42, - [1][0][2][6] = 78, - [1][0][1][6] = 42, - [1][0][3][6] = 50, - [1][0][5][6] = 78, - [1][0][6][6] = 42, - [1][0][9][6] = 42, - [1][0][8][6] = 60, - [1][0][11][6] = 42, - [1][0][2][7] = 78, - [1][0][1][7] = 42, - [1][0][3][7] = 50, - [1][0][5][7] = 78, - [1][0][6][7] = 42, - [1][0][9][7] = 42, - [1][0][8][7] = 60, - [1][0][11][7] = 42, - [1][0][2][8] = 78, - [1][0][1][8] = 42, - [1][0][3][8] = 50, - [1][0][5][8] = 78, - [1][0][6][8] = 42, - [1][0][9][8] = 42, - [1][0][8][8] = 60, - [1][0][11][8] = 42, - [1][0][2][9] = 74, - [1][0][1][9] = 42, - [1][0][3][9] = 50, - [1][0][5][9] = 74, - [1][0][6][9] = 42, - [1][0][9][9] = 42, - [1][0][8][9] = 60, - [1][0][11][9] = 42, - [1][0][2][10] = 74, - [1][0][1][10] = 42, - [1][0][3][10] = 50, - [1][0][5][10] = 74, - [1][0][6][10] = 42, - [1][0][9][10] = 42, - [1][0][8][10] = 60, - [1][0][11][10] = 42, - [1][0][2][11] = 64, - [1][0][1][11] = 42, - [1][0][3][11] = 50, - [1][0][5][11] = 64, - [1][0][6][11] = 42, - [1][0][9][11] = 42, - [1][0][8][11] = 60, - [1][0][11][11] = 42, - [1][0][2][12] = 36, - [1][0][1][12] = 42, - [1][0][3][12] = 50, - [1][0][5][12] = 36, - [1][0][6][12] = 42, - [1][0][9][12] = 42, - [1][0][8][12] = 60, - [1][0][11][12] = 42, - [1][0][2][13] = 127, - [1][0][1][13] = 127, - [1][0][3][13] = 127, - [1][0][5][13] = 127, - [1][0][6][13] = 127, - [1][0][9][13] = 127, - [1][0][8][13] = 127, - [1][0][11][13] = 127, - [1][1][2][0] = 66, - [1][1][1][0] = 30, - [1][1][3][0] = 38, - [1][1][5][0] = 66, - [1][1][6][0] = 30, - [1][1][9][0] = 30, - [1][1][8][0] = 48, - [1][1][11][0] = 30, - [1][1][2][1] = 66, - [1][1][1][1] = 30, - [1][1][3][1] = 38, - [1][1][5][1] = 66, - [1][1][6][1] = 30, - [1][1][9][1] = 30, - [1][1][8][1] = 48, - [1][1][11][1] = 30, - [1][1][2][2] = 70, - [1][1][1][2] = 30, - [1][1][3][2] = 38, - [1][1][5][2] = 70, - [1][1][6][2] = 30, - [1][1][9][2] = 30, - [1][1][8][2] = 48, - [1][1][11][2] = 30, - [1][1][2][3] = 74, - [1][1][1][3] = 30, - [1][1][3][3] = 38, - [1][1][5][3] = 74, - [1][1][6][3] = 30, - [1][1][9][3] = 30, - [1][1][8][3] = 48, - [1][1][11][3] = 30, - [1][1][2][4] = 78, - [1][1][1][4] = 30, - [1][1][3][4] = 38, - [1][1][5][4] = 78, - [1][1][6][4] = 30, - [1][1][9][4] = 30, - [1][1][8][4] = 48, - [1][1][11][4] = 30, - [1][1][2][5] = 78, - [1][1][1][5] = 30, - [1][1][3][5] = 38, - [1][1][5][5] = 78, - [1][1][6][5] = 30, - [1][1][9][5] = 30, - [1][1][8][5] = 48, - [1][1][11][5] = 30, - [1][1][2][6] = 78, - [1][1][1][6] = 30, - [1][1][3][6] = 38, - [1][1][5][6] = 78, - [1][1][6][6] = 30, - [1][1][9][6] = 30, - [1][1][8][6] = 48, - [1][1][11][6] = 30, - [1][1][2][7] = 74, - [1][1][1][7] = 30, - [1][1][3][7] = 38, - [1][1][5][7] = 74, - [1][1][6][7] = 30, - [1][1][9][7] = 30, - [1][1][8][7] = 48, - [1][1][11][7] = 30, - [1][1][2][8] = 70, - [1][1][1][8] = 30, - [1][1][3][8] = 38, - [1][1][5][8] = 70, - [1][1][6][8] = 30, - [1][1][9][8] = 30, - [1][1][8][8] = 48, - [1][1][11][8] = 30, - [1][1][2][9] = 66, - [1][1][1][9] = 30, - [1][1][3][9] = 38, - [1][1][5][9] = 66, - [1][1][6][9] = 30, - [1][1][9][9] = 30, - [1][1][8][9] = 48, - [1][1][11][9] = 30, - [1][1][2][10] = 66, - [1][1][1][10] = 30, - [1][1][3][10] = 38, - [1][1][5][10] = 66, - [1][1][6][10] = 30, - [1][1][9][10] = 30, - [1][1][8][10] = 48, - [1][1][11][10] = 30, - [1][1][2][11] = 60, - [1][1][1][11] = 30, - [1][1][3][11] = 38, - [1][1][5][11] = 60, - [1][1][6][11] = 30, - [1][1][9][11] = 30, - [1][1][8][11] = 48, - [1][1][11][11] = 30, - [1][1][2][12] = 32, - [1][1][1][12] = 30, - [1][1][3][12] = 38, - [1][1][5][12] = 32, - [1][1][6][12] = 30, - [1][1][9][12] = 30, - [1][1][8][12] = 48, - [1][1][11][12] = 30, - [1][1][2][13] = 127, - [1][1][1][13] = 127, - [1][1][3][13] = 127, - [1][1][5][13] = 127, - [1][1][6][13] = 127, - [1][1][9][13] = 127, - [1][1][8][13] = 127, - [1][1][11][13] = 127, - [2][0][2][0] = 76, - [2][0][1][0] = 52, - [2][0][3][0] = 64, - [2][0][5][0] = 76, - [2][0][6][0] = 52, - [2][0][9][0] = 52, - [2][0][8][0] = 60, - [2][0][11][0] = 52, - [2][0][2][1] = 76, - [2][0][1][1] = 52, - [2][0][3][1] = 64, - [2][0][5][1] = 76, - [2][0][6][1] = 52, - [2][0][9][1] = 52, - [2][0][8][1] = 60, - [2][0][11][1] = 52, - [2][0][2][2] = 78, - [2][0][1][2] = 52, - [2][0][3][2] = 64, - [2][0][5][2] = 78, - [2][0][6][2] = 52, - [2][0][9][2] = 52, - [2][0][8][2] = 60, - [2][0][11][2] = 52, - [2][0][2][3] = 78, - [2][0][1][3] = 52, - [2][0][3][3] = 64, - [2][0][5][3] = 78, - [2][0][6][3] = 52, - [2][0][9][3] = 52, - [2][0][8][3] = 60, - [2][0][11][3] = 52, - [2][0][2][4] = 78, - [2][0][1][4] = 52, - [2][0][3][4] = 64, - [2][0][5][4] = 78, - [2][0][6][4] = 52, - [2][0][9][4] = 52, - [2][0][8][4] = 60, - [2][0][11][4] = 52, - [2][0][2][5] = 78, - [2][0][1][5] = 52, - [2][0][3][5] = 64, - [2][0][5][5] = 78, - [2][0][6][5] = 52, - [2][0][9][5] = 52, - [2][0][8][5] = 60, - [2][0][11][5] = 52, - [2][0][2][6] = 78, - [2][0][1][6] = 52, - [2][0][3][6] = 64, - [2][0][5][6] = 78, - [2][0][6][6] = 52, - [2][0][9][6] = 52, - [2][0][8][6] = 60, - [2][0][11][6] = 52, - [2][0][2][7] = 78, - [2][0][1][7] = 52, - [2][0][3][7] = 64, - [2][0][5][7] = 78, - [2][0][6][7] = 52, - [2][0][9][7] = 52, - [2][0][8][7] = 60, - [2][0][11][7] = 52, - [2][0][2][8] = 78, - [2][0][1][8] = 52, - [2][0][3][8] = 64, - [2][0][5][8] = 78, - [2][0][6][8] = 52, - [2][0][9][8] = 52, - [2][0][8][8] = 60, - [2][0][11][8] = 52, - [2][0][2][9] = 76, - [2][0][1][9] = 52, - [2][0][3][9] = 64, - [2][0][5][9] = 76, - [2][0][6][9] = 52, - [2][0][9][9] = 52, - [2][0][8][9] = 60, - [2][0][11][9] = 52, - [2][0][2][10] = 76, - [2][0][1][10] = 52, - [2][0][3][10] = 64, - [2][0][5][10] = 76, - [2][0][6][10] = 52, - [2][0][9][10] = 52, - [2][0][8][10] = 60, - [2][0][11][10] = 52, - [2][0][2][11] = 68, - [2][0][1][11] = 52, - [2][0][3][11] = 64, - [2][0][5][11] = 68, - [2][0][6][11] = 52, - [2][0][9][11] = 52, - [2][0][8][11] = 60, - [2][0][11][11] = 52, - [2][0][2][12] = 40, - [2][0][1][12] = 52, - [2][0][3][12] = 64, - [2][0][5][12] = 40, - [2][0][6][12] = 52, - [2][0][9][12] = 52, - [2][0][8][12] = 60, - [2][0][11][12] = 52, - [2][0][2][13] = 127, - [2][0][1][13] = 127, - [2][0][3][13] = 127, - [2][0][5][13] = 127, - [2][0][6][13] = 127, - [2][0][9][13] = 127, - [2][0][8][13] = 127, - [2][0][11][13] = 127, - [2][1][2][0] = 68, - [2][1][1][0] = 40, - [2][1][3][0] = 52, - [2][1][5][0] = 68, - [2][1][6][0] = 40, - [2][1][9][0] = 40, - [2][1][8][0] = 48, - [2][1][11][0] = 40, - [2][1][2][1] = 68, - [2][1][1][1] = 40, - [2][1][3][1] = 52, - [2][1][5][1] = 68, - [2][1][6][1] = 40, - [2][1][9][1] = 40, - [2][1][8][1] = 48, - [2][1][11][1] = 40, - [2][1][2][2] = 72, - [2][1][1][2] = 40, - [2][1][3][2] = 52, - [2][1][5][2] = 72, - [2][1][6][2] = 40, - [2][1][9][2] = 40, - [2][1][8][2] = 48, - [2][1][11][2] = 40, - [2][1][2][3] = 76, - [2][1][1][3] = 40, - [2][1][3][3] = 52, - [2][1][5][3] = 76, - [2][1][6][3] = 40, - [2][1][9][3] = 40, - [2][1][8][3] = 48, - [2][1][11][3] = 40, - [2][1][2][4] = 78, - [2][1][1][4] = 40, - [2][1][3][4] = 52, - [2][1][5][4] = 78, - [2][1][6][4] = 40, - [2][1][9][4] = 40, - [2][1][8][4] = 48, - [2][1][11][4] = 40, - [2][1][2][5] = 78, - [2][1][1][5] = 40, - [2][1][3][5] = 52, - [2][1][5][5] = 78, - [2][1][6][5] = 40, - [2][1][9][5] = 40, - [2][1][8][5] = 48, - [2][1][11][5] = 40, - [2][1][2][6] = 78, - [2][1][1][6] = 40, - [2][1][3][6] = 52, - [2][1][5][6] = 78, - [2][1][6][6] = 40, - [2][1][9][6] = 40, - [2][1][8][6] = 48, - [2][1][11][6] = 40, - [2][1][2][7] = 78, - [2][1][1][7] = 40, - [2][1][3][7] = 52, - [2][1][5][7] = 78, - [2][1][6][7] = 40, - [2][1][9][7] = 40, - [2][1][8][7] = 48, - [2][1][11][7] = 40, - [2][1][2][8] = 74, - [2][1][1][8] = 40, - [2][1][3][8] = 52, - [2][1][5][8] = 74, - [2][1][6][8] = 40, - [2][1][9][8] = 40, - [2][1][8][8] = 48, - [2][1][11][8] = 40, - [2][1][2][9] = 70, - [2][1][1][9] = 40, - [2][1][3][9] = 52, - [2][1][5][9] = 70, - [2][1][6][9] = 40, - [2][1][9][9] = 40, - [2][1][8][9] = 48, - [2][1][11][9] = 40, - [2][1][2][10] = 70, - [2][1][1][10] = 40, - [2][1][3][10] = 52, - [2][1][5][10] = 70, - [2][1][6][10] = 40, - [2][1][9][10] = 40, - [2][1][8][10] = 48, - [2][1][11][10] = 40, - [2][1][2][11] = 48, - [2][1][1][11] = 40, - [2][1][3][11] = 52, - [2][1][5][11] = 48, - [2][1][6][11] = 40, - [2][1][9][11] = 40, - [2][1][8][11] = 48, - [2][1][11][11] = 40, - [2][1][2][12] = 26, - [2][1][1][12] = 40, - [2][1][3][12] = 52, - [2][1][5][12] = 26, - [2][1][6][12] = 40, - [2][1][9][12] = 40, - [2][1][8][12] = 48, - [2][1][11][12] = 40, - [2][1][2][13] = 127, - [2][1][1][13] = 127, - [2][1][3][13] = 127, - [2][1][5][13] = 127, - [2][1][6][13] = 127, - [2][1][9][13] = 127, - [2][1][8][13] = 127, - [2][1][11][13] = 127, + [0][0][RTW89_WW][0] = 32, + [0][0][RTW89_WW][1] = 32, + [0][0][RTW89_WW][2] = 32, + [0][0][RTW89_WW][3] = 32, + [0][0][RTW89_WW][4] = 32, + [0][0][RTW89_WW][5] = 32, + [0][0][RTW89_WW][6] = 32, + [0][0][RTW89_WW][7] = 32, + [0][0][RTW89_WW][8] = 32, + [0][0][RTW89_WW][9] = 32, + [0][0][RTW89_WW][10] = 32, + [0][0][RTW89_WW][11] = 32, + [0][0][RTW89_WW][12] = 32, + [0][0][RTW89_WW][13] = 0, + [0][1][RTW89_WW][0] = 20, + [0][1][RTW89_WW][1] = 20, + [0][1][RTW89_WW][2] = 20, + [0][1][RTW89_WW][3] = 20, + [0][1][RTW89_WW][4] = 20, + [0][1][RTW89_WW][5] = 20, + [0][1][RTW89_WW][6] = 20, + [0][1][RTW89_WW][7] = 20, + [0][1][RTW89_WW][8] = 20, + [0][1][RTW89_WW][9] = 20, + [0][1][RTW89_WW][10] = 20, + [0][1][RTW89_WW][11] = 20, + [0][1][RTW89_WW][12] = 20, + [0][1][RTW89_WW][13] = 0, + [1][0][RTW89_WW][0] = 42, + [1][0][RTW89_WW][1] = 42, + [1][0][RTW89_WW][2] = 42, + [1][0][RTW89_WW][3] = 42, + [1][0][RTW89_WW][4] = 42, + [1][0][RTW89_WW][5] = 42, + [1][0][RTW89_WW][6] = 42, + [1][0][RTW89_WW][7] = 42, + [1][0][RTW89_WW][8] = 42, + [1][0][RTW89_WW][9] = 42, + [1][0][RTW89_WW][10] = 42, + [1][0][RTW89_WW][11] = 42, + [1][0][RTW89_WW][12] = 36, + [1][0][RTW89_WW][13] = 0, + [1][1][RTW89_WW][0] = 30, + [1][1][RTW89_WW][1] = 30, + [1][1][RTW89_WW][2] = 30, + [1][1][RTW89_WW][3] = 30, + [1][1][RTW89_WW][4] = 30, + [1][1][RTW89_WW][5] = 30, + [1][1][RTW89_WW][6] = 30, + [1][1][RTW89_WW][7] = 30, + [1][1][RTW89_WW][8] = 30, + [1][1][RTW89_WW][9] = 30, + [1][1][RTW89_WW][10] = 30, + [1][1][RTW89_WW][11] = 30, + [1][1][RTW89_WW][12] = 30, + [1][1][RTW89_WW][13] = 0, + [2][0][RTW89_WW][0] = 52, + [2][0][RTW89_WW][1] = 52, + [2][0][RTW89_WW][2] = 52, + [2][0][RTW89_WW][3] = 52, + [2][0][RTW89_WW][4] = 52, + [2][0][RTW89_WW][5] = 52, + [2][0][RTW89_WW][6] = 52, + [2][0][RTW89_WW][7] = 52, + [2][0][RTW89_WW][8] = 52, + [2][0][RTW89_WW][9] = 52, + [2][0][RTW89_WW][10] = 52, + [2][0][RTW89_WW][11] = 52, + [2][0][RTW89_WW][12] = 40, + [2][0][RTW89_WW][13] = 0, + [2][1][RTW89_WW][0] = 40, + [2][1][RTW89_WW][1] = 40, + [2][1][RTW89_WW][2] = 40, + [2][1][RTW89_WW][3] = 40, + [2][1][RTW89_WW][4] = 40, + [2][1][RTW89_WW][5] = 40, + [2][1][RTW89_WW][6] = 40, + [2][1][RTW89_WW][7] = 40, + [2][1][RTW89_WW][8] = 40, + [2][1][RTW89_WW][9] = 40, + [2][1][RTW89_WW][10] = 40, + [2][1][RTW89_WW][11] = 40, + [2][1][RTW89_WW][12] = 26, + [2][1][RTW89_WW][13] = 0, + [0][0][RTW89_FCC][0] = 70, + [0][0][RTW89_ETSI][0] = 32, + [0][0][RTW89_MKK][0] = 40, + [0][0][RTW89_IC][0] = 70, + [0][0][RTW89_KCC][0] = 46, + [0][0][RTW89_ACMA][0] = 32, + [0][0][RTW89_CHILE][0] = 60, + [0][0][RTW89_UKRAINE][0] = 32, + [0][0][RTW89_MEXICO][0] = 70, + [0][0][RTW89_CN][0] = 32, + [0][0][RTW89_QATAR][0] = 32, + [0][0][RTW89_FCC][1] = 70, + [0][0][RTW89_ETSI][1] = 32, + [0][0][RTW89_MKK][1] = 40, + [0][0][RTW89_IC][1] = 70, + [0][0][RTW89_KCC][1] = 46, + [0][0][RTW89_ACMA][1] = 32, + [0][0][RTW89_CHILE][1] = 60, + [0][0][RTW89_UKRAINE][1] = 32, + [0][0][RTW89_MEXICO][1] = 70, + [0][0][RTW89_CN][1] = 32, + [0][0][RTW89_QATAR][1] = 32, + [0][0][RTW89_FCC][2] = 74, + [0][0][RTW89_ETSI][2] = 32, + [0][0][RTW89_MKK][2] = 40, + [0][0][RTW89_IC][2] = 74, + [0][0][RTW89_KCC][2] = 46, + [0][0][RTW89_ACMA][2] = 32, + [0][0][RTW89_CHILE][2] = 60, + [0][0][RTW89_UKRAINE][2] = 32, + [0][0][RTW89_MEXICO][2] = 74, + [0][0][RTW89_CN][2] = 32, + [0][0][RTW89_QATAR][2] = 32, + [0][0][RTW89_FCC][3] = 78, + [0][0][RTW89_ETSI][3] = 32, + [0][0][RTW89_MKK][3] = 40, + [0][0][RTW89_IC][3] = 78, + [0][0][RTW89_KCC][3] = 46, + [0][0][RTW89_ACMA][3] = 32, + [0][0][RTW89_CHILE][3] = 60, + [0][0][RTW89_UKRAINE][3] = 32, + [0][0][RTW89_MEXICO][3] = 78, + [0][0][RTW89_CN][3] = 32, + [0][0][RTW89_QATAR][3] = 32, + [0][0][RTW89_FCC][4] = 78, + [0][0][RTW89_ETSI][4] = 32, + [0][0][RTW89_MKK][4] = 40, + [0][0][RTW89_IC][4] = 78, + [0][0][RTW89_KCC][4] = 46, + [0][0][RTW89_ACMA][4] = 32, + [0][0][RTW89_CHILE][4] = 60, + [0][0][RTW89_UKRAINE][4] = 32, + [0][0][RTW89_MEXICO][4] = 78, + [0][0][RTW89_CN][4] = 32, + [0][0][RTW89_QATAR][4] = 32, + [0][0][RTW89_FCC][5] = 78, + [0][0][RTW89_ETSI][5] = 32, + [0][0][RTW89_MKK][5] = 40, + [0][0][RTW89_IC][5] = 78, + [0][0][RTW89_KCC][5] = 46, + [0][0][RTW89_ACMA][5] = 32, + [0][0][RTW89_CHILE][5] = 60, + [0][0][RTW89_UKRAINE][5] = 32, + [0][0][RTW89_MEXICO][5] = 78, + [0][0][RTW89_CN][5] = 32, + [0][0][RTW89_QATAR][5] = 32, + [0][0][RTW89_FCC][6] = 78, + [0][0][RTW89_ETSI][6] = 32, + [0][0][RTW89_MKK][6] = 40, + [0][0][RTW89_IC][6] = 78, + [0][0][RTW89_KCC][6] = 46, + [0][0][RTW89_ACMA][6] = 32, + [0][0][RTW89_CHILE][6] = 60, + [0][0][RTW89_UKRAINE][6] = 32, + [0][0][RTW89_MEXICO][6] = 78, + [0][0][RTW89_CN][6] = 32, + [0][0][RTW89_QATAR][6] = 32, + [0][0][RTW89_FCC][7] = 78, + [0][0][RTW89_ETSI][7] = 32, + [0][0][RTW89_MKK][7] = 40, + [0][0][RTW89_IC][7] = 78, + [0][0][RTW89_KCC][7] = 46, + [0][0][RTW89_ACMA][7] = 32, + [0][0][RTW89_CHILE][7] = 60, + [0][0][RTW89_UKRAINE][7] = 32, + [0][0][RTW89_MEXICO][7] = 78, + [0][0][RTW89_CN][7] = 32, + [0][0][RTW89_QATAR][7] = 32, + [0][0][RTW89_FCC][8] = 74, + [0][0][RTW89_ETSI][8] = 32, + [0][0][RTW89_MKK][8] = 40, + [0][0][RTW89_IC][8] = 74, + [0][0][RTW89_KCC][8] = 46, + [0][0][RTW89_ACMA][8] = 32, + [0][0][RTW89_CHILE][8] = 60, + [0][0][RTW89_UKRAINE][8] = 32, + [0][0][RTW89_MEXICO][8] = 74, + [0][0][RTW89_CN][8] = 32, + [0][0][RTW89_QATAR][8] = 32, + [0][0][RTW89_FCC][9] = 70, + [0][0][RTW89_ETSI][9] = 32, + [0][0][RTW89_MKK][9] = 40, + [0][0][RTW89_IC][9] = 70, + [0][0][RTW89_KCC][9] = 46, + [0][0][RTW89_ACMA][9] = 32, + [0][0][RTW89_CHILE][9] = 60, + [0][0][RTW89_UKRAINE][9] = 32, + [0][0][RTW89_MEXICO][9] = 70, + [0][0][RTW89_CN][9] = 32, + [0][0][RTW89_QATAR][9] = 32, + [0][0][RTW89_FCC][10] = 70, + [0][0][RTW89_ETSI][10] = 32, + [0][0][RTW89_MKK][10] = 40, + [0][0][RTW89_IC][10] = 70, + [0][0][RTW89_KCC][10] = 46, + [0][0][RTW89_ACMA][10] = 32, + [0][0][RTW89_CHILE][10] = 60, + [0][0][RTW89_UKRAINE][10] = 32, + [0][0][RTW89_MEXICO][10] = 70, + [0][0][RTW89_CN][10] = 32, + [0][0][RTW89_QATAR][10] = 32, + [0][0][RTW89_FCC][11] = 58, + [0][0][RTW89_ETSI][11] = 32, + [0][0][RTW89_MKK][11] = 40, + [0][0][RTW89_IC][11] = 58, + [0][0][RTW89_KCC][11] = 46, + [0][0][RTW89_ACMA][11] = 32, + [0][0][RTW89_CHILE][11] = 58, + [0][0][RTW89_UKRAINE][11] = 32, + [0][0][RTW89_MEXICO][11] = 58, + [0][0][RTW89_CN][11] = 32, + [0][0][RTW89_QATAR][11] = 32, + [0][0][RTW89_FCC][12] = 34, + [0][0][RTW89_ETSI][12] = 32, + [0][0][RTW89_MKK][12] = 40, + [0][0][RTW89_IC][12] = 34, + [0][0][RTW89_KCC][12] = 46, + [0][0][RTW89_ACMA][12] = 32, + [0][0][RTW89_CHILE][12] = 34, + [0][0][RTW89_UKRAINE][12] = 32, + [0][0][RTW89_MEXICO][12] = 34, + [0][0][RTW89_CN][12] = 32, + [0][0][RTW89_QATAR][12] = 32, + [0][0][RTW89_FCC][13] = 127, + [0][0][RTW89_ETSI][13] = 127, + [0][0][RTW89_MKK][13] = 127, + [0][0][RTW89_IC][13] = 127, + [0][0][RTW89_KCC][13] = 127, + [0][0][RTW89_ACMA][13] = 127, + [0][0][RTW89_CHILE][13] = 127, + [0][0][RTW89_UKRAINE][13] = 127, + [0][0][RTW89_MEXICO][13] = 127, + [0][0][RTW89_CN][13] = 127, + [0][0][RTW89_QATAR][13] = 127, + [0][1][RTW89_FCC][0] = 64, + [0][1][RTW89_ETSI][0] = 20, + [0][1][RTW89_MKK][0] = 28, + [0][1][RTW89_IC][0] = 64, + [0][1][RTW89_KCC][0] = 32, + [0][1][RTW89_ACMA][0] = 20, + [0][1][RTW89_CHILE][0] = 48, + [0][1][RTW89_UKRAINE][0] = 20, + [0][1][RTW89_MEXICO][0] = 64, + [0][1][RTW89_CN][0] = 20, + [0][1][RTW89_QATAR][0] = 20, + [0][1][RTW89_FCC][1] = 64, + [0][1][RTW89_ETSI][1] = 20, + [0][1][RTW89_MKK][1] = 28, + [0][1][RTW89_IC][1] = 64, + [0][1][RTW89_KCC][1] = 32, + [0][1][RTW89_ACMA][1] = 20, + [0][1][RTW89_CHILE][1] = 48, + [0][1][RTW89_UKRAINE][1] = 20, + [0][1][RTW89_MEXICO][1] = 64, + [0][1][RTW89_CN][1] = 20, + [0][1][RTW89_QATAR][1] = 20, + [0][1][RTW89_FCC][2] = 68, + [0][1][RTW89_ETSI][2] = 20, + [0][1][RTW89_MKK][2] = 28, + [0][1][RTW89_IC][2] = 68, + [0][1][RTW89_KCC][2] = 32, + [0][1][RTW89_ACMA][2] = 20, + [0][1][RTW89_CHILE][2] = 48, + [0][1][RTW89_UKRAINE][2] = 20, + [0][1][RTW89_MEXICO][2] = 68, + [0][1][RTW89_CN][2] = 20, + [0][1][RTW89_QATAR][2] = 20, + [0][1][RTW89_FCC][3] = 72, + [0][1][RTW89_ETSI][3] = 20, + [0][1][RTW89_MKK][3] = 28, + [0][1][RTW89_IC][3] = 72, + [0][1][RTW89_KCC][3] = 32, + [0][1][RTW89_ACMA][3] = 20, + [0][1][RTW89_CHILE][3] = 48, + [0][1][RTW89_UKRAINE][3] = 20, + [0][1][RTW89_MEXICO][3] = 72, + [0][1][RTW89_CN][3] = 20, + [0][1][RTW89_QATAR][3] = 20, + [0][1][RTW89_FCC][4] = 76, + [0][1][RTW89_ETSI][4] = 20, + [0][1][RTW89_MKK][4] = 28, + [0][1][RTW89_IC][4] = 76, + [0][1][RTW89_KCC][4] = 32, + [0][1][RTW89_ACMA][4] = 20, + [0][1][RTW89_CHILE][4] = 48, + [0][1][RTW89_UKRAINE][4] = 20, + [0][1][RTW89_MEXICO][4] = 76, + [0][1][RTW89_CN][4] = 20, + [0][1][RTW89_QATAR][4] = 20, + [0][1][RTW89_FCC][5] = 78, + [0][1][RTW89_ETSI][5] = 20, + [0][1][RTW89_MKK][5] = 28, + [0][1][RTW89_IC][5] = 78, + [0][1][RTW89_KCC][5] = 32, + [0][1][RTW89_ACMA][5] = 20, + [0][1][RTW89_CHILE][5] = 48, + [0][1][RTW89_UKRAINE][5] = 20, + [0][1][RTW89_MEXICO][5] = 78, + [0][1][RTW89_CN][5] = 20, + [0][1][RTW89_QATAR][5] = 20, + [0][1][RTW89_FCC][6] = 76, + [0][1][RTW89_ETSI][6] = 20, + [0][1][RTW89_MKK][6] = 28, + [0][1][RTW89_IC][6] = 76, + [0][1][RTW89_KCC][6] = 32, + [0][1][RTW89_ACMA][6] = 20, + [0][1][RTW89_CHILE][6] = 48, + [0][1][RTW89_UKRAINE][6] = 20, + [0][1][RTW89_MEXICO][6] = 76, + [0][1][RTW89_CN][6] = 20, + [0][1][RTW89_QATAR][6] = 20, + [0][1][RTW89_FCC][7] = 72, + [0][1][RTW89_ETSI][7] = 20, + [0][1][RTW89_MKK][7] = 28, + [0][1][RTW89_IC][7] = 72, + [0][1][RTW89_KCC][7] = 32, + [0][1][RTW89_ACMA][7] = 20, + [0][1][RTW89_CHILE][7] = 48, + [0][1][RTW89_UKRAINE][7] = 20, + [0][1][RTW89_MEXICO][7] = 72, + [0][1][RTW89_CN][7] = 20, + [0][1][RTW89_QATAR][7] = 20, + [0][1][RTW89_FCC][8] = 68, + [0][1][RTW89_ETSI][8] = 20, + [0][1][RTW89_MKK][8] = 28, + [0][1][RTW89_IC][8] = 68, + [0][1][RTW89_KCC][8] = 32, + [0][1][RTW89_ACMA][8] = 20, + [0][1][RTW89_CHILE][8] = 48, + [0][1][RTW89_UKRAINE][8] = 20, + [0][1][RTW89_MEXICO][8] = 68, + [0][1][RTW89_CN][8] = 20, + [0][1][RTW89_QATAR][8] = 20, + [0][1][RTW89_FCC][9] = 64, + [0][1][RTW89_ETSI][9] = 20, + [0][1][RTW89_MKK][9] = 28, + [0][1][RTW89_IC][9] = 64, + [0][1][RTW89_KCC][9] = 32, + [0][1][RTW89_ACMA][9] = 20, + [0][1][RTW89_CHILE][9] = 48, + [0][1][RTW89_UKRAINE][9] = 20, + [0][1][RTW89_MEXICO][9] = 64, + [0][1][RTW89_CN][9] = 20, + [0][1][RTW89_QATAR][9] = 20, + [0][1][RTW89_FCC][10] = 64, + [0][1][RTW89_ETSI][10] = 20, + [0][1][RTW89_MKK][10] = 28, + [0][1][RTW89_IC][10] = 64, + [0][1][RTW89_KCC][10] = 32, + [0][1][RTW89_ACMA][10] = 20, + [0][1][RTW89_CHILE][10] = 48, + [0][1][RTW89_UKRAINE][10] = 20, + [0][1][RTW89_MEXICO][10] = 64, + [0][1][RTW89_CN][10] = 20, + [0][1][RTW89_QATAR][10] = 20, + [0][1][RTW89_FCC][11] = 54, + [0][1][RTW89_ETSI][11] = 20, + [0][1][RTW89_MKK][11] = 28, + [0][1][RTW89_IC][11] = 54, + [0][1][RTW89_KCC][11] = 32, + [0][1][RTW89_ACMA][11] = 20, + [0][1][RTW89_CHILE][11] = 48, + [0][1][RTW89_UKRAINE][11] = 20, + [0][1][RTW89_MEXICO][11] = 54, + [0][1][RTW89_CN][11] = 20, + [0][1][RTW89_QATAR][11] = 20, + [0][1][RTW89_FCC][12] = 32, + [0][1][RTW89_ETSI][12] = 20, + [0][1][RTW89_MKK][12] = 28, + [0][1][RTW89_IC][12] = 32, + [0][1][RTW89_KCC][12] = 32, + [0][1][RTW89_ACMA][12] = 20, + [0][1][RTW89_CHILE][12] = 32, + [0][1][RTW89_UKRAINE][12] = 20, + [0][1][RTW89_MEXICO][12] = 32, + [0][1][RTW89_CN][12] = 20, + [0][1][RTW89_QATAR][12] = 20, + [0][1][RTW89_FCC][13] = 127, + [0][1][RTW89_ETSI][13] = 127, + [0][1][RTW89_MKK][13] = 127, + [0][1][RTW89_IC][13] = 127, + [0][1][RTW89_KCC][13] = 127, + [0][1][RTW89_ACMA][13] = 127, + [0][1][RTW89_CHILE][13] = 127, + [0][1][RTW89_UKRAINE][13] = 127, + [0][1][RTW89_MEXICO][13] = 127, + [0][1][RTW89_CN][13] = 127, + [0][1][RTW89_QATAR][13] = 127, + [1][0][RTW89_FCC][0] = 72, + [1][0][RTW89_ETSI][0] = 42, + [1][0][RTW89_MKK][0] = 50, + [1][0][RTW89_IC][0] = 72, + [1][0][RTW89_KCC][0] = 58, + [1][0][RTW89_ACMA][0] = 42, + [1][0][RTW89_CHILE][0] = 60, + [1][0][RTW89_UKRAINE][0] = 42, + [1][0][RTW89_MEXICO][0] = 72, + [1][0][RTW89_CN][0] = 42, + [1][0][RTW89_QATAR][0] = 42, + [1][0][RTW89_FCC][1] = 72, + [1][0][RTW89_ETSI][1] = 42, + [1][0][RTW89_MKK][1] = 50, + [1][0][RTW89_IC][1] = 72, + [1][0][RTW89_KCC][1] = 58, + [1][0][RTW89_ACMA][1] = 42, + [1][0][RTW89_CHILE][1] = 60, + [1][0][RTW89_UKRAINE][1] = 42, + [1][0][RTW89_MEXICO][1] = 72, + [1][0][RTW89_CN][1] = 42, + [1][0][RTW89_QATAR][1] = 42, + [1][0][RTW89_FCC][2] = 76, + [1][0][RTW89_ETSI][2] = 42, + [1][0][RTW89_MKK][2] = 50, + [1][0][RTW89_IC][2] = 76, + [1][0][RTW89_KCC][2] = 58, + [1][0][RTW89_ACMA][2] = 42, + [1][0][RTW89_CHILE][2] = 60, + [1][0][RTW89_UKRAINE][2] = 42, + [1][0][RTW89_MEXICO][2] = 76, + [1][0][RTW89_CN][2] = 42, + [1][0][RTW89_QATAR][2] = 42, + [1][0][RTW89_FCC][3] = 78, + [1][0][RTW89_ETSI][3] = 42, + [1][0][RTW89_MKK][3] = 50, + [1][0][RTW89_IC][3] = 78, + [1][0][RTW89_KCC][3] = 58, + [1][0][RTW89_ACMA][3] = 42, + [1][0][RTW89_CHILE][3] = 60, + [1][0][RTW89_UKRAINE][3] = 42, + [1][0][RTW89_MEXICO][3] = 78, + [1][0][RTW89_CN][3] = 42, + [1][0][RTW89_QATAR][3] = 42, + [1][0][RTW89_FCC][4] = 78, + [1][0][RTW89_ETSI][4] = 42, + [1][0][RTW89_MKK][4] = 50, + [1][0][RTW89_IC][4] = 78, + [1][0][RTW89_KCC][4] = 58, + [1][0][RTW89_ACMA][4] = 42, + [1][0][RTW89_CHILE][4] = 60, + [1][0][RTW89_UKRAINE][4] = 42, + [1][0][RTW89_MEXICO][4] = 78, + [1][0][RTW89_CN][4] = 42, + [1][0][RTW89_QATAR][4] = 42, + [1][0][RTW89_FCC][5] = 78, + [1][0][RTW89_ETSI][5] = 42, + [1][0][RTW89_MKK][5] = 50, + [1][0][RTW89_IC][5] = 78, + [1][0][RTW89_KCC][5] = 58, + [1][0][RTW89_ACMA][5] = 42, + [1][0][RTW89_CHILE][5] = 60, + [1][0][RTW89_UKRAINE][5] = 42, + [1][0][RTW89_MEXICO][5] = 78, + [1][0][RTW89_CN][5] = 42, + [1][0][RTW89_QATAR][5] = 42, + [1][0][RTW89_FCC][6] = 78, + [1][0][RTW89_ETSI][6] = 42, + [1][0][RTW89_MKK][6] = 50, + [1][0][RTW89_IC][6] = 78, + [1][0][RTW89_KCC][6] = 58, + [1][0][RTW89_ACMA][6] = 42, + [1][0][RTW89_CHILE][6] = 60, + [1][0][RTW89_UKRAINE][6] = 42, + [1][0][RTW89_MEXICO][6] = 78, + [1][0][RTW89_CN][6] = 42, + [1][0][RTW89_QATAR][6] = 42, + [1][0][RTW89_FCC][7] = 78, + [1][0][RTW89_ETSI][7] = 42, + [1][0][RTW89_MKK][7] = 50, + [1][0][RTW89_IC][7] = 78, + [1][0][RTW89_KCC][7] = 58, + [1][0][RTW89_ACMA][7] = 42, + [1][0][RTW89_CHILE][7] = 60, + [1][0][RTW89_UKRAINE][7] = 42, + [1][0][RTW89_MEXICO][7] = 78, + [1][0][RTW89_CN][7] = 42, + [1][0][RTW89_QATAR][7] = 42, + [1][0][RTW89_FCC][8] = 78, + [1][0][RTW89_ETSI][8] = 42, + [1][0][RTW89_MKK][8] = 50, + [1][0][RTW89_IC][8] = 78, + [1][0][RTW89_KCC][8] = 58, + [1][0][RTW89_ACMA][8] = 42, + [1][0][RTW89_CHILE][8] = 60, + [1][0][RTW89_UKRAINE][8] = 42, + [1][0][RTW89_MEXICO][8] = 78, + [1][0][RTW89_CN][8] = 42, + [1][0][RTW89_QATAR][8] = 42, + [1][0][RTW89_FCC][9] = 74, + [1][0][RTW89_ETSI][9] = 42, + [1][0][RTW89_MKK][9] = 50, + [1][0][RTW89_IC][9] = 74, + [1][0][RTW89_KCC][9] = 58, + [1][0][RTW89_ACMA][9] = 42, + [1][0][RTW89_CHILE][9] = 60, + [1][0][RTW89_UKRAINE][9] = 42, + [1][0][RTW89_MEXICO][9] = 74, + [1][0][RTW89_CN][9] = 42, + [1][0][RTW89_QATAR][9] = 42, + [1][0][RTW89_FCC][10] = 74, + [1][0][RTW89_ETSI][10] = 42, + [1][0][RTW89_MKK][10] = 50, + [1][0][RTW89_IC][10] = 74, + [1][0][RTW89_KCC][10] = 58, + [1][0][RTW89_ACMA][10] = 42, + [1][0][RTW89_CHILE][10] = 60, + [1][0][RTW89_UKRAINE][10] = 42, + [1][0][RTW89_MEXICO][10] = 74, + [1][0][RTW89_CN][10] = 42, + [1][0][RTW89_QATAR][10] = 42, + [1][0][RTW89_FCC][11] = 64, + [1][0][RTW89_ETSI][11] = 42, + [1][0][RTW89_MKK][11] = 50, + [1][0][RTW89_IC][11] = 64, + [1][0][RTW89_KCC][11] = 58, + [1][0][RTW89_ACMA][11] = 42, + [1][0][RTW89_CHILE][11] = 60, + [1][0][RTW89_UKRAINE][11] = 42, + [1][0][RTW89_MEXICO][11] = 64, + [1][0][RTW89_CN][11] = 42, + [1][0][RTW89_QATAR][11] = 42, + [1][0][RTW89_FCC][12] = 36, + [1][0][RTW89_ETSI][12] = 42, + [1][0][RTW89_MKK][12] = 50, + [1][0][RTW89_IC][12] = 36, + [1][0][RTW89_KCC][12] = 58, + [1][0][RTW89_ACMA][12] = 42, + [1][0][RTW89_CHILE][12] = 36, + [1][0][RTW89_UKRAINE][12] = 42, + [1][0][RTW89_MEXICO][12] = 36, + [1][0][RTW89_CN][12] = 42, + [1][0][RTW89_QATAR][12] = 42, + [1][0][RTW89_FCC][13] = 127, + [1][0][RTW89_ETSI][13] = 127, + [1][0][RTW89_MKK][13] = 127, + [1][0][RTW89_IC][13] = 127, + [1][0][RTW89_KCC][13] = 127, + [1][0][RTW89_ACMA][13] = 127, + [1][0][RTW89_CHILE][13] = 127, + [1][0][RTW89_UKRAINE][13] = 127, + [1][0][RTW89_MEXICO][13] = 127, + [1][0][RTW89_CN][13] = 127, + [1][0][RTW89_QATAR][13] = 127, + [1][1][RTW89_FCC][0] = 66, + [1][1][RTW89_ETSI][0] = 30, + [1][1][RTW89_MKK][0] = 38, + [1][1][RTW89_IC][0] = 66, + [1][1][RTW89_KCC][0] = 44, + [1][1][RTW89_ACMA][0] = 30, + [1][1][RTW89_CHILE][0] = 48, + [1][1][RTW89_UKRAINE][0] = 30, + [1][1][RTW89_MEXICO][0] = 66, + [1][1][RTW89_CN][0] = 30, + [1][1][RTW89_QATAR][0] = 30, + [1][1][RTW89_FCC][1] = 66, + [1][1][RTW89_ETSI][1] = 30, + [1][1][RTW89_MKK][1] = 38, + [1][1][RTW89_IC][1] = 66, + [1][1][RTW89_KCC][1] = 44, + [1][1][RTW89_ACMA][1] = 30, + [1][1][RTW89_CHILE][1] = 48, + [1][1][RTW89_UKRAINE][1] = 30, + [1][1][RTW89_MEXICO][1] = 66, + [1][1][RTW89_CN][1] = 30, + [1][1][RTW89_QATAR][1] = 30, + [1][1][RTW89_FCC][2] = 70, + [1][1][RTW89_ETSI][2] = 30, + [1][1][RTW89_MKK][2] = 38, + [1][1][RTW89_IC][2] = 70, + [1][1][RTW89_KCC][2] = 44, + [1][1][RTW89_ACMA][2] = 30, + [1][1][RTW89_CHILE][2] = 48, + [1][1][RTW89_UKRAINE][2] = 30, + [1][1][RTW89_MEXICO][2] = 70, + [1][1][RTW89_CN][2] = 30, + [1][1][RTW89_QATAR][2] = 30, + [1][1][RTW89_FCC][3] = 74, + [1][1][RTW89_ETSI][3] = 30, + [1][1][RTW89_MKK][3] = 38, + [1][1][RTW89_IC][3] = 74, + [1][1][RTW89_KCC][3] = 44, + [1][1][RTW89_ACMA][3] = 30, + [1][1][RTW89_CHILE][3] = 48, + [1][1][RTW89_UKRAINE][3] = 30, + [1][1][RTW89_MEXICO][3] = 74, + [1][1][RTW89_CN][3] = 30, + [1][1][RTW89_QATAR][3] = 30, + [1][1][RTW89_FCC][4] = 78, + [1][1][RTW89_ETSI][4] = 30, + [1][1][RTW89_MKK][4] = 38, + [1][1][RTW89_IC][4] = 78, + [1][1][RTW89_KCC][4] = 44, + [1][1][RTW89_ACMA][4] = 30, + [1][1][RTW89_CHILE][4] = 48, + [1][1][RTW89_UKRAINE][4] = 30, + [1][1][RTW89_MEXICO][4] = 78, + [1][1][RTW89_CN][4] = 30, + [1][1][RTW89_QATAR][4] = 30, + [1][1][RTW89_FCC][5] = 78, + [1][1][RTW89_ETSI][5] = 30, + [1][1][RTW89_MKK][5] = 38, + [1][1][RTW89_IC][5] = 78, + [1][1][RTW89_KCC][5] = 44, + [1][1][RTW89_ACMA][5] = 30, + [1][1][RTW89_CHILE][5] = 48, + [1][1][RTW89_UKRAINE][5] = 30, + [1][1][RTW89_MEXICO][5] = 78, + [1][1][RTW89_CN][5] = 30, + [1][1][RTW89_QATAR][5] = 30, + [1][1][RTW89_FCC][6] = 78, + [1][1][RTW89_ETSI][6] = 30, + [1][1][RTW89_MKK][6] = 38, + [1][1][RTW89_IC][6] = 78, + [1][1][RTW89_KCC][6] = 44, + [1][1][RTW89_ACMA][6] = 30, + [1][1][RTW89_CHILE][6] = 48, + [1][1][RTW89_UKRAINE][6] = 30, + [1][1][RTW89_MEXICO][6] = 78, + [1][1][RTW89_CN][6] = 30, + [1][1][RTW89_QATAR][6] = 30, + [1][1][RTW89_FCC][7] = 74, + [1][1][RTW89_ETSI][7] = 30, + [1][1][RTW89_MKK][7] = 38, + [1][1][RTW89_IC][7] = 74, + [1][1][RTW89_KCC][7] = 44, + [1][1][RTW89_ACMA][7] = 30, + [1][1][RTW89_CHILE][7] = 48, + [1][1][RTW89_UKRAINE][7] = 30, + [1][1][RTW89_MEXICO][7] = 74, + [1][1][RTW89_CN][7] = 30, + [1][1][RTW89_QATAR][7] = 30, + [1][1][RTW89_FCC][8] = 70, + [1][1][RTW89_ETSI][8] = 30, + [1][1][RTW89_MKK][8] = 38, + [1][1][RTW89_IC][8] = 70, + [1][1][RTW89_KCC][8] = 44, + [1][1][RTW89_ACMA][8] = 30, + [1][1][RTW89_CHILE][8] = 48, + [1][1][RTW89_UKRAINE][8] = 30, + [1][1][RTW89_MEXICO][8] = 70, + [1][1][RTW89_CN][8] = 30, + [1][1][RTW89_QATAR][8] = 30, + [1][1][RTW89_FCC][9] = 66, + [1][1][RTW89_ETSI][9] = 30, + [1][1][RTW89_MKK][9] = 38, + [1][1][RTW89_IC][9] = 66, + [1][1][RTW89_KCC][9] = 44, + [1][1][RTW89_ACMA][9] = 30, + [1][1][RTW89_CHILE][9] = 48, + [1][1][RTW89_UKRAINE][9] = 30, + [1][1][RTW89_MEXICO][9] = 66, + [1][1][RTW89_CN][9] = 30, + [1][1][RTW89_QATAR][9] = 30, + [1][1][RTW89_FCC][10] = 66, + [1][1][RTW89_ETSI][10] = 30, + [1][1][RTW89_MKK][10] = 38, + [1][1][RTW89_IC][10] = 66, + [1][1][RTW89_KCC][10] = 44, + [1][1][RTW89_ACMA][10] = 30, + [1][1][RTW89_CHILE][10] = 48, + [1][1][RTW89_UKRAINE][10] = 30, + [1][1][RTW89_MEXICO][10] = 66, + [1][1][RTW89_CN][10] = 30, + [1][1][RTW89_QATAR][10] = 30, + [1][1][RTW89_FCC][11] = 60, + [1][1][RTW89_ETSI][11] = 30, + [1][1][RTW89_MKK][11] = 38, + [1][1][RTW89_IC][11] = 60, + [1][1][RTW89_KCC][11] = 44, + [1][1][RTW89_ACMA][11] = 30, + [1][1][RTW89_CHILE][11] = 48, + [1][1][RTW89_UKRAINE][11] = 30, + [1][1][RTW89_MEXICO][11] = 60, + [1][1][RTW89_CN][11] = 30, + [1][1][RTW89_QATAR][11] = 30, + [1][1][RTW89_FCC][12] = 32, + [1][1][RTW89_ETSI][12] = 30, + [1][1][RTW89_MKK][12] = 38, + [1][1][RTW89_IC][12] = 32, + [1][1][RTW89_KCC][12] = 44, + [1][1][RTW89_ACMA][12] = 30, + [1][1][RTW89_CHILE][12] = 32, + [1][1][RTW89_UKRAINE][12] = 30, + [1][1][RTW89_MEXICO][12] = 32, + [1][1][RTW89_CN][12] = 30, + [1][1][RTW89_QATAR][12] = 30, + [1][1][RTW89_FCC][13] = 127, + [1][1][RTW89_ETSI][13] = 127, + [1][1][RTW89_MKK][13] = 127, + [1][1][RTW89_IC][13] = 127, + [1][1][RTW89_KCC][13] = 127, + [1][1][RTW89_ACMA][13] = 127, + [1][1][RTW89_CHILE][13] = 127, + [1][1][RTW89_UKRAINE][13] = 127, + [1][1][RTW89_MEXICO][13] = 127, + [1][1][RTW89_CN][13] = 127, + [1][1][RTW89_QATAR][13] = 127, + [2][0][RTW89_FCC][0] = 76, + [2][0][RTW89_ETSI][0] = 52, + [2][0][RTW89_MKK][0] = 64, + [2][0][RTW89_IC][0] = 76, + [2][0][RTW89_KCC][0] = 70, + [2][0][RTW89_ACMA][0] = 52, + [2][0][RTW89_CHILE][0] = 60, + [2][0][RTW89_UKRAINE][0] = 52, + [2][0][RTW89_MEXICO][0] = 76, + [2][0][RTW89_CN][0] = 52, + [2][0][RTW89_QATAR][0] = 52, + [2][0][RTW89_FCC][1] = 76, + [2][0][RTW89_ETSI][1] = 52, + [2][0][RTW89_MKK][1] = 64, + [2][0][RTW89_IC][1] = 76, + [2][0][RTW89_KCC][1] = 70, + [2][0][RTW89_ACMA][1] = 52, + [2][0][RTW89_CHILE][1] = 60, + [2][0][RTW89_UKRAINE][1] = 52, + [2][0][RTW89_MEXICO][1] = 76, + [2][0][RTW89_CN][1] = 52, + [2][0][RTW89_QATAR][1] = 52, + [2][0][RTW89_FCC][2] = 78, + [2][0][RTW89_ETSI][2] = 52, + [2][0][RTW89_MKK][2] = 64, + [2][0][RTW89_IC][2] = 78, + [2][0][RTW89_KCC][2] = 70, + [2][0][RTW89_ACMA][2] = 52, + [2][0][RTW89_CHILE][2] = 60, + [2][0][RTW89_UKRAINE][2] = 52, + [2][0][RTW89_MEXICO][2] = 78, + [2][0][RTW89_CN][2] = 52, + [2][0][RTW89_QATAR][2] = 52, + [2][0][RTW89_FCC][3] = 78, + [2][0][RTW89_ETSI][3] = 52, + [2][0][RTW89_MKK][3] = 64, + [2][0][RTW89_IC][3] = 78, + [2][0][RTW89_KCC][3] = 70, + [2][0][RTW89_ACMA][3] = 52, + [2][0][RTW89_CHILE][3] = 60, + [2][0][RTW89_UKRAINE][3] = 52, + [2][0][RTW89_MEXICO][3] = 78, + [2][0][RTW89_CN][3] = 52, + [2][0][RTW89_QATAR][3] = 52, + [2][0][RTW89_FCC][4] = 78, + [2][0][RTW89_ETSI][4] = 52, + [2][0][RTW89_MKK][4] = 64, + [2][0][RTW89_IC][4] = 78, + [2][0][RTW89_KCC][4] = 70, + [2][0][RTW89_ACMA][4] = 52, + [2][0][RTW89_CHILE][4] = 60, + [2][0][RTW89_UKRAINE][4] = 52, + [2][0][RTW89_MEXICO][4] = 78, + [2][0][RTW89_CN][4] = 52, + [2][0][RTW89_QATAR][4] = 52, + [2][0][RTW89_FCC][5] = 78, + [2][0][RTW89_ETSI][5] = 52, + [2][0][RTW89_MKK][5] = 64, + [2][0][RTW89_IC][5] = 78, + [2][0][RTW89_KCC][5] = 70, + [2][0][RTW89_ACMA][5] = 52, + [2][0][RTW89_CHILE][5] = 60, + [2][0][RTW89_UKRAINE][5] = 52, + [2][0][RTW89_MEXICO][5] = 78, + [2][0][RTW89_CN][5] = 52, + [2][0][RTW89_QATAR][5] = 52, + [2][0][RTW89_FCC][6] = 78, + [2][0][RTW89_ETSI][6] = 52, + [2][0][RTW89_MKK][6] = 64, + [2][0][RTW89_IC][6] = 78, + [2][0][RTW89_KCC][6] = 70, + [2][0][RTW89_ACMA][6] = 52, + [2][0][RTW89_CHILE][6] = 60, + [2][0][RTW89_UKRAINE][6] = 52, + [2][0][RTW89_MEXICO][6] = 78, + [2][0][RTW89_CN][6] = 52, + [2][0][RTW89_QATAR][6] = 52, + [2][0][RTW89_FCC][7] = 78, + [2][0][RTW89_ETSI][7] = 52, + [2][0][RTW89_MKK][7] = 64, + [2][0][RTW89_IC][7] = 78, + [2][0][RTW89_KCC][7] = 70, + [2][0][RTW89_ACMA][7] = 52, + [2][0][RTW89_CHILE][7] = 60, + [2][0][RTW89_UKRAINE][7] = 52, + [2][0][RTW89_MEXICO][7] = 78, + [2][0][RTW89_CN][7] = 52, + [2][0][RTW89_QATAR][7] = 52, + [2][0][RTW89_FCC][8] = 78, + [2][0][RTW89_ETSI][8] = 52, + [2][0][RTW89_MKK][8] = 64, + [2][0][RTW89_IC][8] = 78, + [2][0][RTW89_KCC][8] = 70, + [2][0][RTW89_ACMA][8] = 52, + [2][0][RTW89_CHILE][8] = 60, + [2][0][RTW89_UKRAINE][8] = 52, + [2][0][RTW89_MEXICO][8] = 78, + [2][0][RTW89_CN][8] = 52, + [2][0][RTW89_QATAR][8] = 52, + [2][0][RTW89_FCC][9] = 76, + [2][0][RTW89_ETSI][9] = 52, + [2][0][RTW89_MKK][9] = 64, + [2][0][RTW89_IC][9] = 76, + [2][0][RTW89_KCC][9] = 70, + [2][0][RTW89_ACMA][9] = 52, + [2][0][RTW89_CHILE][9] = 60, + [2][0][RTW89_UKRAINE][9] = 52, + [2][0][RTW89_MEXICO][9] = 76, + [2][0][RTW89_CN][9] = 52, + [2][0][RTW89_QATAR][9] = 52, + [2][0][RTW89_FCC][10] = 76, + [2][0][RTW89_ETSI][10] = 52, + [2][0][RTW89_MKK][10] = 64, + [2][0][RTW89_IC][10] = 76, + [2][0][RTW89_KCC][10] = 70, + [2][0][RTW89_ACMA][10] = 52, + [2][0][RTW89_CHILE][10] = 60, + [2][0][RTW89_UKRAINE][10] = 52, + [2][0][RTW89_MEXICO][10] = 76, + [2][0][RTW89_CN][10] = 52, + [2][0][RTW89_QATAR][10] = 52, + [2][0][RTW89_FCC][11] = 68, + [2][0][RTW89_ETSI][11] = 52, + [2][0][RTW89_MKK][11] = 64, + [2][0][RTW89_IC][11] = 68, + [2][0][RTW89_KCC][11] = 70, + [2][0][RTW89_ACMA][11] = 52, + [2][0][RTW89_CHILE][11] = 60, + [2][0][RTW89_UKRAINE][11] = 52, + [2][0][RTW89_MEXICO][11] = 68, + [2][0][RTW89_CN][11] = 52, + [2][0][RTW89_QATAR][11] = 52, + [2][0][RTW89_FCC][12] = 40, + [2][0][RTW89_ETSI][12] = 52, + [2][0][RTW89_MKK][12] = 64, + [2][0][RTW89_IC][12] = 40, + [2][0][RTW89_KCC][12] = 70, + [2][0][RTW89_ACMA][12] = 52, + [2][0][RTW89_CHILE][12] = 40, + [2][0][RTW89_UKRAINE][12] = 52, + [2][0][RTW89_MEXICO][12] = 40, + [2][0][RTW89_CN][12] = 52, + [2][0][RTW89_QATAR][12] = 52, + [2][0][RTW89_FCC][13] = 127, + [2][0][RTW89_ETSI][13] = 127, + [2][0][RTW89_MKK][13] = 127, + [2][0][RTW89_IC][13] = 127, + [2][0][RTW89_KCC][13] = 127, + [2][0][RTW89_ACMA][13] = 127, + [2][0][RTW89_CHILE][13] = 127, + [2][0][RTW89_UKRAINE][13] = 127, + [2][0][RTW89_MEXICO][13] = 127, + [2][0][RTW89_CN][13] = 127, + [2][0][RTW89_QATAR][13] = 127, + [2][1][RTW89_FCC][0] = 68, + [2][1][RTW89_ETSI][0] = 40, + [2][1][RTW89_MKK][0] = 52, + [2][1][RTW89_IC][0] = 68, + [2][1][RTW89_KCC][0] = 56, + [2][1][RTW89_ACMA][0] = 40, + [2][1][RTW89_CHILE][0] = 48, + [2][1][RTW89_UKRAINE][0] = 40, + [2][1][RTW89_MEXICO][0] = 68, + [2][1][RTW89_CN][0] = 40, + [2][1][RTW89_QATAR][0] = 40, + [2][1][RTW89_FCC][1] = 68, + [2][1][RTW89_ETSI][1] = 40, + [2][1][RTW89_MKK][1] = 52, + [2][1][RTW89_IC][1] = 68, + [2][1][RTW89_KCC][1] = 56, + [2][1][RTW89_ACMA][1] = 40, + [2][1][RTW89_CHILE][1] = 48, + [2][1][RTW89_UKRAINE][1] = 40, + [2][1][RTW89_MEXICO][1] = 68, + [2][1][RTW89_CN][1] = 40, + [2][1][RTW89_QATAR][1] = 40, + [2][1][RTW89_FCC][2] = 72, + [2][1][RTW89_ETSI][2] = 40, + [2][1][RTW89_MKK][2] = 52, + [2][1][RTW89_IC][2] = 72, + [2][1][RTW89_KCC][2] = 56, + [2][1][RTW89_ACMA][2] = 40, + [2][1][RTW89_CHILE][2] = 48, + [2][1][RTW89_UKRAINE][2] = 40, + [2][1][RTW89_MEXICO][2] = 72, + [2][1][RTW89_CN][2] = 40, + [2][1][RTW89_QATAR][2] = 40, + [2][1][RTW89_FCC][3] = 76, + [2][1][RTW89_ETSI][3] = 40, + [2][1][RTW89_MKK][3] = 52, + [2][1][RTW89_IC][3] = 76, + [2][1][RTW89_KCC][3] = 56, + [2][1][RTW89_ACMA][3] = 40, + [2][1][RTW89_CHILE][3] = 48, + [2][1][RTW89_UKRAINE][3] = 40, + [2][1][RTW89_MEXICO][3] = 76, + [2][1][RTW89_CN][3] = 40, + [2][1][RTW89_QATAR][3] = 40, + [2][1][RTW89_FCC][4] = 78, + [2][1][RTW89_ETSI][4] = 40, + [2][1][RTW89_MKK][4] = 52, + [2][1][RTW89_IC][4] = 78, + [2][1][RTW89_KCC][4] = 56, + [2][1][RTW89_ACMA][4] = 40, + [2][1][RTW89_CHILE][4] = 48, + [2][1][RTW89_UKRAINE][4] = 40, + [2][1][RTW89_MEXICO][4] = 78, + [2][1][RTW89_CN][4] = 40, + [2][1][RTW89_QATAR][4] = 40, + [2][1][RTW89_FCC][5] = 78, + [2][1][RTW89_ETSI][5] = 40, + [2][1][RTW89_MKK][5] = 52, + [2][1][RTW89_IC][5] = 78, + [2][1][RTW89_KCC][5] = 56, + [2][1][RTW89_ACMA][5] = 40, + [2][1][RTW89_CHILE][5] = 48, + [2][1][RTW89_UKRAINE][5] = 40, + [2][1][RTW89_MEXICO][5] = 78, + [2][1][RTW89_CN][5] = 40, + [2][1][RTW89_QATAR][5] = 40, + [2][1][RTW89_FCC][6] = 78, + [2][1][RTW89_ETSI][6] = 40, + [2][1][RTW89_MKK][6] = 52, + [2][1][RTW89_IC][6] = 78, + [2][1][RTW89_KCC][6] = 56, + [2][1][RTW89_ACMA][6] = 40, + [2][1][RTW89_CHILE][6] = 48, + [2][1][RTW89_UKRAINE][6] = 40, + [2][1][RTW89_MEXICO][6] = 78, + [2][1][RTW89_CN][6] = 40, + [2][1][RTW89_QATAR][6] = 40, + [2][1][RTW89_FCC][7] = 78, + [2][1][RTW89_ETSI][7] = 40, + [2][1][RTW89_MKK][7] = 52, + [2][1][RTW89_IC][7] = 78, + [2][1][RTW89_KCC][7] = 56, + [2][1][RTW89_ACMA][7] = 40, + [2][1][RTW89_CHILE][7] = 48, + [2][1][RTW89_UKRAINE][7] = 40, + [2][1][RTW89_MEXICO][7] = 78, + [2][1][RTW89_CN][7] = 40, + [2][1][RTW89_QATAR][7] = 40, + [2][1][RTW89_FCC][8] = 74, + [2][1][RTW89_ETSI][8] = 40, + [2][1][RTW89_MKK][8] = 52, + [2][1][RTW89_IC][8] = 74, + [2][1][RTW89_KCC][8] = 56, + [2][1][RTW89_ACMA][8] = 40, + [2][1][RTW89_CHILE][8] = 48, + [2][1][RTW89_UKRAINE][8] = 40, + [2][1][RTW89_MEXICO][8] = 74, + [2][1][RTW89_CN][8] = 40, + [2][1][RTW89_QATAR][8] = 40, + [2][1][RTW89_FCC][9] = 70, + [2][1][RTW89_ETSI][9] = 40, + [2][1][RTW89_MKK][9] = 52, + [2][1][RTW89_IC][9] = 70, + [2][1][RTW89_KCC][9] = 56, + [2][1][RTW89_ACMA][9] = 40, + [2][1][RTW89_CHILE][9] = 48, + [2][1][RTW89_UKRAINE][9] = 40, + [2][1][RTW89_MEXICO][9] = 70, + [2][1][RTW89_CN][9] = 40, + [2][1][RTW89_QATAR][9] = 40, + [2][1][RTW89_FCC][10] = 70, + [2][1][RTW89_ETSI][10] = 40, + [2][1][RTW89_MKK][10] = 52, + [2][1][RTW89_IC][10] = 70, + [2][1][RTW89_KCC][10] = 56, + [2][1][RTW89_ACMA][10] = 40, + [2][1][RTW89_CHILE][10] = 48, + [2][1][RTW89_UKRAINE][10] = 40, + [2][1][RTW89_MEXICO][10] = 70, + [2][1][RTW89_CN][10] = 40, + [2][1][RTW89_QATAR][10] = 40, + [2][1][RTW89_FCC][11] = 48, + [2][1][RTW89_ETSI][11] = 40, + [2][1][RTW89_MKK][11] = 52, + [2][1][RTW89_IC][11] = 48, + [2][1][RTW89_KCC][11] = 56, + [2][1][RTW89_ACMA][11] = 40, + [2][1][RTW89_CHILE][11] = 48, + [2][1][RTW89_UKRAINE][11] = 40, + [2][1][RTW89_MEXICO][11] = 48, + [2][1][RTW89_CN][11] = 40, + [2][1][RTW89_QATAR][11] = 40, + [2][1][RTW89_FCC][12] = 26, + [2][1][RTW89_ETSI][12] = 40, + [2][1][RTW89_MKK][12] = 52, + [2][1][RTW89_IC][12] = 26, + [2][1][RTW89_KCC][12] = 56, + [2][1][RTW89_ACMA][12] = 40, + [2][1][RTW89_CHILE][12] = 26, + [2][1][RTW89_UKRAINE][12] = 40, + [2][1][RTW89_MEXICO][12] = 26, + [2][1][RTW89_CN][12] = 40, + [2][1][RTW89_QATAR][12] = 40, + [2][1][RTW89_FCC][13] = 127, + [2][1][RTW89_ETSI][13] = 127, + [2][1][RTW89_MKK][13] = 127, + [2][1][RTW89_IC][13] = 127, + [2][1][RTW89_KCC][13] = 127, + [2][1][RTW89_ACMA][13] = 127, + [2][1][RTW89_CHILE][13] = 127, + [2][1][RTW89_UKRAINE][13] = 127, + [2][1][RTW89_MEXICO][13] = 127, + [2][1][RTW89_CN][13] = 127, + [2][1][RTW89_QATAR][13] = 127, }; const s8 rtw89_8852a_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [RTW89_REGD_NUM][RTW89_5G_CH_NUM] = { - [0][0][0][0] = 22, - [0][0][0][2] = 22, - [0][0][0][4] = 22, - [0][0][0][6] = 22, - [0][0][0][8] = 24, - [0][0][0][10] = 24, - [0][0][0][12] = 24, - [0][0][0][14] = 24, - [0][0][0][15] = 24, - [0][0][0][17] = 24, - [0][0][0][19] = 24, - [0][0][0][21] = 24, - [0][0][0][23] = 24, - [0][0][0][25] = 24, - [0][0][0][27] = 24, - [0][0][0][29] = 24, - [0][0][0][31] = 24, - [0][0][0][33] = 24, - [0][0][0][35] = 24, - [0][0][0][37] = 24, - [0][0][0][38] = 28, - [0][0][0][40] = 28, - [0][0][0][42] = 28, - [0][0][0][44] = 28, - [0][0][0][46] = 28, - [0][1][0][0] = 8, - [0][1][0][2] = 8, - [0][1][0][4] = 8, - [0][1][0][6] = 8, - [0][1][0][8] = 12, - [0][1][0][10] = 12, - [0][1][0][12] = 12, - [0][1][0][14] = 12, - [0][1][0][15] = 12, - [0][1][0][17] = 12, - [0][1][0][19] = 12, - [0][1][0][21] = 12, - [0][1][0][23] = 12, - [0][1][0][25] = 12, - [0][1][0][27] = 12, - [0][1][0][29] = 12, - [0][1][0][31] = 12, - [0][1][0][33] = 12, - [0][1][0][35] = 12, - [0][1][0][37] = 12, - [0][1][0][38] = 16, - [0][1][0][40] = 16, - [0][1][0][42] = 16, - [0][1][0][44] = 16, - [0][1][0][46] = 16, - [1][0][0][0] = 30, - [1][0][0][2] = 30, - [1][0][0][4] = 30, - [1][0][0][6] = 30, - [1][0][0][8] = 36, - [1][0][0][10] = 36, - [1][0][0][12] = 36, - [1][0][0][14] = 36, - [1][0][0][15] = 36, - [1][0][0][17] = 36, - [1][0][0][19] = 36, - [1][0][0][21] = 36, - [1][0][0][23] = 36, - [1][0][0][25] = 36, - [1][0][0][27] = 36, - [1][0][0][29] = 36, - [1][0][0][31] = 36, - [1][0][0][33] = 36, - [1][0][0][35] = 36, - [1][0][0][37] = 36, - [1][0][0][38] = 28, - [1][0][0][40] = 28, - [1][0][0][42] = 28, - [1][0][0][44] = 28, - [1][0][0][46] = 28, - [1][1][0][0] = 18, - [1][1][0][2] = 18, - [1][1][0][4] = 18, - [1][1][0][6] = 18, - [1][1][0][8] = 22, - [1][1][0][10] = 22, - [1][1][0][12] = 22, - [1][1][0][14] = 22, - [1][1][0][15] = 22, - [1][1][0][17] = 22, - [1][1][0][19] = 22, - [1][1][0][21] = 22, - [1][1][0][23] = 22, - [1][1][0][25] = 22, - [1][1][0][27] = 22, - [1][1][0][29] = 22, - [1][1][0][31] = 22, - [1][1][0][33] = 22, - [1][1][0][35] = 22, - [1][1][0][37] = 22, - [1][1][0][38] = 16, - [1][1][0][40] = 16, - [1][1][0][42] = 16, - [1][1][0][44] = 16, - [1][1][0][46] = 16, - [2][0][0][0] = 30, - [2][0][0][2] = 30, - [2][0][0][4] = 30, - [2][0][0][6] = 30, - [2][0][0][8] = 46, - [2][0][0][10] = 46, - [2][0][0][12] = 46, - [2][0][0][14] = 46, - [2][0][0][15] = 46, - [2][0][0][17] = 46, - [2][0][0][19] = 46, - [2][0][0][21] = 46, - [2][0][0][23] = 46, - [2][0][0][25] = 46, - [2][0][0][27] = 46, - [2][0][0][29] = 46, - [2][0][0][31] = 46, - [2][0][0][33] = 46, - [2][0][0][35] = 46, - [2][0][0][37] = 46, - [2][0][0][38] = 28, - [2][0][0][40] = 28, - [2][0][0][42] = 28, - [2][0][0][44] = 28, - [2][0][0][46] = 28, - [2][1][0][0] = 18, - [2][1][0][2] = 18, - [2][1][0][4] = 18, - [2][1][0][6] = 18, - [2][1][0][8] = 32, - [2][1][0][10] = 32, - [2][1][0][12] = 32, - [2][1][0][14] = 32, - [2][1][0][15] = 32, - [2][1][0][17] = 32, - [2][1][0][19] = 32, - [2][1][0][21] = 32, - [2][1][0][23] = 32, - [2][1][0][25] = 32, - [2][1][0][27] = 32, - [2][1][0][29] = 32, - [2][1][0][31] = 32, - [2][1][0][33] = 32, - [2][1][0][35] = 32, - [2][1][0][37] = 32, - [2][1][0][38] = 16, - [2][1][0][40] = 16, - [2][1][0][42] = 16, - [2][1][0][44] = 16, - [2][1][0][46] = 16, - [0][0][2][0] = 48, - [0][0][1][0] = 24, - [0][0][3][0] = 26, - [0][0][5][0] = 22, - [0][0][6][0] = 24, - [0][0][9][0] = 24, - [0][0][8][0] = 30, - [0][0][11][0] = 24, - [0][0][2][2] = 48, - [0][0][1][2] = 24, - [0][0][3][2] = 26, - [0][0][5][2] = 22, - [0][0][6][2] = 24, - [0][0][9][2] = 24, - [0][0][8][2] = 30, - [0][0][11][2] = 24, - [0][0][2][4] = 48, - [0][0][1][4] = 24, - [0][0][3][4] = 26, - [0][0][5][4] = 22, - [0][0][6][4] = 24, - [0][0][9][4] = 24, - [0][0][8][4] = 30, - [0][0][11][4] = 24, - [0][0][2][6] = 48, - [0][0][1][6] = 24, - [0][0][3][6] = 26, - [0][0][5][6] = 22, - [0][0][6][6] = 24, - [0][0][9][6] = 24, - [0][0][8][6] = 30, - [0][0][11][6] = 24, - [0][0][2][8] = 48, - [0][0][1][8] = 24, - [0][0][3][8] = 26, - [0][0][5][8] = 48, - [0][0][6][8] = 24, - [0][0][9][8] = 24, - [0][0][8][8] = 54, - [0][0][11][8] = 24, - [0][0][2][10] = 48, - [0][0][1][10] = 24, - [0][0][3][10] = 26, - [0][0][5][10] = 48, - [0][0][6][10] = 24, - [0][0][9][10] = 24, - [0][0][8][10] = 54, - [0][0][11][10] = 24, - [0][0][2][12] = 48, - [0][0][1][12] = 24, - [0][0][3][12] = 26, - [0][0][5][12] = 48, - [0][0][6][12] = 24, - [0][0][9][12] = 24, - [0][0][8][12] = 54, - [0][0][11][12] = 24, - [0][0][2][14] = 48, - [0][0][1][14] = 24, - [0][0][3][14] = 26, - [0][0][5][14] = 48, - [0][0][6][14] = 24, - [0][0][9][14] = 24, - [0][0][8][14] = 54, - [0][0][11][14] = 24, - [0][0][2][15] = 48, - [0][0][1][15] = 24, - [0][0][3][15] = 44, - [0][0][5][15] = 48, - [0][0][6][15] = 24, - [0][0][9][15] = 24, - [0][0][8][15] = 54, - [0][0][11][15] = 24, - [0][0][2][17] = 48, - [0][0][1][17] = 24, - [0][0][3][17] = 44, - [0][0][5][17] = 48, - [0][0][6][17] = 24, - [0][0][9][17] = 24, - [0][0][8][17] = 54, - [0][0][11][17] = 24, - [0][0][2][19] = 48, - [0][0][1][19] = 24, - [0][0][3][19] = 44, - [0][0][5][19] = 48, - [0][0][6][19] = 24, - [0][0][9][19] = 24, - [0][0][8][19] = 54, - [0][0][11][19] = 24, - [0][0][2][21] = 48, - [0][0][1][21] = 24, - [0][0][3][21] = 44, - [0][0][5][21] = 48, - [0][0][6][21] = 24, - [0][0][9][21] = 24, - [0][0][8][21] = 54, - [0][0][11][21] = 24, - [0][0][2][23] = 48, - [0][0][1][23] = 24, - [0][0][3][23] = 44, - [0][0][5][23] = 48, - [0][0][6][23] = 24, - [0][0][9][23] = 24, - [0][0][8][23] = 54, - [0][0][11][23] = 24, - [0][0][2][25] = 48, - [0][0][1][25] = 24, - [0][0][3][25] = 44, - [0][0][5][25] = 127, - [0][0][6][25] = 24, - [0][0][9][25] = 127, - [0][0][8][25] = 54, - [0][0][11][25] = 24, - [0][0][2][27] = 48, - [0][0][1][27] = 24, - [0][0][3][27] = 44, - [0][0][5][27] = 127, - [0][0][6][27] = 24, - [0][0][9][27] = 127, - [0][0][8][27] = 54, - [0][0][11][27] = 24, - [0][0][2][29] = 48, - [0][0][1][29] = 24, - [0][0][3][29] = 44, - [0][0][5][29] = 127, - [0][0][6][29] = 24, - [0][0][9][29] = 127, - [0][0][8][29] = 54, - [0][0][11][29] = 24, - [0][0][2][31] = 48, - [0][0][1][31] = 24, - [0][0][3][31] = 44, - [0][0][5][31] = 48, - [0][0][6][31] = 24, - [0][0][9][31] = 24, - [0][0][8][31] = 54, - [0][0][11][31] = 24, - [0][0][2][33] = 48, - [0][0][1][33] = 24, - [0][0][3][33] = 44, - [0][0][5][33] = 48, - [0][0][6][33] = 24, - [0][0][9][33] = 24, - [0][0][8][33] = 54, - [0][0][11][33] = 24, - [0][0][2][35] = 48, - [0][0][1][35] = 24, - [0][0][3][35] = 44, - [0][0][5][35] = 48, - [0][0][6][35] = 24, - [0][0][9][35] = 24, - [0][0][8][35] = 54, - [0][0][11][35] = 24, - [0][0][2][37] = 48, - [0][0][1][37] = 127, - [0][0][3][37] = 44, - [0][0][5][37] = 48, - [0][0][6][37] = 24, - [0][0][9][37] = 48, - [0][0][8][37] = 54, - [0][0][11][37] = 127, - [0][0][2][38] = 76, - [0][0][1][38] = 28, - [0][0][3][38] = 127, - [0][0][5][38] = 76, - [0][0][6][38] = 28, - [0][0][9][38] = 76, - [0][0][8][38] = 54, - [0][0][11][38] = 28, - [0][0][2][40] = 76, - [0][0][1][40] = 28, - [0][0][3][40] = 127, - [0][0][5][40] = 76, - [0][0][6][40] = 28, - [0][0][9][40] = 76, - [0][0][8][40] = 54, - [0][0][11][40] = 28, - [0][0][2][42] = 76, - [0][0][1][42] = 28, - [0][0][3][42] = 127, - [0][0][5][42] = 76, - [0][0][6][42] = 28, - [0][0][9][42] = 76, - [0][0][8][42] = 54, - [0][0][11][42] = 28, - [0][0][2][44] = 76, - [0][0][1][44] = 28, - [0][0][3][44] = 127, - [0][0][5][44] = 76, - [0][0][6][44] = 28, - [0][0][9][44] = 76, - [0][0][8][44] = 54, - [0][0][11][44] = 28, - [0][0][2][46] = 76, - [0][0][1][46] = 28, - [0][0][3][46] = 127, - [0][0][5][46] = 76, - [0][0][6][46] = 28, - [0][0][9][46] = 76, - [0][0][8][46] = 54, - [0][0][11][46] = 28, - [0][1][2][0] = 36, - [0][1][1][0] = 12, - [0][1][3][0] = 14, - [0][1][5][0] = 8, - [0][1][6][0] = 12, - [0][1][9][0] = 12, - [0][1][8][0] = 18, - [0][1][11][0] = 12, - [0][1][2][2] = 36, - [0][1][1][2] = 12, - [0][1][3][2] = 14, - [0][1][5][2] = 8, - [0][1][6][2] = 12, - [0][1][9][2] = 12, - [0][1][8][2] = 18, - [0][1][11][2] = 12, - [0][1][2][4] = 36, - [0][1][1][4] = 12, - [0][1][3][4] = 14, - [0][1][5][4] = 8, - [0][1][6][4] = 12, - [0][1][9][4] = 12, - [0][1][8][4] = 18, - [0][1][11][4] = 12, - [0][1][2][6] = 36, - [0][1][1][6] = 12, - [0][1][3][6] = 14, - [0][1][5][6] = 8, - [0][1][6][6] = 12, - [0][1][9][6] = 12, - [0][1][8][6] = 18, - [0][1][11][6] = 12, - [0][1][2][8] = 36, - [0][1][1][8] = 12, - [0][1][3][8] = 14, - [0][1][5][8] = 36, - [0][1][6][8] = 12, - [0][1][9][8] = 12, - [0][1][8][8] = 42, - [0][1][11][8] = 12, - [0][1][2][10] = 36, - [0][1][1][10] = 12, - [0][1][3][10] = 14, - [0][1][5][10] = 36, - [0][1][6][10] = 12, - [0][1][9][10] = 12, - [0][1][8][10] = 42, - [0][1][11][10] = 12, - [0][1][2][12] = 36, - [0][1][1][12] = 12, - [0][1][3][12] = 14, - [0][1][5][12] = 36, - [0][1][6][12] = 12, - [0][1][9][12] = 12, - [0][1][8][12] = 42, - [0][1][11][12] = 12, - [0][1][2][14] = 36, - [0][1][1][14] = 12, - [0][1][3][14] = 14, - [0][1][5][14] = 36, - [0][1][6][14] = 12, - [0][1][9][14] = 12, - [0][1][8][14] = 42, - [0][1][11][14] = 12, - [0][1][2][15] = 36, - [0][1][1][15] = 12, - [0][1][3][15] = 32, - [0][1][5][15] = 36, - [0][1][6][15] = 12, - [0][1][9][15] = 12, - [0][1][8][15] = 42, - [0][1][11][15] = 12, - [0][1][2][17] = 36, - [0][1][1][17] = 12, - [0][1][3][17] = 32, - [0][1][5][17] = 36, - [0][1][6][17] = 12, - [0][1][9][17] = 12, - [0][1][8][17] = 42, - [0][1][11][17] = 12, - [0][1][2][19] = 36, - [0][1][1][19] = 12, - [0][1][3][19] = 32, - [0][1][5][19] = 36, - [0][1][6][19] = 12, - [0][1][9][19] = 12, - [0][1][8][19] = 42, - [0][1][11][19] = 12, - [0][1][2][21] = 36, - [0][1][1][21] = 12, - [0][1][3][21] = 32, - [0][1][5][21] = 36, - [0][1][6][21] = 12, - [0][1][9][21] = 12, - [0][1][8][21] = 42, - [0][1][11][21] = 12, - [0][1][2][23] = 36, - [0][1][1][23] = 12, - [0][1][3][23] = 32, - [0][1][5][23] = 36, - [0][1][6][23] = 12, - [0][1][9][23] = 12, - [0][1][8][23] = 42, - [0][1][11][23] = 12, - [0][1][2][25] = 36, - [0][1][1][25] = 12, - [0][1][3][25] = 32, - [0][1][5][25] = 127, - [0][1][6][25] = 12, - [0][1][9][25] = 127, - [0][1][8][25] = 42, - [0][1][11][25] = 12, - [0][1][2][27] = 36, - [0][1][1][27] = 12, - [0][1][3][27] = 32, - [0][1][5][27] = 127, - [0][1][6][27] = 12, - [0][1][9][27] = 127, - [0][1][8][27] = 42, - [0][1][11][27] = 12, - [0][1][2][29] = 36, - [0][1][1][29] = 12, - [0][1][3][29] = 32, - [0][1][5][29] = 127, - [0][1][6][29] = 12, - [0][1][9][29] = 127, - [0][1][8][29] = 42, - [0][1][11][29] = 12, - [0][1][2][31] = 36, - [0][1][1][31] = 12, - [0][1][3][31] = 32, - [0][1][5][31] = 36, - [0][1][6][31] = 12, - [0][1][9][31] = 12, - [0][1][8][31] = 42, - [0][1][11][31] = 12, - [0][1][2][33] = 36, - [0][1][1][33] = 12, - [0][1][3][33] = 32, - [0][1][5][33] = 36, - [0][1][6][33] = 12, - [0][1][9][33] = 12, - [0][1][8][33] = 42, - [0][1][11][33] = 12, - [0][1][2][35] = 36, - [0][1][1][35] = 12, - [0][1][3][35] = 32, - [0][1][5][35] = 36, - [0][1][6][35] = 12, - [0][1][9][35] = 12, - [0][1][8][35] = 42, - [0][1][11][35] = 12, - [0][1][2][37] = 36, - [0][1][1][37] = 127, - [0][1][3][37] = 32, - [0][1][5][37] = 36, - [0][1][6][37] = 12, - [0][1][9][37] = 36, - [0][1][8][37] = 42, - [0][1][11][37] = 127, - [0][1][2][38] = 72, - [0][1][1][38] = 16, - [0][1][3][38] = 127, - [0][1][5][38] = 72, - [0][1][6][38] = 16, - [0][1][9][38] = 76, - [0][1][8][38] = 42, - [0][1][11][38] = 16, - [0][1][2][40] = 76, - [0][1][1][40] = 16, - [0][1][3][40] = 127, - [0][1][5][40] = 76, - [0][1][6][40] = 16, - [0][1][9][40] = 76, - [0][1][8][40] = 42, - [0][1][11][40] = 16, - [0][1][2][42] = 76, - [0][1][1][42] = 16, - [0][1][3][42] = 127, - [0][1][5][42] = 76, - [0][1][6][42] = 16, - [0][1][9][42] = 76, - [0][1][8][42] = 42, - [0][1][11][42] = 16, - [0][1][2][44] = 76, - [0][1][1][44] = 16, - [0][1][3][44] = 127, - [0][1][5][44] = 76, - [0][1][6][44] = 16, - [0][1][9][44] = 76, - [0][1][8][44] = 42, - [0][1][11][44] = 16, - [0][1][2][46] = 76, - [0][1][1][46] = 16, - [0][1][3][46] = 127, - [0][1][5][46] = 76, - [0][1][6][46] = 16, - [0][1][9][46] = 76, - [0][1][8][46] = 42, - [0][1][11][46] = 16, - [1][0][2][0] = 62, - [1][0][1][0] = 36, - [1][0][3][0] = 36, - [1][0][5][0] = 34, - [1][0][6][0] = 36, - [1][0][9][0] = 36, - [1][0][8][0] = 30, - [1][0][11][0] = 36, - [1][0][2][2] = 62, - [1][0][1][2] = 36, - [1][0][3][2] = 36, - [1][0][5][2] = 34, - [1][0][6][2] = 36, - [1][0][9][2] = 36, - [1][0][8][2] = 30, - [1][0][11][2] = 36, - [1][0][2][4] = 62, - [1][0][1][4] = 36, - [1][0][3][4] = 36, - [1][0][5][4] = 34, - [1][0][6][4] = 36, - [1][0][9][4] = 36, - [1][0][8][4] = 30, - [1][0][11][4] = 36, - [1][0][2][6] = 62, - [1][0][1][6] = 36, - [1][0][3][6] = 36, - [1][0][5][6] = 34, - [1][0][6][6] = 36, - [1][0][9][6] = 36, - [1][0][8][6] = 30, - [1][0][11][6] = 36, - [1][0][2][8] = 62, - [1][0][1][8] = 36, - [1][0][3][8] = 36, - [1][0][5][8] = 62, - [1][0][6][8] = 36, - [1][0][9][8] = 36, - [1][0][8][8] = 54, - [1][0][11][8] = 36, - [1][0][2][10] = 62, - [1][0][1][10] = 36, - [1][0][3][10] = 36, - [1][0][5][10] = 62, - [1][0][6][10] = 36, - [1][0][9][10] = 36, - [1][0][8][10] = 54, - [1][0][11][10] = 36, - [1][0][2][12] = 62, - [1][0][1][12] = 36, - [1][0][3][12] = 36, - [1][0][5][12] = 62, - [1][0][6][12] = 36, - [1][0][9][12] = 36, - [1][0][8][12] = 54, - [1][0][11][12] = 36, - [1][0][2][14] = 62, - [1][0][1][14] = 36, - [1][0][3][14] = 36, - [1][0][5][14] = 62, - [1][0][6][14] = 36, - [1][0][9][14] = 36, - [1][0][8][14] = 54, - [1][0][11][14] = 36, - [1][0][2][15] = 62, - [1][0][1][15] = 36, - [1][0][3][15] = 58, - [1][0][5][15] = 62, - [1][0][6][15] = 36, - [1][0][9][15] = 36, - [1][0][8][15] = 54, - [1][0][11][15] = 36, - [1][0][2][17] = 62, - [1][0][1][17] = 36, - [1][0][3][17] = 58, - [1][0][5][17] = 62, - [1][0][6][17] = 36, - [1][0][9][17] = 36, - [1][0][8][17] = 54, - [1][0][11][17] = 36, - [1][0][2][19] = 62, - [1][0][1][19] = 36, - [1][0][3][19] = 58, - [1][0][5][19] = 62, - [1][0][6][19] = 36, - [1][0][9][19] = 36, - [1][0][8][19] = 54, - [1][0][11][19] = 36, - [1][0][2][21] = 62, - [1][0][1][21] = 36, - [1][0][3][21] = 58, - [1][0][5][21] = 62, - [1][0][6][21] = 36, - [1][0][9][21] = 36, - [1][0][8][21] = 54, - [1][0][11][21] = 36, - [1][0][2][23] = 62, - [1][0][1][23] = 36, - [1][0][3][23] = 58, - [1][0][5][23] = 62, - [1][0][6][23] = 36, - [1][0][9][23] = 36, - [1][0][8][23] = 54, - [1][0][11][23] = 36, - [1][0][2][25] = 62, - [1][0][1][25] = 36, - [1][0][3][25] = 58, - [1][0][5][25] = 127, - [1][0][6][25] = 36, - [1][0][9][25] = 127, - [1][0][8][25] = 54, - [1][0][11][25] = 36, - [1][0][2][27] = 62, - [1][0][1][27] = 36, - [1][0][3][27] = 58, - [1][0][5][27] = 127, - [1][0][6][27] = 36, - [1][0][9][27] = 127, - [1][0][8][27] = 54, - [1][0][11][27] = 36, - [1][0][2][29] = 62, - [1][0][1][29] = 36, - [1][0][3][29] = 58, - [1][0][5][29] = 127, - [1][0][6][29] = 36, - [1][0][9][29] = 127, - [1][0][8][29] = 54, - [1][0][11][29] = 36, - [1][0][2][31] = 62, - [1][0][1][31] = 36, - [1][0][3][31] = 58, - [1][0][5][31] = 62, - [1][0][6][31] = 36, - [1][0][9][31] = 36, - [1][0][8][31] = 54, - [1][0][11][31] = 36, - [1][0][2][33] = 62, - [1][0][1][33] = 36, - [1][0][3][33] = 58, - [1][0][5][33] = 62, - [1][0][6][33] = 36, - [1][0][9][33] = 36, - [1][0][8][33] = 54, - [1][0][11][33] = 36, - [1][0][2][35] = 62, - [1][0][1][35] = 36, - [1][0][3][35] = 58, - [1][0][5][35] = 62, - [1][0][6][35] = 36, - [1][0][9][35] = 36, - [1][0][8][35] = 54, - [1][0][11][35] = 36, - [1][0][2][37] = 56, - [1][0][1][37] = 62, - [1][0][3][37] = 127, - [1][0][5][37] = 58, - [1][0][6][37] = 62, - [1][0][9][37] = 36, - [1][0][8][37] = 62, - [1][0][11][37] = 54, - [1][0][2][38] = 76, - [1][0][1][38] = 28, - [1][0][3][38] = 127, - [1][0][5][38] = 76, - [1][0][6][38] = 28, - [1][0][9][38] = 76, - [1][0][8][38] = 54, - [1][0][11][38] = 28, - [1][0][2][40] = 76, - [1][0][1][40] = 28, - [1][0][3][40] = 127, - [1][0][5][40] = 76, - [1][0][6][40] = 28, - [1][0][9][40] = 76, - [1][0][8][40] = 54, - [1][0][11][40] = 28, - [1][0][2][42] = 76, - [1][0][1][42] = 28, - [1][0][3][42] = 127, - [1][0][5][42] = 76, - [1][0][6][42] = 28, - [1][0][9][42] = 76, - [1][0][8][42] = 54, - [1][0][11][42] = 28, - [1][0][2][44] = 76, - [1][0][1][44] = 28, - [1][0][3][44] = 127, - [1][0][5][44] = 76, - [1][0][6][44] = 28, - [1][0][9][44] = 76, - [1][0][8][44] = 54, - [1][0][11][44] = 28, - [1][0][2][46] = 76, - [1][0][1][46] = 28, - [1][0][3][46] = 127, - [1][0][5][46] = 76, - [1][0][6][46] = 28, - [1][0][9][46] = 76, - [1][0][8][46] = 54, - [1][0][11][46] = 28, - [1][1][2][0] = 46, - [1][1][1][0] = 22, - [1][1][3][0] = 24, - [1][1][5][0] = 18, - [1][1][6][0] = 22, - [1][1][9][0] = 22, - [1][1][8][0] = 18, - [1][1][11][0] = 22, - [1][1][2][2] = 46, - [1][1][1][2] = 22, - [1][1][3][2] = 24, - [1][1][5][2] = 18, - [1][1][6][2] = 22, - [1][1][9][2] = 22, - [1][1][8][2] = 18, - [1][1][11][2] = 22, - [1][1][2][4] = 46, - [1][1][1][4] = 22, - [1][1][3][4] = 24, - [1][1][5][4] = 18, - [1][1][6][4] = 22, - [1][1][9][4] = 22, - [1][1][8][4] = 18, - [1][1][11][4] = 22, - [1][1][2][6] = 46, - [1][1][1][6] = 22, - [1][1][3][6] = 24, - [1][1][5][6] = 18, - [1][1][6][6] = 22, - [1][1][9][6] = 22, - [1][1][8][6] = 18, - [1][1][11][6] = 22, - [1][1][2][8] = 46, - [1][1][1][8] = 22, - [1][1][3][8] = 24, - [1][1][5][8] = 46, - [1][1][6][8] = 22, - [1][1][9][8] = 22, - [1][1][8][8] = 42, - [1][1][11][8] = 22, - [1][1][2][10] = 46, - [1][1][1][10] = 22, - [1][1][3][10] = 24, - [1][1][5][10] = 46, - [1][1][6][10] = 22, - [1][1][9][10] = 22, - [1][1][8][10] = 42, - [1][1][11][10] = 22, - [1][1][2][12] = 46, - [1][1][1][12] = 22, - [1][1][3][12] = 24, - [1][1][5][12] = 46, - [1][1][6][12] = 22, - [1][1][9][12] = 22, - [1][1][8][12] = 42, - [1][1][11][12] = 22, - [1][1][2][14] = 46, - [1][1][1][14] = 22, - [1][1][3][14] = 24, - [1][1][5][14] = 46, - [1][1][6][14] = 22, - [1][1][9][14] = 22, - [1][1][8][14] = 42, - [1][1][11][14] = 22, - [1][1][2][15] = 46, - [1][1][1][15] = 22, - [1][1][3][15] = 46, - [1][1][5][15] = 46, - [1][1][6][15] = 22, - [1][1][9][15] = 22, - [1][1][8][15] = 42, - [1][1][11][15] = 22, - [1][1][2][17] = 46, - [1][1][1][17] = 22, - [1][1][3][17] = 46, - [1][1][5][17] = 46, - [1][1][6][17] = 22, - [1][1][9][17] = 22, - [1][1][8][17] = 42, - [1][1][11][17] = 22, - [1][1][2][19] = 46, - [1][1][1][19] = 22, - [1][1][3][19] = 46, - [1][1][5][19] = 46, - [1][1][6][19] = 22, - [1][1][9][19] = 22, - [1][1][8][19] = 42, - [1][1][11][19] = 22, - [1][1][2][21] = 46, - [1][1][1][21] = 22, - [1][1][3][21] = 46, - [1][1][5][21] = 46, - [1][1][6][21] = 22, - [1][1][9][21] = 22, - [1][1][8][21] = 42, - [1][1][11][21] = 22, - [1][1][2][23] = 46, - [1][1][1][23] = 22, - [1][1][3][23] = 46, - [1][1][5][23] = 46, - [1][1][6][23] = 22, - [1][1][9][23] = 22, - [1][1][8][23] = 42, - [1][1][11][23] = 22, - [1][1][2][25] = 46, - [1][1][1][25] = 22, - [1][1][3][25] = 46, - [1][1][5][25] = 127, - [1][1][6][25] = 22, - [1][1][9][25] = 127, - [1][1][8][25] = 42, - [1][1][11][25] = 22, - [1][1][2][27] = 46, - [1][1][1][27] = 22, - [1][1][3][27] = 46, - [1][1][5][27] = 127, - [1][1][6][27] = 22, - [1][1][9][27] = 127, - [1][1][8][27] = 42, - [1][1][11][27] = 22, - [1][1][2][29] = 46, - [1][1][1][29] = 22, - [1][1][3][29] = 46, - [1][1][5][29] = 127, - [1][1][6][29] = 22, - [1][1][9][29] = 127, - [1][1][8][29] = 42, - [1][1][11][29] = 22, - [1][1][2][31] = 46, - [1][1][1][31] = 22, - [1][1][3][31] = 46, - [1][1][5][31] = 46, - [1][1][6][31] = 22, - [1][1][9][31] = 22, - [1][1][8][31] = 42, - [1][1][11][31] = 22, - [1][1][2][33] = 46, - [1][1][1][33] = 22, - [1][1][3][33] = 46, - [1][1][5][33] = 46, - [1][1][6][33] = 22, - [1][1][9][33] = 22, - [1][1][8][33] = 42, - [1][1][11][33] = 22, - [1][1][2][35] = 46, - [1][1][1][35] = 22, - [1][1][3][35] = 46, - [1][1][5][35] = 46, - [1][1][6][35] = 22, - [1][1][9][35] = 22, - [1][1][8][35] = 42, - [1][1][11][35] = 22, - [1][1][2][37] = 46, - [1][1][1][37] = 127, - [1][1][3][37] = 46, - [1][1][5][37] = 46, - [1][1][6][37] = 22, - [1][1][9][37] = 50, - [1][1][8][37] = 42, - [1][1][11][37] = 127, - [1][1][2][38] = 74, - [1][1][1][38] = 16, - [1][1][3][38] = 127, - [1][1][5][38] = 74, - [1][1][6][38] = 16, - [1][1][9][38] = 76, - [1][1][8][38] = 42, - [1][1][11][38] = 16, - [1][1][2][40] = 76, - [1][1][1][40] = 16, - [1][1][3][40] = 127, - [1][1][5][40] = 76, - [1][1][6][40] = 16, - [1][1][9][40] = 76, - [1][1][8][40] = 42, - [1][1][11][40] = 16, - [1][1][2][42] = 76, - [1][1][1][42] = 16, - [1][1][3][42] = 127, - [1][1][5][42] = 76, - [1][1][6][42] = 16, - [1][1][9][42] = 76, - [1][1][8][42] = 42, - [1][1][11][42] = 16, - [1][1][2][44] = 76, - [1][1][1][44] = 16, - [1][1][3][44] = 127, - [1][1][5][44] = 76, - [1][1][6][44] = 16, - [1][1][9][44] = 76, - [1][1][8][44] = 42, - [1][1][11][44] = 16, - [1][1][2][46] = 76, - [1][1][1][46] = 16, - [1][1][3][46] = 127, - [1][1][5][46] = 76, - [1][1][6][46] = 16, - [1][1][9][46] = 76, - [1][1][8][46] = 42, - [1][1][11][46] = 16, - [2][0][2][0] = 74, - [2][0][1][0] = 46, - [2][0][3][0] = 50, - [2][0][5][0] = 46, - [2][0][6][0] = 46, - [2][0][9][0] = 46, - [2][0][8][0] = 30, - [2][0][11][0] = 46, - [2][0][2][2] = 74, - [2][0][1][2] = 46, - [2][0][3][2] = 50, - [2][0][5][2] = 46, - [2][0][6][2] = 46, - [2][0][9][2] = 46, - [2][0][8][2] = 30, - [2][0][11][2] = 46, - [2][0][2][4] = 74, - [2][0][1][4] = 46, - [2][0][3][4] = 50, - [2][0][5][4] = 46, - [2][0][6][4] = 46, - [2][0][9][4] = 46, - [2][0][8][4] = 30, - [2][0][11][4] = 46, - [2][0][2][6] = 74, - [2][0][1][6] = 46, - [2][0][3][6] = 50, - [2][0][5][6] = 46, - [2][0][6][6] = 46, - [2][0][9][6] = 46, - [2][0][8][6] = 30, - [2][0][11][6] = 46, - [2][0][2][8] = 74, - [2][0][1][8] = 46, - [2][0][3][8] = 50, - [2][0][5][8] = 66, - [2][0][6][8] = 46, - [2][0][9][8] = 46, - [2][0][8][8] = 54, - [2][0][11][8] = 46, - [2][0][2][10] = 74, - [2][0][1][10] = 46, - [2][0][3][10] = 50, - [2][0][5][10] = 66, - [2][0][6][10] = 46, - [2][0][9][10] = 46, - [2][0][8][10] = 54, - [2][0][11][10] = 46, - [2][0][2][12] = 74, - [2][0][1][12] = 46, - [2][0][3][12] = 50, - [2][0][5][12] = 66, - [2][0][6][12] = 46, - [2][0][9][12] = 46, - [2][0][8][12] = 54, - [2][0][11][12] = 46, - [2][0][2][14] = 74, - [2][0][1][14] = 46, - [2][0][3][14] = 50, - [2][0][5][14] = 66, - [2][0][6][14] = 46, - [2][0][9][14] = 46, - [2][0][8][14] = 54, - [2][0][11][14] = 46, - [2][0][2][15] = 74, - [2][0][1][15] = 46, - [2][0][3][15] = 70, - [2][0][5][15] = 74, - [2][0][6][15] = 46, - [2][0][9][15] = 46, - [2][0][8][15] = 54, - [2][0][11][15] = 46, - [2][0][2][17] = 74, - [2][0][1][17] = 46, - [2][0][3][17] = 70, - [2][0][5][17] = 74, - [2][0][6][17] = 46, - [2][0][9][17] = 46, - [2][0][8][17] = 54, - [2][0][11][17] = 46, - [2][0][2][19] = 74, - [2][0][1][19] = 46, - [2][0][3][19] = 70, - [2][0][5][19] = 74, - [2][0][6][19] = 46, - [2][0][9][19] = 46, - [2][0][8][19] = 54, - [2][0][11][19] = 46, - [2][0][2][21] = 74, - [2][0][1][21] = 46, - [2][0][3][21] = 70, - [2][0][5][21] = 74, - [2][0][6][21] = 46, - [2][0][9][21] = 46, - [2][0][8][21] = 54, - [2][0][11][21] = 46, - [2][0][2][23] = 74, - [2][0][1][23] = 46, - [2][0][3][23] = 70, - [2][0][5][23] = 74, - [2][0][6][23] = 46, - [2][0][9][23] = 46, - [2][0][8][23] = 54, - [2][0][11][23] = 46, - [2][0][2][25] = 74, - [2][0][1][25] = 46, - [2][0][3][25] = 70, - [2][0][5][25] = 127, - [2][0][6][25] = 46, - [2][0][9][25] = 127, - [2][0][8][25] = 54, - [2][0][11][25] = 46, - [2][0][2][27] = 74, - [2][0][1][27] = 46, - [2][0][3][27] = 70, - [2][0][5][27] = 127, - [2][0][6][27] = 46, - [2][0][9][27] = 127, - [2][0][8][27] = 54, - [2][0][11][27] = 46, - [2][0][2][29] = 74, - [2][0][1][29] = 46, - [2][0][3][29] = 70, - [2][0][5][29] = 127, - [2][0][6][29] = 46, - [2][0][9][29] = 127, - [2][0][8][29] = 54, - [2][0][11][29] = 46, - [2][0][2][31] = 74, - [2][0][1][31] = 46, - [2][0][3][31] = 70, - [2][0][5][31] = 74, - [2][0][6][31] = 46, - [2][0][9][31] = 46, - [2][0][8][31] = 54, - [2][0][11][31] = 46, - [2][0][2][33] = 74, - [2][0][1][33] = 46, - [2][0][3][33] = 70, - [2][0][5][33] = 74, - [2][0][6][33] = 46, - [2][0][9][33] = 46, - [2][0][8][33] = 54, - [2][0][11][33] = 46, - [2][0][2][35] = 74, - [2][0][1][35] = 46, - [2][0][3][35] = 70, - [2][0][5][35] = 74, - [2][0][6][35] = 46, - [2][0][9][35] = 46, - [2][0][8][35] = 54, - [2][0][11][35] = 46, - [2][0][2][37] = 74, - [2][0][1][37] = 127, - [2][0][3][37] = 70, - [2][0][5][37] = 74, - [2][0][6][37] = 46, - [2][0][9][37] = 74, - [2][0][8][37] = 54, - [2][0][11][37] = 127, - [2][0][2][38] = 76, - [2][0][1][38] = 28, - [2][0][3][38] = 127, - [2][0][5][38] = 76, - [2][0][6][38] = 28, - [2][0][9][38] = 76, - [2][0][8][38] = 54, - [2][0][11][38] = 28, - [2][0][2][40] = 76, - [2][0][1][40] = 28, - [2][0][3][40] = 127, - [2][0][5][40] = 76, - [2][0][6][40] = 28, - [2][0][9][40] = 76, - [2][0][8][40] = 54, - [2][0][11][40] = 28, - [2][0][2][42] = 76, - [2][0][1][42] = 28, - [2][0][3][42] = 127, - [2][0][5][42] = 76, - [2][0][6][42] = 28, - [2][0][9][42] = 76, - [2][0][8][42] = 54, - [2][0][11][42] = 28, - [2][0][2][44] = 76, - [2][0][1][44] = 28, - [2][0][3][44] = 127, - [2][0][5][44] = 76, - [2][0][6][44] = 28, - [2][0][9][44] = 76, - [2][0][8][44] = 54, - [2][0][11][44] = 28, - [2][0][2][46] = 76, - [2][0][1][46] = 28, - [2][0][3][46] = 127, - [2][0][5][46] = 76, - [2][0][6][46] = 28, - [2][0][9][46] = 76, - [2][0][8][46] = 54, - [2][0][11][46] = 28, - [2][1][2][0] = 58, - [2][1][1][0] = 32, - [2][1][3][0] = 38, - [2][1][5][0] = 30, - [2][1][6][0] = 32, - [2][1][9][0] = 32, - [2][1][8][0] = 18, - [2][1][11][0] = 32, - [2][1][2][2] = 58, - [2][1][1][2] = 32, - [2][1][3][2] = 38, - [2][1][5][2] = 30, - [2][1][6][2] = 32, - [2][1][9][2] = 32, - [2][1][8][2] = 18, - [2][1][11][2] = 32, - [2][1][2][4] = 58, - [2][1][1][4] = 32, - [2][1][3][4] = 38, - [2][1][5][4] = 30, - [2][1][6][4] = 32, - [2][1][9][4] = 32, - [2][1][8][4] = 18, - [2][1][11][4] = 32, - [2][1][2][6] = 58, - [2][1][1][6] = 32, - [2][1][3][6] = 38, - [2][1][5][6] = 30, - [2][1][6][6] = 32, - [2][1][9][6] = 32, - [2][1][8][6] = 18, - [2][1][11][6] = 32, - [2][1][2][8] = 58, - [2][1][1][8] = 32, - [2][1][3][8] = 38, - [2][1][5][8] = 52, - [2][1][6][8] = 32, - [2][1][9][8] = 32, - [2][1][8][8] = 42, - [2][1][11][8] = 32, - [2][1][2][10] = 58, - [2][1][1][10] = 32, - [2][1][3][10] = 38, - [2][1][5][10] = 52, - [2][1][6][10] = 32, - [2][1][9][10] = 32, - [2][1][8][10] = 42, - [2][1][11][10] = 32, - [2][1][2][12] = 58, - [2][1][1][12] = 32, - [2][1][3][12] = 38, - [2][1][5][12] = 52, - [2][1][6][12] = 32, - [2][1][9][12] = 32, - [2][1][8][12] = 42, - [2][1][11][12] = 32, - [2][1][2][14] = 58, - [2][1][1][14] = 32, - [2][1][3][14] = 38, - [2][1][5][14] = 52, - [2][1][6][14] = 32, - [2][1][9][14] = 32, - [2][1][8][14] = 42, - [2][1][11][14] = 32, - [2][1][2][15] = 58, - [2][1][1][15] = 32, - [2][1][3][15] = 58, - [2][1][5][15] = 58, - [2][1][6][15] = 32, - [2][1][9][15] = 32, - [2][1][8][15] = 42, - [2][1][11][15] = 32, - [2][1][2][17] = 58, - [2][1][1][17] = 32, - [2][1][3][17] = 58, - [2][1][5][17] = 58, - [2][1][6][17] = 32, - [2][1][9][17] = 32, - [2][1][8][17] = 42, - [2][1][11][17] = 32, - [2][1][2][19] = 58, - [2][1][1][19] = 32, - [2][1][3][19] = 58, - [2][1][5][19] = 58, - [2][1][6][19] = 32, - [2][1][9][19] = 32, - [2][1][8][19] = 42, - [2][1][11][19] = 32, - [2][1][2][21] = 58, - [2][1][1][21] = 32, - [2][1][3][21] = 58, - [2][1][5][21] = 58, - [2][1][6][21] = 32, - [2][1][9][21] = 32, - [2][1][8][21] = 42, - [2][1][11][21] = 32, - [2][1][2][23] = 58, - [2][1][1][23] = 32, - [2][1][3][23] = 58, - [2][1][5][23] = 58, - [2][1][6][23] = 32, - [2][1][9][23] = 32, - [2][1][8][23] = 42, - [2][1][11][23] = 32, - [2][1][2][25] = 58, - [2][1][1][25] = 32, - [2][1][3][25] = 58, - [2][1][5][25] = 127, - [2][1][6][25] = 32, - [2][1][9][25] = 127, - [2][1][8][25] = 42, - [2][1][11][25] = 32, - [2][1][2][27] = 58, - [2][1][1][27] = 32, - [2][1][3][27] = 58, - [2][1][5][27] = 127, - [2][1][6][27] = 32, - [2][1][9][27] = 127, - [2][1][8][27] = 42, - [2][1][11][27] = 32, - [2][1][2][29] = 58, - [2][1][1][29] = 32, - [2][1][3][29] = 58, - [2][1][5][29] = 127, - [2][1][6][29] = 32, - [2][1][9][29] = 127, - [2][1][8][29] = 42, - [2][1][11][29] = 32, - [2][1][2][31] = 58, - [2][1][1][31] = 32, - [2][1][3][31] = 58, - [2][1][5][31] = 58, - [2][1][6][31] = 32, - [2][1][9][31] = 32, - [2][1][8][31] = 42, - [2][1][11][31] = 32, - [2][1][2][33] = 58, - [2][1][1][33] = 32, - [2][1][3][33] = 58, - [2][1][5][33] = 58, - [2][1][6][33] = 32, - [2][1][9][33] = 32, - [2][1][8][33] = 42, - [2][1][11][33] = 32, - [2][1][2][35] = 58, - [2][1][1][35] = 32, - [2][1][3][35] = 58, - [2][1][5][35] = 58, - [2][1][6][35] = 32, - [2][1][9][35] = 32, - [2][1][8][35] = 42, - [2][1][11][35] = 32, - [2][1][2][37] = 58, - [2][1][1][37] = 127, - [2][1][3][37] = 58, - [2][1][5][37] = 58, - [2][1][6][37] = 32, - [2][1][9][37] = 62, - [2][1][8][37] = 42, - [2][1][11][37] = 127, - [2][1][2][38] = 76, - [2][1][1][38] = 16, - [2][1][3][38] = 127, - [2][1][5][38] = 76, - [2][1][6][38] = 16, - [2][1][9][38] = 76, - [2][1][8][38] = 42, - [2][1][11][38] = 16, - [2][1][2][40] = 76, - [2][1][1][40] = 16, - [2][1][3][40] = 127, - [2][1][5][40] = 76, - [2][1][6][40] = 16, - [2][1][9][40] = 76, - [2][1][8][40] = 42, - [2][1][11][40] = 16, - [2][1][2][42] = 76, - [2][1][1][42] = 16, - [2][1][3][42] = 127, - [2][1][5][42] = 76, - [2][1][6][42] = 16, - [2][1][9][42] = 76, - [2][1][8][42] = 42, - [2][1][11][42] = 16, - [2][1][2][44] = 76, - [2][1][1][44] = 16, - [2][1][3][44] = 127, - [2][1][5][44] = 76, - [2][1][6][44] = 16, - [2][1][9][44] = 76, - [2][1][8][44] = 42, - [2][1][11][44] = 16, - [2][1][2][46] = 76, - [2][1][1][46] = 16, - [2][1][3][46] = 127, - [2][1][5][46] = 76, - [2][1][6][46] = 16, - [2][1][9][46] = 76, - [2][1][8][46] = 42, - [2][1][11][46] = 16, + [0][0][RTW89_WW][0] = 22, + [0][0][RTW89_WW][2] = 22, + [0][0][RTW89_WW][4] = 22, + [0][0][RTW89_WW][6] = 20, + [0][0][RTW89_WW][8] = 24, + [0][0][RTW89_WW][10] = 24, + [0][0][RTW89_WW][12] = 24, + [0][0][RTW89_WW][14] = 24, + [0][0][RTW89_WW][15] = 24, + [0][0][RTW89_WW][17] = 24, + [0][0][RTW89_WW][19] = 24, + [0][0][RTW89_WW][21] = 24, + [0][0][RTW89_WW][23] = 24, + [0][0][RTW89_WW][25] = 24, + [0][0][RTW89_WW][27] = 24, + [0][0][RTW89_WW][29] = 24, + [0][0][RTW89_WW][31] = 24, + [0][0][RTW89_WW][33] = 24, + [0][0][RTW89_WW][35] = 24, + [0][0][RTW89_WW][37] = 44, + [0][0][RTW89_WW][38] = 28, + [0][0][RTW89_WW][40] = 28, + [0][0][RTW89_WW][42] = 28, + [0][0][RTW89_WW][44] = 28, + [0][0][RTW89_WW][46] = 28, + [0][1][RTW89_WW][0] = 8, + [0][1][RTW89_WW][2] = 8, + [0][1][RTW89_WW][4] = 8, + [0][1][RTW89_WW][6] = 4, + [0][1][RTW89_WW][8] = 12, + [0][1][RTW89_WW][10] = 12, + [0][1][RTW89_WW][12] = 12, + [0][1][RTW89_WW][14] = 12, + [0][1][RTW89_WW][15] = 12, + [0][1][RTW89_WW][17] = 12, + [0][1][RTW89_WW][19] = 12, + [0][1][RTW89_WW][21] = 12, + [0][1][RTW89_WW][23] = 12, + [0][1][RTW89_WW][25] = 12, + [0][1][RTW89_WW][27] = 12, + [0][1][RTW89_WW][29] = 12, + [0][1][RTW89_WW][31] = 12, + [0][1][RTW89_WW][33] = 12, + [0][1][RTW89_WW][35] = 12, + [0][1][RTW89_WW][37] = 32, + [0][1][RTW89_WW][38] = 16, + [0][1][RTW89_WW][40] = 16, + [0][1][RTW89_WW][42] = 16, + [0][1][RTW89_WW][44] = 16, + [0][1][RTW89_WW][46] = 16, + [1][0][RTW89_WW][0] = 30, + [1][0][RTW89_WW][2] = 30, + [1][0][RTW89_WW][4] = 30, + [1][0][RTW89_WW][6] = 30, + [1][0][RTW89_WW][8] = 36, + [1][0][RTW89_WW][10] = 36, + [1][0][RTW89_WW][12] = 36, + [1][0][RTW89_WW][14] = 36, + [1][0][RTW89_WW][15] = 36, + [1][0][RTW89_WW][17] = 36, + [1][0][RTW89_WW][19] = 36, + [1][0][RTW89_WW][21] = 36, + [1][0][RTW89_WW][23] = 36, + [1][0][RTW89_WW][25] = 36, + [1][0][RTW89_WW][27] = 36, + [1][0][RTW89_WW][29] = 36, + [1][0][RTW89_WW][31] = 36, + [1][0][RTW89_WW][33] = 36, + [1][0][RTW89_WW][35] = 36, + [1][0][RTW89_WW][37] = 54, + [1][0][RTW89_WW][38] = 28, + [1][0][RTW89_WW][40] = 28, + [1][0][RTW89_WW][42] = 28, + [1][0][RTW89_WW][44] = 28, + [1][0][RTW89_WW][46] = 28, + [1][1][RTW89_WW][0] = 18, + [1][1][RTW89_WW][2] = 18, + [1][1][RTW89_WW][4] = 18, + [1][1][RTW89_WW][6] = 16, + [1][1][RTW89_WW][8] = 22, + [1][1][RTW89_WW][10] = 22, + [1][1][RTW89_WW][12] = 22, + [1][1][RTW89_WW][14] = 22, + [1][1][RTW89_WW][15] = 22, + [1][1][RTW89_WW][17] = 22, + [1][1][RTW89_WW][19] = 22, + [1][1][RTW89_WW][21] = 22, + [1][1][RTW89_WW][23] = 22, + [1][1][RTW89_WW][25] = 22, + [1][1][RTW89_WW][27] = 22, + [1][1][RTW89_WW][29] = 22, + [1][1][RTW89_WW][31] = 22, + [1][1][RTW89_WW][33] = 22, + [1][1][RTW89_WW][35] = 22, + [1][1][RTW89_WW][37] = 42, + [1][1][RTW89_WW][38] = 16, + [1][1][RTW89_WW][40] = 16, + [1][1][RTW89_WW][42] = 16, + [1][1][RTW89_WW][44] = 16, + [1][1][RTW89_WW][46] = 16, + [2][0][RTW89_WW][0] = 30, + [2][0][RTW89_WW][2] = 30, + [2][0][RTW89_WW][4] = 30, + [2][0][RTW89_WW][6] = 30, + [2][0][RTW89_WW][8] = 46, + [2][0][RTW89_WW][10] = 46, + [2][0][RTW89_WW][12] = 46, + [2][0][RTW89_WW][14] = 46, + [2][0][RTW89_WW][15] = 46, + [2][0][RTW89_WW][17] = 46, + [2][0][RTW89_WW][19] = 46, + [2][0][RTW89_WW][21] = 46, + [2][0][RTW89_WW][23] = 46, + [2][0][RTW89_WW][25] = 46, + [2][0][RTW89_WW][27] = 46, + [2][0][RTW89_WW][29] = 46, + [2][0][RTW89_WW][31] = 46, + [2][0][RTW89_WW][33] = 46, + [2][0][RTW89_WW][35] = 46, + [2][0][RTW89_WW][37] = 54, + [2][0][RTW89_WW][38] = 28, + [2][0][RTW89_WW][40] = 28, + [2][0][RTW89_WW][42] = 28, + [2][0][RTW89_WW][44] = 28, + [2][0][RTW89_WW][46] = 28, + [2][1][RTW89_WW][0] = 18, + [2][1][RTW89_WW][2] = 18, + [2][1][RTW89_WW][4] = 18, + [2][1][RTW89_WW][6] = 18, + [2][1][RTW89_WW][8] = 32, + [2][1][RTW89_WW][10] = 32, + [2][1][RTW89_WW][12] = 32, + [2][1][RTW89_WW][14] = 32, + [2][1][RTW89_WW][15] = 32, + [2][1][RTW89_WW][17] = 32, + [2][1][RTW89_WW][19] = 32, + [2][1][RTW89_WW][21] = 32, + [2][1][RTW89_WW][23] = 32, + [2][1][RTW89_WW][25] = 32, + [2][1][RTW89_WW][27] = 32, + [2][1][RTW89_WW][29] = 32, + [2][1][RTW89_WW][31] = 32, + [2][1][RTW89_WW][33] = 32, + [2][1][RTW89_WW][35] = 32, + [2][1][RTW89_WW][37] = 42, + [2][1][RTW89_WW][38] = 16, + [2][1][RTW89_WW][40] = 16, + [2][1][RTW89_WW][42] = 16, + [2][1][RTW89_WW][44] = 16, + [2][1][RTW89_WW][46] = 16, + [0][0][RTW89_FCC][0] = 48, + [0][0][RTW89_ETSI][0] = 24, + [0][0][RTW89_MKK][0] = 26, + [0][0][RTW89_IC][0] = 22, + [0][0][RTW89_KCC][0] = 46, + [0][0][RTW89_ACMA][0] = 24, + [0][0][RTW89_CHILE][0] = 30, + [0][0][RTW89_UKRAINE][0] = 24, + [0][0][RTW89_MEXICO][0] = 48, + [0][0][RTW89_CN][0] = 24, + [0][0][RTW89_QATAR][0] = 24, + [0][0][RTW89_FCC][2] = 48, + [0][0][RTW89_ETSI][2] = 24, + [0][0][RTW89_MKK][2] = 26, + [0][0][RTW89_IC][2] = 22, + [0][0][RTW89_KCC][2] = 46, + [0][0][RTW89_ACMA][2] = 24, + [0][0][RTW89_CHILE][2] = 30, + [0][0][RTW89_UKRAINE][2] = 24, + [0][0][RTW89_MEXICO][2] = 48, + [0][0][RTW89_CN][2] = 24, + [0][0][RTW89_QATAR][2] = 24, + [0][0][RTW89_FCC][4] = 48, + [0][0][RTW89_ETSI][4] = 24, + [0][0][RTW89_MKK][4] = 26, + [0][0][RTW89_IC][4] = 22, + [0][0][RTW89_KCC][4] = 46, + [0][0][RTW89_ACMA][4] = 24, + [0][0][RTW89_CHILE][4] = 30, + [0][0][RTW89_UKRAINE][4] = 24, + [0][0][RTW89_MEXICO][4] = 48, + [0][0][RTW89_CN][4] = 24, + [0][0][RTW89_QATAR][4] = 24, + [0][0][RTW89_FCC][6] = 48, + [0][0][RTW89_ETSI][6] = 24, + [0][0][RTW89_MKK][6] = 26, + [0][0][RTW89_IC][6] = 22, + [0][0][RTW89_KCC][6] = 20, + [0][0][RTW89_ACMA][6] = 24, + [0][0][RTW89_CHILE][6] = 30, + [0][0][RTW89_UKRAINE][6] = 24, + [0][0][RTW89_MEXICO][6] = 48, + [0][0][RTW89_CN][6] = 24, + [0][0][RTW89_QATAR][6] = 24, + [0][0][RTW89_FCC][8] = 48, + [0][0][RTW89_ETSI][8] = 24, + [0][0][RTW89_MKK][8] = 26, + [0][0][RTW89_IC][8] = 48, + [0][0][RTW89_KCC][8] = 46, + [0][0][RTW89_ACMA][8] = 24, + [0][0][RTW89_CHILE][8] = 48, + [0][0][RTW89_UKRAINE][8] = 24, + [0][0][RTW89_MEXICO][8] = 48, + [0][0][RTW89_CN][8] = 24, + [0][0][RTW89_QATAR][8] = 24, + [0][0][RTW89_FCC][10] = 48, + [0][0][RTW89_ETSI][10] = 24, + [0][0][RTW89_MKK][10] = 26, + [0][0][RTW89_IC][10] = 48, + [0][0][RTW89_KCC][10] = 46, + [0][0][RTW89_ACMA][10] = 24, + [0][0][RTW89_CHILE][10] = 48, + [0][0][RTW89_UKRAINE][10] = 24, + [0][0][RTW89_MEXICO][10] = 48, + [0][0][RTW89_CN][10] = 24, + [0][0][RTW89_QATAR][10] = 24, + [0][0][RTW89_FCC][12] = 48, + [0][0][RTW89_ETSI][12] = 24, + [0][0][RTW89_MKK][12] = 26, + [0][0][RTW89_IC][12] = 48, + [0][0][RTW89_KCC][12] = 46, + [0][0][RTW89_ACMA][12] = 24, + [0][0][RTW89_CHILE][12] = 48, + [0][0][RTW89_UKRAINE][12] = 24, + [0][0][RTW89_MEXICO][12] = 48, + [0][0][RTW89_CN][12] = 24, + [0][0][RTW89_QATAR][12] = 24, + [0][0][RTW89_FCC][14] = 48, + [0][0][RTW89_ETSI][14] = 24, + [0][0][RTW89_MKK][14] = 26, + [0][0][RTW89_IC][14] = 48, + [0][0][RTW89_KCC][14] = 46, + [0][0][RTW89_ACMA][14] = 24, + [0][0][RTW89_CHILE][14] = 48, + [0][0][RTW89_UKRAINE][14] = 24, + [0][0][RTW89_MEXICO][14] = 48, + [0][0][RTW89_CN][14] = 24, + [0][0][RTW89_QATAR][14] = 24, + [0][0][RTW89_FCC][15] = 48, + [0][0][RTW89_ETSI][15] = 24, + [0][0][RTW89_MKK][15] = 44, + [0][0][RTW89_IC][15] = 48, + [0][0][RTW89_KCC][15] = 46, + [0][0][RTW89_ACMA][15] = 24, + [0][0][RTW89_CHILE][15] = 48, + [0][0][RTW89_UKRAINE][15] = 24, + [0][0][RTW89_MEXICO][15] = 48, + [0][0][RTW89_CN][15] = 127, + [0][0][RTW89_QATAR][15] = 24, + [0][0][RTW89_FCC][17] = 48, + [0][0][RTW89_ETSI][17] = 24, + [0][0][RTW89_MKK][17] = 44, + [0][0][RTW89_IC][17] = 48, + [0][0][RTW89_KCC][17] = 46, + [0][0][RTW89_ACMA][17] = 24, + [0][0][RTW89_CHILE][17] = 48, + [0][0][RTW89_UKRAINE][17] = 24, + [0][0][RTW89_MEXICO][17] = 48, + [0][0][RTW89_CN][17] = 127, + [0][0][RTW89_QATAR][17] = 24, + [0][0][RTW89_FCC][19] = 48, + [0][0][RTW89_ETSI][19] = 24, + [0][0][RTW89_MKK][19] = 44, + [0][0][RTW89_IC][19] = 48, + [0][0][RTW89_KCC][19] = 46, + [0][0][RTW89_ACMA][19] = 24, + [0][0][RTW89_CHILE][19] = 48, + [0][0][RTW89_UKRAINE][19] = 24, + [0][0][RTW89_MEXICO][19] = 48, + [0][0][RTW89_CN][19] = 127, + [0][0][RTW89_QATAR][19] = 24, + [0][0][RTW89_FCC][21] = 48, + [0][0][RTW89_ETSI][21] = 24, + [0][0][RTW89_MKK][21] = 44, + [0][0][RTW89_IC][21] = 48, + [0][0][RTW89_KCC][21] = 46, + [0][0][RTW89_ACMA][21] = 24, + [0][0][RTW89_CHILE][21] = 48, + [0][0][RTW89_UKRAINE][21] = 24, + [0][0][RTW89_MEXICO][21] = 48, + [0][0][RTW89_CN][21] = 127, + [0][0][RTW89_QATAR][21] = 24, + [0][0][RTW89_FCC][23] = 48, + [0][0][RTW89_ETSI][23] = 24, + [0][0][RTW89_MKK][23] = 44, + [0][0][RTW89_IC][23] = 48, + [0][0][RTW89_KCC][23] = 46, + [0][0][RTW89_ACMA][23] = 24, + [0][0][RTW89_CHILE][23] = 48, + [0][0][RTW89_UKRAINE][23] = 24, + [0][0][RTW89_MEXICO][23] = 48, + [0][0][RTW89_CN][23] = 127, + [0][0][RTW89_QATAR][23] = 24, + [0][0][RTW89_FCC][25] = 48, + [0][0][RTW89_ETSI][25] = 24, + [0][0][RTW89_MKK][25] = 44, + [0][0][RTW89_IC][25] = 127, + [0][0][RTW89_KCC][25] = 46, + [0][0][RTW89_ACMA][25] = 127, + [0][0][RTW89_CHILE][25] = 48, + [0][0][RTW89_UKRAINE][25] = 24, + [0][0][RTW89_MEXICO][25] = 48, + [0][0][RTW89_CN][25] = 127, + [0][0][RTW89_QATAR][25] = 24, + [0][0][RTW89_FCC][27] = 48, + [0][0][RTW89_ETSI][27] = 24, + [0][0][RTW89_MKK][27] = 44, + [0][0][RTW89_IC][27] = 127, + [0][0][RTW89_KCC][27] = 46, + [0][0][RTW89_ACMA][27] = 127, + [0][0][RTW89_CHILE][27] = 48, + [0][0][RTW89_UKRAINE][27] = 24, + [0][0][RTW89_MEXICO][27] = 48, + [0][0][RTW89_CN][27] = 127, + [0][0][RTW89_QATAR][27] = 24, + [0][0][RTW89_FCC][29] = 48, + [0][0][RTW89_ETSI][29] = 24, + [0][0][RTW89_MKK][29] = 44, + [0][0][RTW89_IC][29] = 127, + [0][0][RTW89_KCC][29] = 46, + [0][0][RTW89_ACMA][29] = 127, + [0][0][RTW89_CHILE][29] = 48, + [0][0][RTW89_UKRAINE][29] = 24, + [0][0][RTW89_MEXICO][29] = 48, + [0][0][RTW89_CN][29] = 127, + [0][0][RTW89_QATAR][29] = 24, + [0][0][RTW89_FCC][31] = 48, + [0][0][RTW89_ETSI][31] = 24, + [0][0][RTW89_MKK][31] = 44, + [0][0][RTW89_IC][31] = 48, + [0][0][RTW89_KCC][31] = 46, + [0][0][RTW89_ACMA][31] = 24, + [0][0][RTW89_CHILE][31] = 48, + [0][0][RTW89_UKRAINE][31] = 24, + [0][0][RTW89_MEXICO][31] = 48, + [0][0][RTW89_CN][31] = 127, + [0][0][RTW89_QATAR][31] = 24, + [0][0][RTW89_FCC][33] = 48, + [0][0][RTW89_ETSI][33] = 24, + [0][0][RTW89_MKK][33] = 44, + [0][0][RTW89_IC][33] = 48, + [0][0][RTW89_KCC][33] = 46, + [0][0][RTW89_ACMA][33] = 24, + [0][0][RTW89_CHILE][33] = 48, + [0][0][RTW89_UKRAINE][33] = 24, + [0][0][RTW89_MEXICO][33] = 48, + [0][0][RTW89_CN][33] = 127, + [0][0][RTW89_QATAR][33] = 24, + [0][0][RTW89_FCC][35] = 48, + [0][0][RTW89_ETSI][35] = 24, + [0][0][RTW89_MKK][35] = 44, + [0][0][RTW89_IC][35] = 48, + [0][0][RTW89_KCC][35] = 46, + [0][0][RTW89_ACMA][35] = 24, + [0][0][RTW89_CHILE][35] = 48, + [0][0][RTW89_UKRAINE][35] = 24, + [0][0][RTW89_MEXICO][35] = 48, + [0][0][RTW89_CN][35] = 127, + [0][0][RTW89_QATAR][35] = 24, + [0][0][RTW89_FCC][37] = 48, + [0][0][RTW89_ETSI][37] = 127, + [0][0][RTW89_MKK][37] = 44, + [0][0][RTW89_IC][37] = 48, + [0][0][RTW89_KCC][37] = 46, + [0][0][RTW89_ACMA][37] = 48, + [0][0][RTW89_CHILE][37] = 48, + [0][0][RTW89_UKRAINE][37] = 127, + [0][0][RTW89_MEXICO][37] = 48, + [0][0][RTW89_CN][37] = 127, + [0][0][RTW89_QATAR][37] = 127, + [0][0][RTW89_FCC][38] = 76, + [0][0][RTW89_ETSI][38] = 28, + [0][0][RTW89_MKK][38] = 127, + [0][0][RTW89_IC][38] = 76, + [0][0][RTW89_KCC][38] = 46, + [0][0][RTW89_ACMA][38] = 76, + [0][0][RTW89_CHILE][38] = 54, + [0][0][RTW89_UKRAINE][38] = 28, + [0][0][RTW89_MEXICO][38] = 76, + [0][0][RTW89_CN][38] = 62, + [0][0][RTW89_QATAR][38] = 28, + [0][0][RTW89_FCC][40] = 76, + [0][0][RTW89_ETSI][40] = 28, + [0][0][RTW89_MKK][40] = 127, + [0][0][RTW89_IC][40] = 76, + [0][0][RTW89_KCC][40] = 46, + [0][0][RTW89_ACMA][40] = 76, + [0][0][RTW89_CHILE][40] = 54, + [0][0][RTW89_UKRAINE][40] = 28, + [0][0][RTW89_MEXICO][40] = 76, + [0][0][RTW89_CN][40] = 62, + [0][0][RTW89_QATAR][40] = 28, + [0][0][RTW89_FCC][42] = 76, + [0][0][RTW89_ETSI][42] = 28, + [0][0][RTW89_MKK][42] = 127, + [0][0][RTW89_IC][42] = 76, + [0][0][RTW89_KCC][42] = 46, + [0][0][RTW89_ACMA][42] = 76, + [0][0][RTW89_CHILE][42] = 54, + [0][0][RTW89_UKRAINE][42] = 28, + [0][0][RTW89_MEXICO][42] = 76, + [0][0][RTW89_CN][42] = 62, + [0][0][RTW89_QATAR][42] = 28, + [0][0][RTW89_FCC][44] = 76, + [0][0][RTW89_ETSI][44] = 28, + [0][0][RTW89_MKK][44] = 127, + [0][0][RTW89_IC][44] = 76, + [0][0][RTW89_KCC][44] = 46, + [0][0][RTW89_ACMA][44] = 76, + [0][0][RTW89_CHILE][44] = 54, + [0][0][RTW89_UKRAINE][44] = 28, + [0][0][RTW89_MEXICO][44] = 76, + [0][0][RTW89_CN][44] = 62, + [0][0][RTW89_QATAR][44] = 28, + [0][0][RTW89_FCC][46] = 76, + [0][0][RTW89_ETSI][46] = 28, + [0][0][RTW89_MKK][46] = 127, + [0][0][RTW89_IC][46] = 76, + [0][0][RTW89_KCC][46] = 46, + [0][0][RTW89_ACMA][46] = 76, + [0][0][RTW89_CHILE][46] = 54, + [0][0][RTW89_UKRAINE][46] = 28, + [0][0][RTW89_MEXICO][46] = 76, + [0][0][RTW89_CN][46] = 62, + [0][0][RTW89_QATAR][46] = 28, + [0][1][RTW89_FCC][0] = 36, + [0][1][RTW89_ETSI][0] = 12, + [0][1][RTW89_MKK][0] = 14, + [0][1][RTW89_IC][0] = 8, + [0][1][RTW89_KCC][0] = 32, + [0][1][RTW89_ACMA][0] = 12, + [0][1][RTW89_CHILE][0] = 18, + [0][1][RTW89_UKRAINE][0] = 12, + [0][1][RTW89_MEXICO][0] = 36, + [0][1][RTW89_CN][0] = 12, + [0][1][RTW89_QATAR][0] = 12, + [0][1][RTW89_FCC][2] = 36, + [0][1][RTW89_ETSI][2] = 12, + [0][1][RTW89_MKK][2] = 14, + [0][1][RTW89_IC][2] = 8, + [0][1][RTW89_KCC][2] = 32, + [0][1][RTW89_ACMA][2] = 12, + [0][1][RTW89_CHILE][2] = 18, + [0][1][RTW89_UKRAINE][2] = 12, + [0][1][RTW89_MEXICO][2] = 36, + [0][1][RTW89_CN][2] = 12, + [0][1][RTW89_QATAR][2] = 12, + [0][1][RTW89_FCC][4] = 36, + [0][1][RTW89_ETSI][4] = 12, + [0][1][RTW89_MKK][4] = 14, + [0][1][RTW89_IC][4] = 8, + [0][1][RTW89_KCC][4] = 32, + [0][1][RTW89_ACMA][4] = 12, + [0][1][RTW89_CHILE][4] = 18, + [0][1][RTW89_UKRAINE][4] = 12, + [0][1][RTW89_MEXICO][4] = 36, + [0][1][RTW89_CN][4] = 12, + [0][1][RTW89_QATAR][4] = 12, + [0][1][RTW89_FCC][6] = 36, + [0][1][RTW89_ETSI][6] = 12, + [0][1][RTW89_MKK][6] = 14, + [0][1][RTW89_IC][6] = 8, + [0][1][RTW89_KCC][6] = 4, + [0][1][RTW89_ACMA][6] = 12, + [0][1][RTW89_CHILE][6] = 18, + [0][1][RTW89_UKRAINE][6] = 12, + [0][1][RTW89_MEXICO][6] = 36, + [0][1][RTW89_CN][6] = 12, + [0][1][RTW89_QATAR][6] = 12, + [0][1][RTW89_FCC][8] = 36, + [0][1][RTW89_ETSI][8] = 12, + [0][1][RTW89_MKK][8] = 14, + [0][1][RTW89_IC][8] = 36, + [0][1][RTW89_KCC][8] = 32, + [0][1][RTW89_ACMA][8] = 12, + [0][1][RTW89_CHILE][8] = 36, + [0][1][RTW89_UKRAINE][8] = 12, + [0][1][RTW89_MEXICO][8] = 36, + [0][1][RTW89_CN][8] = 12, + [0][1][RTW89_QATAR][8] = 12, + [0][1][RTW89_FCC][10] = 36, + [0][1][RTW89_ETSI][10] = 12, + [0][1][RTW89_MKK][10] = 14, + [0][1][RTW89_IC][10] = 36, + [0][1][RTW89_KCC][10] = 32, + [0][1][RTW89_ACMA][10] = 12, + [0][1][RTW89_CHILE][10] = 36, + [0][1][RTW89_UKRAINE][10] = 12, + [0][1][RTW89_MEXICO][10] = 36, + [0][1][RTW89_CN][10] = 12, + [0][1][RTW89_QATAR][10] = 12, + [0][1][RTW89_FCC][12] = 36, + [0][1][RTW89_ETSI][12] = 12, + [0][1][RTW89_MKK][12] = 14, + [0][1][RTW89_IC][12] = 36, + [0][1][RTW89_KCC][12] = 32, + [0][1][RTW89_ACMA][12] = 12, + [0][1][RTW89_CHILE][12] = 36, + [0][1][RTW89_UKRAINE][12] = 12, + [0][1][RTW89_MEXICO][12] = 36, + [0][1][RTW89_CN][12] = 12, + [0][1][RTW89_QATAR][12] = 12, + [0][1][RTW89_FCC][14] = 36, + [0][1][RTW89_ETSI][14] = 12, + [0][1][RTW89_MKK][14] = 14, + [0][1][RTW89_IC][14] = 36, + [0][1][RTW89_KCC][14] = 32, + [0][1][RTW89_ACMA][14] = 12, + [0][1][RTW89_CHILE][14] = 36, + [0][1][RTW89_UKRAINE][14] = 12, + [0][1][RTW89_MEXICO][14] = 36, + [0][1][RTW89_CN][14] = 12, + [0][1][RTW89_QATAR][14] = 12, + [0][1][RTW89_FCC][15] = 36, + [0][1][RTW89_ETSI][15] = 12, + [0][1][RTW89_MKK][15] = 32, + [0][1][RTW89_IC][15] = 36, + [0][1][RTW89_KCC][15] = 32, + [0][1][RTW89_ACMA][15] = 12, + [0][1][RTW89_CHILE][15] = 36, + [0][1][RTW89_UKRAINE][15] = 12, + [0][1][RTW89_MEXICO][15] = 36, + [0][1][RTW89_CN][15] = 127, + [0][1][RTW89_QATAR][15] = 12, + [0][1][RTW89_FCC][17] = 36, + [0][1][RTW89_ETSI][17] = 12, + [0][1][RTW89_MKK][17] = 32, + [0][1][RTW89_IC][17] = 36, + [0][1][RTW89_KCC][17] = 32, + [0][1][RTW89_ACMA][17] = 12, + [0][1][RTW89_CHILE][17] = 36, + [0][1][RTW89_UKRAINE][17] = 12, + [0][1][RTW89_MEXICO][17] = 36, + [0][1][RTW89_CN][17] = 127, + [0][1][RTW89_QATAR][17] = 12, + [0][1][RTW89_FCC][19] = 36, + [0][1][RTW89_ETSI][19] = 12, + [0][1][RTW89_MKK][19] = 32, + [0][1][RTW89_IC][19] = 36, + [0][1][RTW89_KCC][19] = 32, + [0][1][RTW89_ACMA][19] = 12, + [0][1][RTW89_CHILE][19] = 36, + [0][1][RTW89_UKRAINE][19] = 12, + [0][1][RTW89_MEXICO][19] = 36, + [0][1][RTW89_CN][19] = 127, + [0][1][RTW89_QATAR][19] = 12, + [0][1][RTW89_FCC][21] = 36, + [0][1][RTW89_ETSI][21] = 12, + [0][1][RTW89_MKK][21] = 32, + [0][1][RTW89_IC][21] = 36, + [0][1][RTW89_KCC][21] = 32, + [0][1][RTW89_ACMA][21] = 12, + [0][1][RTW89_CHILE][21] = 36, + [0][1][RTW89_UKRAINE][21] = 12, + [0][1][RTW89_MEXICO][21] = 36, + [0][1][RTW89_CN][21] = 127, + [0][1][RTW89_QATAR][21] = 12, + [0][1][RTW89_FCC][23] = 36, + [0][1][RTW89_ETSI][23] = 12, + [0][1][RTW89_MKK][23] = 32, + [0][1][RTW89_IC][23] = 36, + [0][1][RTW89_KCC][23] = 32, + [0][1][RTW89_ACMA][23] = 12, + [0][1][RTW89_CHILE][23] = 36, + [0][1][RTW89_UKRAINE][23] = 12, + [0][1][RTW89_MEXICO][23] = 36, + [0][1][RTW89_CN][23] = 127, + [0][1][RTW89_QATAR][23] = 12, + [0][1][RTW89_FCC][25] = 36, + [0][1][RTW89_ETSI][25] = 12, + [0][1][RTW89_MKK][25] = 32, + [0][1][RTW89_IC][25] = 127, + [0][1][RTW89_KCC][25] = 32, + [0][1][RTW89_ACMA][25] = 127, + [0][1][RTW89_CHILE][25] = 36, + [0][1][RTW89_UKRAINE][25] = 12, + [0][1][RTW89_MEXICO][25] = 36, + [0][1][RTW89_CN][25] = 127, + [0][1][RTW89_QATAR][25] = 12, + [0][1][RTW89_FCC][27] = 36, + [0][1][RTW89_ETSI][27] = 12, + [0][1][RTW89_MKK][27] = 32, + [0][1][RTW89_IC][27] = 127, + [0][1][RTW89_KCC][27] = 32, + [0][1][RTW89_ACMA][27] = 127, + [0][1][RTW89_CHILE][27] = 36, + [0][1][RTW89_UKRAINE][27] = 12, + [0][1][RTW89_MEXICO][27] = 36, + [0][1][RTW89_CN][27] = 127, + [0][1][RTW89_QATAR][27] = 12, + [0][1][RTW89_FCC][29] = 36, + [0][1][RTW89_ETSI][29] = 12, + [0][1][RTW89_MKK][29] = 32, + [0][1][RTW89_IC][29] = 127, + [0][1][RTW89_KCC][29] = 32, + [0][1][RTW89_ACMA][29] = 127, + [0][1][RTW89_CHILE][29] = 36, + [0][1][RTW89_UKRAINE][29] = 12, + [0][1][RTW89_MEXICO][29] = 36, + [0][1][RTW89_CN][29] = 127, + [0][1][RTW89_QATAR][29] = 12, + [0][1][RTW89_FCC][31] = 36, + [0][1][RTW89_ETSI][31] = 12, + [0][1][RTW89_MKK][31] = 32, + [0][1][RTW89_IC][31] = 36, + [0][1][RTW89_KCC][31] = 32, + [0][1][RTW89_ACMA][31] = 12, + [0][1][RTW89_CHILE][31] = 36, + [0][1][RTW89_UKRAINE][31] = 12, + [0][1][RTW89_MEXICO][31] = 36, + [0][1][RTW89_CN][31] = 127, + [0][1][RTW89_QATAR][31] = 12, + [0][1][RTW89_FCC][33] = 36, + [0][1][RTW89_ETSI][33] = 12, + [0][1][RTW89_MKK][33] = 32, + [0][1][RTW89_IC][33] = 36, + [0][1][RTW89_KCC][33] = 32, + [0][1][RTW89_ACMA][33] = 12, + [0][1][RTW89_CHILE][33] = 36, + [0][1][RTW89_UKRAINE][33] = 12, + [0][1][RTW89_MEXICO][33] = 36, + [0][1][RTW89_CN][33] = 127, + [0][1][RTW89_QATAR][33] = 12, + [0][1][RTW89_FCC][35] = 36, + [0][1][RTW89_ETSI][35] = 12, + [0][1][RTW89_MKK][35] = 32, + [0][1][RTW89_IC][35] = 36, + [0][1][RTW89_KCC][35] = 32, + [0][1][RTW89_ACMA][35] = 12, + [0][1][RTW89_CHILE][35] = 36, + [0][1][RTW89_UKRAINE][35] = 12, + [0][1][RTW89_MEXICO][35] = 36, + [0][1][RTW89_CN][35] = 127, + [0][1][RTW89_QATAR][35] = 12, + [0][1][RTW89_FCC][37] = 36, + [0][1][RTW89_ETSI][37] = 127, + [0][1][RTW89_MKK][37] = 32, + [0][1][RTW89_IC][37] = 36, + [0][1][RTW89_KCC][37] = 32, + [0][1][RTW89_ACMA][37] = 36, + [0][1][RTW89_CHILE][37] = 36, + [0][1][RTW89_UKRAINE][37] = 127, + [0][1][RTW89_MEXICO][37] = 36, + [0][1][RTW89_CN][37] = 127, + [0][1][RTW89_QATAR][37] = 127, + [0][1][RTW89_FCC][38] = 72, + [0][1][RTW89_ETSI][38] = 16, + [0][1][RTW89_MKK][38] = 127, + [0][1][RTW89_IC][38] = 72, + [0][1][RTW89_KCC][38] = 32, + [0][1][RTW89_ACMA][38] = 76, + [0][1][RTW89_CHILE][38] = 42, + [0][1][RTW89_UKRAINE][38] = 16, + [0][1][RTW89_MEXICO][38] = 72, + [0][1][RTW89_CN][38] = 50, + [0][1][RTW89_QATAR][38] = 16, + [0][1][RTW89_FCC][40] = 76, + [0][1][RTW89_ETSI][40] = 16, + [0][1][RTW89_MKK][40] = 127, + [0][1][RTW89_IC][40] = 76, + [0][1][RTW89_KCC][40] = 32, + [0][1][RTW89_ACMA][40] = 76, + [0][1][RTW89_CHILE][40] = 42, + [0][1][RTW89_UKRAINE][40] = 16, + [0][1][RTW89_MEXICO][40] = 76, + [0][1][RTW89_CN][40] = 50, + [0][1][RTW89_QATAR][40] = 16, + [0][1][RTW89_FCC][42] = 76, + [0][1][RTW89_ETSI][42] = 16, + [0][1][RTW89_MKK][42] = 127, + [0][1][RTW89_IC][42] = 76, + [0][1][RTW89_KCC][42] = 32, + [0][1][RTW89_ACMA][42] = 76, + [0][1][RTW89_CHILE][42] = 42, + [0][1][RTW89_UKRAINE][42] = 16, + [0][1][RTW89_MEXICO][42] = 76, + [0][1][RTW89_CN][42] = 50, + [0][1][RTW89_QATAR][42] = 16, + [0][1][RTW89_FCC][44] = 76, + [0][1][RTW89_ETSI][44] = 16, + [0][1][RTW89_MKK][44] = 127, + [0][1][RTW89_IC][44] = 76, + [0][1][RTW89_KCC][44] = 32, + [0][1][RTW89_ACMA][44] = 76, + [0][1][RTW89_CHILE][44] = 42, + [0][1][RTW89_UKRAINE][44] = 16, + [0][1][RTW89_MEXICO][44] = 76, + [0][1][RTW89_CN][44] = 50, + [0][1][RTW89_QATAR][44] = 16, + [0][1][RTW89_FCC][46] = 76, + [0][1][RTW89_ETSI][46] = 16, + [0][1][RTW89_MKK][46] = 127, + [0][1][RTW89_IC][46] = 76, + [0][1][RTW89_KCC][46] = 32, + [0][1][RTW89_ACMA][46] = 76, + [0][1][RTW89_CHILE][46] = 42, + [0][1][RTW89_UKRAINE][46] = 16, + [0][1][RTW89_MEXICO][46] = 76, + [0][1][RTW89_CN][46] = 50, + [0][1][RTW89_QATAR][46] = 16, + [1][0][RTW89_FCC][0] = 62, + [1][0][RTW89_ETSI][0] = 36, + [1][0][RTW89_MKK][0] = 36, + [1][0][RTW89_IC][0] = 34, + [1][0][RTW89_KCC][0] = 58, + [1][0][RTW89_ACMA][0] = 36, + [1][0][RTW89_CHILE][0] = 30, + [1][0][RTW89_UKRAINE][0] = 36, + [1][0][RTW89_MEXICO][0] = 62, + [1][0][RTW89_CN][0] = 36, + [1][0][RTW89_QATAR][0] = 36, + [1][0][RTW89_FCC][2] = 62, + [1][0][RTW89_ETSI][2] = 36, + [1][0][RTW89_MKK][2] = 36, + [1][0][RTW89_IC][2] = 34, + [1][0][RTW89_KCC][2] = 58, + [1][0][RTW89_ACMA][2] = 36, + [1][0][RTW89_CHILE][2] = 30, + [1][0][RTW89_UKRAINE][2] = 36, + [1][0][RTW89_MEXICO][2] = 62, + [1][0][RTW89_CN][2] = 36, + [1][0][RTW89_QATAR][2] = 36, + [1][0][RTW89_FCC][4] = 62, + [1][0][RTW89_ETSI][4] = 36, + [1][0][RTW89_MKK][4] = 36, + [1][0][RTW89_IC][4] = 34, + [1][0][RTW89_KCC][4] = 58, + [1][0][RTW89_ACMA][4] = 36, + [1][0][RTW89_CHILE][4] = 30, + [1][0][RTW89_UKRAINE][4] = 36, + [1][0][RTW89_MEXICO][4] = 62, + [1][0][RTW89_CN][4] = 36, + [1][0][RTW89_QATAR][4] = 36, + [1][0][RTW89_FCC][6] = 62, + [1][0][RTW89_ETSI][6] = 36, + [1][0][RTW89_MKK][6] = 36, + [1][0][RTW89_IC][6] = 34, + [1][0][RTW89_KCC][6] = 32, + [1][0][RTW89_ACMA][6] = 36, + [1][0][RTW89_CHILE][6] = 30, + [1][0][RTW89_UKRAINE][6] = 36, + [1][0][RTW89_MEXICO][6] = 62, + [1][0][RTW89_CN][6] = 36, + [1][0][RTW89_QATAR][6] = 36, + [1][0][RTW89_FCC][8] = 62, + [1][0][RTW89_ETSI][8] = 36, + [1][0][RTW89_MKK][8] = 36, + [1][0][RTW89_IC][8] = 62, + [1][0][RTW89_KCC][8] = 58, + [1][0][RTW89_ACMA][8] = 36, + [1][0][RTW89_CHILE][8] = 54, + [1][0][RTW89_UKRAINE][8] = 36, + [1][0][RTW89_MEXICO][8] = 62, + [1][0][RTW89_CN][8] = 36, + [1][0][RTW89_QATAR][8] = 36, + [1][0][RTW89_FCC][10] = 62, + [1][0][RTW89_ETSI][10] = 36, + [1][0][RTW89_MKK][10] = 36, + [1][0][RTW89_IC][10] = 62, + [1][0][RTW89_KCC][10] = 58, + [1][0][RTW89_ACMA][10] = 36, + [1][0][RTW89_CHILE][10] = 54, + [1][0][RTW89_UKRAINE][10] = 36, + [1][0][RTW89_MEXICO][10] = 62, + [1][0][RTW89_CN][10] = 36, + [1][0][RTW89_QATAR][10] = 36, + [1][0][RTW89_FCC][12] = 62, + [1][0][RTW89_ETSI][12] = 36, + [1][0][RTW89_MKK][12] = 36, + [1][0][RTW89_IC][12] = 62, + [1][0][RTW89_KCC][12] = 58, + [1][0][RTW89_ACMA][12] = 36, + [1][0][RTW89_CHILE][12] = 54, + [1][0][RTW89_UKRAINE][12] = 36, + [1][0][RTW89_MEXICO][12] = 62, + [1][0][RTW89_CN][12] = 36, + [1][0][RTW89_QATAR][12] = 36, + [1][0][RTW89_FCC][14] = 62, + [1][0][RTW89_ETSI][14] = 36, + [1][0][RTW89_MKK][14] = 36, + [1][0][RTW89_IC][14] = 62, + [1][0][RTW89_KCC][14] = 58, + [1][0][RTW89_ACMA][14] = 36, + [1][0][RTW89_CHILE][14] = 54, + [1][0][RTW89_UKRAINE][14] = 36, + [1][0][RTW89_MEXICO][14] = 62, + [1][0][RTW89_CN][14] = 36, + [1][0][RTW89_QATAR][14] = 36, + [1][0][RTW89_FCC][15] = 62, + [1][0][RTW89_ETSI][15] = 36, + [1][0][RTW89_MKK][15] = 58, + [1][0][RTW89_IC][15] = 62, + [1][0][RTW89_KCC][15] = 58, + [1][0][RTW89_ACMA][15] = 36, + [1][0][RTW89_CHILE][15] = 54, + [1][0][RTW89_UKRAINE][15] = 36, + [1][0][RTW89_MEXICO][15] = 62, + [1][0][RTW89_CN][15] = 127, + [1][0][RTW89_QATAR][15] = 36, + [1][0][RTW89_FCC][17] = 62, + [1][0][RTW89_ETSI][17] = 36, + [1][0][RTW89_MKK][17] = 58, + [1][0][RTW89_IC][17] = 62, + [1][0][RTW89_KCC][17] = 58, + [1][0][RTW89_ACMA][17] = 36, + [1][0][RTW89_CHILE][17] = 54, + [1][0][RTW89_UKRAINE][17] = 36, + [1][0][RTW89_MEXICO][17] = 62, + [1][0][RTW89_CN][17] = 127, + [1][0][RTW89_QATAR][17] = 36, + [1][0][RTW89_FCC][19] = 62, + [1][0][RTW89_ETSI][19] = 36, + [1][0][RTW89_MKK][19] = 58, + [1][0][RTW89_IC][19] = 62, + [1][0][RTW89_KCC][19] = 58, + [1][0][RTW89_ACMA][19] = 36, + [1][0][RTW89_CHILE][19] = 54, + [1][0][RTW89_UKRAINE][19] = 36, + [1][0][RTW89_MEXICO][19] = 62, + [1][0][RTW89_CN][19] = 127, + [1][0][RTW89_QATAR][19] = 36, + [1][0][RTW89_FCC][21] = 62, + [1][0][RTW89_ETSI][21] = 36, + [1][0][RTW89_MKK][21] = 58, + [1][0][RTW89_IC][21] = 62, + [1][0][RTW89_KCC][21] = 58, + [1][0][RTW89_ACMA][21] = 36, + [1][0][RTW89_CHILE][21] = 54, + [1][0][RTW89_UKRAINE][21] = 36, + [1][0][RTW89_MEXICO][21] = 62, + [1][0][RTW89_CN][21] = 127, + [1][0][RTW89_QATAR][21] = 36, + [1][0][RTW89_FCC][23] = 62, + [1][0][RTW89_ETSI][23] = 36, + [1][0][RTW89_MKK][23] = 58, + [1][0][RTW89_IC][23] = 62, + [1][0][RTW89_KCC][23] = 58, + [1][0][RTW89_ACMA][23] = 36, + [1][0][RTW89_CHILE][23] = 54, + [1][0][RTW89_UKRAINE][23] = 36, + [1][0][RTW89_MEXICO][23] = 62, + [1][0][RTW89_CN][23] = 127, + [1][0][RTW89_QATAR][23] = 36, + [1][0][RTW89_FCC][25] = 62, + [1][0][RTW89_ETSI][25] = 36, + [1][0][RTW89_MKK][25] = 58, + [1][0][RTW89_IC][25] = 127, + [1][0][RTW89_KCC][25] = 58, + [1][0][RTW89_ACMA][25] = 127, + [1][0][RTW89_CHILE][25] = 54, + [1][0][RTW89_UKRAINE][25] = 36, + [1][0][RTW89_MEXICO][25] = 62, + [1][0][RTW89_CN][25] = 127, + [1][0][RTW89_QATAR][25] = 36, + [1][0][RTW89_FCC][27] = 62, + [1][0][RTW89_ETSI][27] = 36, + [1][0][RTW89_MKK][27] = 58, + [1][0][RTW89_IC][27] = 127, + [1][0][RTW89_KCC][27] = 58, + [1][0][RTW89_ACMA][27] = 127, + [1][0][RTW89_CHILE][27] = 54, + [1][0][RTW89_UKRAINE][27] = 36, + [1][0][RTW89_MEXICO][27] = 62, + [1][0][RTW89_CN][27] = 127, + [1][0][RTW89_QATAR][27] = 36, + [1][0][RTW89_FCC][29] = 62, + [1][0][RTW89_ETSI][29] = 36, + [1][0][RTW89_MKK][29] = 58, + [1][0][RTW89_IC][29] = 127, + [1][0][RTW89_KCC][29] = 58, + [1][0][RTW89_ACMA][29] = 127, + [1][0][RTW89_CHILE][29] = 54, + [1][0][RTW89_UKRAINE][29] = 36, + [1][0][RTW89_MEXICO][29] = 62, + [1][0][RTW89_CN][29] = 127, + [1][0][RTW89_QATAR][29] = 36, + [1][0][RTW89_FCC][31] = 62, + [1][0][RTW89_ETSI][31] = 36, + [1][0][RTW89_MKK][31] = 58, + [1][0][RTW89_IC][31] = 62, + [1][0][RTW89_KCC][31] = 58, + [1][0][RTW89_ACMA][31] = 36, + [1][0][RTW89_CHILE][31] = 54, + [1][0][RTW89_UKRAINE][31] = 36, + [1][0][RTW89_MEXICO][31] = 62, + [1][0][RTW89_CN][31] = 127, + [1][0][RTW89_QATAR][31] = 36, + [1][0][RTW89_FCC][33] = 62, + [1][0][RTW89_ETSI][33] = 36, + [1][0][RTW89_MKK][33] = 58, + [1][0][RTW89_IC][33] = 62, + [1][0][RTW89_KCC][33] = 58, + [1][0][RTW89_ACMA][33] = 36, + [1][0][RTW89_CHILE][33] = 54, + [1][0][RTW89_UKRAINE][33] = 36, + [1][0][RTW89_MEXICO][33] = 62, + [1][0][RTW89_CN][33] = 127, + [1][0][RTW89_QATAR][33] = 36, + [1][0][RTW89_FCC][35] = 62, + [1][0][RTW89_ETSI][35] = 36, + [1][0][RTW89_MKK][35] = 58, + [1][0][RTW89_IC][35] = 62, + [1][0][RTW89_KCC][35] = 58, + [1][0][RTW89_ACMA][35] = 36, + [1][0][RTW89_CHILE][35] = 54, + [1][0][RTW89_UKRAINE][35] = 36, + [1][0][RTW89_MEXICO][35] = 62, + [1][0][RTW89_CN][35] = 127, + [1][0][RTW89_QATAR][35] = 36, + [1][0][RTW89_FCC][37] = 62, + [1][0][RTW89_ETSI][37] = 127, + [1][0][RTW89_MKK][37] = 58, + [1][0][RTW89_IC][37] = 62, + [1][0][RTW89_KCC][37] = 58, + [1][0][RTW89_ACMA][37] = 62, + [1][0][RTW89_CHILE][37] = 54, + [1][0][RTW89_UKRAINE][37] = 127, + [1][0][RTW89_MEXICO][37] = 62, + [1][0][RTW89_CN][37] = 127, + [1][0][RTW89_QATAR][37] = 127, + [1][0][RTW89_FCC][38] = 76, + [1][0][RTW89_ETSI][38] = 28, + [1][0][RTW89_MKK][38] = 127, + [1][0][RTW89_IC][38] = 76, + [1][0][RTW89_KCC][38] = 58, + [1][0][RTW89_ACMA][38] = 76, + [1][0][RTW89_CHILE][38] = 54, + [1][0][RTW89_UKRAINE][38] = 28, + [1][0][RTW89_MEXICO][38] = 76, + [1][0][RTW89_CN][38] = 74, + [1][0][RTW89_QATAR][38] = 28, + [1][0][RTW89_FCC][40] = 76, + [1][0][RTW89_ETSI][40] = 28, + [1][0][RTW89_MKK][40] = 127, + [1][0][RTW89_IC][40] = 76, + [1][0][RTW89_KCC][40] = 58, + [1][0][RTW89_ACMA][40] = 76, + [1][0][RTW89_CHILE][40] = 54, + [1][0][RTW89_UKRAINE][40] = 28, + [1][0][RTW89_MEXICO][40] = 76, + [1][0][RTW89_CN][40] = 74, + [1][0][RTW89_QATAR][40] = 28, + [1][0][RTW89_FCC][42] = 76, + [1][0][RTW89_ETSI][42] = 28, + [1][0][RTW89_MKK][42] = 127, + [1][0][RTW89_IC][42] = 76, + [1][0][RTW89_KCC][42] = 58, + [1][0][RTW89_ACMA][42] = 76, + [1][0][RTW89_CHILE][42] = 54, + [1][0][RTW89_UKRAINE][42] = 28, + [1][0][RTW89_MEXICO][42] = 76, + [1][0][RTW89_CN][42] = 74, + [1][0][RTW89_QATAR][42] = 28, + [1][0][RTW89_FCC][44] = 76, + [1][0][RTW89_ETSI][44] = 28, + [1][0][RTW89_MKK][44] = 127, + [1][0][RTW89_IC][44] = 76, + [1][0][RTW89_KCC][44] = 58, + [1][0][RTW89_ACMA][44] = 76, + [1][0][RTW89_CHILE][44] = 54, + [1][0][RTW89_UKRAINE][44] = 28, + [1][0][RTW89_MEXICO][44] = 76, + [1][0][RTW89_CN][44] = 74, + [1][0][RTW89_QATAR][44] = 28, + [1][0][RTW89_FCC][46] = 76, + [1][0][RTW89_ETSI][46] = 28, + [1][0][RTW89_MKK][46] = 127, + [1][0][RTW89_IC][46] = 76, + [1][0][RTW89_KCC][46] = 58, + [1][0][RTW89_ACMA][46] = 76, + [1][0][RTW89_CHILE][46] = 54, + [1][0][RTW89_UKRAINE][46] = 28, + [1][0][RTW89_MEXICO][46] = 76, + [1][0][RTW89_CN][46] = 74, + [1][0][RTW89_QATAR][46] = 28, + [1][1][RTW89_FCC][0] = 46, + [1][1][RTW89_ETSI][0] = 22, + [1][1][RTW89_MKK][0] = 24, + [1][1][RTW89_IC][0] = 18, + [1][1][RTW89_KCC][0] = 44, + [1][1][RTW89_ACMA][0] = 22, + [1][1][RTW89_CHILE][0] = 18, + [1][1][RTW89_UKRAINE][0] = 22, + [1][1][RTW89_MEXICO][0] = 46, + [1][1][RTW89_CN][0] = 22, + [1][1][RTW89_QATAR][0] = 22, + [1][1][RTW89_FCC][2] = 46, + [1][1][RTW89_ETSI][2] = 22, + [1][1][RTW89_MKK][2] = 24, + [1][1][RTW89_IC][2] = 18, + [1][1][RTW89_KCC][2] = 44, + [1][1][RTW89_ACMA][2] = 22, + [1][1][RTW89_CHILE][2] = 18, + [1][1][RTW89_UKRAINE][2] = 22, + [1][1][RTW89_MEXICO][2] = 46, + [1][1][RTW89_CN][2] = 22, + [1][1][RTW89_QATAR][2] = 22, + [1][1][RTW89_FCC][4] = 46, + [1][1][RTW89_ETSI][4] = 22, + [1][1][RTW89_MKK][4] = 24, + [1][1][RTW89_IC][4] = 18, + [1][1][RTW89_KCC][4] = 44, + [1][1][RTW89_ACMA][4] = 22, + [1][1][RTW89_CHILE][4] = 18, + [1][1][RTW89_UKRAINE][4] = 22, + [1][1][RTW89_MEXICO][4] = 46, + [1][1][RTW89_CN][4] = 22, + [1][1][RTW89_QATAR][4] = 22, + [1][1][RTW89_FCC][6] = 46, + [1][1][RTW89_ETSI][6] = 22, + [1][1][RTW89_MKK][6] = 24, + [1][1][RTW89_IC][6] = 18, + [1][1][RTW89_KCC][6] = 16, + [1][1][RTW89_ACMA][6] = 22, + [1][1][RTW89_CHILE][6] = 18, + [1][1][RTW89_UKRAINE][6] = 22, + [1][1][RTW89_MEXICO][6] = 46, + [1][1][RTW89_CN][6] = 22, + [1][1][RTW89_QATAR][6] = 22, + [1][1][RTW89_FCC][8] = 46, + [1][1][RTW89_ETSI][8] = 22, + [1][1][RTW89_MKK][8] = 24, + [1][1][RTW89_IC][8] = 46, + [1][1][RTW89_KCC][8] = 44, + [1][1][RTW89_ACMA][8] = 22, + [1][1][RTW89_CHILE][8] = 42, + [1][1][RTW89_UKRAINE][8] = 22, + [1][1][RTW89_MEXICO][8] = 46, + [1][1][RTW89_CN][8] = 22, + [1][1][RTW89_QATAR][8] = 22, + [1][1][RTW89_FCC][10] = 46, + [1][1][RTW89_ETSI][10] = 22, + [1][1][RTW89_MKK][10] = 24, + [1][1][RTW89_IC][10] = 46, + [1][1][RTW89_KCC][10] = 44, + [1][1][RTW89_ACMA][10] = 22, + [1][1][RTW89_CHILE][10] = 42, + [1][1][RTW89_UKRAINE][10] = 22, + [1][1][RTW89_MEXICO][10] = 46, + [1][1][RTW89_CN][10] = 22, + [1][1][RTW89_QATAR][10] = 22, + [1][1][RTW89_FCC][12] = 46, + [1][1][RTW89_ETSI][12] = 22, + [1][1][RTW89_MKK][12] = 24, + [1][1][RTW89_IC][12] = 46, + [1][1][RTW89_KCC][12] = 44, + [1][1][RTW89_ACMA][12] = 22, + [1][1][RTW89_CHILE][12] = 42, + [1][1][RTW89_UKRAINE][12] = 22, + [1][1][RTW89_MEXICO][12] = 46, + [1][1][RTW89_CN][12] = 22, + [1][1][RTW89_QATAR][12] = 22, + [1][1][RTW89_FCC][14] = 46, + [1][1][RTW89_ETSI][14] = 22, + [1][1][RTW89_MKK][14] = 24, + [1][1][RTW89_IC][14] = 46, + [1][1][RTW89_KCC][14] = 44, + [1][1][RTW89_ACMA][14] = 22, + [1][1][RTW89_CHILE][14] = 42, + [1][1][RTW89_UKRAINE][14] = 22, + [1][1][RTW89_MEXICO][14] = 46, + [1][1][RTW89_CN][14] = 22, + [1][1][RTW89_QATAR][14] = 22, + [1][1][RTW89_FCC][15] = 46, + [1][1][RTW89_ETSI][15] = 22, + [1][1][RTW89_MKK][15] = 46, + [1][1][RTW89_IC][15] = 46, + [1][1][RTW89_KCC][15] = 44, + [1][1][RTW89_ACMA][15] = 22, + [1][1][RTW89_CHILE][15] = 42, + [1][1][RTW89_UKRAINE][15] = 22, + [1][1][RTW89_MEXICO][15] = 46, + [1][1][RTW89_CN][15] = 127, + [1][1][RTW89_QATAR][15] = 22, + [1][1][RTW89_FCC][17] = 46, + [1][1][RTW89_ETSI][17] = 22, + [1][1][RTW89_MKK][17] = 46, + [1][1][RTW89_IC][17] = 46, + [1][1][RTW89_KCC][17] = 44, + [1][1][RTW89_ACMA][17] = 22, + [1][1][RTW89_CHILE][17] = 42, + [1][1][RTW89_UKRAINE][17] = 22, + [1][1][RTW89_MEXICO][17] = 46, + [1][1][RTW89_CN][17] = 127, + [1][1][RTW89_QATAR][17] = 22, + [1][1][RTW89_FCC][19] = 46, + [1][1][RTW89_ETSI][19] = 22, + [1][1][RTW89_MKK][19] = 46, + [1][1][RTW89_IC][19] = 46, + [1][1][RTW89_KCC][19] = 44, + [1][1][RTW89_ACMA][19] = 22, + [1][1][RTW89_CHILE][19] = 42, + [1][1][RTW89_UKRAINE][19] = 22, + [1][1][RTW89_MEXICO][19] = 46, + [1][1][RTW89_CN][19] = 127, + [1][1][RTW89_QATAR][19] = 22, + [1][1][RTW89_FCC][21] = 46, + [1][1][RTW89_ETSI][21] = 22, + [1][1][RTW89_MKK][21] = 46, + [1][1][RTW89_IC][21] = 46, + [1][1][RTW89_KCC][21] = 44, + [1][1][RTW89_ACMA][21] = 22, + [1][1][RTW89_CHILE][21] = 42, + [1][1][RTW89_UKRAINE][21] = 22, + [1][1][RTW89_MEXICO][21] = 46, + [1][1][RTW89_CN][21] = 127, + [1][1][RTW89_QATAR][21] = 22, + [1][1][RTW89_FCC][23] = 46, + [1][1][RTW89_ETSI][23] = 22, + [1][1][RTW89_MKK][23] = 46, + [1][1][RTW89_IC][23] = 46, + [1][1][RTW89_KCC][23] = 44, + [1][1][RTW89_ACMA][23] = 22, + [1][1][RTW89_CHILE][23] = 42, + [1][1][RTW89_UKRAINE][23] = 22, + [1][1][RTW89_MEXICO][23] = 46, + [1][1][RTW89_CN][23] = 127, + [1][1][RTW89_QATAR][23] = 22, + [1][1][RTW89_FCC][25] = 46, + [1][1][RTW89_ETSI][25] = 22, + [1][1][RTW89_MKK][25] = 46, + [1][1][RTW89_IC][25] = 127, + [1][1][RTW89_KCC][25] = 44, + [1][1][RTW89_ACMA][25] = 127, + [1][1][RTW89_CHILE][25] = 42, + [1][1][RTW89_UKRAINE][25] = 22, + [1][1][RTW89_MEXICO][25] = 46, + [1][1][RTW89_CN][25] = 127, + [1][1][RTW89_QATAR][25] = 22, + [1][1][RTW89_FCC][27] = 46, + [1][1][RTW89_ETSI][27] = 22, + [1][1][RTW89_MKK][27] = 46, + [1][1][RTW89_IC][27] = 127, + [1][1][RTW89_KCC][27] = 44, + [1][1][RTW89_ACMA][27] = 127, + [1][1][RTW89_CHILE][27] = 42, + [1][1][RTW89_UKRAINE][27] = 22, + [1][1][RTW89_MEXICO][27] = 46, + [1][1][RTW89_CN][27] = 127, + [1][1][RTW89_QATAR][27] = 22, + [1][1][RTW89_FCC][29] = 46, + [1][1][RTW89_ETSI][29] = 22, + [1][1][RTW89_MKK][29] = 46, + [1][1][RTW89_IC][29] = 127, + [1][1][RTW89_KCC][29] = 44, + [1][1][RTW89_ACMA][29] = 127, + [1][1][RTW89_CHILE][29] = 42, + [1][1][RTW89_UKRAINE][29] = 22, + [1][1][RTW89_MEXICO][29] = 46, + [1][1][RTW89_CN][29] = 127, + [1][1][RTW89_QATAR][29] = 22, + [1][1][RTW89_FCC][31] = 46, + [1][1][RTW89_ETSI][31] = 22, + [1][1][RTW89_MKK][31] = 46, + [1][1][RTW89_IC][31] = 46, + [1][1][RTW89_KCC][31] = 44, + [1][1][RTW89_ACMA][31] = 22, + [1][1][RTW89_CHILE][31] = 42, + [1][1][RTW89_UKRAINE][31] = 22, + [1][1][RTW89_MEXICO][31] = 46, + [1][1][RTW89_CN][31] = 127, + [1][1][RTW89_QATAR][31] = 22, + [1][1][RTW89_FCC][33] = 46, + [1][1][RTW89_ETSI][33] = 22, + [1][1][RTW89_MKK][33] = 46, + [1][1][RTW89_IC][33] = 46, + [1][1][RTW89_KCC][33] = 44, + [1][1][RTW89_ACMA][33] = 22, + [1][1][RTW89_CHILE][33] = 42, + [1][1][RTW89_UKRAINE][33] = 22, + [1][1][RTW89_MEXICO][33] = 46, + [1][1][RTW89_CN][33] = 127, + [1][1][RTW89_QATAR][33] = 22, + [1][1][RTW89_FCC][35] = 46, + [1][1][RTW89_ETSI][35] = 22, + [1][1][RTW89_MKK][35] = 46, + [1][1][RTW89_IC][35] = 46, + [1][1][RTW89_KCC][35] = 44, + [1][1][RTW89_ACMA][35] = 22, + [1][1][RTW89_CHILE][35] = 42, + [1][1][RTW89_UKRAINE][35] = 22, + [1][1][RTW89_MEXICO][35] = 46, + [1][1][RTW89_CN][35] = 127, + [1][1][RTW89_QATAR][35] = 22, + [1][1][RTW89_FCC][37] = 46, + [1][1][RTW89_ETSI][37] = 127, + [1][1][RTW89_MKK][37] = 46, + [1][1][RTW89_IC][37] = 46, + [1][1][RTW89_KCC][37] = 44, + [1][1][RTW89_ACMA][37] = 50, + [1][1][RTW89_CHILE][37] = 42, + [1][1][RTW89_UKRAINE][37] = 127, + [1][1][RTW89_MEXICO][37] = 46, + [1][1][RTW89_CN][37] = 127, + [1][1][RTW89_QATAR][37] = 127, + [1][1][RTW89_FCC][38] = 74, + [1][1][RTW89_ETSI][38] = 16, + [1][1][RTW89_MKK][38] = 127, + [1][1][RTW89_IC][38] = 74, + [1][1][RTW89_KCC][38] = 44, + [1][1][RTW89_ACMA][38] = 76, + [1][1][RTW89_CHILE][38] = 42, + [1][1][RTW89_UKRAINE][38] = 16, + [1][1][RTW89_MEXICO][38] = 74, + [1][1][RTW89_CN][38] = 62, + [1][1][RTW89_QATAR][38] = 16, + [1][1][RTW89_FCC][40] = 76, + [1][1][RTW89_ETSI][40] = 16, + [1][1][RTW89_MKK][40] = 127, + [1][1][RTW89_IC][40] = 76, + [1][1][RTW89_KCC][40] = 44, + [1][1][RTW89_ACMA][40] = 76, + [1][1][RTW89_CHILE][40] = 42, + [1][1][RTW89_UKRAINE][40] = 16, + [1][1][RTW89_MEXICO][40] = 76, + [1][1][RTW89_CN][40] = 62, + [1][1][RTW89_QATAR][40] = 16, + [1][1][RTW89_FCC][42] = 76, + [1][1][RTW89_ETSI][42] = 16, + [1][1][RTW89_MKK][42] = 127, + [1][1][RTW89_IC][42] = 76, + [1][1][RTW89_KCC][42] = 44, + [1][1][RTW89_ACMA][42] = 76, + [1][1][RTW89_CHILE][42] = 42, + [1][1][RTW89_UKRAINE][42] = 16, + [1][1][RTW89_MEXICO][42] = 76, + [1][1][RTW89_CN][42] = 62, + [1][1][RTW89_QATAR][42] = 16, + [1][1][RTW89_FCC][44] = 76, + [1][1][RTW89_ETSI][44] = 16, + [1][1][RTW89_MKK][44] = 127, + [1][1][RTW89_IC][44] = 76, + [1][1][RTW89_KCC][44] = 44, + [1][1][RTW89_ACMA][44] = 76, + [1][1][RTW89_CHILE][44] = 42, + [1][1][RTW89_UKRAINE][44] = 16, + [1][1][RTW89_MEXICO][44] = 76, + [1][1][RTW89_CN][44] = 62, + [1][1][RTW89_QATAR][44] = 16, + [1][1][RTW89_FCC][46] = 76, + [1][1][RTW89_ETSI][46] = 16, + [1][1][RTW89_MKK][46] = 127, + [1][1][RTW89_IC][46] = 76, + [1][1][RTW89_KCC][46] = 44, + [1][1][RTW89_ACMA][46] = 76, + [1][1][RTW89_CHILE][46] = 42, + [1][1][RTW89_UKRAINE][46] = 16, + [1][1][RTW89_MEXICO][46] = 76, + [1][1][RTW89_CN][46] = 62, + [1][1][RTW89_QATAR][46] = 16, + [2][0][RTW89_FCC][0] = 74, + [2][0][RTW89_ETSI][0] = 46, + [2][0][RTW89_MKK][0] = 50, + [2][0][RTW89_IC][0] = 46, + [2][0][RTW89_KCC][0] = 70, + [2][0][RTW89_ACMA][0] = 46, + [2][0][RTW89_CHILE][0] = 30, + [2][0][RTW89_UKRAINE][0] = 46, + [2][0][RTW89_MEXICO][0] = 62, + [2][0][RTW89_CN][0] = 46, + [2][0][RTW89_QATAR][0] = 46, + [2][0][RTW89_FCC][2] = 74, + [2][0][RTW89_ETSI][2] = 46, + [2][0][RTW89_MKK][2] = 50, + [2][0][RTW89_IC][2] = 46, + [2][0][RTW89_KCC][2] = 70, + [2][0][RTW89_ACMA][2] = 46, + [2][0][RTW89_CHILE][2] = 30, + [2][0][RTW89_UKRAINE][2] = 46, + [2][0][RTW89_MEXICO][2] = 62, + [2][0][RTW89_CN][2] = 46, + [2][0][RTW89_QATAR][2] = 46, + [2][0][RTW89_FCC][4] = 74, + [2][0][RTW89_ETSI][4] = 46, + [2][0][RTW89_MKK][4] = 50, + [2][0][RTW89_IC][4] = 46, + [2][0][RTW89_KCC][4] = 70, + [2][0][RTW89_ACMA][4] = 46, + [2][0][RTW89_CHILE][4] = 30, + [2][0][RTW89_UKRAINE][4] = 46, + [2][0][RTW89_MEXICO][4] = 62, + [2][0][RTW89_CN][4] = 46, + [2][0][RTW89_QATAR][4] = 46, + [2][0][RTW89_FCC][6] = 74, + [2][0][RTW89_ETSI][6] = 46, + [2][0][RTW89_MKK][6] = 50, + [2][0][RTW89_IC][6] = 46, + [2][0][RTW89_KCC][6] = 44, + [2][0][RTW89_ACMA][6] = 46, + [2][0][RTW89_CHILE][6] = 30, + [2][0][RTW89_UKRAINE][6] = 46, + [2][0][RTW89_MEXICO][6] = 62, + [2][0][RTW89_CN][6] = 46, + [2][0][RTW89_QATAR][6] = 46, + [2][0][RTW89_FCC][8] = 74, + [2][0][RTW89_ETSI][8] = 46, + [2][0][RTW89_MKK][8] = 50, + [2][0][RTW89_IC][8] = 66, + [2][0][RTW89_KCC][8] = 70, + [2][0][RTW89_ACMA][8] = 46, + [2][0][RTW89_CHILE][8] = 54, + [2][0][RTW89_UKRAINE][8] = 46, + [2][0][RTW89_MEXICO][8] = 74, + [2][0][RTW89_CN][8] = 46, + [2][0][RTW89_QATAR][8] = 46, + [2][0][RTW89_FCC][10] = 74, + [2][0][RTW89_ETSI][10] = 46, + [2][0][RTW89_MKK][10] = 50, + [2][0][RTW89_IC][10] = 66, + [2][0][RTW89_KCC][10] = 70, + [2][0][RTW89_ACMA][10] = 46, + [2][0][RTW89_CHILE][10] = 54, + [2][0][RTW89_UKRAINE][10] = 46, + [2][0][RTW89_MEXICO][10] = 74, + [2][0][RTW89_CN][10] = 46, + [2][0][RTW89_QATAR][10] = 46, + [2][0][RTW89_FCC][12] = 74, + [2][0][RTW89_ETSI][12] = 46, + [2][0][RTW89_MKK][12] = 50, + [2][0][RTW89_IC][12] = 66, + [2][0][RTW89_KCC][12] = 70, + [2][0][RTW89_ACMA][12] = 46, + [2][0][RTW89_CHILE][12] = 54, + [2][0][RTW89_UKRAINE][12] = 46, + [2][0][RTW89_MEXICO][12] = 74, + [2][0][RTW89_CN][12] = 46, + [2][0][RTW89_QATAR][12] = 46, + [2][0][RTW89_FCC][14] = 74, + [2][0][RTW89_ETSI][14] = 46, + [2][0][RTW89_MKK][14] = 50, + [2][0][RTW89_IC][14] = 66, + [2][0][RTW89_KCC][14] = 70, + [2][0][RTW89_ACMA][14] = 46, + [2][0][RTW89_CHILE][14] = 54, + [2][0][RTW89_UKRAINE][14] = 46, + [2][0][RTW89_MEXICO][14] = 74, + [2][0][RTW89_CN][14] = 46, + [2][0][RTW89_QATAR][14] = 46, + [2][0][RTW89_FCC][15] = 74, + [2][0][RTW89_ETSI][15] = 46, + [2][0][RTW89_MKK][15] = 70, + [2][0][RTW89_IC][15] = 74, + [2][0][RTW89_KCC][15] = 70, + [2][0][RTW89_ACMA][15] = 46, + [2][0][RTW89_CHILE][15] = 54, + [2][0][RTW89_UKRAINE][15] = 46, + [2][0][RTW89_MEXICO][15] = 74, + [2][0][RTW89_CN][15] = 127, + [2][0][RTW89_QATAR][15] = 46, + [2][0][RTW89_FCC][17] = 74, + [2][0][RTW89_ETSI][17] = 46, + [2][0][RTW89_MKK][17] = 70, + [2][0][RTW89_IC][17] = 74, + [2][0][RTW89_KCC][17] = 70, + [2][0][RTW89_ACMA][17] = 46, + [2][0][RTW89_CHILE][17] = 54, + [2][0][RTW89_UKRAINE][17] = 46, + [2][0][RTW89_MEXICO][17] = 74, + [2][0][RTW89_CN][17] = 127, + [2][0][RTW89_QATAR][17] = 46, + [2][0][RTW89_FCC][19] = 74, + [2][0][RTW89_ETSI][19] = 46, + [2][0][RTW89_MKK][19] = 70, + [2][0][RTW89_IC][19] = 74, + [2][0][RTW89_KCC][19] = 70, + [2][0][RTW89_ACMA][19] = 46, + [2][0][RTW89_CHILE][19] = 54, + [2][0][RTW89_UKRAINE][19] = 46, + [2][0][RTW89_MEXICO][19] = 74, + [2][0][RTW89_CN][19] = 127, + [2][0][RTW89_QATAR][19] = 46, + [2][0][RTW89_FCC][21] = 74, + [2][0][RTW89_ETSI][21] = 46, + [2][0][RTW89_MKK][21] = 70, + [2][0][RTW89_IC][21] = 74, + [2][0][RTW89_KCC][21] = 70, + [2][0][RTW89_ACMA][21] = 46, + [2][0][RTW89_CHILE][21] = 54, + [2][0][RTW89_UKRAINE][21] = 46, + [2][0][RTW89_MEXICO][21] = 74, + [2][0][RTW89_CN][21] = 127, + [2][0][RTW89_QATAR][21] = 46, + [2][0][RTW89_FCC][23] = 74, + [2][0][RTW89_ETSI][23] = 46, + [2][0][RTW89_MKK][23] = 70, + [2][0][RTW89_IC][23] = 74, + [2][0][RTW89_KCC][23] = 70, + [2][0][RTW89_ACMA][23] = 46, + [2][0][RTW89_CHILE][23] = 54, + [2][0][RTW89_UKRAINE][23] = 46, + [2][0][RTW89_MEXICO][23] = 74, + [2][0][RTW89_CN][23] = 127, + [2][0][RTW89_QATAR][23] = 46, + [2][0][RTW89_FCC][25] = 74, + [2][0][RTW89_ETSI][25] = 46, + [2][0][RTW89_MKK][25] = 70, + [2][0][RTW89_IC][25] = 127, + [2][0][RTW89_KCC][25] = 70, + [2][0][RTW89_ACMA][25] = 127, + [2][0][RTW89_CHILE][25] = 54, + [2][0][RTW89_UKRAINE][25] = 46, + [2][0][RTW89_MEXICO][25] = 74, + [2][0][RTW89_CN][25] = 127, + [2][0][RTW89_QATAR][25] = 46, + [2][0][RTW89_FCC][27] = 74, + [2][0][RTW89_ETSI][27] = 46, + [2][0][RTW89_MKK][27] = 70, + [2][0][RTW89_IC][27] = 127, + [2][0][RTW89_KCC][27] = 70, + [2][0][RTW89_ACMA][27] = 127, + [2][0][RTW89_CHILE][27] = 54, + [2][0][RTW89_UKRAINE][27] = 46, + [2][0][RTW89_MEXICO][27] = 74, + [2][0][RTW89_CN][27] = 127, + [2][0][RTW89_QATAR][27] = 46, + [2][0][RTW89_FCC][29] = 74, + [2][0][RTW89_ETSI][29] = 46, + [2][0][RTW89_MKK][29] = 70, + [2][0][RTW89_IC][29] = 127, + [2][0][RTW89_KCC][29] = 70, + [2][0][RTW89_ACMA][29] = 127, + [2][0][RTW89_CHILE][29] = 54, + [2][0][RTW89_UKRAINE][29] = 46, + [2][0][RTW89_MEXICO][29] = 74, + [2][0][RTW89_CN][29] = 127, + [2][0][RTW89_QATAR][29] = 46, + [2][0][RTW89_FCC][31] = 74, + [2][0][RTW89_ETSI][31] = 46, + [2][0][RTW89_MKK][31] = 70, + [2][0][RTW89_IC][31] = 74, + [2][0][RTW89_KCC][31] = 70, + [2][0][RTW89_ACMA][31] = 46, + [2][0][RTW89_CHILE][31] = 54, + [2][0][RTW89_UKRAINE][31] = 46, + [2][0][RTW89_MEXICO][31] = 74, + [2][0][RTW89_CN][31] = 127, + [2][0][RTW89_QATAR][31] = 46, + [2][0][RTW89_FCC][33] = 74, + [2][0][RTW89_ETSI][33] = 46, + [2][0][RTW89_MKK][33] = 70, + [2][0][RTW89_IC][33] = 74, + [2][0][RTW89_KCC][33] = 70, + [2][0][RTW89_ACMA][33] = 46, + [2][0][RTW89_CHILE][33] = 54, + [2][0][RTW89_UKRAINE][33] = 46, + [2][0][RTW89_MEXICO][33] = 74, + [2][0][RTW89_CN][33] = 127, + [2][0][RTW89_QATAR][33] = 46, + [2][0][RTW89_FCC][35] = 74, + [2][0][RTW89_ETSI][35] = 46, + [2][0][RTW89_MKK][35] = 70, + [2][0][RTW89_IC][35] = 74, + [2][0][RTW89_KCC][35] = 70, + [2][0][RTW89_ACMA][35] = 46, + [2][0][RTW89_CHILE][35] = 54, + [2][0][RTW89_UKRAINE][35] = 46, + [2][0][RTW89_MEXICO][35] = 74, + [2][0][RTW89_CN][35] = 127, + [2][0][RTW89_QATAR][35] = 46, + [2][0][RTW89_FCC][37] = 74, + [2][0][RTW89_ETSI][37] = 127, + [2][0][RTW89_MKK][37] = 70, + [2][0][RTW89_IC][37] = 74, + [2][0][RTW89_KCC][37] = 70, + [2][0][RTW89_ACMA][37] = 74, + [2][0][RTW89_CHILE][37] = 54, + [2][0][RTW89_UKRAINE][37] = 127, + [2][0][RTW89_MEXICO][37] = 74, + [2][0][RTW89_CN][37] = 127, + [2][0][RTW89_QATAR][37] = 127, + [2][0][RTW89_FCC][38] = 76, + [2][0][RTW89_ETSI][38] = 28, + [2][0][RTW89_MKK][38] = 127, + [2][0][RTW89_IC][38] = 76, + [2][0][RTW89_KCC][38] = 70, + [2][0][RTW89_ACMA][38] = 76, + [2][0][RTW89_CHILE][38] = 54, + [2][0][RTW89_UKRAINE][38] = 28, + [2][0][RTW89_MEXICO][38] = 76, + [2][0][RTW89_CN][38] = 76, + [2][0][RTW89_QATAR][38] = 28, + [2][0][RTW89_FCC][40] = 76, + [2][0][RTW89_ETSI][40] = 28, + [2][0][RTW89_MKK][40] = 127, + [2][0][RTW89_IC][40] = 76, + [2][0][RTW89_KCC][40] = 70, + [2][0][RTW89_ACMA][40] = 76, + [2][0][RTW89_CHILE][40] = 54, + [2][0][RTW89_UKRAINE][40] = 28, + [2][0][RTW89_MEXICO][40] = 76, + [2][0][RTW89_CN][40] = 76, + [2][0][RTW89_QATAR][40] = 28, + [2][0][RTW89_FCC][42] = 76, + [2][0][RTW89_ETSI][42] = 28, + [2][0][RTW89_MKK][42] = 127, + [2][0][RTW89_IC][42] = 76, + [2][0][RTW89_KCC][42] = 70, + [2][0][RTW89_ACMA][42] = 76, + [2][0][RTW89_CHILE][42] = 54, + [2][0][RTW89_UKRAINE][42] = 28, + [2][0][RTW89_MEXICO][42] = 76, + [2][0][RTW89_CN][42] = 76, + [2][0][RTW89_QATAR][42] = 28, + [2][0][RTW89_FCC][44] = 76, + [2][0][RTW89_ETSI][44] = 28, + [2][0][RTW89_MKK][44] = 127, + [2][0][RTW89_IC][44] = 76, + [2][0][RTW89_KCC][44] = 70, + [2][0][RTW89_ACMA][44] = 76, + [2][0][RTW89_CHILE][44] = 54, + [2][0][RTW89_UKRAINE][44] = 28, + [2][0][RTW89_MEXICO][44] = 76, + [2][0][RTW89_CN][44] = 76, + [2][0][RTW89_QATAR][44] = 28, + [2][0][RTW89_FCC][46] = 76, + [2][0][RTW89_ETSI][46] = 28, + [2][0][RTW89_MKK][46] = 127, + [2][0][RTW89_IC][46] = 76, + [2][0][RTW89_KCC][46] = 70, + [2][0][RTW89_ACMA][46] = 76, + [2][0][RTW89_CHILE][46] = 54, + [2][0][RTW89_UKRAINE][46] = 28, + [2][0][RTW89_MEXICO][46] = 76, + [2][0][RTW89_CN][46] = 76, + [2][0][RTW89_QATAR][46] = 28, + [2][1][RTW89_FCC][0] = 58, + [2][1][RTW89_ETSI][0] = 32, + [2][1][RTW89_MKK][0] = 38, + [2][1][RTW89_IC][0] = 30, + [2][1][RTW89_KCC][0] = 54, + [2][1][RTW89_ACMA][0] = 32, + [2][1][RTW89_CHILE][0] = 18, + [2][1][RTW89_UKRAINE][0] = 32, + [2][1][RTW89_MEXICO][0] = 50, + [2][1][RTW89_CN][0] = 32, + [2][1][RTW89_QATAR][0] = 32, + [2][1][RTW89_FCC][2] = 58, + [2][1][RTW89_ETSI][2] = 32, + [2][1][RTW89_MKK][2] = 38, + [2][1][RTW89_IC][2] = 30, + [2][1][RTW89_KCC][2] = 54, + [2][1][RTW89_ACMA][2] = 32, + [2][1][RTW89_CHILE][2] = 18, + [2][1][RTW89_UKRAINE][2] = 32, + [2][1][RTW89_MEXICO][2] = 50, + [2][1][RTW89_CN][2] = 32, + [2][1][RTW89_QATAR][2] = 32, + [2][1][RTW89_FCC][4] = 58, + [2][1][RTW89_ETSI][4] = 32, + [2][1][RTW89_MKK][4] = 38, + [2][1][RTW89_IC][4] = 30, + [2][1][RTW89_KCC][4] = 54, + [2][1][RTW89_ACMA][4] = 32, + [2][1][RTW89_CHILE][4] = 18, + [2][1][RTW89_UKRAINE][4] = 32, + [2][1][RTW89_MEXICO][4] = 50, + [2][1][RTW89_CN][4] = 32, + [2][1][RTW89_QATAR][4] = 32, + [2][1][RTW89_FCC][6] = 58, + [2][1][RTW89_ETSI][6] = 32, + [2][1][RTW89_MKK][6] = 38, + [2][1][RTW89_IC][6] = 30, + [2][1][RTW89_KCC][6] = 26, + [2][1][RTW89_ACMA][6] = 32, + [2][1][RTW89_CHILE][6] = 18, + [2][1][RTW89_UKRAINE][6] = 32, + [2][1][RTW89_MEXICO][6] = 50, + [2][1][RTW89_CN][6] = 32, + [2][1][RTW89_QATAR][6] = 32, + [2][1][RTW89_FCC][8] = 58, + [2][1][RTW89_ETSI][8] = 32, + [2][1][RTW89_MKK][8] = 38, + [2][1][RTW89_IC][8] = 52, + [2][1][RTW89_KCC][8] = 54, + [2][1][RTW89_ACMA][8] = 32, + [2][1][RTW89_CHILE][8] = 42, + [2][1][RTW89_UKRAINE][8] = 32, + [2][1][RTW89_MEXICO][8] = 58, + [2][1][RTW89_CN][8] = 32, + [2][1][RTW89_QATAR][8] = 32, + [2][1][RTW89_FCC][10] = 58, + [2][1][RTW89_ETSI][10] = 32, + [2][1][RTW89_MKK][10] = 38, + [2][1][RTW89_IC][10] = 52, + [2][1][RTW89_KCC][10] = 54, + [2][1][RTW89_ACMA][10] = 32, + [2][1][RTW89_CHILE][10] = 42, + [2][1][RTW89_UKRAINE][10] = 32, + [2][1][RTW89_MEXICO][10] = 58, + [2][1][RTW89_CN][10] = 32, + [2][1][RTW89_QATAR][10] = 32, + [2][1][RTW89_FCC][12] = 58, + [2][1][RTW89_ETSI][12] = 32, + [2][1][RTW89_MKK][12] = 38, + [2][1][RTW89_IC][12] = 52, + [2][1][RTW89_KCC][12] = 54, + [2][1][RTW89_ACMA][12] = 32, + [2][1][RTW89_CHILE][12] = 42, + [2][1][RTW89_UKRAINE][12] = 32, + [2][1][RTW89_MEXICO][12] = 58, + [2][1][RTW89_CN][12] = 32, + [2][1][RTW89_QATAR][12] = 32, + [2][1][RTW89_FCC][14] = 58, + [2][1][RTW89_ETSI][14] = 32, + [2][1][RTW89_MKK][14] = 38, + [2][1][RTW89_IC][14] = 52, + [2][1][RTW89_KCC][14] = 54, + [2][1][RTW89_ACMA][14] = 32, + [2][1][RTW89_CHILE][14] = 42, + [2][1][RTW89_UKRAINE][14] = 32, + [2][1][RTW89_MEXICO][14] = 58, + [2][1][RTW89_CN][14] = 32, + [2][1][RTW89_QATAR][14] = 32, + [2][1][RTW89_FCC][15] = 58, + [2][1][RTW89_ETSI][15] = 32, + [2][1][RTW89_MKK][15] = 58, + [2][1][RTW89_IC][15] = 58, + [2][1][RTW89_KCC][15] = 54, + [2][1][RTW89_ACMA][15] = 32, + [2][1][RTW89_CHILE][15] = 42, + [2][1][RTW89_UKRAINE][15] = 32, + [2][1][RTW89_MEXICO][15] = 58, + [2][1][RTW89_CN][15] = 127, + [2][1][RTW89_QATAR][15] = 32, + [2][1][RTW89_FCC][17] = 58, + [2][1][RTW89_ETSI][17] = 32, + [2][1][RTW89_MKK][17] = 58, + [2][1][RTW89_IC][17] = 58, + [2][1][RTW89_KCC][17] = 54, + [2][1][RTW89_ACMA][17] = 32, + [2][1][RTW89_CHILE][17] = 42, + [2][1][RTW89_UKRAINE][17] = 32, + [2][1][RTW89_MEXICO][17] = 58, + [2][1][RTW89_CN][17] = 127, + [2][1][RTW89_QATAR][17] = 32, + [2][1][RTW89_FCC][19] = 58, + [2][1][RTW89_ETSI][19] = 32, + [2][1][RTW89_MKK][19] = 58, + [2][1][RTW89_IC][19] = 58, + [2][1][RTW89_KCC][19] = 54, + [2][1][RTW89_ACMA][19] = 32, + [2][1][RTW89_CHILE][19] = 42, + [2][1][RTW89_UKRAINE][19] = 32, + [2][1][RTW89_MEXICO][19] = 58, + [2][1][RTW89_CN][19] = 127, + [2][1][RTW89_QATAR][19] = 32, + [2][1][RTW89_FCC][21] = 58, + [2][1][RTW89_ETSI][21] = 32, + [2][1][RTW89_MKK][21] = 58, + [2][1][RTW89_IC][21] = 58, + [2][1][RTW89_KCC][21] = 54, + [2][1][RTW89_ACMA][21] = 32, + [2][1][RTW89_CHILE][21] = 42, + [2][1][RTW89_UKRAINE][21] = 32, + [2][1][RTW89_MEXICO][21] = 58, + [2][1][RTW89_CN][21] = 127, + [2][1][RTW89_QATAR][21] = 32, + [2][1][RTW89_FCC][23] = 58, + [2][1][RTW89_ETSI][23] = 32, + [2][1][RTW89_MKK][23] = 58, + [2][1][RTW89_IC][23] = 58, + [2][1][RTW89_KCC][23] = 54, + [2][1][RTW89_ACMA][23] = 32, + [2][1][RTW89_CHILE][23] = 42, + [2][1][RTW89_UKRAINE][23] = 32, + [2][1][RTW89_MEXICO][23] = 58, + [2][1][RTW89_CN][23] = 127, + [2][1][RTW89_QATAR][23] = 32, + [2][1][RTW89_FCC][25] = 58, + [2][1][RTW89_ETSI][25] = 32, + [2][1][RTW89_MKK][25] = 58, + [2][1][RTW89_IC][25] = 127, + [2][1][RTW89_KCC][25] = 54, + [2][1][RTW89_ACMA][25] = 127, + [2][1][RTW89_CHILE][25] = 42, + [2][1][RTW89_UKRAINE][25] = 32, + [2][1][RTW89_MEXICO][25] = 58, + [2][1][RTW89_CN][25] = 127, + [2][1][RTW89_QATAR][25] = 32, + [2][1][RTW89_FCC][27] = 58, + [2][1][RTW89_ETSI][27] = 32, + [2][1][RTW89_MKK][27] = 58, + [2][1][RTW89_IC][27] = 127, + [2][1][RTW89_KCC][27] = 54, + [2][1][RTW89_ACMA][27] = 127, + [2][1][RTW89_CHILE][27] = 42, + [2][1][RTW89_UKRAINE][27] = 32, + [2][1][RTW89_MEXICO][27] = 58, + [2][1][RTW89_CN][27] = 127, + [2][1][RTW89_QATAR][27] = 32, + [2][1][RTW89_FCC][29] = 58, + [2][1][RTW89_ETSI][29] = 32, + [2][1][RTW89_MKK][29] = 58, + [2][1][RTW89_IC][29] = 127, + [2][1][RTW89_KCC][29] = 54, + [2][1][RTW89_ACMA][29] = 127, + [2][1][RTW89_CHILE][29] = 42, + [2][1][RTW89_UKRAINE][29] = 32, + [2][1][RTW89_MEXICO][29] = 58, + [2][1][RTW89_CN][29] = 127, + [2][1][RTW89_QATAR][29] = 32, + [2][1][RTW89_FCC][31] = 58, + [2][1][RTW89_ETSI][31] = 32, + [2][1][RTW89_MKK][31] = 58, + [2][1][RTW89_IC][31] = 58, + [2][1][RTW89_KCC][31] = 54, + [2][1][RTW89_ACMA][31] = 32, + [2][1][RTW89_CHILE][31] = 42, + [2][1][RTW89_UKRAINE][31] = 32, + [2][1][RTW89_MEXICO][31] = 58, + [2][1][RTW89_CN][31] = 127, + [2][1][RTW89_QATAR][31] = 32, + [2][1][RTW89_FCC][33] = 58, + [2][1][RTW89_ETSI][33] = 32, + [2][1][RTW89_MKK][33] = 58, + [2][1][RTW89_IC][33] = 58, + [2][1][RTW89_KCC][33] = 54, + [2][1][RTW89_ACMA][33] = 32, + [2][1][RTW89_CHILE][33] = 42, + [2][1][RTW89_UKRAINE][33] = 32, + [2][1][RTW89_MEXICO][33] = 58, + [2][1][RTW89_CN][33] = 127, + [2][1][RTW89_QATAR][33] = 32, + [2][1][RTW89_FCC][35] = 58, + [2][1][RTW89_ETSI][35] = 32, + [2][1][RTW89_MKK][35] = 58, + [2][1][RTW89_IC][35] = 58, + [2][1][RTW89_KCC][35] = 54, + [2][1][RTW89_ACMA][35] = 32, + [2][1][RTW89_CHILE][35] = 42, + [2][1][RTW89_UKRAINE][35] = 32, + [2][1][RTW89_MEXICO][35] = 58, + [2][1][RTW89_CN][35] = 127, + [2][1][RTW89_QATAR][35] = 32, + [2][1][RTW89_FCC][37] = 58, + [2][1][RTW89_ETSI][37] = 127, + [2][1][RTW89_MKK][37] = 58, + [2][1][RTW89_IC][37] = 58, + [2][1][RTW89_KCC][37] = 54, + [2][1][RTW89_ACMA][37] = 62, + [2][1][RTW89_CHILE][37] = 42, + [2][1][RTW89_UKRAINE][37] = 127, + [2][1][RTW89_MEXICO][37] = 58, + [2][1][RTW89_CN][37] = 127, + [2][1][RTW89_QATAR][37] = 127, + [2][1][RTW89_FCC][38] = 76, + [2][1][RTW89_ETSI][38] = 16, + [2][1][RTW89_MKK][38] = 127, + [2][1][RTW89_IC][38] = 76, + [2][1][RTW89_KCC][38] = 54, + [2][1][RTW89_ACMA][38] = 76, + [2][1][RTW89_CHILE][38] = 42, + [2][1][RTW89_UKRAINE][38] = 16, + [2][1][RTW89_MEXICO][38] = 76, + [2][1][RTW89_CN][38] = 64, + [2][1][RTW89_QATAR][38] = 16, + [2][1][RTW89_FCC][40] = 76, + [2][1][RTW89_ETSI][40] = 16, + [2][1][RTW89_MKK][40] = 127, + [2][1][RTW89_IC][40] = 76, + [2][1][RTW89_KCC][40] = 54, + [2][1][RTW89_ACMA][40] = 76, + [2][1][RTW89_CHILE][40] = 42, + [2][1][RTW89_UKRAINE][40] = 16, + [2][1][RTW89_MEXICO][40] = 76, + [2][1][RTW89_CN][40] = 64, + [2][1][RTW89_QATAR][40] = 16, + [2][1][RTW89_FCC][42] = 76, + [2][1][RTW89_ETSI][42] = 16, + [2][1][RTW89_MKK][42] = 127, + [2][1][RTW89_IC][42] = 76, + [2][1][RTW89_KCC][42] = 54, + [2][1][RTW89_ACMA][42] = 76, + [2][1][RTW89_CHILE][42] = 42, + [2][1][RTW89_UKRAINE][42] = 16, + [2][1][RTW89_MEXICO][42] = 76, + [2][1][RTW89_CN][42] = 64, + [2][1][RTW89_QATAR][42] = 16, + [2][1][RTW89_FCC][44] = 76, + [2][1][RTW89_ETSI][44] = 16, + [2][1][RTW89_MKK][44] = 127, + [2][1][RTW89_IC][44] = 76, + [2][1][RTW89_KCC][44] = 54, + [2][1][RTW89_ACMA][44] = 76, + [2][1][RTW89_CHILE][44] = 42, + [2][1][RTW89_UKRAINE][44] = 16, + [2][1][RTW89_MEXICO][44] = 76, + [2][1][RTW89_CN][44] = 64, + [2][1][RTW89_QATAR][44] = 16, + [2][1][RTW89_FCC][46] = 76, + [2][1][RTW89_ETSI][46] = 16, + [2][1][RTW89_MKK][46] = 127, + [2][1][RTW89_IC][46] = 76, + [2][1][RTW89_KCC][46] = 54, + [2][1][RTW89_ACMA][46] = 76, + [2][1][RTW89_CHILE][46] = 42, + [2][1][RTW89_UKRAINE][46] = 16, + [2][1][RTW89_MEXICO][46] = 76, + [2][1][RTW89_CN][46] = 64, + [2][1][RTW89_QATAR][46] = 16, }; #define DECLARE_DIG_TABLE(name) \ diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h index f1e0fe36107d..75b11249f306 100644 --- a/drivers/net/wireless/realtek/rtw89/txrx.h +++ b/drivers/net/wireless/realtek/rtw89/txrx.h @@ -140,52 +140,56 @@ le32_get_bits((rxdesc)->dword5, GENMASK(7, 0)) #define RTW89_GET_RXINFO_USR_NUM(rpt) \ - le32_get_bits(*((__le32 *)rpt), GENMASK(3, 0)) + le32_get_bits(*((const __le32 *)rpt), GENMASK(3, 0)) #define RTW89_GET_RXINFO_FW_DEFINE(rpt) \ - le32_get_bits(*((__le32 *)rpt), GENMASK(15, 8)) + le32_get_bits(*((const __le32 *)rpt), GENMASK(15, 8)) #define RTW89_GET_RXINFO_LSIG_LEN(rpt) \ - le32_get_bits(*((__le32 *)rpt), GENMASK(27, 16)) + le32_get_bits(*((const __le32 *)rpt), GENMASK(27, 16)) #define RTW89_GET_RXINFO_IS_TO_SELF(rpt) \ - le32_get_bits(*((__le32 *)rpt), BIT(28)) + le32_get_bits(*((const __le32 *)rpt), BIT(28)) #define RTW89_GET_RXINFO_RX_CNT_VLD(rpt) \ - le32_get_bits(*((__le32 *)rpt), BIT(29)) + le32_get_bits(*((const __le32 *)rpt), BIT(29)) #define RTW89_GET_RXINFO_LONG_RXD(rpt) \ - le32_get_bits(*((__le32 *)rpt), GENMASK(31, 30)) + le32_get_bits(*((const __le32 *)rpt), GENMASK(31, 30)) #define RTW89_GET_RXINFO_SERVICE(rpt) \ - le32_get_bits(*((__le32 *)(rpt) + 1), GENMASK(15, 0)) + le32_get_bits(*((const __le32 *)(rpt) + 1), GENMASK(15, 0)) #define RTW89_GET_RXINFO_PLCP_LEN(rpt) \ - le32_get_bits(*((__le32 *)(rpt) + 1), GENMASK(23, 16)) + le32_get_bits(*((const __le32 *)(rpt) + 1), GENMASK(23, 16)) #define RTW89_GET_RXINFO_MAC_ID_VALID(rpt, usr) \ - le32_get_bits(*((__le32 *)(rpt) + (usr) + 2), BIT(0)) + le32_get_bits(*((const __le32 *)(rpt) + (usr) + 2), BIT(0)) #define RTW89_GET_RXINFO_DATA(rpt, usr) \ - le32_get_bits(*((__le32 *)(rpt) + (usr) + 2), BIT(1)) + le32_get_bits(*((const __le32 *)(rpt) + (usr) + 2), BIT(1)) #define RTW89_GET_RXINFO_CTRL(rpt, usr) \ - le32_get_bits(*((__le32 *)(rpt) + (usr) + 2), BIT(2)) + le32_get_bits(*((const __le32 *)(rpt) + (usr) + 2), BIT(2)) #define RTW89_GET_RXINFO_MGMT(rpt, usr) \ - le32_get_bits(*((__le32 *)(rpt) + (usr) + 2), BIT(3)) + le32_get_bits(*((const __le32 *)(rpt) + (usr) + 2), BIT(3)) #define RTW89_GET_RXINFO_BCM(rpt, usr) \ - le32_get_bits(*((__le32 *)(rpt) + (usr) + 2), BIT(4)) + le32_get_bits(*((const __le32 *)(rpt) + (usr) + 2), BIT(4)) #define RTW89_GET_RXINFO_MACID(rpt, usr) \ - le32_get_bits(*((__le32 *)(rpt) + (usr) + 2), GENMASK(15, 8)) + le32_get_bits(*((const __le32 *)(rpt) + (usr) + 2), GENMASK(15, 8)) +#define RTW89_GET_PHY_STS_IE_MAP(sts) \ + le32_get_bits(*((const __le32 *)(sts)), GENMASK(4, 0)) #define RTW89_GET_PHY_STS_RSSI_A(sts) \ - le32_get_bits(*((__le32 *)(sts) + 1), GENMASK(7, 0)) + le32_get_bits(*((const __le32 *)(sts) + 1), GENMASK(7, 0)) #define RTW89_GET_PHY_STS_RSSI_B(sts) \ - le32_get_bits(*((__le32 *)(sts) + 1), GENMASK(15, 8)) + le32_get_bits(*((const __le32 *)(sts) + 1), GENMASK(15, 8)) #define RTW89_GET_PHY_STS_RSSI_C(sts) \ - le32_get_bits(*((__le32 *)(sts) + 1), GENMASK(23, 16)) + le32_get_bits(*((const __le32 *)(sts) + 1), GENMASK(23, 16)) #define RTW89_GET_PHY_STS_RSSI_D(sts) \ - le32_get_bits(*((__le32 *)(sts) + 1), GENMASK(31, 24)) + le32_get_bits(*((const __le32 *)(sts) + 1), GENMASK(31, 24)) #define RTW89_GET_PHY_STS_LEN(sts) \ - le32_get_bits(*((__le32 *)sts), GENMASK(15, 8)) + le32_get_bits(*((const __le32 *)sts), GENMASK(15, 8)) #define RTW89_GET_PHY_STS_RSSI_AVG(sts) \ - le32_get_bits(*((__le32 *)sts), GENMASK(31, 24)) + le32_get_bits(*((const __le32 *)sts), GENMASK(31, 24)) #define RTW89_GET_PHY_STS_IE_TYPE(ie) \ - le32_get_bits(*((__le32 *)ie), GENMASK(4, 0)) + le32_get_bits(*((const __le32 *)ie), GENMASK(4, 0)) #define RTW89_GET_PHY_STS_IE_LEN(ie) \ - le32_get_bits(*((__le32 *)ie), GENMASK(11, 5)) -#define RTW89_GET_PHY_STS_IE0_CFO(ie) \ - le32_get_bits(*((__le32 *)(ie) + 1), GENMASK(31, 20)) + le32_get_bits(*((const __le32 *)ie), GENMASK(11, 5)) +#define RTW89_GET_PHY_STS_IE01_CH_IDX(ie) \ + le32_get_bits(*((const __le32 *)ie), GENMASK(23, 16)) +#define RTW89_GET_PHY_STS_IE01_CFO(ie) \ + le32_get_bits(*((const __le32 *)(ie) + 1), GENMASK(31, 20)) enum rtw89_tx_channel { RTW89_TXCH_ACH0 = 0, @@ -251,45 +255,6 @@ enum rtw89_tx_qsel { /* reserved */ }; -enum rtw89_phy_status_ie_type { - RTW89_PHYSTS_IE00_CMN_CCK = 0, - RTW89_PHYSTS_IE01_CMN_OFDM = 1, - RTW89_PHYSTS_IE02_CMN_EXT_AX = 2, - RTW89_PHYSTS_IE03_CMN_EXT_SEG_1 = 3, - RTW89_PHYSTS_IE04_CMN_EXT_PATH_A = 4, - RTW89_PHYSTS_IE05_CMN_EXT_PATH_B = 5, - RTW89_PHYSTS_IE06_CMN_EXT_PATH_C = 6, - RTW89_PHYSTS_IE07_CMN_EXT_PATH_D = 7, - RTW89_PHYSTS_IE08_FTR_CH = 8, - RTW89_PHYSTS_IE09_FTR_PLCP_0 = 9, - RTW89_PHYSTS_IE10_FTR_PLCP_EXT = 10, - RTW89_PHYSTS_IE11_FTR_PLCP_HISTOGRAM = 11, - RTW89_PHYSTS_IE12_MU_EIGEN_INFO = 12, - RTW89_PHYSTS_IE13_DL_MU_DEF = 13, - RTW89_PHYSTS_IE14_TB_UL_CQI = 14, - RTW89_PHYSTS_IE15_TB_UL_DEF = 15, - RTW89_PHYSTS_IE16_RSVD16 = 16, - RTW89_PHYSTS_IE17_TB_UL_CTRL = 17, - RTW89_PHYSTS_IE18_DBG_OFDM_FD_CMN = 18, - RTW89_PHYSTS_IE19_DBG_OFDM_TD_CMN = 19, - RTW89_PHYSTS_IE20_DBG_OFDM_FD_USER_SEG_0 = 20, - RTW89_PHYSTS_IE21_DBG_OFDM_FD_USER_SEG_1 = 21, - RTW89_PHYSTS_IE22_DBG_OFDM_FD_USER_AGC = 22, - RTW89_PHYSTS_IE23_RSVD23 = 23, - RTW89_PHYSTS_IE24_DBG_OFDM_TD_PATH_A = 24, - RTW89_PHYSTS_IE25_DBG_OFDM_TD_PATH_B = 25, - RTW89_PHYSTS_IE26_DBG_OFDM_TD_PATH_C = 26, - RTW89_PHYSTS_IE27_DBG_OFDM_TD_PATH_D = 27, - RTW89_PHYSTS_IE28_DBG_CCK_PATH_A = 28, - RTW89_PHYSTS_IE29_DBG_CCK_PATH_B = 29, - RTW89_PHYSTS_IE30_DBG_CCK_PATH_C = 30, - RTW89_PHYSTS_IE31_DBG_CCK_PATH_D = 31, - - /* keep last */ - RTW89_PHYSTS_IE_NUM, - RTW89_PHYSTS_IE_MAX = RTW89_PHYSTS_IE_NUM - 1 -}; - static inline u8 rtw89_core_get_qsel(struct rtw89_dev *rtwdev, u8 tid) { switch (tid) { diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index e70c1c7fdf59..913e11fb3807 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -1108,6 +1108,9 @@ static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw, break; } + if (ii >= RSI_MAX_VIFS) + return status; + mutex_lock(&common->mutex); if (ssn != NULL) diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c index f1bf71e6c608..5d1490fc32db 100644 --- a/drivers/net/wireless/rsi/rsi_91x_main.c +++ b/drivers/net/wireless/rsi/rsi_91x_main.c @@ -23,6 +23,7 @@ #include "rsi_common.h" #include "rsi_coex.h" #include "rsi_hal.h" +#include "rsi_usb.h" u32 rsi_zone_enabled = /* INFO_ZONE | INIT_ZONE | @@ -168,6 +169,9 @@ int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len) frame_desc = &rx_pkt[index]; actual_length = *(u16 *)&frame_desc[0]; offset = *(u16 *)&frame_desc[2]; + if (!rcv_pkt_len && offset > + RSI_MAX_RX_USB_PKT_SIZE - FRAME_DESC_SZ) + goto fail; queueno = rsi_get_queueno(frame_desc, offset); length = rsi_get_length(frame_desc, offset); diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index 6821ea991895..66fe386ec9cc 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -269,8 +269,12 @@ static void rsi_rx_done_handler(struct urb *urb) struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)rx_cb->data; int status = -EINVAL; + if (!rx_cb->rx_skb) + return; + if (urb->status) { dev_kfree_skb(rx_cb->rx_skb); + rx_cb->rx_skb = NULL; return; } @@ -294,8 +298,10 @@ out: if (rsi_rx_urb_submit(dev->priv, rx_cb->ep_num, GFP_ATOMIC)) rsi_dbg(ERR_ZONE, "%s: Failed in urb submission", __func__); - if (status) + if (status) { dev_kfree_skb(rx_cb->rx_skb); + rx_cb->rx_skb = NULL; + } } static void rsi_rx_urb_kill(struct rsi_hw *adapter, u8 ep_num) @@ -324,7 +330,6 @@ static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num, gfp_t mem_flags) struct sk_buff *skb; u8 dword_align_bytes = 0; -#define RSI_MAX_RX_USB_PKT_SIZE 3000 skb = dev_alloc_skb(RSI_MAX_RX_USB_PKT_SIZE); if (!skb) return -ENOMEM; diff --git a/drivers/net/wireless/rsi/rsi_usb.h b/drivers/net/wireless/rsi/rsi_usb.h index 254d19b66412..961851748bc4 100644 --- a/drivers/net/wireless/rsi/rsi_usb.h +++ b/drivers/net/wireless/rsi/rsi_usb.h @@ -44,6 +44,8 @@ #define RSI_USB_BUF_SIZE 4096 #define RSI_USB_CTRL_BUF_SIZE 0x04 +#define RSI_MAX_RX_USB_PKT_SIZE 3000 + struct rx_usb_ctrl_block { u8 *data; struct urb *rx_urb; diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index 136a0d3b23c9..a25a6143e65f 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -1520,6 +1520,12 @@ int wl1251_init_ieee80211(struct wl1251 *wl) wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); wl->hw->wiphy->max_scan_ssids = 1; + + /* We set max_scan_ie_len to a random value to make wpa_supplicant scans not + * fail, as the driver will the ignore the extra passed IEs anyway + */ + wl->hw->wiphy->max_scan_ie_len = 512; + wl->hw->wiphy->bands[NL80211_BAND_2GHZ] = &wl1251_band_2ghz; wl->hw->queues = 4; diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index 9fd8cf2d270c..72fc41ac83c0 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -26,7 +26,7 @@ #include "wl12xx_80211.h" #include "io.h" -static bool dump = false; +static bool dump; struct wl12xx_sdio_glue { struct device *dev; |