Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
0002 /*
0003  * Copyright (C) 2021 Intel Corporation
0004  */
0005 
0006 #include <net/mac80211.h>
0007 #include "fw/api/rs.h"
0008 #include "iwl-drv.h"
0009 #include "iwl-config.h"
0010 
0011 #define IWL_DECLARE_RATE_INFO(r) \
0012     [IWL_RATE_##r##M_INDEX] = IWL_RATE_##r##M_PLCP
0013 
0014 /*
0015  * Translate from fw_rate_index (IWL_RATE_XXM_INDEX) to PLCP
0016  * */
0017 static const u8 fw_rate_idx_to_plcp[IWL_RATE_COUNT] = {
0018     IWL_DECLARE_RATE_INFO(1),
0019     IWL_DECLARE_RATE_INFO(2),
0020     IWL_DECLARE_RATE_INFO(5),
0021     IWL_DECLARE_RATE_INFO(11),
0022     IWL_DECLARE_RATE_INFO(6),
0023     IWL_DECLARE_RATE_INFO(9),
0024     IWL_DECLARE_RATE_INFO(12),
0025     IWL_DECLARE_RATE_INFO(18),
0026     IWL_DECLARE_RATE_INFO(24),
0027     IWL_DECLARE_RATE_INFO(36),
0028     IWL_DECLARE_RATE_INFO(48),
0029     IWL_DECLARE_RATE_INFO(54),
0030 };
0031 
0032 /* mbps, mcs */
0033 static const struct iwl_rate_mcs_info rate_mcs[IWL_RATE_COUNT] = {
0034     {  "1", "BPSK DSSS"},
0035     {  "2", "QPSK DSSS"},
0036     {"5.5", "BPSK CCK"},
0037     { "11", "QPSK CCK"},
0038     {  "6", "BPSK 1/2"},
0039     {  "9", "BPSK 1/2"},
0040     { "12", "QPSK 1/2"},
0041     { "18", "QPSK 3/4"},
0042     { "24", "16QAM 1/2"},
0043     { "36", "16QAM 3/4"},
0044     { "48", "64QAM 2/3"},
0045     { "54", "64QAM 3/4"},
0046     { "60", "64QAM 5/6"},
0047 };
0048 
0049 static const char * const ant_name[] = {
0050     [ANT_NONE] = "None",
0051     [ANT_A]    = "A",
0052     [ANT_B]    = "B",
0053     [ANT_AB]   = "AB",
0054 };
0055 
0056 static const char * const pretty_bw[] = {
0057     "20Mhz",
0058     "40Mhz",
0059     "80Mhz",
0060     "160 Mhz",
0061     "320Mhz",
0062 };
0063 
0064 u8 iwl_fw_rate_idx_to_plcp(int idx)
0065 {
0066     return fw_rate_idx_to_plcp[idx];
0067 }
0068 IWL_EXPORT_SYMBOL(iwl_fw_rate_idx_to_plcp);
0069 
0070 const struct iwl_rate_mcs_info *iwl_rate_mcs(int idx)
0071 {
0072     return &rate_mcs[idx];
0073 }
0074 IWL_EXPORT_SYMBOL(iwl_rate_mcs);
0075 
0076 const char *iwl_rs_pretty_ant(u8 ant)
0077 {
0078     if (ant >= ARRAY_SIZE(ant_name))
0079         return "UNKNOWN";
0080 
0081     return ant_name[ant];
0082 }
0083 IWL_EXPORT_SYMBOL(iwl_rs_pretty_ant);
0084 
0085 const char *iwl_rs_pretty_bw(int bw)
0086 {
0087     if (bw >= ARRAY_SIZE(pretty_bw))
0088         return "unknown bw";
0089 
0090     return pretty_bw[bw];
0091 }
0092 IWL_EXPORT_SYMBOL(iwl_rs_pretty_bw);
0093 
0094 static u32 iwl_legacy_rate_to_fw_idx(u32 rate_n_flags)
0095 {
0096     int rate = rate_n_flags & RATE_LEGACY_RATE_MSK_V1;
0097     int idx;
0098     bool ofdm = !(rate_n_flags & RATE_MCS_CCK_MSK_V1);
0099     int offset = ofdm ? IWL_FIRST_OFDM_RATE : 0;
0100     int last = ofdm ? IWL_RATE_COUNT_LEGACY : IWL_FIRST_OFDM_RATE;
0101 
0102     for (idx = offset; idx < last; idx++)
0103         if (iwl_fw_rate_idx_to_plcp(idx) == rate)
0104             return idx - offset;
0105     return IWL_RATE_INVALID;
0106 }
0107 
0108 u32 iwl_new_rate_from_v1(u32 rate_v1)
0109 {
0110     u32 rate_v2 = 0;
0111     u32 dup = 0;
0112 
0113     if (rate_v1 == 0)
0114         return rate_v1;
0115     /* convert rate */
0116     if (rate_v1 & RATE_MCS_HT_MSK_V1) {
0117         u32 nss = 0;
0118 
0119         rate_v2 |= RATE_MCS_HT_MSK;
0120         rate_v2 |=
0121             rate_v1 & RATE_HT_MCS_RATE_CODE_MSK_V1;
0122         nss = (rate_v1 & RATE_HT_MCS_MIMO2_MSK) >>
0123             RATE_HT_MCS_NSS_POS_V1;
0124         rate_v2 |= nss << RATE_MCS_NSS_POS;
0125     } else if (rate_v1 & RATE_MCS_VHT_MSK_V1 ||
0126            rate_v1 & RATE_MCS_HE_MSK_V1) {
0127         rate_v2 |= rate_v1 & RATE_VHT_MCS_RATE_CODE_MSK;
0128 
0129         rate_v2 |= rate_v1 & RATE_VHT_MCS_MIMO2_MSK;
0130 
0131         if (rate_v1 & RATE_MCS_HE_MSK_V1) {
0132             u32 he_type_bits = rate_v1 & RATE_MCS_HE_TYPE_MSK_V1;
0133             u32 he_type = he_type_bits >> RATE_MCS_HE_TYPE_POS_V1;
0134             u32 he_106t = (rate_v1 & RATE_MCS_HE_106T_MSK_V1) >>
0135                 RATE_MCS_HE_106T_POS_V1;
0136             u32 he_gi_ltf = (rate_v1 & RATE_MCS_HE_GI_LTF_MSK_V1) >>
0137                 RATE_MCS_HE_GI_LTF_POS;
0138 
0139             if ((he_type_bits == RATE_MCS_HE_TYPE_SU ||
0140                  he_type_bits == RATE_MCS_HE_TYPE_EXT_SU) &&
0141                 he_gi_ltf == RATE_MCS_HE_SU_4_LTF)
0142                 /* the new rate have an additional bit to
0143                  * represent the value 4 rather then using SGI
0144                  * bit for this purpose - as it was done in the old
0145                  * rate */
0146                 he_gi_ltf += (rate_v1 & RATE_MCS_SGI_MSK_V1) >>
0147                     RATE_MCS_SGI_POS_V1;
0148 
0149             rate_v2 |= he_gi_ltf << RATE_MCS_HE_GI_LTF_POS;
0150             rate_v2 |= he_type << RATE_MCS_HE_TYPE_POS;
0151             rate_v2 |= he_106t << RATE_MCS_HE_106T_POS;
0152             rate_v2 |= rate_v1 & RATE_HE_DUAL_CARRIER_MODE_MSK;
0153             rate_v2 |= RATE_MCS_HE_MSK;
0154         } else {
0155             rate_v2 |= RATE_MCS_VHT_MSK;
0156         }
0157     /* if legacy format */
0158     } else {
0159         u32 legacy_rate = iwl_legacy_rate_to_fw_idx(rate_v1);
0160 
0161         if (WARN_ON_ONCE(legacy_rate == IWL_RATE_INVALID))
0162             legacy_rate = (rate_v1 & RATE_MCS_CCK_MSK_V1) ?
0163                 IWL_FIRST_CCK_RATE : IWL_FIRST_OFDM_RATE;
0164 
0165         rate_v2 |= legacy_rate;
0166         if (!(rate_v1 & RATE_MCS_CCK_MSK_V1))
0167             rate_v2 |= RATE_MCS_LEGACY_OFDM_MSK;
0168     }
0169 
0170     /* convert flags */
0171     if (rate_v1 & RATE_MCS_LDPC_MSK_V1)
0172         rate_v2 |= RATE_MCS_LDPC_MSK;
0173     rate_v2 |= (rate_v1 & RATE_MCS_CHAN_WIDTH_MSK_V1) |
0174         (rate_v1 & RATE_MCS_ANT_AB_MSK) |
0175         (rate_v1 & RATE_MCS_STBC_MSK) |
0176         (rate_v1 & RATE_MCS_BF_MSK);
0177 
0178     dup = (rate_v1 & RATE_MCS_DUP_MSK_V1) >> RATE_MCS_DUP_POS_V1;
0179     if (dup) {
0180         rate_v2 |= RATE_MCS_DUP_MSK;
0181         rate_v2 |= dup << RATE_MCS_CHAN_WIDTH_POS;
0182     }
0183 
0184     if ((!(rate_v1 & RATE_MCS_HE_MSK_V1)) &&
0185         (rate_v1 & RATE_MCS_SGI_MSK_V1))
0186         rate_v2 |= RATE_MCS_SGI_MSK;
0187 
0188     return rate_v2;
0189 }
0190 IWL_EXPORT_SYMBOL(iwl_new_rate_from_v1);
0191 
0192 int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate)
0193 {
0194     char *type;
0195     u8 mcs = 0, nss = 0;
0196     u8 ant = (rate & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS;
0197     u32 bw = (rate & RATE_MCS_CHAN_WIDTH_MSK) >>
0198         RATE_MCS_CHAN_WIDTH_POS;
0199     u32 format = rate & RATE_MCS_MOD_TYPE_MSK;
0200     bool sgi;
0201 
0202     if (format == RATE_MCS_CCK_MSK ||
0203         format == RATE_MCS_LEGACY_OFDM_MSK) {
0204         int legacy_rate = rate & RATE_LEGACY_RATE_MSK;
0205         int index = format == RATE_MCS_CCK_MSK ?
0206             legacy_rate :
0207             legacy_rate + IWL_FIRST_OFDM_RATE;
0208 
0209         return scnprintf(buf, bufsz, "Legacy | ANT: %s Rate: %s Mbps",
0210                  iwl_rs_pretty_ant(ant),
0211                  index == IWL_RATE_INVALID ? "BAD" :
0212                  iwl_rate_mcs(index)->mbps);
0213     }
0214 
0215     if (format ==  RATE_MCS_VHT_MSK)
0216         type = "VHT";
0217     else if (format ==  RATE_MCS_HT_MSK)
0218         type = "HT";
0219     else if (format == RATE_MCS_HE_MSK)
0220         type = "HE";
0221     else
0222         type = "Unknown"; /* shouldn't happen */
0223 
0224     mcs = format == RATE_MCS_HT_MSK ?
0225         RATE_HT_MCS_INDEX(rate) :
0226         rate & RATE_MCS_CODE_MSK;
0227     nss = ((rate & RATE_MCS_NSS_MSK)
0228            >> RATE_MCS_NSS_POS) + 1;
0229     sgi = format == RATE_MCS_HE_MSK ?
0230         iwl_he_is_sgi(rate) :
0231         rate & RATE_MCS_SGI_MSK;
0232 
0233     return scnprintf(buf, bufsz,
0234              "0x%x: %s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s%s",
0235              rate, type, iwl_rs_pretty_ant(ant), iwl_rs_pretty_bw(bw), mcs, nss,
0236              (sgi) ? "SGI " : "NGI ",
0237              (rate & RATE_MCS_STBC_MSK) ? "STBC " : "",
0238              (rate & RATE_MCS_LDPC_MSK) ? "LDPC " : "",
0239              (rate & RATE_HE_DUAL_CARRIER_MODE_MSK) ? "DCM " : "",
0240              (rate & RATE_MCS_BF_MSK) ? "BF " : "");
0241 }
0242 IWL_EXPORT_SYMBOL(rs_pretty_print_rate);
0243 
0244 bool iwl_he_is_sgi(u32 rate_n_flags)
0245 {
0246     u32 type = rate_n_flags & RATE_MCS_HE_TYPE_MSK;
0247     u32 ltf_gi = rate_n_flags & RATE_MCS_HE_GI_LTF_MSK;
0248 
0249     if (type == RATE_MCS_HE_TYPE_SU ||
0250         type == RATE_MCS_HE_TYPE_EXT_SU)
0251         return ltf_gi == RATE_MCS_HE_SU_4_LTF_08_GI;
0252     return false;
0253 }
0254 IWL_EXPORT_SYMBOL(iwl_he_is_sgi);
0255