blob: f8c761edf8808717575e5b4a6b3385b048205cf3 [file] [log] [blame]
/*
* Copyright (c) 2014-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/**
* DOC: reg_services.c
* This file defines regulatory component service functions
*/
#include "reg_services.h"
#include "reg_priv.h"
#include "reg_db_parser.h"
#include <scheduler_api.h>
#include <qdf_platform.h>
#define CHAN_12_CENT_FREQ 2467
#define MAX_PWR_FCC_CHAN_12 8
#define CHAN_13_CENT_FREQ 2472
#define MAX_PWR_FCC_CHAN_13 2
#define CHAN_144_CENT_FREQ 5720
#define DEFAULT_WORLD_REGDMN 0x60
#define IS_VALID_PSOC_REG_OBJ(psoc_priv_obj) (NULL != psoc_priv_obj)
#define IS_VALID_PDEV_REG_OBJ(pdev_priv_obj) (NULL != pdev_priv_obj)
const struct chan_map *channel_map;
const struct bonded_channel bonded_chan_40mhz_list[] = {
{36, 40},
{44, 48},
{52, 56},
{60, 64},
{100, 104},
{108, 112},
{116, 120},
{124, 128},
{132, 136},
{140, 144},
{149, 153},
{157, 161},
{165, 169}
};
const struct bonded_channel bonded_chan_80mhz_list[] = {
{36, 48},
{52, 64},
{100, 112},
{116, 128},
{132, 144},
{149, 161}
};
const struct bonded_channel bonded_chan_160mhz_list[] = {
{36, 64},
{100, 128}
};
const enum phy_ch_width get_next_lower_bw[] = {
[CH_WIDTH_80P80MHZ] = CH_WIDTH_160MHZ,
[CH_WIDTH_160MHZ] = CH_WIDTH_80MHZ,
[CH_WIDTH_80MHZ] = CH_WIDTH_40MHZ,
[CH_WIDTH_40MHZ] = CH_WIDTH_20MHZ,
[CH_WIDTH_20MHZ] = CH_WIDTH_10MHZ,
[CH_WIDTH_10MHZ] = CH_WIDTH_5MHZ,
[CH_WIDTH_5MHZ] = CH_WIDTH_INVALID
};
#ifdef CONFIG_LEGACY_CHAN_ENUM
static const struct chan_map channel_map_old[NUM_CHANNELS] = {
[CHAN_ENUM_1] = {2412, 1, 2, 40},
[CHAN_ENUM_2] = {2417, 2, 2, 40},
[CHAN_ENUM_3] = {2422, 3, 2, 40},
[CHAN_ENUM_4] = {2427, 4, 2, 40},
[CHAN_ENUM_5] = {2432, 5, 2, 40},
[CHAN_ENUM_6] = {2437, 6, 2, 40},
[CHAN_ENUM_7] = {2442, 7, 2, 40},
[CHAN_ENUM_8] = {2447, 8, 2, 40},
[CHAN_ENUM_9] = {2452, 9, 2, 40},
[CHAN_ENUM_10] = {2457, 10, 2, 40},
[CHAN_ENUM_11] = {2462, 11, 2, 40},
[CHAN_ENUM_12] = {2467, 12, 2, 40},
[CHAN_ENUM_13] = {2472, 13, 2, 40},
[CHAN_ENUM_14] = {2484, 14, 2, 40},
[CHAN_ENUM_36] = {5180, 36, 2, 160},
[CHAN_ENUM_40] = {5200, 40, 2, 160},
[CHAN_ENUM_44] = {5220, 44, 2, 160},
[CHAN_ENUM_48] = {5240, 48, 2, 160},
[CHAN_ENUM_52] = {5260, 52, 2, 160},
[CHAN_ENUM_56] = {5280, 56, 2, 160},
[CHAN_ENUM_60] = {5300, 60, 2, 160},
[CHAN_ENUM_64] = {5320, 64, 2, 160},
[CHAN_ENUM_100] = {5500, 100, 2, 160},
[CHAN_ENUM_104] = {5520, 104, 2, 160},
[CHAN_ENUM_108] = {5540, 108, 2, 160},
[CHAN_ENUM_112] = {5560, 112, 2, 160},
[CHAN_ENUM_116] = {5580, 116, 2, 160},
[CHAN_ENUM_120] = {5600, 120, 2, 160},
[CHAN_ENUM_124] = {5620, 124, 2, 160},
[CHAN_ENUM_128] = {5640, 128, 2, 160},
[CHAN_ENUM_132] = {5660, 132, 2, 160},
[CHAN_ENUM_136] = {5680, 136, 2, 160},
[CHAN_ENUM_140] = {5700, 140, 2, 160},
[CHAN_ENUM_144] = {5720, 144, 2, 160},
[CHAN_ENUM_149] = {5745, 149, 2, 160},
[CHAN_ENUM_153] = {5765, 153, 2, 160},
[CHAN_ENUM_157] = {5785, 157, 2, 160},
[CHAN_ENUM_161] = {5805, 161, 2, 160},
[CHAN_ENUM_165] = {5825, 165, 2, 160},
#ifndef WLAN_FEATURE_DSRC
[CHAN_ENUM_169] = {5845, 169, 2, 40},
[CHAN_ENUM_173] = {5865, 173, 2, 20},
#else
[CHAN_ENUM_170] = {5852, 170, 2, 20},
[CHAN_ENUM_171] = {5855, 171, 2, 20},
[CHAN_ENUM_172] = {5860, 172, 2, 20},
[CHAN_ENUM_173] = {5865, 173, 2, 20},
[CHAN_ENUM_174] = {5870, 174, 2, 20},
[CHAN_ENUM_175] = {5875, 175, 2, 20},
[CHAN_ENUM_176] = {5880, 176, 2, 20},
[CHAN_ENUM_177] = {5885, 177, 2, 20},
[CHAN_ENUM_178] = {5890, 178, 2, 20},
[CHAN_ENUM_179] = {5895, 179, 2, 20},
[CHAN_ENUM_180] = {5900, 180, 2, 20},
[CHAN_ENUM_181] = {5905, 181, 2, 20},
[CHAN_ENUM_182] = {5910, 182, 2, 20},
[CHAN_ENUM_183] = {5915, 183, 2, 20},
[CHAN_ENUM_184] = {5920, 184, 2, 20},
#endif
};
#else
static const struct chan_map channel_map_us[NUM_CHANNELS] = {
[CHAN_ENUM_2412] = {2412, 1, 20, 40},
[CHAN_ENUM_2417] = {2417, 2, 20, 40},
[CHAN_ENUM_2422] = {2422, 3, 20, 40},
[CHAN_ENUM_2427] = {2427, 4, 20, 40},
[CHAN_ENUM_2432] = {2432, 5, 20, 40},
[CHAN_ENUM_2437] = {2437, 6, 20, 40},
[CHAN_ENUM_2442] = {2442, 7, 20, 40},
[CHAN_ENUM_2447] = {2447, 8, 20, 40},
[CHAN_ENUM_2452] = {2452, 9, 20, 40},
[CHAN_ENUM_2457] = {2457, 10, 20, 40},
[CHAN_ENUM_2462] = {2462, 11, 20, 40},
[CHAN_ENUM_2467] = {2467, 12, 20, 40},
[CHAN_ENUM_2472] = {2472, 13, 20, 40},
[CHAN_ENUM_2484] = {2484, 14, 20, 20},
[CHAN_ENUM_4912] = {4912, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4915] = {4915, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4917] = {4917, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4920] = {4920, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4922] = {4922, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4925] = {4925, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4927] = {4927, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4932] = {4932, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4935] = {4935, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4937] = {4937, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4940] = {4940, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4942] = {4942, 1, 5, 5},
[CHAN_ENUM_4945] = {4945, 11, 10, 10},
[CHAN_ENUM_4947] = {4947, 2, 5, 5},
[CHAN_ENUM_4950] = {4950, 20, 10, 20},
[CHAN_ENUM_4952] = {4952, 3, 5, 5},
[CHAN_ENUM_4955] = {4955, 21, 10, 20},
[CHAN_ENUM_4957] = {4957, 4, 5, 5},
[CHAN_ENUM_4960] = {4960, 22, 10, 20},
[CHAN_ENUM_4962] = {4962, 5, 5, 5},
[CHAN_ENUM_4965] = {4965, 23, 10, 20},
[CHAN_ENUM_4967] = {4967, 6, 5, 5},
[CHAN_ENUM_4970] = {4970, 24, 10, 20},
[CHAN_ENUM_4972] = {4972, 7, 5, 5},
[CHAN_ENUM_4975] = {4975, 25, 10, 20},
[CHAN_ENUM_4977] = {4977, 8, 5, 5},
[CHAN_ENUM_4980] = {4980, 26, 10, 20},
[CHAN_ENUM_4982] = {4982, 9, 5, 5},
[CHAN_ENUM_4985] = {4985, 19, 10, 10},
[CHAN_ENUM_4987] = {4987, 10, 5, 5},
[CHAN_ENUM_5032] = {5032, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5035] = {5035, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5037] = {5037, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5040] = {5040, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5042] = {5042, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5045] = {5045, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5047] = {5047, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5052] = {5052, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5055] = {5055, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5057] = {5057, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5060] = {5060, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5080] = {5080, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5180] = {5180, 36, 2, 160},
[CHAN_ENUM_5200] = {5200, 40, 2, 160},
[CHAN_ENUM_5220] = {5220, 44, 2, 160},
[CHAN_ENUM_5240] = {5240, 48, 2, 160},
[CHAN_ENUM_5260] = {5260, 52, 2, 160},
[CHAN_ENUM_5280] = {5280, 56, 2, 160},
[CHAN_ENUM_5300] = {5300, 60, 2, 160},
[CHAN_ENUM_5320] = {5320, 64, 2, 160},
[CHAN_ENUM_5500] = {5500, 100, 2, 160},
[CHAN_ENUM_5520] = {5520, 104, 2, 160},
[CHAN_ENUM_5540] = {5540, 108, 2, 160},
[CHAN_ENUM_5560] = {5560, 112, 2, 160},
[CHAN_ENUM_5580] = {5580, 116, 2, 160},
[CHAN_ENUM_5600] = {5600, 120, 2, 160},
[CHAN_ENUM_5620] = {5620, 124, 2, 160},
[CHAN_ENUM_5640] = {5640, 128, 2, 160},
[CHAN_ENUM_5660] = {5660, 132, 2, 160},
[CHAN_ENUM_5680] = {5680, 136, 2, 160},
[CHAN_ENUM_5700] = {5700, 140, 2, 160},
[CHAN_ENUM_5720] = {5720, 144, 2, 160},
[CHAN_ENUM_5745] = {5745, 149, 2, 160},
[CHAN_ENUM_5765] = {5765, 153, 2, 160},
[CHAN_ENUM_5785] = {5785, 157, 2, 160},
[CHAN_ENUM_5805] = {5805, 161, 2, 160},
[CHAN_ENUM_5825] = {5825, 165, 2, 160},
[CHAN_ENUM_5845] = {5845, 169, 2, 160},
[CHAN_ENUM_5850] = {5850, 170, 2, 160},
[CHAN_ENUM_5855] = {5855, 171, 2, 160},
[CHAN_ENUM_5860] = {5860, 172, 2, 160},
[CHAN_ENUM_5865] = {5865, 173, 2, 160},
[CHAN_ENUM_5870] = {5870, 174, 2, 160},
[CHAN_ENUM_5875] = {5875, 175, 2, 160},
[CHAN_ENUM_5880] = {5880, 176, 2, 160},
[CHAN_ENUM_5885] = {5885, 177, 2, 160},
[CHAN_ENUM_5890] = {5890, 178, 2, 160},
[CHAN_ENUM_5895] = {5895, 179, 2, 160},
[CHAN_ENUM_5900] = {5900, 180, 2, 160},
[CHAN_ENUM_5905] = {5905, 181, 2, 160},
[CHAN_ENUM_5910] = {5910, 182, 2, 160},
[CHAN_ENUM_5915] = {5915, 183, 2, 160},
[CHAN_ENUM_5920] = {5920, 184, 2, 160},
};
static const struct chan_map channel_map_eu[NUM_CHANNELS] = {
[CHAN_ENUM_2412] = {2412, 1, 20, 40},
[CHAN_ENUM_2417] = {2417, 2, 20, 40},
[CHAN_ENUM_2422] = {2422, 3, 20, 40},
[CHAN_ENUM_2427] = {2427, 4, 20, 40},
[CHAN_ENUM_2432] = {2432, 5, 20, 40},
[CHAN_ENUM_2437] = {2437, 6, 20, 40},
[CHAN_ENUM_2442] = {2442, 7, 20, 40},
[CHAN_ENUM_2447] = {2447, 8, 20, 40},
[CHAN_ENUM_2452] = {2452, 9, 20, 40},
[CHAN_ENUM_2457] = {2457, 10, 20, 40},
[CHAN_ENUM_2462] = {2462, 11, 20, 40},
[CHAN_ENUM_2467] = {2467, 12, 20, 40},
[CHAN_ENUM_2472] = {2472, 13, 20, 40},
[CHAN_ENUM_2484] = {2484, 14, 20, 20},
[CHAN_ENUM_4912] = {4912, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4915] = {4915, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4917] = {4917, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4920] = {4920, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4922] = {4922, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4925] = {4925, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4927] = {4927, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4932] = {4932, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4935] = {4935, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4937] = {4937, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4940] = {4940, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4942] = {4942, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4945] = {4945, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4947] = {4947, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4950] = {4950, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4952] = {4952, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4955] = {4955, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4957] = {4957, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4960] = {4960, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4962] = {4962, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4965] = {4965, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4967] = {4967, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4970] = {4970, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4972] = {4972, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4975] = {4975, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4977] = {4977, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4980] = {4980, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4982] = {4982, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4985] = {4985, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4987] = {4987, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5032] = {5032, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5035] = {5035, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5037] = {5037, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5040] = {5040, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5042] = {5042, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5045] = {5045, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5047] = {5047, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5052] = {5052, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5055] = {5055, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5057] = {5057, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5060] = {5060, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5080] = {5080, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5180] = {5180, 36, 2, 160},
[CHAN_ENUM_5200] = {5200, 40, 2, 160},
[CHAN_ENUM_5220] = {5220, 44, 2, 160},
[CHAN_ENUM_5240] = {5240, 48, 2, 160},
[CHAN_ENUM_5260] = {5260, 52, 2, 160},
[CHAN_ENUM_5280] = {5280, 56, 2, 160},
[CHAN_ENUM_5300] = {5300, 60, 2, 160},
[CHAN_ENUM_5320] = {5320, 64, 2, 160},
[CHAN_ENUM_5500] = {5500, 100, 2, 160},
[CHAN_ENUM_5520] = {5520, 104, 2, 160},
[CHAN_ENUM_5540] = {5540, 108, 2, 160},
[CHAN_ENUM_5560] = {5560, 112, 2, 160},
[CHAN_ENUM_5580] = {5580, 116, 2, 160},
[CHAN_ENUM_5600] = {5600, 120, 2, 160},
[CHAN_ENUM_5620] = {5620, 124, 2, 160},
[CHAN_ENUM_5640] = {5640, 128, 2, 160},
[CHAN_ENUM_5660] = {5660, 132, 2, 160},
[CHAN_ENUM_5680] = {5680, 136, 2, 160},
[CHAN_ENUM_5700] = {5700, 140, 2, 160},
[CHAN_ENUM_5720] = {5720, 144, 2, 160},
[CHAN_ENUM_5745] = {5745, 149, 2, 160},
[CHAN_ENUM_5765] = {5765, 153, 2, 160},
[CHAN_ENUM_5785] = {5785, 157, 2, 160},
[CHAN_ENUM_5805] = {5805, 161, 2, 160},
[CHAN_ENUM_5825] = {5825, 165, 2, 160},
[CHAN_ENUM_5845] = {5845, 169, 2, 160},
[CHAN_ENUM_5850] = {5850, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5855] = {5855, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5860] = {5860, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5865] = {5865, 173, 2, 160},
[CHAN_ENUM_5870] = {5870, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5875] = {5875, 175, 2, 160},
[CHAN_ENUM_5880] = {5880, 176, 2, 160},
[CHAN_ENUM_5885] = {5885, 177, 2, 160},
[CHAN_ENUM_5890] = {5890, 178, 2, 160},
[CHAN_ENUM_5895] = {5895, 179, 2, 160},
[CHAN_ENUM_5900] = {5900, 180, 2, 160},
[CHAN_ENUM_5905] = {5905, 181, 2, 160},
[CHAN_ENUM_5910] = {5910, 182, 2, 160},
[CHAN_ENUM_5915] = {5915, 183, 2, 160},
[CHAN_ENUM_5920] = {5920, 184, 2, 160},
};
static const struct chan_map channel_map_jp[NUM_CHANNELS] = {
[CHAN_ENUM_2412] = {2412, 1, 20, 40},
[CHAN_ENUM_2417] = {2417, 2, 20, 40},
[CHAN_ENUM_2422] = {2422, 3, 20, 40},
[CHAN_ENUM_2427] = {2427, 4, 20, 40},
[CHAN_ENUM_2432] = {2432, 5, 20, 40},
[CHAN_ENUM_2437] = {2437, 6, 20, 40},
[CHAN_ENUM_2442] = {2442, 7, 20, 40},
[CHAN_ENUM_2447] = {2447, 8, 20, 40},
[CHAN_ENUM_2452] = {2452, 9, 20, 40},
[CHAN_ENUM_2457] = {2457, 10, 20, 40},
[CHAN_ENUM_2462] = {2462, 11, 20, 40},
[CHAN_ENUM_2467] = {2467, 12, 20, 40},
[CHAN_ENUM_2472] = {2472, 13, 20, 40},
[CHAN_ENUM_2484] = {2484, 14, 20, 20},
[CHAN_ENUM_4912] = {4912, 182, 5, 5},
[CHAN_ENUM_4915] = {4915, 183, 10, 10},
[CHAN_ENUM_4917] = {4917, 183, 5, 5},
[CHAN_ENUM_4920] = {4920, 184, 10, 20},
[CHAN_ENUM_4922] = {4922, 184, 5, 5},
[CHAN_ENUM_4925] = {4925, 185, 10, 10},
[CHAN_ENUM_4927] = {4927, 185, 5, 5},
[CHAN_ENUM_4932] = {4932, 186, 5, 5},
[CHAN_ENUM_4935] = {4935, 187, 10, 10},
[CHAN_ENUM_4937] = {4937, 187, 5, 5},
[CHAN_ENUM_4940] = {4940, 188, 10, 20},
[CHAN_ENUM_4942] = {4942, 188, 5, 5},
[CHAN_ENUM_4945] = {4945, 189, 10, 10},
[CHAN_ENUM_4947] = {4947, 189, 5, 5},
[CHAN_ENUM_4950] = {4950, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4952] = {4952, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4955] = {4955, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4957] = {4957, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4960] = {4960, 192, 20, 20},
[CHAN_ENUM_4962] = {4962, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4965] = {4965, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4967] = {4967, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4970] = {4970, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4972] = {4972, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4975] = {4975, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4977] = {4977, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4980] = {4980, 196, 20, 20},
[CHAN_ENUM_4982] = {4982, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4985] = {4985, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4987] = {4987, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5032] = {5032, 6, 5, 5},
[CHAN_ENUM_5035] = {5035, 7, 10, 10},
[CHAN_ENUM_5037] = {5037, 7, 5, 5},
[CHAN_ENUM_5040] = {5040, 8, 10, 20},
[CHAN_ENUM_5042] = {5042, 8, 5, 5},
[CHAN_ENUM_5045] = {5045, 9, 10, 10},
[CHAN_ENUM_5047] = {5047, 9, 5, 5},
[CHAN_ENUM_5052] = {5052, 10, 5, 5},
[CHAN_ENUM_5055] = {5055, 11, 10, 10},
[CHAN_ENUM_5057] = {5057, 11, 5, 5},
[CHAN_ENUM_5060] = {5060, 12, 20, 20},
[CHAN_ENUM_5080] = {5080, 16, 20, 20},
[CHAN_ENUM_5180] = {5180, 36, 2, 160},
[CHAN_ENUM_5200] = {5200, 40, 2, 160},
[CHAN_ENUM_5220] = {5220, 44, 2, 160},
[CHAN_ENUM_5240] = {5240, 48, 2, 160},
[CHAN_ENUM_5260] = {5260, 52, 2, 160},
[CHAN_ENUM_5280] = {5280, 56, 2, 160},
[CHAN_ENUM_5300] = {5300, 60, 2, 160},
[CHAN_ENUM_5320] = {5320, 64, 2, 160},
[CHAN_ENUM_5500] = {5500, 100, 2, 160},
[CHAN_ENUM_5520] = {5520, 104, 2, 160},
[CHAN_ENUM_5540] = {5540, 108, 2, 160},
[CHAN_ENUM_5560] = {5560, 112, 2, 160},
[CHAN_ENUM_5580] = {5580, 116, 2, 160},
[CHAN_ENUM_5600] = {5600, 120, 2, 160},
[CHAN_ENUM_5620] = {5620, 124, 2, 160},
[CHAN_ENUM_5640] = {5640, 128, 2, 160},
[CHAN_ENUM_5660] = {5660, 132, 2, 160},
[CHAN_ENUM_5680] = {5680, 136, 2, 160},
[CHAN_ENUM_5700] = {5700, 140, 2, 160},
[CHAN_ENUM_5720] = {5720, 144, 2, 160},
[CHAN_ENUM_5745] = {5745, 149, 2, 160},
[CHAN_ENUM_5765] = {5765, 153, 2, 160},
[CHAN_ENUM_5785] = {5785, 157, 2, 160},
[CHAN_ENUM_5805] = {5805, 161, 2, 160},
[CHAN_ENUM_5825] = {5825, 165, 2, 160},
[CHAN_ENUM_5845] = {5845, 169, 2, 160},
[CHAN_ENUM_5850] = {5850, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5855] = {5855, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5860] = {5860, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5865] = {5865, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5870] = {5870, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5875] = {5875, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5880] = {5880, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5885] = {5885, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5890] = {5890, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5895] = {5895, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5900] = {5900, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5905] = {5905, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5910] = {5910, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5915] = {5915, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5920] = {5920, INVALID_CHANNEL_NUM, 2, 160},
};
static const struct chan_map channel_map_global[NUM_CHANNELS] = {
[CHAN_ENUM_2412] = {2412, 1, 20, 40},
[CHAN_ENUM_2417] = {2417, 2, 20, 40},
[CHAN_ENUM_2422] = {2422, 3, 20, 40},
[CHAN_ENUM_2427] = {2427, 4, 20, 40},
[CHAN_ENUM_2432] = {2432, 5, 20, 40},
[CHAN_ENUM_2437] = {2437, 6, 20, 40},
[CHAN_ENUM_2442] = {2442, 7, 20, 40},
[CHAN_ENUM_2447] = {2447, 8, 20, 40},
[CHAN_ENUM_2452] = {2452, 9, 20, 40},
[CHAN_ENUM_2457] = {2457, 10, 20, 40},
[CHAN_ENUM_2462] = {2462, 11, 20, 40},
[CHAN_ENUM_2467] = {2467, 12, 20, 40},
[CHAN_ENUM_2472] = {2472, 13, 20, 40},
[CHAN_ENUM_2484] = {2484, 14, 20, 20},
[CHAN_ENUM_4912] = {4912, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4915] = {4915, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4917] = {4917, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4920] = {4920, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4922] = {4922, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4925] = {4925, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4927] = {4927, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4932] = {4932, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4935] = {4935, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4937] = {4937, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4940] = {4940, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4942] = {4942, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4945] = {4945, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4947] = {4947, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4950] = {4950, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4952] = {4952, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4955] = {4955, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4957] = {4957, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4960] = {4960, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4962] = {4962, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4965] = {4965, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4967] = {4967, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4970] = {4970, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4972] = {4972, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4975] = {4975, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4977] = {4977, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4980] = {4980, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4982] = {4982, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4985] = {4985, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4987] = {4987, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5032] = {5032, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5035] = {5035, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5037] = {5037, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5040] = {5040, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5042] = {5042, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5045] = {5045, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5047] = {5047, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5052] = {5052, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5055] = {5055, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5057] = {5057, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5060] = {5060, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5080] = {5080, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5180] = {5180, 36, 2, 160},
[CHAN_ENUM_5200] = {5200, 40, 2, 160},
[CHAN_ENUM_5220] = {5220, 44, 2, 160},
[CHAN_ENUM_5240] = {5240, 48, 2, 160},
[CHAN_ENUM_5260] = {5260, 52, 2, 160},
[CHAN_ENUM_5280] = {5280, 56, 2, 160},
[CHAN_ENUM_5300] = {5300, 60, 2, 160},
[CHAN_ENUM_5320] = {5320, 64, 2, 160},
[CHAN_ENUM_5500] = {5500, 100, 2, 160},
[CHAN_ENUM_5520] = {5520, 104, 2, 160},
[CHAN_ENUM_5540] = {5540, 108, 2, 160},
[CHAN_ENUM_5560] = {5560, 112, 2, 160},
[CHAN_ENUM_5580] = {5580, 116, 2, 160},
[CHAN_ENUM_5600] = {5600, 120, 2, 160},
[CHAN_ENUM_5620] = {5620, 124, 2, 160},
[CHAN_ENUM_5640] = {5640, 128, 2, 160},
[CHAN_ENUM_5660] = {5660, 132, 2, 160},
[CHAN_ENUM_5680] = {5680, 136, 2, 160},
[CHAN_ENUM_5700] = {5700, 140, 2, 160},
[CHAN_ENUM_5720] = {5720, 144, 2, 160},
[CHAN_ENUM_5745] = {5745, 149, 2, 160},
[CHAN_ENUM_5765] = {5765, 153, 2, 160},
[CHAN_ENUM_5785] = {5785, 157, 2, 160},
[CHAN_ENUM_5805] = {5805, 161, 2, 160},
[CHAN_ENUM_5825] = {5825, 165, 2, 160},
[CHAN_ENUM_5845] = {5845, 169, 2, 160},
[CHAN_ENUM_5850] = {5850, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5855] = {5855, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5860] = {5860, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5865] = {5865, 173, 2, 160},
[CHAN_ENUM_5870] = {5870, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5875] = {5875, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5880] = {5880, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5885] = {5885, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5890] = {5890, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5895] = {5895, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5900] = {5900, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5905] = {5905, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5910] = {5910, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5915] = {5915, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5920] = {5920, INVALID_CHANNEL_NUM, 2, 160},
};
static const struct chan_map channel_map_china[NUM_CHANNELS] = {
[CHAN_ENUM_2412] = {2412, 1, 20, 40},
[CHAN_ENUM_2417] = {2417, 2, 20, 40},
[CHAN_ENUM_2422] = {2422, 3, 20, 40},
[CHAN_ENUM_2427] = {2427, 4, 20, 40},
[CHAN_ENUM_2432] = {2432, 5, 20, 40},
[CHAN_ENUM_2437] = {2437, 6, 20, 40},
[CHAN_ENUM_2442] = {2442, 7, 20, 40},
[CHAN_ENUM_2447] = {2447, 8, 20, 40},
[CHAN_ENUM_2452] = {2452, 9, 20, 40},
[CHAN_ENUM_2457] = {2457, 10, 20, 40},
[CHAN_ENUM_2462] = {2462, 11, 20, 40},
[CHAN_ENUM_2467] = {2467, 12, 20, 40},
[CHAN_ENUM_2472] = {2472, 13, 20, 40},
[CHAN_ENUM_2484] = {2484, 14, 20, 20},
[CHAN_ENUM_4912] = {4912, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4915] = {4915, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4917] = {4917, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4920] = {4920, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4922] = {4922, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4925] = {4925, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4927] = {4927, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4932] = {4932, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4935] = {4935, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4937] = {4937, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4940] = {4940, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4942] = {4942, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4945] = {4945, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4947] = {4947, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4950] = {4950, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4952] = {4952, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4955] = {4955, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4957] = {4957, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4960] = {4960, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4962] = {4962, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4965] = {4965, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4967] = {4967, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4970] = {4970, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4972] = {4972, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4975] = {4975, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4977] = {4977, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4980] = {4980, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4982] = {4982, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4985] = {4985, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_4987] = {4987, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5032] = {5032, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5035] = {5035, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5037] = {5037, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5040] = {5040, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5042] = {5042, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5045] = {5045, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5047] = {5047, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5052] = {5052, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5055] = {5055, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5057] = {5057, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5060] = {5060, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5080] = {5080, INVALID_CHANNEL_NUM, 2, 20},
[CHAN_ENUM_5180] = {5180, 36, 2, 160},
[CHAN_ENUM_5200] = {5200, 40, 2, 160},
[CHAN_ENUM_5220] = {5220, 44, 2, 160},
[CHAN_ENUM_5240] = {5240, 48, 2, 160},
[CHAN_ENUM_5260] = {5260, 52, 2, 160},
[CHAN_ENUM_5280] = {5280, 56, 2, 160},
[CHAN_ENUM_5300] = {5300, 60, 2, 160},
[CHAN_ENUM_5320] = {5320, 64, 2, 160},
[CHAN_ENUM_5500] = {5500, 100, 2, 160},
[CHAN_ENUM_5520] = {5520, 104, 2, 160},
[CHAN_ENUM_5540] = {5540, 108, 2, 160},
[CHAN_ENUM_5560] = {5560, 112, 2, 160},
[CHAN_ENUM_5580] = {5580, 116, 2, 160},
[CHAN_ENUM_5600] = {5600, 120, 2, 160},
[CHAN_ENUM_5620] = {5620, 124, 2, 160},
[CHAN_ENUM_5640] = {5640, 128, 2, 160},
[CHAN_ENUM_5660] = {5660, 132, 2, 160},
[CHAN_ENUM_5680] = {5680, 136, 2, 160},
[CHAN_ENUM_5700] = {5700, 140, 2, 160},
[CHAN_ENUM_5720] = {5720, 144, 2, 160},
[CHAN_ENUM_5745] = {5745, 149, 2, 160},
[CHAN_ENUM_5765] = {5765, 153, 2, 160},
[CHAN_ENUM_5785] = {5785, 157, 2, 160},
[CHAN_ENUM_5805] = {5805, 161, 2, 160},
[CHAN_ENUM_5825] = {5825, 165, 2, 160},
[CHAN_ENUM_5845] = {5845, 169, 2, 160},
[CHAN_ENUM_5850] = {5850, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5855] = {5855, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5860] = {5860, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5865] = {5865, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5870] = {5870, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5875] = {5875, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5880] = {5880, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5885] = {5885, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5890] = {5890, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5895] = {5895, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5900] = {5900, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5905] = {5905, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5910] = {5910, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5915] = {5915, INVALID_CHANNEL_NUM, 2, 160},
[CHAN_ENUM_5920] = {5920, INVALID_CHANNEL_NUM, 2, 160},
};
#endif
static struct reg_dmn_supp_op_classes reg_dmn_curr_supp_opp_classes = { 0 };
static const struct reg_dmn_op_class_map_t global_op_class[] = {
{81, 25, BW20, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} },
{82, 25, BW20, {14} },
{83, 40, BW40_LOW_PRIMARY, {1, 2, 3, 4, 5, 6, 7, 8, 9} },
{84, 40, BW40_HIGH_PRIMARY, {5, 6, 7, 8, 9, 10, 11, 12, 13} },
{115, 20, BW20, {36, 40, 44, 48} },
{116, 40, BW40_LOW_PRIMARY, {36, 44} },
{117, 40, BW40_HIGH_PRIMARY, {40, 48} },
{118, 20, BW20, {52, 56, 60, 64} },
{119, 40, BW40_LOW_PRIMARY, {52, 60} },
{120, 40, BW40_HIGH_PRIMARY, {56, 64} },
{121, 20, BW20,
{100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140} },
{122, 40, BW40_LOW_PRIMARY, {100, 108, 116, 124, 132} },
{123, 40, BW40_HIGH_PRIMARY, {104, 112, 120, 128, 136} },
{125, 20, BW20, {149, 153, 157, 161, 165, 169} },
{126, 40, BW40_LOW_PRIMARY, {149, 157} },
{127, 40, BW40_HIGH_PRIMARY, {153, 161} },
{128, 80, BW80, {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108,
112, 116, 120, 124, 128, 132, 136, 140, 144,
149, 153, 157, 161} },
{0, 0, 0, {0} },
};
static const struct reg_dmn_op_class_map_t us_op_class[] = {
{1, 20, BW20, {36, 40, 44, 48} },
{2, 20, BW20, {52, 56, 60, 64} },
{4, 20, BW20, {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140,
144} },
{5, 20, BW20, {149, 153, 157, 161, 165} },
{12, 25, BW20, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} },
{22, 40, BW40_LOW_PRIMARY, {36, 44} },
{23, 40, BW40_LOW_PRIMARY, {52, 60} },
{24, 40, BW40_LOW_PRIMARY, {100, 108, 116, 124, 132} },
{26, 40, BW40_LOW_PRIMARY, {149, 157} },
{27, 40, BW40_HIGH_PRIMARY, {40, 48} },
{28, 40, BW40_HIGH_PRIMARY, {56, 64} },
{29, 40, BW40_HIGH_PRIMARY, {104, 112, 120, 128, 136} },
{31, 40, BW40_HIGH_PRIMARY, {153, 161} },
{32, 40, BW40_LOW_PRIMARY, {1, 2, 3, 4, 5, 6, 7} },
{33, 40, BW40_HIGH_PRIMARY, {5, 6, 7, 8, 9, 10, 11} },
{128, 80, BW80, {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108,
112, 116, 120, 124, 128, 132, 136, 140, 144,
149, 153, 157, 161} },
{0, 0, 0, {0} },
};
static const struct reg_dmn_op_class_map_t euro_op_class[] = {
{1, 20, BW20, {36, 40, 44, 48} },
{2, 20, BW20, {52, 56, 60, 64} },
{3, 20, BW20, {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140} },
{4, 25, BW20, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} },
{5, 40, BW40_LOW_PRIMARY, {36, 44} },
{6, 40, BW40_LOW_PRIMARY, {52, 60} },
{7, 40, BW40_LOW_PRIMARY, {100, 108, 116, 124, 132} },
{8, 40, BW40_HIGH_PRIMARY, {40, 48} },
{9, 40, BW40_HIGH_PRIMARY, {56, 64} },
{10, 40, BW40_HIGH_PRIMARY, {104, 112, 120, 128, 136} },
{11, 40, BW40_LOW_PRIMARY, {1, 2, 3, 4, 5, 6, 7, 8, 9} },
{12, 40, BW40_HIGH_PRIMARY, {5, 6, 7, 8, 9, 10, 11, 12, 13} },
{17, 20, BW20, {149, 153, 157, 161, 165, 169} },
{128, 80, BW80, {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112,
116, 120, 124, 128} },
{0, 0, 0, {0} },
};
static const struct reg_dmn_op_class_map_t japan_op_class[] = {
{1, 20, BW20, {36, 40, 44, 48} },
{30, 25, BW20, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} },
{31, 25, BW20, {14} },
{32, 20, BW20, {52, 56, 60, 64} },
{34, 20, BW20,
{100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140} },
{36, 40, BW40_LOW_PRIMARY, {36, 44} },
{37, 40, BW40_LOW_PRIMARY, {52, 60} },
{39, 40, BW40_LOW_PRIMARY, {100, 108, 116, 124, 132} },
{41, 40, BW40_HIGH_PRIMARY, {40, 48} },
{42, 40, BW40_HIGH_PRIMARY, {56, 64} },
{44, 40, BW40_HIGH_PRIMARY, {104, 112, 120, 128, 136} },
{128, 80, BW80, {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112,
116, 120, 124, 128} },
{0, 0, 0, {0} },
};
struct wlan_regulatory_psoc_priv_obj *reg_get_psoc_obj(
struct wlan_objmgr_psoc *psoc)
{
struct wlan_regulatory_psoc_priv_obj *soc_reg;
if (!psoc) {
reg_alert("psoc is NULL");
return NULL;
}
soc_reg = wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_REGULATORY);
return soc_reg;
}
/**
* reg_get_pdev_obj() - Provides the reg component object pointer
* @psoc: pointer to psoc object.
*
* Return: reg component object pointer
*/
static struct wlan_regulatory_pdev_priv_obj *reg_get_pdev_obj(
struct wlan_objmgr_pdev *pdev)
{
struct wlan_regulatory_pdev_priv_obj *pdev_reg;
if (!pdev) {
reg_alert("pdev is NULL");
return NULL;
}
pdev_reg = wlan_objmgr_pdev_get_comp_private_obj(pdev,
WLAN_UMAC_COMP_REGULATORY);
return pdev_reg;
}
/**
* reg_get_bw_value() - give bandwidth value
* bw: bandwidth enum
*
* Return: uint16_t
*/
uint16_t reg_get_bw_value(enum phy_ch_width bw)
{
switch (bw) {
case CH_WIDTH_20MHZ:
return 20;
case CH_WIDTH_40MHZ:
return 40;
case CH_WIDTH_80MHZ:
return 80;
case CH_WIDTH_160MHZ:
return 160;
case CH_WIDTH_80P80MHZ:
return 160;
case CH_WIDTH_INVALID:
return 0;
case CH_WIDTH_5MHZ:
return 5;
case CH_WIDTH_10MHZ:
return 10;
case CH_WIDTH_MAX:
return 160;
default:
return 0;
}
}
/**
* reg_get_channel_list_with_power() - Provides the channel list with power
* @ch_list: pointer to the channel list.
*
* Return: QDF_STATUS
*/
QDF_STATUS reg_get_channel_list_with_power(struct wlan_objmgr_pdev *pdev,
struct channel_power *ch_list,
uint8_t *num_chan)
{
int i, count;
struct regulatory_channel *reg_channels;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
if (!num_chan || !ch_list) {
reg_err("chan_list or num_ch is NULL");
return QDF_STATUS_E_FAILURE;
}
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("reg pdev priv obj is NULL");
return QDF_STATUS_E_FAILURE;
}
/* set the current channel list */
reg_channels = pdev_priv_obj->cur_chan_list;
for (i = 0, count = 0; i < NUM_CHANNELS; i++) {
if (reg_channels[i].state &&
reg_channels[i].state != REGULATORY_CHAN_DISABLED) {
ch_list[count].chan_num =
reg_channels[i].chan_num;
ch_list[count++].tx_power =
reg_channels[i].tx_power;
}
}
*num_chan = count;
return QDF_STATUS_SUCCESS;
}
enum channel_enum reg_get_chan_enum(uint32_t chan_num)
{
uint32_t count;
for (count = 0; count < NUM_CHANNELS; count++)
if (channel_map[count].chan_num == chan_num)
return count;
reg_debug_rl("invalid channel %d", chan_num);
return INVALID_CHANNEL;
}
/**
* reg_get_channel_state() - Get channel state from regulatory
* @ch: channel number.
*
* Return: channel state
*/
enum channel_state reg_get_channel_state(struct wlan_objmgr_pdev *pdev,
uint32_t ch)
{
enum channel_enum ch_idx;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
ch_idx = reg_get_chan_enum(ch);
if (INVALID_CHANNEL == ch_idx)
return CHANNEL_STATE_INVALID;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("pdev reg obj is NULL");
return CHANNEL_STATE_INVALID;
}
return pdev_priv_obj->cur_chan_list[ch_idx].state;
}
bool reg_chan_has_dfs_attribute(struct wlan_objmgr_pdev *pdev, uint32_t ch)
{
enum channel_enum ch_idx;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
ch_idx = reg_get_chan_enum(ch);
if (ch_idx == INVALID_CHANNEL)
return false;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("pdev reg obj is NULL");
return false;
}
if (pdev_priv_obj->cur_chan_list[ch_idx].chan_flags &
REGULATORY_CHAN_RADAR)
return true;
return false;
}
/**
* reg_get_5g_bonded_chan_array() - get ptr to bonded channel
* @oper_ch: operating channel number
* @bonded_chan_ar: bonded channel array
* @bonded_chan_ptr_ptr: bonded channel ptr ptr
*
* Return: bonded channel state
*/
static enum channel_state reg_get_5g_bonded_chan_array(
struct wlan_objmgr_pdev *pdev,
uint32_t oper_chan,
const struct bonded_channel bonded_chan_ar[],
uint16_t array_size,
const struct bonded_channel **bonded_chan_ptr_ptr)
{
int i;
uint8_t chan_num;
const struct bonded_channel *bonded_chan_ptr = NULL;
enum channel_state chan_state = CHANNEL_STATE_INVALID;
enum channel_state temp_chan_state;
for (i = 0; i < array_size; i++) {
if ((oper_chan >= bonded_chan_ar[i].start_ch) &&
(oper_chan <= bonded_chan_ar[i].end_ch)) {
bonded_chan_ptr = &(bonded_chan_ar[i]);
break;
}
}
if (NULL == bonded_chan_ptr)
return chan_state;
*bonded_chan_ptr_ptr = bonded_chan_ptr;
chan_num = bonded_chan_ptr->start_ch;
while (chan_num <= bonded_chan_ptr->end_ch) {
temp_chan_state = reg_get_channel_state(pdev, chan_num);
if (temp_chan_state < chan_state)
chan_state = temp_chan_state;
chan_num = chan_num + 4;
}
return chan_state;
}
/**
* reg_get_5g_bonded_channel() - get the 5G bonded channel state
* @chan_num: channel number
* @ch_width: channel width
* @bonded_chan_ptr_ptr: bonded channel ptr ptr
*
* Return: channel state
*/
static enum channel_state reg_get_5g_bonded_channel(
struct wlan_objmgr_pdev *pdev, uint32_t chan_num,
enum phy_ch_width ch_width,
const struct bonded_channel **bonded_chan_ptr_ptr)
{
if (CH_WIDTH_80P80MHZ == ch_width)
return reg_get_5g_bonded_chan_array(pdev, chan_num,
bonded_chan_80mhz_list,
QDF_ARRAY_SIZE(bonded_chan_80mhz_list),
bonded_chan_ptr_ptr);
else if (CH_WIDTH_160MHZ == ch_width)
return reg_get_5g_bonded_chan_array(pdev, chan_num,
bonded_chan_160mhz_list,
QDF_ARRAY_SIZE(bonded_chan_160mhz_list),
bonded_chan_ptr_ptr);
else if (CH_WIDTH_80MHZ == ch_width)
return reg_get_5g_bonded_chan_array(pdev, chan_num,
bonded_chan_80mhz_list,
QDF_ARRAY_SIZE(bonded_chan_80mhz_list),
bonded_chan_ptr_ptr);
else if (CH_WIDTH_40MHZ == ch_width)
return reg_get_5g_bonded_chan_array(pdev, chan_num,
bonded_chan_40mhz_list,
QDF_ARRAY_SIZE(bonded_chan_40mhz_list),
bonded_chan_ptr_ptr);
else
return reg_get_channel_state(pdev, chan_num);
}
/**
* reg_get_5g_bonded_channel_state() - Get channel state for 5G bonded channel
* @ch: channel number.
* @bw: channel band width
*
* Return: channel state
*/
enum channel_state reg_get_5g_bonded_channel_state(
struct wlan_objmgr_pdev *pdev,
uint8_t ch, enum phy_ch_width bw)
{
enum channel_enum ch_indx;
enum channel_state chan_state;
struct regulatory_channel *reg_channels;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
bool bw_enabled = false;
const struct bonded_channel *bonded_chan_ptr = NULL;
if (CH_WIDTH_80P80MHZ < bw) {
reg_err("bw passed is not good");
return CHANNEL_STATE_INVALID;
}
chan_state = reg_get_5g_bonded_channel(pdev, ch, bw, &bonded_chan_ptr);
if ((CHANNEL_STATE_INVALID == chan_state) ||
(CHANNEL_STATE_DISABLE == chan_state))
return chan_state;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("pdev reg obj is NULL");
return CHANNEL_STATE_INVALID;
}
reg_channels = pdev_priv_obj->cur_chan_list;
ch_indx = reg_get_chan_enum(ch);
if (INVALID_CHANNEL == ch_indx)
return CHANNEL_STATE_INVALID;
if (CH_WIDTH_5MHZ == bw)
bw_enabled = true;
else if (CH_WIDTH_10MHZ == bw)
bw_enabled = (reg_channels[ch_indx].min_bw <= 10) &&
(reg_channels[ch_indx].max_bw >= 10);
else if (CH_WIDTH_20MHZ == bw)
bw_enabled = (reg_channels[ch_indx].min_bw <= 20) &&
(reg_channels[ch_indx].max_bw >= 20);
else if (CH_WIDTH_40MHZ == bw)
bw_enabled = (reg_channels[ch_indx].min_bw <= 40) &&
(reg_channels[ch_indx].max_bw >= 40);
else if (CH_WIDTH_80MHZ == bw)
bw_enabled = (reg_channels[ch_indx].min_bw <= 80) &&
(reg_channels[ch_indx].max_bw >= 80);
else if (CH_WIDTH_160MHZ == bw)
bw_enabled = (reg_channels[ch_indx].min_bw <= 160) &&
(reg_channels[ch_indx].max_bw >= 160);
else if (CH_WIDTH_80P80MHZ == bw)
bw_enabled = (reg_channels[ch_indx].min_bw <= 80) &&
(reg_channels[ch_indx].max_bw >= 80);
if (bw_enabled)
return chan_state;
else
return CHANNEL_STATE_DISABLE;
}
/**
* reg_get_2g_bonded_channel_state() - Get channel state for 2G bonded channel
* @ch: channel number.
* @bw: channel band width
*
* Return: channel state
*/
enum channel_state reg_get_2g_bonded_channel_state(
struct wlan_objmgr_pdev *pdev,
uint8_t oper_ch, uint8_t sec_ch,
enum phy_ch_width bw)
{
enum channel_enum chan_idx;
enum channel_state chan_state;
struct regulatory_channel *reg_channels;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
bool bw_enabled = false;
enum channel_state chan_state2 = CHANNEL_STATE_INVALID;
if (CH_WIDTH_40MHZ < bw)
return CHANNEL_STATE_INVALID;
if (CH_WIDTH_40MHZ == bw) {
if ((sec_ch + 4 != oper_ch) &&
(oper_ch + 4 != sec_ch))
return CHANNEL_STATE_INVALID;
chan_state2 = reg_get_channel_state(pdev, sec_ch);
if (CHANNEL_STATE_INVALID == chan_state2)
return chan_state2;
}
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("reg pdev priv obj is NULL");
return CHANNEL_STATE_INVALID;
}
reg_channels = pdev_priv_obj->cur_chan_list;
chan_state = reg_get_channel_state(pdev, oper_ch);
if (chan_state2 < chan_state)
chan_state = chan_state2;
if ((CHANNEL_STATE_INVALID == chan_state) ||
(CHANNEL_STATE_DISABLE == chan_state))
return chan_state;
chan_idx = reg_get_chan_enum(oper_ch);
if (INVALID_CHANNEL == chan_idx)
return CHANNEL_STATE_INVALID;
if (CH_WIDTH_5MHZ == bw)
bw_enabled = true;
else if (CH_WIDTH_10MHZ == bw)
bw_enabled = (reg_channels[chan_idx].min_bw <= 10) &&
(reg_channels[chan_idx].max_bw >= 10);
else if (CH_WIDTH_20MHZ == bw)
bw_enabled = (reg_channels[chan_idx].min_bw <= 20) &&
(reg_channels[chan_idx].max_bw >= 20);
else if (CH_WIDTH_40MHZ == bw)
bw_enabled = (reg_channels[chan_idx].min_bw <= 40) &&
(reg_channels[chan_idx].max_bw >= 40);
if (bw_enabled)
return chan_state;
else
return CHANNEL_STATE_DISABLE;
return CHANNEL_STATE_ENABLE;
}
static enum channel_state reg_combine_channel_states(
enum channel_state chan_state1,
enum channel_state chan_state2)
{
if ((CHANNEL_STATE_INVALID == chan_state1) ||
(CHANNEL_STATE_INVALID == chan_state2))
return CHANNEL_STATE_INVALID;
else
return min(chan_state1, chan_state2);
}
/**
* reg_set_5g_channel_params () - Sets channel parameteres for given bandwidth
* @ch: channel number.
* @ch_params: pointer to the channel parameters.
*
* Return: None
*/
static void reg_set_5g_channel_params(struct wlan_objmgr_pdev *pdev,
uint8_t ch,
struct ch_params *ch_params)
{
/*
* Set channel parameters like center frequency for a bonded channel
* state. Also return the maximum bandwidth supported by the channel.
*/
enum channel_state chan_state = CHANNEL_STATE_ENABLE;
enum channel_state chan_state2 = CHANNEL_STATE_ENABLE;
const struct bonded_channel *bonded_chan_ptr = NULL;
const struct bonded_channel *bonded_chan_ptr2 = NULL;
if (NULL == ch_params) {
reg_err("ch_params is NULL");
return;
}
if (CH_WIDTH_MAX <= ch_params->ch_width) {
if (0 != ch_params->center_freq_seg1)
ch_params->ch_width = CH_WIDTH_80P80MHZ;
else
ch_params->ch_width = CH_WIDTH_160MHZ;
}
while (ch_params->ch_width != CH_WIDTH_INVALID) {
bonded_chan_ptr = NULL;
bonded_chan_ptr2 = NULL;
chan_state = reg_get_5g_bonded_channel(pdev, ch,
ch_params->ch_width, &bonded_chan_ptr);
chan_state = reg_get_5g_bonded_channel_state(pdev, ch,
ch_params->ch_width);
if (CH_WIDTH_80P80MHZ == ch_params->ch_width) {
chan_state2 = reg_get_5g_bonded_channel_state(pdev,
ch_params->center_freq_seg1 - 2,
CH_WIDTH_80MHZ);
chan_state = reg_combine_channel_states(chan_state,
chan_state2);
}
if ((CHANNEL_STATE_ENABLE != chan_state) &&
(CHANNEL_STATE_DFS != chan_state))
goto update_bw;
if (CH_WIDTH_20MHZ >= ch_params->ch_width) {
ch_params->sec_ch_offset = NO_SEC_CH;
ch_params->center_freq_seg0 = ch;
break;
} else if (CH_WIDTH_40MHZ <= ch_params->ch_width) {
reg_get_5g_bonded_chan_array(pdev, ch,
bonded_chan_40mhz_list,
QDF_ARRAY_SIZE(bonded_chan_40mhz_list),
&bonded_chan_ptr2);
if (!bonded_chan_ptr || !bonded_chan_ptr2)
goto update_bw;
if (ch == bonded_chan_ptr2->start_ch)
ch_params->sec_ch_offset = LOW_PRIMARY_CH;
else
ch_params->sec_ch_offset = HIGH_PRIMARY_CH;
ch_params->center_freq_seg0 =
(bonded_chan_ptr->start_ch +
bonded_chan_ptr->end_ch)/2;
break;
}
update_bw:
ch_params->ch_width = get_next_lower_bw[ch_params->ch_width];
}
if (CH_WIDTH_160MHZ == ch_params->ch_width) {
ch_params->center_freq_seg1 = ch_params->center_freq_seg0;
chan_state = reg_get_5g_bonded_channel(pdev, ch,
CH_WIDTH_80MHZ, &bonded_chan_ptr);
if (bonded_chan_ptr)
ch_params->center_freq_seg0 =
(bonded_chan_ptr->start_ch +
bonded_chan_ptr->end_ch)/2;
}
/* Overwrite center_freq_seg1 to 0 for non 160 and 80+80 width */
if (!(ch_params->ch_width == CH_WIDTH_160MHZ ||
ch_params->ch_width == CH_WIDTH_80P80MHZ))
ch_params->center_freq_seg1 = 0;
reg_debug("ch %d ch_wd %d freq0 %d freq1 %d", ch,
ch_params->ch_width, ch_params->center_freq_seg0,
ch_params->center_freq_seg1);
}
/**
* reg_set_2g_channel_params() - set the 2.4G bonded channel parameters
* @oper_ch: operating channel
* @ch_params: channel parameters
* @sec_ch_2g: 2.4G secondary channel
*
* Return: void
*/
static void reg_set_2g_channel_params(struct wlan_objmgr_pdev *pdev,
uint16_t oper_ch, struct ch_params *ch_params,
uint16_t sec_ch_2g)
{
enum channel_state chan_state = CHANNEL_STATE_ENABLE;
if (CH_WIDTH_MAX <= ch_params->ch_width)
ch_params->ch_width = CH_WIDTH_40MHZ;
if ((reg_get_bw_value(ch_params->ch_width) > 20) && !sec_ch_2g) {
if (oper_ch >= 1 && oper_ch <= 5)
sec_ch_2g = oper_ch + 4;
else if (oper_ch >= 6 && oper_ch <= 13)
sec_ch_2g = oper_ch - 4;
}
while (ch_params->ch_width != CH_WIDTH_INVALID) {
chan_state = reg_get_2g_bonded_channel_state(pdev, oper_ch,
sec_ch_2g,
ch_params->ch_width);
if (CHANNEL_STATE_ENABLE == chan_state) {
if (CH_WIDTH_40MHZ == ch_params->ch_width) {
if (oper_ch < sec_ch_2g)
ch_params->sec_ch_offset =
LOW_PRIMARY_CH;
else
ch_params->sec_ch_offset =
HIGH_PRIMARY_CH;
ch_params->center_freq_seg0 =
(oper_ch + sec_ch_2g)/2;
} else {
ch_params->sec_ch_offset = NO_SEC_CH;
ch_params->center_freq_seg0 = oper_ch;
}
break;
}
ch_params->ch_width = get_next_lower_bw[ch_params->ch_width];
}
/* Overwrite center_freq_seg1 to 0 for 2.4 Ghz */
ch_params->center_freq_seg1 = 0;
}
/**
* reg_set_channel_params () - Sets channel parameteres for given bandwidth
* @ch: channel number.
* @ch_params: pointer to the channel parameters.
*
* Return: None
*/
void reg_set_channel_params(struct wlan_objmgr_pdev *pdev,
uint8_t ch, uint8_t sec_ch_2g,
struct ch_params *ch_params)
{
if (REG_IS_5GHZ_CH(ch))
reg_set_5g_channel_params(pdev, ch, ch_params);
else if (REG_IS_24GHZ_CH(ch))
reg_set_2g_channel_params(pdev, ch, ch_params,
sec_ch_2g);
}
QDF_STATUS reg_get_curr_band(struct wlan_objmgr_pdev *pdev,
enum band_info *band)
{
struct wlan_regulatory_pdev_priv_obj *pdev_reg;
pdev_reg = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_reg)) {
reg_err("pdev reg component is NULL");
return QDF_STATUS_E_INVAL;
}
*band = pdev_reg->band_capability;
return QDF_STATUS_SUCCESS;
}
static bool
reg_is_world_ctry_code(uint16_t ctry_code)
{
if ((ctry_code & 0xFFF0) == DEFAULT_WORLD_REGDMN)
return true;
return false;
}
QDF_STATUS reg_read_default_country(struct wlan_objmgr_psoc *psoc,
uint8_t *country_code)
{
struct wlan_regulatory_psoc_priv_obj *psoc_reg;
if (!country_code) {
reg_err("country_code is NULL");
return QDF_STATUS_E_INVAL;
}
psoc_reg = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(psoc_reg)) {
reg_err("psoc reg component is NULL");
return QDF_STATUS_E_INVAL;
}
qdf_mem_copy(country_code,
psoc_reg->def_country,
REG_ALPHA2_LEN + 1);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS reg_read_current_country(struct wlan_objmgr_psoc *psoc,
uint8_t *country_code)
{
struct wlan_regulatory_psoc_priv_obj *psoc_reg;
if (!country_code) {
reg_err("country_code is NULL");
return QDF_STATUS_E_INVAL;
}
psoc_reg = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(psoc_reg)) {
reg_err("psoc reg component is NULL");
return QDF_STATUS_E_INVAL;
}
qdf_mem_copy(country_code,
psoc_reg->cur_country,
REG_ALPHA2_LEN + 1);
return QDF_STATUS_SUCCESS;
}
/**
* reg_set_default_country() - Read the default country for the regdomain
* @country: country code.
*
* Return: QDF_STATUS
*/
QDF_STATUS reg_set_default_country(struct wlan_objmgr_psoc *psoc,
uint8_t *country)
{
struct wlan_regulatory_psoc_priv_obj *psoc_reg;
if (!country) {
reg_err("country is NULL");
return QDF_STATUS_E_INVAL;
}
psoc_reg = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(psoc_reg)) {
reg_err("psoc reg component is NULL");
return QDF_STATUS_E_INVAL;
}
reg_info("setting default_country: %s", country);
qdf_mem_copy(psoc_reg->def_country,
country, REG_ALPHA2_LEN + 1);
return QDF_STATUS_SUCCESS;
}
bool reg_is_world_alpha2(uint8_t *alpha2)
{
if ((alpha2[0] == '0') && (alpha2[1] == '0'))
return true;
return false;
}
bool reg_is_us_alpha2(uint8_t *alpha2)
{
if ((alpha2[0] == 'U') && (alpha2[1] == 'S'))
return true;
return false;
}
QDF_STATUS reg_set_country(struct wlan_objmgr_pdev *pdev,
uint8_t *country)
{
struct wlan_regulatory_psoc_priv_obj *psoc_reg;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
struct wlan_lmac_if_reg_tx_ops *tx_ops;
struct set_country country_code;
struct wlan_objmgr_psoc *psoc;
struct cc_regdmn_s rd;
uint8_t pdev_id;
if (!pdev) {
reg_err("pdev is NULL");
return QDF_STATUS_E_INVAL;
}
if (!country) {
reg_err("country code is NULL");
return QDF_STATUS_E_INVAL;
}
pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
psoc = wlan_pdev_get_psoc(pdev);
psoc_reg = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(psoc_reg)) {
reg_err("psoc reg component is NULL");
return QDF_STATUS_E_INVAL;
}
if (!qdf_mem_cmp(psoc_reg->cur_country,
country, REG_ALPHA2_LEN)) {
reg_err("country is not different");
return QDF_STATUS_SUCCESS;
}
reg_debug("programming new country:%s to firmware", country);
qdf_mem_copy(country_code.country,
country, REG_ALPHA2_LEN + 1);
country_code.pdev_id = pdev_id;
if (reg_is_world_alpha2(country))
psoc_reg->world_country_pending[pdev_id] = true;
else
psoc_reg->new_user_ctry_pending[pdev_id] = true;
if (psoc_reg->offload_enabled) {
tx_ops = reg_get_psoc_tx_ops(psoc);
if (tx_ops->set_country_code) {
tx_ops->set_country_code(psoc, &country_code);
} else {
reg_err("country set fw handler not present");
psoc_reg->new_user_ctry_pending[pdev_id] = false;
return QDF_STATUS_E_FAULT;
}
} else {
if (reg_is_world_alpha2(country)) {
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("reg component pdev priv is NULL");
psoc_reg->new_user_ctry_pending[pdev_id] =
false;
return QDF_STATUS_E_INVAL;
}
if (reg_is_world_ctry_code(
pdev_priv_obj->def_region_domain))
rd.cc.regdmn_id =
pdev_priv_obj->def_region_domain;
else
rd.cc.regdmn_id = DEFAULT_WORLD_REGDMN;
rd.flags = REGDMN_IS_SET;
} else {
qdf_mem_copy(rd.cc.alpha, country,
REG_ALPHA2_LEN + 1);
rd.flags = ALPHA_IS_SET;
}
reg_program_chan_list(pdev, &rd);
}
return QDF_STATUS_SUCCESS;
}
QDF_STATUS reg_set_11d_country(struct wlan_objmgr_pdev *pdev,
uint8_t *country)
{
struct wlan_regulatory_psoc_priv_obj *psoc_reg;
struct set_country country_code;
struct wlan_objmgr_psoc *psoc;
struct cc_regdmn_s rd;
QDF_STATUS status;
uint8_t pdev_id;
if (!country) {
reg_err("country code is NULL");
return QDF_STATUS_E_INVAL;
}
pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
psoc = wlan_pdev_get_psoc(pdev);
psoc_reg = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(psoc_reg)) {
reg_err("psoc reg component is NULL");
return QDF_STATUS_E_INVAL;
}
if (!qdf_mem_cmp(psoc_reg->cur_country,
country, REG_ALPHA2_LEN)) {
reg_debug("country is not different");
return QDF_STATUS_SUCCESS;
}
reg_info("programming new 11d country:%c%c to firmware",
country[0], country[1]);
qdf_mem_copy(country_code.country,
country, REG_ALPHA2_LEN + 1);
country_code.pdev_id = pdev_id;
psoc_reg->new_11d_ctry_pending[pdev_id] = true;
if (psoc_reg->offload_enabled) {
reg_err("reg offload, 11d offload too!");
status = QDF_STATUS_E_FAULT;
} else {
qdf_mem_copy(rd.cc.alpha, country, REG_ALPHA2_LEN + 1);
rd.flags = ALPHA_IS_SET;
reg_program_chan_list(pdev, &rd);
status = QDF_STATUS_SUCCESS;
}
return status;
}
QDF_STATUS reg_reset_country(struct wlan_objmgr_psoc *psoc)
{
struct wlan_regulatory_psoc_priv_obj *psoc_reg;
psoc_reg = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(psoc_reg)) {
reg_err("psoc reg component is NULL");
return QDF_STATUS_E_INVAL;
}
reg_info("re-setting user country to default");
qdf_mem_copy(psoc_reg->cur_country,
psoc_reg->def_country,
REG_ALPHA2_LEN + 1);
reg_debug("set cur_country %.2s", psoc_reg->cur_country);
return QDF_STATUS_SUCCESS;
}
/**
* reg_get_current_dfs_region () - Get the current dfs region
* @dfs_reg: pointer to dfs region
*
* Return: None
*/
void reg_get_current_dfs_region(struct wlan_objmgr_pdev *pdev,
enum dfs_reg *dfs_reg)
{
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("reg component pdev priv is NULL");
return;
}
*dfs_reg = pdev_priv_obj->dfs_region;
}
#ifdef CONFIG_LEGACY_CHAN_ENUM
static void reg_init_channel_map(enum dfs_reg dfs_region)
{
channel_map = channel_map_old;
}
#else
static void reg_init_channel_map(enum dfs_reg dfs_region)
{
switch (dfs_region) {
case DFS_UNINIT_REG:
case DFS_UNDEF_REG:
channel_map = channel_map_global;
break;
case DFS_FCC_REG:
channel_map = channel_map_us;
break;
case DFS_ETSI_REG:
channel_map = channel_map_eu;
break;
case DFS_MKK_REG:
channel_map = channel_map_jp;
break;
case DFS_CN_REG:
channel_map = channel_map_china;
break;
case DFS_KR_REG:
channel_map = channel_map_eu;
break;
}
}
#endif
/**
* reg_set_dfs_region () - Set the current dfs region
* @dfs_reg: pointer to dfs region
*
* Return: None
*/
void reg_set_dfs_region(struct wlan_objmgr_pdev *pdev,
enum dfs_reg dfs_reg)
{
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("psoc reg component is NULL");
return;
}
pdev_priv_obj->dfs_region = dfs_reg;
reg_init_channel_map(dfs_reg);
}
QDF_STATUS reg_get_domain_from_country_code(v_REGDOMAIN_t *reg_domain_ptr,
const uint8_t *country_alpha2,
enum country_src source)
{
if (NULL == reg_domain_ptr) {
reg_err("Invalid reg domain pointer");
return QDF_STATUS_E_FAULT;
}
*reg_domain_ptr = 0;
if (NULL == country_alpha2) {
reg_err("Country code array is NULL");
return QDF_STATUS_E_FAULT;
}
return QDF_STATUS_SUCCESS;
}
uint32_t reg_get_channel_reg_power(struct wlan_objmgr_pdev *pdev,
uint32_t chan_num)
{
enum channel_enum chan_enum;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
struct regulatory_channel *reg_channels;
chan_enum = reg_get_chan_enum(chan_num);
if (chan_enum == INVALID_CHANNEL) {
reg_err("channel is invalid");
return QDF_STATUS_E_FAILURE;
}
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("reg pdev priv obj is NULL");
return QDF_STATUS_E_FAILURE;
}
reg_channels = pdev_priv_obj->cur_chan_list;
return reg_channels[chan_enum].tx_power;
}
uint32_t reg_get_channel_freq(struct wlan_objmgr_pdev *pdev,
uint32_t chan_num)
{
enum channel_enum chan_enum;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
struct regulatory_channel *reg_channels;
chan_enum = reg_get_chan_enum(chan_num);
if (chan_enum == INVALID_CHANNEL)
return CHANNEL_STATE_INVALID;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("reg pdev priv obj is NULL");
return QDF_STATUS_E_FAILURE;
}
reg_channels = pdev_priv_obj->cur_chan_list;
return reg_channels[chan_enum].center_freq;
}
bool reg_is_dfs_ch(struct wlan_objmgr_pdev *pdev,
uint32_t chan)
{
enum channel_state ch_state;
ch_state = reg_get_channel_state(pdev, chan);
return ch_state == CHANNEL_STATE_DFS;
}
bool reg_is_passive_or_disable_ch(struct wlan_objmgr_pdev *pdev,
uint32_t chan)
{
enum channel_state ch_state;
ch_state = reg_get_channel_state(pdev, chan);
return (ch_state == CHANNEL_STATE_DFS) ||
(ch_state == CHANNEL_STATE_DISABLE);
}
#ifdef WLAN_FEATURE_DSRC
bool reg_is_dsrc_chan(struct wlan_objmgr_pdev *pdev, uint32_t chan)
{
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
uint32_t freq = 0;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("reg pdev priv obj is NULL");
return false;
}
if (!REG_IS_5GHZ_CH(chan))
return false;
freq = reg_chan_to_freq(pdev, chan);
if (!(freq >= REG_DSRC_START_FREQ && freq <= REG_DSRC_END_FREQ))
return false;
return true;
}
#else
bool reg_is_etsi13_regdmn(struct wlan_objmgr_pdev *pdev)
{
struct cur_regdmn_info cur_reg_dmn;
QDF_STATUS status;
status = reg_get_curr_regdomain(pdev, &cur_reg_dmn);
if (QDF_STATUS_SUCCESS != status) {
reg_debug("Failed to get reg domain");
return false;
}
return reg_etsi13_regdmn(cur_reg_dmn.dmn_id_5g);
}
bool reg_is_etsi13_srd_chan(struct wlan_objmgr_pdev *pdev, uint32_t chan)
{
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
uint32_t freq = 0;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("reg pdev priv obj is NULL");
return false;
}
if (!REG_IS_5GHZ_CH(chan))
return false;
freq = reg_chan_to_freq(pdev, chan);
if (!(freq >= REG_ETSI13_SRD_START_FREQ &&
freq <= REG_ETSI13_SRD_END_FREQ))
return false;
return reg_is_etsi13_regdmn(pdev);
}
#define SRD_MASTER_MODE_FOR_SAP 0
#define SRD_MASTER_MODE_FOR_GO 2
#define SRD_MASTER_MODE_FOR_NAN 4
bool reg_is_etsi13_srd_chan_allowed_master_mode(struct wlan_objmgr_pdev *pdev,
enum QDF_OPMODE vdev_opmode)
{
struct wlan_objmgr_psoc *psoc;
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
if (!pdev) {
reg_alert("pdev is NULL");
return true;
}
psoc = wlan_pdev_get_psoc(pdev);
psoc_priv_obj = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(psoc_priv_obj)) {
reg_alert("psoc reg component is NULL");
return true;
}
switch (vdev_opmode) {
case QDF_SAP_MODE:
if (!(psoc_priv_obj->enable_srd_chan_in_master_mode &
SRD_MASTER_MODE_FOR_SAP))
return false;
break;
case QDF_P2P_GO_MODE:
if (!(psoc_priv_obj->enable_srd_chan_in_master_mode &
SRD_MASTER_MODE_FOR_GO))
return false;
break;
case QDF_NAN_DISC_MODE:
if (!(psoc_priv_obj->enable_srd_chan_in_master_mode &
SRD_MASTER_MODE_FOR_NAN))
return false;
break;
default :
reg_err("Invalid mode passed %d", vdev_opmode);
return false;
}
return reg_is_etsi13_regdmn(pdev);
}
#endif
uint32_t reg_freq_to_chan(struct wlan_objmgr_pdev *pdev,
uint32_t freq)
{
uint32_t count;
struct regulatory_channel *chan_list;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
if (freq == 0) {
reg_err("Invalid freq %d", freq);
return 0;
}
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("reg pdev priv obj is NULL");
return 0;
}
chan_list = pdev_priv_obj->mas_chan_list;
for (count = 0; count < NUM_CHANNELS; count++) {
if (chan_list[count].center_freq >= freq)
break;
}
if (count == NUM_CHANNELS)
goto end;
if (chan_list[count].center_freq == freq)
return chan_list[count].chan_num;
if (count == 0)
goto end;
if ((chan_list[count - 1].chan_num == INVALID_CHANNEL_NUM) ||
(chan_list[count].chan_num == INVALID_CHANNEL_NUM)) {
reg_err("Frequency %d invalid in current reg domain", freq);
return 0;
}
return (chan_list[count - 1].chan_num +
(freq - chan_list[count - 1].center_freq) / 5);
end:
reg_err("invalid frequency %d", freq);
return 0;
}
static uint16_t reg_compute_chan_to_freq(struct wlan_objmgr_pdev *pdev,
uint8_t chan_num,
enum channel_enum min_chan_range,
enum channel_enum max_chan_range)
{
uint16_t count;
struct regulatory_channel *chan_list;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("reg pdev priv obj is NULL");
return 0;
}
chan_list = pdev_priv_obj->mas_chan_list;
for (count = min_chan_range; count <= max_chan_range; count++) {
if (reg_chan_is_49ghz(pdev, chan_list[count].chan_num)) {
if (chan_list[count].chan_num == chan_num)
break;
continue;
} else if ((chan_list[count].chan_num >= chan_num) &&
(chan_list[count].state != CHANNEL_STATE_DISABLE) &&
!(chan_list[count].chan_flags &
REGULATORY_CHAN_DISABLED) &&
(chan_list[count].chan_num != INVALID_CHANNEL_NUM))
break;
}
if (count == max_chan_range + 1)
goto end;
if (chan_list[count].chan_num == chan_num) {
if (chan_list[count].chan_flags & REGULATORY_CHAN_DISABLED)
reg_err("Channel %d disabled in current reg domain",
chan_num);
return chan_list[count].center_freq;
}
if (count == min_chan_range)
goto end;
if ((chan_list[count - 1].chan_num == INVALID_CHANNEL_NUM) ||
reg_chan_is_49ghz(pdev, chan_list[count - 1].chan_num) ||
(chan_list[count].chan_num == INVALID_CHANNEL_NUM)) {
reg_err("Channel %d invalid in current reg domain",
chan_num);
return 0;
}
return (chan_list[count - 1].center_freq +
(chan_num - chan_list[count - 1].chan_num) * 5);
end:
reg_debug_rl("Invalid channel %d", chan_num);
return 0;
}
uint16_t reg_legacy_chan_to_freq(struct wlan_objmgr_pdev *pdev,
uint8_t chan_num)
{
uint16_t min_chan_range = MIN_24GHZ_CHANNEL;
uint16_t max_chan_range = MAX_5GHZ_CHANNEL;
if (chan_num == 0) {
reg_err("Invalid channel %d", chan_num);
return 0;
}
return reg_compute_chan_to_freq(pdev, chan_num,
min_chan_range,
max_chan_range);
}
uint32_t reg_chan_to_freq(struct wlan_objmgr_pdev *pdev,
uint32_t chan_num)
{
uint32_t count;
struct regulatory_channel *chan_list;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("reg pdev priv obj is NULL");
return QDF_STATUS_E_FAILURE;
}
chan_list = pdev_priv_obj->cur_chan_list;
for (count = 0; count < NUM_CHANNELS; count++)
if (chan_list[count].chan_num == chan_num) {
if (reg_chan_in_range(chan_list,
pdev_priv_obj->range_2g_low,
pdev_priv_obj->range_2g_high,
pdev_priv_obj->range_5g_low,
pdev_priv_obj->range_5g_high,
count)) {
return chan_list[count].center_freq;
}
}
reg_debug_rl("invalid channel %d", chan_num);
return 0;
}
#ifndef CONFIG_LEGACY_CHAN_ENUM
bool reg_chan_is_49ghz(struct wlan_objmgr_pdev *pdev,
uint8_t chan_num)
{
uint32_t freq = 0;
freq = reg_chan_to_freq(pdev, chan_num);
return REG_IS_49GHZ_FREQ(freq) ? true : false;
}
#else
bool reg_chan_is_49ghz(struct wlan_objmgr_pdev *pdev,
uint8_t chan_num)
{
return false;
}
#endif
enum band_info reg_chan_to_band(uint32_t chan_num)
{
if (chan_num <= 14)
return BAND_2G;
return BAND_5G;
}
uint16_t reg_dmn_get_chanwidth_from_opclass(uint8_t *country,
uint8_t channel,
uint8_t opclass)
{
const struct reg_dmn_op_class_map_t *class;
uint16_t i;
if (!qdf_mem_cmp(country, "US", 2))
class = us_op_class;
else if (!qdf_mem_cmp(country, "EU", 2))
class = euro_op_class;
else if (!qdf_mem_cmp(country, "JP", 2))
class = japan_op_class;
else
class = global_op_class;
while (class->op_class) {
if (opclass == class->op_class) {
for (i = 0;
(i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
class->channels[i]);
i++) {
if (channel == class->channels[i])
return class->ch_spacing;
}
}
class++;
}
return 0;
}
uint16_t reg_dmn_get_opclass_from_channel(uint8_t *country,
uint8_t channel,
uint8_t offset)
{
const struct reg_dmn_op_class_map_t *class = NULL;
uint16_t i = 0;
if (!qdf_mem_cmp(country, "US", 2))
class = us_op_class;
else if (!qdf_mem_cmp(country, "EU", 2))
class = euro_op_class;
else if (!qdf_mem_cmp(country, "JP", 2))
class = japan_op_class;
else
class = global_op_class;
while (class->op_class) {
if ((offset == class->offset) || (offset == BWALL)) {
for (i = 0;
(i < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
class->channels[i]); i++) {
if (channel == class->channels[i])
return class->op_class;
}
}
class++;
}
return 0;
}
uint16_t reg_dmn_set_curr_opclasses(uint8_t num_classes,
uint8_t *class)
{
uint8_t i;
if (REG_MAX_SUPP_OPER_CLASSES < num_classes) {
reg_err("invalid num classes %d", num_classes);
return 0;
}
for (i = 0; i < num_classes; i++)
reg_dmn_curr_supp_opp_classes.classes[i] = class[i];
reg_dmn_curr_supp_opp_classes.num_classes = num_classes;
return 0;
}
uint16_t reg_dmn_get_curr_opclasses(uint8_t *num_classes,
uint8_t *class)
{
uint8_t i;
if (!num_classes || !class) {
reg_err("either num_classes or class is null");
return 0;
}
for (i = 0; i < reg_dmn_curr_supp_opp_classes.num_classes; i++)
class[i] = reg_dmn_curr_supp_opp_classes.classes[i];
*num_classes = reg_dmn_curr_supp_opp_classes.num_classes;
return 0;
}
static void reg_fill_channel_info(enum channel_enum chan_enum,
struct cur_reg_rule *reg_rule,
struct regulatory_channel *master_list,
uint16_t min_bw)
{
master_list[chan_enum].chan_flags &=
~REGULATORY_CHAN_DISABLED;
master_list[chan_enum].tx_power = reg_rule->reg_power;
master_list[chan_enum].ant_gain = reg_rule->ant_gain;
master_list[chan_enum].state = CHANNEL_STATE_ENABLE;
if (reg_rule->flags & REGULATORY_CHAN_NO_IR) {
master_list[chan_enum].chan_flags |=
REGULATORY_CHAN_NO_IR;
master_list[chan_enum].state =
CHANNEL_STATE_DFS;
}
if (reg_rule->flags & REGULATORY_CHAN_RADAR) {
master_list[chan_enum].chan_flags |=
REGULATORY_CHAN_RADAR;
master_list[chan_enum].state =
CHANNEL_STATE_DFS;
}
if (reg_rule->flags & REGULATORY_CHAN_INDOOR_ONLY)
master_list[chan_enum].chan_flags |=
REGULATORY_CHAN_INDOOR_ONLY;
if (reg_rule->flags & REGULATORY_CHAN_NO_OFDM)
master_list[chan_enum].chan_flags |=
REGULATORY_CHAN_NO_OFDM;
master_list[chan_enum].min_bw = min_bw;
if (20 == master_list[chan_enum].max_bw)
master_list[chan_enum].max_bw = reg_rule->max_bw;
}
static void reg_populate_band_channels(enum channel_enum start_chan,
enum channel_enum end_chan,
struct cur_reg_rule *rule_start_ptr,
uint32_t num_reg_rules,
uint16_t min_reg_bw,
struct regulatory_channel *mas_chan_list)
{
struct cur_reg_rule *found_rule_ptr;
struct cur_reg_rule *cur_rule_ptr;
struct regulatory_channel;
enum channel_enum chan_enum;
uint32_t rule_num, bw;
uint16_t max_bw;
uint16_t min_bw;
for (chan_enum = start_chan; chan_enum <= end_chan; chan_enum++) {
found_rule_ptr = NULL;
max_bw = QDF_MIN((uint16_t)20, channel_map[chan_enum].max_bw);
min_bw = QDF_MAX(min_reg_bw, channel_map[chan_enum].min_bw);
if (channel_map[chan_enum].chan_num == INVALID_CHANNEL_NUM)
continue;
for (bw = max_bw; bw >= min_bw; bw = bw/2) {
for (rule_num = 0, cur_rule_ptr =
rule_start_ptr;
rule_num < num_reg_rules;
cur_rule_ptr++, rule_num++) {
if ((cur_rule_ptr->start_freq <=
mas_chan_list[chan_enum].center_freq -
bw/2) &&
(cur_rule_ptr->end_freq >=
mas_chan_list[chan_enum].center_freq +
bw/2) && (min_bw <= bw)) {
found_rule_ptr = cur_rule_ptr;
break;
}
}
if (found_rule_ptr)
break;
}
if (found_rule_ptr) {
mas_chan_list[chan_enum].max_bw = bw;
reg_fill_channel_info(chan_enum, found_rule_ptr,
mas_chan_list, min_bw);
/* Disable 2.4 Ghz channels that dont have 20 mhz bw */
if (start_chan == MIN_24GHZ_CHANNEL &&
20 > mas_chan_list[chan_enum].max_bw) {
mas_chan_list[chan_enum].chan_flags |=
REGULATORY_CHAN_DISABLED;
mas_chan_list[chan_enum].state =
REGULATORY_CHAN_DISABLED;
}
}
}
}
static void reg_update_max_bw_per_rule(uint32_t num_reg_rules,
struct cur_reg_rule *reg_rule_start,
uint16_t max_bw)
{
uint32_t count;
for (count = 0; count < num_reg_rules; count++)
reg_rule_start[count].max_bw =
min(reg_rule_start[count].max_bw, max_bw);
}
static void reg_do_auto_bw_correction(uint32_t num_reg_rules,
struct cur_reg_rule *reg_rule_ptr,
uint16_t max_bw)
{
uint32_t count;
uint16_t new_bw;
for (count = 0; count < num_reg_rules - 1; count++) {
if ((reg_rule_ptr[count].end_freq ==
reg_rule_ptr[count+1].start_freq) &&
((reg_rule_ptr[count].max_bw + reg_rule_ptr[count+1].max_bw)
<= max_bw)) {
new_bw = reg_rule_ptr[count].max_bw +
reg_rule_ptr[count+1].max_bw;
reg_rule_ptr[count].max_bw = new_bw;
reg_rule_ptr[count+1].max_bw = new_bw;
}
}
}
static void reg_modify_chan_list_for_dfs_channels(struct regulatory_channel
*chan_list,
bool dfs_enabled)
{
enum channel_enum chan_enum;
if (dfs_enabled)
return;
for (chan_enum = 0; chan_enum < NUM_CHANNELS; chan_enum++) {
if (CHANNEL_STATE_DFS == chan_list[chan_enum].state) {
chan_list[chan_enum].state =
CHANNEL_STATE_DISABLE;
chan_list[chan_enum].chan_flags |=
REGULATORY_CHAN_DISABLED;
}
}
}
static void reg_modify_chan_list_for_indoor_channels(
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj)
{
enum channel_enum chan_enum;
struct regulatory_channel *chan_list = pdev_priv_obj->cur_chan_list;
if (!pdev_priv_obj->indoor_chan_enabled) {
for (chan_enum = 0; chan_enum < NUM_CHANNELS; chan_enum++) {
if (REGULATORY_CHAN_INDOOR_ONLY &
chan_list[chan_enum].chan_flags) {
chan_list[chan_enum].state =
CHANNEL_STATE_DFS;
chan_list[chan_enum].chan_flags |=
REGULATORY_CHAN_NO_IR;
}
}
}
if (pdev_priv_obj->force_ssc_disable_indoor_channel &&
pdev_priv_obj->sap_state) {
for (chan_enum = 0; chan_enum < NUM_CHANNELS; chan_enum++) {
if (REGULATORY_CHAN_INDOOR_ONLY &
chan_list[chan_enum].chan_flags) {
chan_list[chan_enum].state =
CHANNEL_STATE_DISABLE;
chan_list[chan_enum].chan_flags |=
REGULATORY_CHAN_DISABLED;
}
}
}
}
#ifdef DISABLE_CHANNEL_LIST
static void reg_modify_chan_list_for_cached_channels(
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj)
{
uint32_t i, j, num_cache_channels = pdev_priv_obj->num_cache_channels;
struct regulatory_channel *chan_list = pdev_priv_obj->cur_chan_list;
struct regulatory_channel *cache_chan_list =
pdev_priv_obj->cache_disable_chan_list;
if (!num_cache_channels)
return;
if (pdev_priv_obj->disable_cached_channels) {
for (i = 0; i < num_cache_channels; i++)
for (j = 0; j < NUM_CHANNELS; j++)
if (cache_chan_list[i].chan_num ==
chan_list[j].chan_num) {
chan_list[j].state =
CHANNEL_STATE_DISABLE;
chan_list[j].chan_flags |=
REGULATORY_CHAN_DISABLED;
}
}
}
#else
static void reg_modify_chan_list_for_cached_channels(
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj)
{
}
#endif
static void reg_modify_chan_list_for_band(struct regulatory_channel *chan_list,
enum band_info band_val)
{
enum channel_enum chan_enum;
if (BAND_2G == band_val) {
for (chan_enum = MIN_5GHZ_CHANNEL;
chan_enum <= MAX_5GHZ_CHANNEL;
chan_enum++) {
chan_list[chan_enum].chan_flags |=
REGULATORY_CHAN_DISABLED;
chan_list[chan_enum].state = CHANNEL_STATE_DISABLE;
}
}
if (BAND_5G == band_val) {
for (chan_enum = MIN_24GHZ_CHANNEL;
chan_enum <= MAX_24GHZ_CHANNEL;
chan_enum++) {
chan_list[chan_enum].chan_flags |=
REGULATORY_CHAN_DISABLED;
chan_list[chan_enum].state = CHANNEL_STATE_DISABLE;
}
}
}
static void reg_modify_chan_list_for_fcc_channel(struct regulatory_channel
*chan_list,
bool set_fcc_channel)
{
enum channel_enum chan_enum;
if (set_fcc_channel) {
for (chan_enum = 0; chan_enum < NUM_CHANNELS; chan_enum++) {
if (chan_list[chan_enum].center_freq ==
CHAN_12_CENT_FREQ)
chan_list[chan_enum].tx_power =
MAX_PWR_FCC_CHAN_12;
if (chan_list[chan_enum].center_freq ==
CHAN_13_CENT_FREQ)
chan_list[chan_enum].tx_power =
MAX_PWR_FCC_CHAN_13;
}
}
}
static void reg_modify_chan_list_for_chan_144(struct regulatory_channel
*chan_list,
bool en_chan_144)
{
enum channel_enum chan_enum;
if (en_chan_144)
return;
for (chan_enum = 0; chan_enum < NUM_CHANNELS; chan_enum++) {
if (chan_list[chan_enum].center_freq == CHAN_144_CENT_FREQ) {
chan_list[chan_enum].chan_flags |=
REGULATORY_CHAN_DISABLED;
chan_list[chan_enum].state =
CHANNEL_STATE_DISABLE;
}
}
}
static void
reg_modify_chan_list_for_nol_list(struct regulatory_channel *chan_list)
{
enum channel_enum chan_enum;
for (chan_enum = 0; chan_enum < NUM_CHANNELS;
chan_enum++) {
if (chan_list[chan_enum].nol_chan) {
chan_list[chan_enum].state =
CHANNEL_STATE_DISABLE;
chan_list[chan_enum].chan_flags |=
REGULATORY_CHAN_DISABLED;
}
}
}
/**
* reg_find_low_limit_chan_enum() - Find low limit 2G and 5G channel enums.
* @chan_list: Pointer to regulatory channel list.
* @low_freq: low limit frequency.
* @low_limit: pointer to output low limit enum.
*
* Return: None
*/
static void reg_find_low_limit_chan_enum(struct regulatory_channel *chan_list,
uint32_t low_freq,
uint32_t *low_limit)
{
enum channel_enum chan_enum;
uint16_t min_bw;
uint16_t max_bw;
uint32_t center_freq;
for (chan_enum = 0; chan_enum < NUM_CHANNELS; chan_enum++) {
min_bw = chan_list[chan_enum].min_bw;
max_bw = chan_list[chan_enum].max_bw;
center_freq = chan_list[chan_enum].center_freq;
if ((center_freq - min_bw/2) >= low_freq) {
if ((center_freq - max_bw/2) < low_freq) {
if (max_bw <= 20)
max_bw = ((center_freq -
low_freq) * 2);
if (max_bw < min_bw)
max_bw = min_bw;
chan_list[chan_enum].max_bw = max_bw;
}
*low_limit = chan_enum;
break;
}
}
}
/**
* reg_find_high_limit_chan_enum() - Find high limit 2G and 5G channel enums.
* @chan_list: Pointer to regulatory channel list.
* @high_freq: high limit frequency.
* @high_limit: pointer to output high limit enum.
*
* Return: None
*/
static void reg_find_high_limit_chan_enum(struct regulatory_channel *chan_list,
uint32_t high_freq,
uint32_t *high_limit)
{
enum channel_enum chan_enum;
uint16_t min_bw;
uint16_t max_bw;
uint32_t center_freq;
for (chan_enum = NUM_CHANNELS - 1; chan_enum >= 0; chan_enum--) {
min_bw = chan_list[chan_enum].min_bw;
max_bw = chan_list[chan_enum].max_bw;
center_freq = chan_list[chan_enum].center_freq;
if (center_freq + min_bw/2 <= high_freq) {
if ((center_freq + max_bw/2) > high_freq) {
if (max_bw <= 20)
max_bw = ((high_freq -
center_freq) * 2);
if (max_bw < min_bw)
max_bw = min_bw;
chan_list[chan_enum].max_bw = max_bw;
}
*high_limit = chan_enum;
break;
}
if (chan_enum == 0)
break;
}
}
/**
* reg_modify_chan_list_for_freq_range() - Modify channel list for the given low
* and high frequency range.
* @chan_list: Pointer to regulatory channel list.
* @low_freq_2g: Low frequency 2G.
* @high_freq_2g: High frequency 2G.
* @low_freq_5g: Low frequency 5G.
* @high_freq_5g: High frequency 5G.
*
* Return: None
*/
static void
reg_modify_chan_list_for_freq_range(struct regulatory_channel *chan_list,
uint32_t low_freq_2g,
uint32_t high_freq_2g,
uint32_t low_freq_5g,
uint32_t high_freq_5g)
{
uint32_t low_limit_2g = NUM_CHANNELS;
uint32_t high_limit_2g = NUM_CHANNELS;
uint32_t low_limit_5g = NUM_CHANNELS;
uint32_t high_limit_5g = NUM_CHANNELS;
enum channel_enum chan_enum;
bool chan_in_range;
reg_find_low_limit_chan_enum(chan_list, low_freq_2g, &low_limit_2g);
reg_find_low_limit_chan_enum(chan_list, low_freq_5g, &low_limit_5g);
reg_find_high_limit_chan_enum(chan_list, high_freq_2g, &high_limit_2g);
reg_find_high_limit_chan_enum(chan_list, high_freq_5g, &high_limit_5g);
for (chan_enum = 0; chan_enum < NUM_CHANNELS; chan_enum++) {
chan_in_range = false;
if ((low_limit_2g <= chan_enum) &&
(high_limit_2g >= chan_enum) &&
(low_limit_2g != NUM_CHANNELS) &&
(high_limit_2g != NUM_CHANNELS))
chan_in_range = true;
if ((low_limit_5g <= chan_enum) &&
(high_limit_5g >= chan_enum) &&
(low_limit_5g != NUM_CHANNELS) &&
(high_limit_5g != NUM_CHANNELS))
chan_in_range = true;
if (!chan_in_range) {
chan_list[chan_enum].chan_flags |=
REGULATORY_CHAN_DISABLED;
chan_list[chan_enum].state =
CHANNEL_STATE_DISABLE;
}
}
}
bool reg_chan_in_range(struct regulatory_channel *chan_list,
uint32_t low_freq_2g,
uint32_t high_freq_2g,
uint32_t low_freq_5g,
uint32_t high_freq_5g,
enum channel_enum ch_enum)
{
uint32_t low_limit_2g = NUM_CHANNELS;
uint32_t high_limit_2g = NUM_CHANNELS;
uint32_t low_limit_5g = NUM_CHANNELS;
uint32_t high_limit_5g = NUM_CHANNELS;
bool chan_in_range;
enum channel_enum chan_enum;
uint16_t min_bw;
uint32_t center_freq;
for (chan_enum = 0; chan_enum < NUM_CHANNELS; chan_enum++) {
min_bw = chan_list[chan_enum].min_bw;
center_freq = chan_list[chan_enum].center_freq;
if ((center_freq - min_bw/2) >= low_freq_2g) {
low_limit_2g = chan_enum;
break;
}
}
for (chan_enum = 0; chan_enum < NUM_CHANNELS; chan_enum++) {
min_bw = chan_list[chan_enum].min_bw;
center_freq = chan_list[chan_enum].center_freq;
if ((center_freq - min_bw/2) >= low_freq_5g) {
low_limit_5g = chan_enum;
break;
}
}
for (chan_enum = NUM_CHANNELS - 1; chan_enum >= 0; chan_enum--) {
min_bw = chan_list[chan_enum].min_bw;
center_freq = chan_list[chan_enum].center_freq;
if (center_freq + min_bw/2 <= high_freq_2g) {
high_limit_2g = chan_enum;
break;
}
if (chan_enum == 0)
break;
}
for (chan_enum = NUM_CHANNELS - 1; chan_enum >= 0; chan_enum--) {
min_bw = chan_list[chan_enum].min_bw;
center_freq = chan_list[chan_enum].center_freq;
if (center_freq + min_bw/2 <= high_freq_5g) {
high_limit_5g = chan_enum;
break;
}
if (chan_enum == 0)
break;
}
chan_in_range = false;
if ((low_limit_2g <= ch_enum) &&
(high_limit_2g >= ch_enum) &&
(low_limit_2g != NUM_CHANNELS) &&
(high_limit_2g != NUM_CHANNELS))
chan_in_range = true;
if ((low_limit_5g <= ch_enum) &&
(high_limit_5g >= ch_enum) &&
(low_limit_5g != NUM_CHANNELS) &&
(high_limit_5g != NUM_CHANNELS))
chan_in_range = true;
if (chan_in_range)
return true;
else
return false;
}
static void reg_init_pdev_mas_chan_list(struct wlan_regulatory_pdev_priv_obj
*pdev_priv_obj,
struct mas_chan_params
*mas_chan_params)
{
qdf_mem_copy(pdev_priv_obj->mas_chan_list,
mas_chan_params->mas_chan_list,
NUM_CHANNELS * sizeof(struct regulatory_channel));
pdev_priv_obj->dfs_region = mas_chan_params->dfs_region;
pdev_priv_obj->phybitmap = mas_chan_params->phybitmap;
pdev_priv_obj->reg_dmn_pair = mas_chan_params->reg_dmn_pair;
pdev_priv_obj->ctry_code = mas_chan_params->ctry_code;
pdev_priv_obj->def_region_domain = mas_chan_params->reg_dmn_pair;
pdev_priv_obj->def_country_code = mas_chan_params->ctry_code;
qdf_mem_copy(pdev_priv_obj->default_country,
mas_chan_params->default_country, REG_ALPHA2_LEN + 1);
qdf_mem_copy(pdev_priv_obj->current_country,
mas_chan_params->current_country, REG_ALPHA2_LEN + 1);
}
/**
* reg_modify_chan_list_for_srd_channels() - Modify SRD channels in ETSI13
* @pdev: Pointer to pdev object
* @chan_list: Current channel list
*
* This function converts SRD channels to passive in ETSI13 regulatory domain
* when enable_srd_chan_in_master_mode is not set.
*/
static void
reg_modify_chan_list_for_srd_channels(struct wlan_objmgr_pdev *pdev,
struct regulatory_channel *chan_list)
{
enum channel_enum chan_enum;
struct wlan_objmgr_psoc *psoc;
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
if (!reg_is_etsi13_regdmn(pdev))
return;
psoc = wlan_pdev_get_psoc(pdev);
psoc_priv_obj = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(psoc_priv_obj)) {
reg_alert("psoc reg component is NULL");
return;
}
if (psoc_priv_obj->enable_srd_chan_in_master_mode)
return;
for (chan_enum = 0; chan_enum < NUM_CHANNELS; chan_enum++) {
if (chan_list[chan_enum].chan_flags & REGULATORY_CHAN_DISABLED)
continue;
if (reg_is_etsi13_srd_chan(pdev,
chan_list[chan_enum].chan_num)) {
chan_list[chan_enum].state =
CHANNEL_STATE_DFS;
chan_list[chan_enum].chan_flags |=
REGULATORY_CHAN_NO_IR;
}
}
}
static void reg_compute_pdev_current_chan_list(struct
wlan_regulatory_pdev_priv_obj
*pdev_priv_obj)
{
qdf_mem_copy(pdev_priv_obj->cur_chan_list,
pdev_priv_obj->mas_chan_list,
NUM_CHANNELS * sizeof(struct regulatory_channel));
reg_modify_chan_list_for_freq_range(pdev_priv_obj->cur_chan_list,
pdev_priv_obj->range_2g_low,
pdev_priv_obj->range_2g_high,
pdev_priv_obj->range_5g_low,
pdev_priv_obj->range_5g_high);
reg_modify_chan_list_for_band(pdev_priv_obj->cur_chan_list,
pdev_priv_obj->band_capability);
reg_modify_chan_list_for_dfs_channels(pdev_priv_obj->cur_chan_list,
pdev_priv_obj->dfs_enabled);
reg_modify_chan_list_for_nol_list(pdev_priv_obj->cur_chan_list);
reg_modify_chan_list_for_indoor_channels(pdev_priv_obj);
reg_modify_chan_list_for_fcc_channel(pdev_priv_obj->cur_chan_list,
pdev_priv_obj->set_fcc_channel);
reg_modify_chan_list_for_chan_144(pdev_priv_obj->cur_chan_list,
pdev_priv_obj->en_chan_144);
reg_modify_chan_list_for_cached_channels(pdev_priv_obj);
reg_modify_chan_list_for_srd_channels(pdev_priv_obj->pdev_ptr,
pdev_priv_obj->cur_chan_list);
}
static void reg_call_chan_change_cbks(struct wlan_objmgr_psoc *psoc,
struct wlan_objmgr_pdev *pdev)
{
struct chan_change_cbk_entry *cbk_list;
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
struct regulatory_channel *cur_chan_list;
uint32_t ctr;
struct avoid_freq_ind_data *avoid_freq_ind = NULL;
reg_chan_change_callback callback;
psoc_priv_obj = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(psoc_priv_obj)) {
reg_alert("psoc reg component is NULL");
return;
}
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_alert("pdev reg component is NULL");
return;
}
cur_chan_list = qdf_mem_malloc(NUM_CHANNELS * sizeof(*cur_chan_list));
if (NULL == cur_chan_list) {
reg_alert("Mem alloc failed for current channel list");
return;
}
qdf_mem_copy(cur_chan_list,
pdev_priv_obj->cur_chan_list,
NUM_CHANNELS *
sizeof(struct regulatory_channel));
if (psoc_priv_obj->ch_avoid_ind) {
avoid_freq_ind = qdf_mem_malloc(sizeof(*avoid_freq_ind));
if (!avoid_freq_ind) {
reg_alert("Mem alloc failed for avoid freq ind");
goto skip_ch_avoid_ind;
}
qdf_mem_copy(&avoid_freq_ind->freq_list,
&psoc_priv_obj->avoid_freq_list,
sizeof(struct ch_avoid_ind_type));
qdf_mem_copy(&avoid_freq_ind->chan_list,
&psoc_priv_obj->unsafe_chan_list,
sizeof(struct unsafe_ch_list));
psoc_priv_obj->ch_avoid_ind = false;
}
skip_ch_avoid_ind:
cbk_list = psoc_priv_obj->cbk_list;
for (ctr = 0; ctr < REG_MAX_CHAN_CHANGE_CBKS; ctr++) {
callback = NULL;
qdf_spin_lock_bh(&psoc_priv_obj->cbk_list_lock);
if (cbk_list[ctr].cbk != NULL)
callback = cbk_list[ctr].cbk;
qdf_spin_unlock_bh(&psoc_priv_obj->cbk_list_lock);
if (callback != NULL)
callback(psoc, pdev, cur_chan_list, avoid_freq_ind,
cbk_list[ctr].arg);
}
qdf_mem_free(cur_chan_list);
if (avoid_freq_ind)
qdf_mem_free(avoid_freq_ind);
}
static struct reg_sched_payload
*reg_alloc_and_fill_payload(struct wlan_objmgr_psoc *psoc,
struct wlan_objmgr_pdev *pdev)
{
struct reg_sched_payload *payload;
payload = qdf_mem_malloc(sizeof(*payload));
if (payload != NULL) {
payload->psoc = psoc;
payload->pdev = pdev;
}
return payload;
}
#ifdef CONFIG_MCL
static QDF_STATUS reg_chan_change_flush_cbk_sb(struct scheduler_msg *msg)
{
struct reg_sched_payload *load = msg->bodyptr;
struct wlan_objmgr_psoc *psoc = load->psoc;
struct wlan_objmgr_pdev *pdev = load->pdev;
wlan_objmgr_pdev_release_ref(pdev, WLAN_REGULATORY_SB_ID);
wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID);
qdf_mem_free(load);
return QDF_STATUS_SUCCESS;
}
static QDF_STATUS reg_sched_chan_change_cbks_sb(struct scheduler_msg *msg)
{
struct reg_sched_payload *load = msg->bodyptr;
struct wlan_objmgr_psoc *psoc = load->psoc;
struct wlan_objmgr_pdev *pdev = load->pdev;
reg_call_chan_change_cbks(psoc, pdev);
wlan_objmgr_pdev_release_ref(pdev, WLAN_REGULATORY_SB_ID);
wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID);
qdf_mem_free(load);
return QDF_STATUS_SUCCESS;
}
static QDF_STATUS reg_chan_change_flush_cbk_nb(struct scheduler_msg *msg)
{
struct reg_sched_payload *load = msg->bodyptr;
struct wlan_objmgr_psoc *psoc = load->psoc;
struct wlan_objmgr_pdev *pdev = load->pdev;
wlan_objmgr_pdev_release_ref(pdev, WLAN_REGULATORY_NB_ID);
wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_NB_ID);
qdf_mem_free(load);
return QDF_STATUS_SUCCESS;
}
static QDF_STATUS reg_sched_chan_change_cbks_nb(struct scheduler_msg *msg)
{
struct reg_sched_payload *load = msg->bodyptr;
struct wlan_objmgr_psoc *psoc = load->psoc;
struct wlan_objmgr_pdev *pdev = load->pdev;
reg_call_chan_change_cbks(psoc, pdev);
wlan_objmgr_pdev_release_ref(pdev, WLAN_REGULATORY_NB_ID);
wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_NB_ID);
qdf_mem_free(load);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS reg_send_scheduler_msg_sb(struct wlan_objmgr_psoc *psoc,
struct wlan_objmgr_pdev *pdev)
{
struct scheduler_msg msg = {0};
struct reg_sched_payload *payload;
QDF_STATUS status;
status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_REGULATORY_SB_ID);
if (QDF_IS_STATUS_ERROR(status)) {
reg_err("error taking psoc ref cnt");
return status;
}
status = wlan_objmgr_pdev_try_get_ref(pdev, WLAN_REGULATORY_SB_ID);
if (QDF_IS_STATUS_ERROR(status)) {
wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID);
reg_err("error taking pdev ref cnt");
return status;
}
payload = reg_alloc_and_fill_payload(psoc, pdev);
if (payload == NULL) {
reg_err("payload memory alloc failed");
wlan_objmgr_pdev_release_ref(pdev, WLAN_REGULATORY_SB_ID);
wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID);
return QDF_STATUS_E_NOMEM;
}
msg.bodyptr = payload;
msg.callback = reg_sched_chan_change_cbks_sb;
msg.flush_callback = reg_chan_change_flush_cbk_sb;
status = scheduler_post_message(QDF_MODULE_ID_REGULATORY,
QDF_MODULE_ID_REGULATORY,
QDF_MODULE_ID_TARGET_IF, &msg);
if (QDF_IS_STATUS_ERROR(status)) {
wlan_objmgr_pdev_release_ref(pdev, WLAN_REGULATORY_SB_ID);
wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID);
reg_err("scheduler msg posting failed");
qdf_mem_free(payload);
}
return status;
}
static QDF_STATUS reg_send_scheduler_msg_nb(struct wlan_objmgr_psoc *psoc,
struct wlan_objmgr_pdev *pdev)
{
struct scheduler_msg msg = {0};
struct reg_sched_payload *payload;
QDF_STATUS status;
status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_REGULATORY_NB_ID);
if (QDF_IS_STATUS_ERROR(status)) {
reg_err("error taking psoc ref cnt");
return status;
}
status = wlan_objmgr_pdev_try_get_ref(pdev, WLAN_REGULATORY_NB_ID);
if (QDF_IS_STATUS_ERROR(status)) {
wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_NB_ID);
reg_err("error taking pdev ref cnt");
return status;
}
payload = reg_alloc_and_fill_payload(psoc, pdev);
if (payload == NULL) {
reg_err("payload memory alloc failed");
wlan_objmgr_pdev_release_ref(pdev, WLAN_REGULATORY_NB_ID);
wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_NB_ID);
return QDF_STATUS_E_NOMEM;
}
msg.bodyptr = payload;
msg.callback = reg_sched_chan_change_cbks_nb;
msg.flush_callback = reg_chan_change_flush_cbk_nb;
status = scheduler_post_message(QDF_MODULE_ID_REGULATORY,
QDF_MODULE_ID_REGULATORY,
QDF_MODULE_ID_OS_IF, &msg);
if (QDF_IS_STATUS_ERROR(status)) {
wlan_objmgr_pdev_release_ref(pdev, WLAN_REGULATORY_NB_ID);
wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_NB_ID);
reg_err("scheduler msg posting failed");
qdf_mem_free(payload);
}
return status;
}
static QDF_STATUS reg_send_11d_flush_cbk(struct scheduler_msg *msg)
{
struct reg_11d_scan_msg *scan_msg_11d = msg->bodyptr;
struct wlan_objmgr_psoc *psoc = scan_msg_11d->psoc;
wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID);
qdf_mem_free(scan_msg_11d);
return QDF_STATUS_SUCCESS;
}
static QDF_STATUS reg_send_11d_msg_cbk(struct scheduler_msg *msg)
{
struct reg_11d_scan_msg *scan_msg_11d = msg->bodyptr;
struct wlan_objmgr_psoc *psoc = scan_msg_11d->psoc;
struct wlan_lmac_if_reg_tx_ops *tx_ops;
struct reg_start_11d_scan_req start_req;
struct reg_stop_11d_scan_req stop_req;
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
tx_ops = reg_get_psoc_tx_ops(psoc);
psoc_priv_obj = (struct wlan_regulatory_psoc_priv_obj *)
wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_REGULATORY);
if (!psoc_priv_obj) {
reg_err("psoc priv obj is NULL");
goto end;
}
if (psoc_priv_obj->vdev_id_for_11d_scan == INVALID_VDEV_ID) {
psoc_priv_obj->enable_11d_supp = false;
reg_err("No valid vdev for 11d scan command");
goto end;
}
if (scan_msg_11d->enable_11d_supp) {
start_req.vdev_id = psoc_priv_obj->vdev_id_for_11d_scan;
start_req.scan_period_msec = psoc_priv_obj->scan_11d_interval;
start_req.start_interval_msec = 0;
reg_debug("sending start msg");
tx_ops->start_11d_scan(psoc, &start_req);
} else {
stop_req.vdev_id = psoc_priv_obj->vdev_id_for_11d_scan;
reg_debug("sending stop msg");
tx_ops->stop_11d_scan(psoc, &stop_req);
}
end:
qdf_mem_free(scan_msg_11d);
wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID);
return QDF_STATUS_SUCCESS;
}
static QDF_STATUS reg_sched_11d_msg(struct reg_11d_scan_msg *scan_msg_11d)
{
struct scheduler_msg msg = {0};
QDF_STATUS status;
status = wlan_objmgr_psoc_try_get_ref(scan_msg_11d->psoc,
WLAN_REGULATORY_SB_ID);
if (QDF_IS_STATUS_ERROR(status)) {
reg_err("error taking psoc ref cnt");
return status;
}
msg.bodyptr = scan_msg_11d;
msg.callback = reg_send_11d_msg_cbk;
msg.flush_callback = reg_send_11d_flush_cbk;
status = scheduler_post_message(QDF_MODULE_ID_REGULATORY,
QDF_MODULE_ID_REGULATORY,
QDF_MODULE_ID_TARGET_IF, &msg);
if (QDF_IS_STATUS_ERROR(status))
wlan_objmgr_psoc_release_ref(scan_msg_11d->psoc,
WLAN_REGULATORY_SB_ID);
return status;
}
#else
QDF_STATUS reg_send_scheduler_msg_sb(struct wlan_objmgr_psoc *psoc,
struct wlan_objmgr_pdev *pdev)
{
return QDF_STATUS_SUCCESS;
}
static QDF_STATUS reg_send_scheduler_msg_nb(struct wlan_objmgr_psoc *psoc,
struct wlan_objmgr_pdev *pdev)
{
return QDF_STATUS_SUCCESS;
}
static QDF_STATUS reg_sched_11d_msg(struct wlan_objmgr_psoc *psoc)
{
return QDF_STATUS_SUCCESS;
}
#endif
void reg_reset_reg_rules(struct reg_rule_info *reg_rules)
{
qdf_mem_zero(reg_rules, sizeof(*reg_rules));
}
static void reg_save_reg_rules_to_pdev(struct reg_rule_info *psoc_reg_rules,
struct wlan_regulatory_pdev_priv_obj
*pdev_priv_obj)
{
uint32_t reg_rule_len;
struct reg_rule_info *pdev_reg_rules;
qdf_spin_lock_bh(&pdev_priv_obj->reg_rules_lock);
pdev_reg_rules = &pdev_priv_obj->reg_rules;
reg_reset_reg_rules(pdev_reg_rules);
pdev_reg_rules->num_of_reg_rules = psoc_reg_rules->num_of_reg_rules;
if (!pdev_reg_rules->num_of_reg_rules) {
qdf_spin_unlock_bh(&pdev_priv_obj->reg_rules_lock);
reg_err("no reg rules in psoc");
return;
}
reg_rule_len = pdev_reg_rules->num_of_reg_rules *
sizeof(struct cur_reg_rule);
qdf_mem_copy(pdev_reg_rules->reg_rules,
psoc_reg_rules->reg_rules,
reg_rule_len);
qdf_mem_copy(pdev_reg_rules->alpha2, pdev_priv_obj->current_country,
REG_ALPHA2_LEN + 1);
pdev_reg_rules->dfs_region = pdev_priv_obj->dfs_region;
qdf_spin_unlock_bh(&pdev_priv_obj->reg_rules_lock);
}
static void reg_propagate_mas_chan_list_to_pdev(struct wlan_objmgr_psoc *psoc,
void *object, void *arg)
{
struct wlan_objmgr_pdev *pdev = (struct wlan_objmgr_pdev *)object;
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
enum direction *dir = arg;
uint32_t pdev_id;
struct wlan_lmac_if_reg_tx_ops *reg_tx_ops;
struct reg_rule_info *psoc_reg_rules;
psoc_priv_obj = (struct wlan_regulatory_psoc_priv_obj *)
wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_REGULATORY);
if (NULL == psoc_priv_obj) {
reg_err("psoc priv obj is NULL");
return;
}
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("reg pdev priv obj is NULL");
return;
}
pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
reg_init_pdev_mas_chan_list(pdev_priv_obj,
&psoc_priv_obj->mas_chan_params[pdev_id]);
psoc_reg_rules = &psoc_priv_obj->mas_chan_params[pdev_id].reg_rules;
reg_save_reg_rules_to_pdev(psoc_reg_rules, pdev_priv_obj);
reg_compute_pdev_current_chan_list(pdev_priv_obj);
reg_tx_ops = reg_get_psoc_tx_ops(psoc);
if (reg_tx_ops->fill_umac_legacy_chanlist) {
reg_tx_ops->fill_umac_legacy_chanlist(pdev,
pdev_priv_obj->cur_chan_list);
} else {
if (*dir == NORTHBOUND)
reg_send_scheduler_msg_nb(psoc, pdev);
else
reg_send_scheduler_msg_sb(psoc, pdev);
}
}
static void reg_run_11d_state_machine(struct wlan_objmgr_psoc *psoc)
{
bool temp_11d_support;
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
bool world_mode;
struct reg_11d_scan_msg *scan_msg_11d;
psoc_priv_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_REGULATORY);
if (!psoc_priv_obj) {
reg_err("reg psoc private obj is NULL");
return;
}
if (psoc_priv_obj->vdev_id_for_11d_scan == INVALID_VDEV_ID) {
psoc_priv_obj->enable_11d_supp = false;
reg_err("No valid vdev for 11d scan command");
return;
}
world_mode = reg_is_world_alpha2(psoc_priv_obj->cur_country);
temp_11d_support = psoc_priv_obj->enable_11d_supp;
if ((psoc_priv_obj->enable_11d_in_world_mode) && (world_mode))
psoc_priv_obj->enable_11d_supp = true;
else if (((psoc_priv_obj->user_ctry_set) &&
(psoc_priv_obj->user_ctry_priority)) ||
(psoc_priv_obj->master_vdev_cnt))
psoc_priv_obj->enable_11d_supp = false;
else
psoc_priv_obj->enable_11d_supp =
psoc_priv_obj->enable_11d_supp_original;
reg_debug("inside 11d state machine:tmp %d 11d_supp %d org %d set %d pri %d cnt %d vdev %d",
temp_11d_support,
psoc_priv_obj->enable_11d_supp,
psoc_priv_obj->enable_11d_supp_original,
psoc_priv_obj->user_ctry_set,
psoc_priv_obj->user_ctry_priority,
psoc_priv_obj->master_vdev_cnt,
psoc_priv_obj->vdev_id_for_11d_scan);
if ((temp_11d_support != psoc_priv_obj->enable_11d_supp) &&
(psoc_priv_obj->is_11d_offloaded)) {
scan_msg_11d = qdf_mem_malloc(sizeof(*scan_msg_11d));
if (!scan_msg_11d)
return;
scan_msg_11d->psoc = psoc;
scan_msg_11d->enable_11d_supp =
psoc_priv_obj->enable_11d_supp;
reg_sched_11d_msg(scan_msg_11d);
}
}
void reg_reset_ctry_pending_hints(struct wlan_regulatory_psoc_priv_obj
*soc_reg)
{
uint8_t ctr;
if (!soc_reg->offload_enabled)
return;
for (ctr = 0; ctr < PSOC_MAX_PHY_REG_CAP; ctr++) {
soc_reg->new_user_ctry_pending[ctr] = false;
soc_reg->new_init_ctry_pending[ctr] = false;
soc_reg->new_11d_ctry_pending[ctr] = false;
soc_reg->world_country_pending[ctr] = false;
}
}
/**
* reg_set_curr_country() - Set current country update
* @soc_reg: regulatory private object
* @regulat_info: regulatory info from firmware
* @tx_ops: send operations for regulatory component
*
* During SSR or restart of wlan modules after interface change timer phase,
* this function is used to send the recent user/11d country code to firmware.
*
* Return: QDF_STATUS_SUCCESS if correct country is configured
* else return failure
* error code.
*/
static QDF_STATUS reg_set_curr_country(
struct wlan_regulatory_psoc_priv_obj *soc_reg,
struct cur_regulatory_info *regulat_info,
struct wlan_lmac_if_reg_tx_ops *tx_ops)
{
struct wlan_objmgr_psoc *psoc = regulat_info->psoc;
uint8_t pdev_id;
uint8_t phy_num;
struct set_country country_code;
QDF_STATUS status;
/*
* During SSR/WLAN restart ignore master channel list
* for all events and in the last event handling if
* current country and default country is different, send the last
* configured (soc_reg->cur_country) country.
*/
if ((regulat_info->num_phy != regulat_info->phy_id + 1) ||
(!qdf_mem_cmp(soc_reg->cur_country, regulat_info->alpha2,
REG_ALPHA2_LEN)))
return QDF_STATUS_SUCCESS;
pdev_id = regulat_info->phy_id;
for(phy_num = 0; phy_num < regulat_info->num_phy; phy_num++) {
if (soc_reg->cc_src == SOURCE_USERSPACE)
soc_reg->new_user_ctry_pending[phy_num] = true;
else if (soc_reg->cc_src == SOURCE_11D)
soc_reg->new_11d_ctry_pending[phy_num] = true;
else
soc_reg->world_country_pending[phy_num] = true;
}
qdf_mem_zero(&country_code, sizeof(country_code));
qdf_mem_copy(country_code.country, soc_reg->cur_country,
sizeof(soc_reg->cur_country));
country_code.pdev_id = pdev_id;
if (!tx_ops || !tx_ops->set_country_code) {
reg_err("No regulatory tx_ops for set_country_code");
status = QDF_STATUS_E_FAULT;
goto error;
}
status = tx_ops->set_country_code(psoc, &country_code);
if (QDF_IS_STATUS_ERROR(status)) {
reg_err("Failed to send country code to firmware");
goto error;
}
reg_debug("Target CC: %.2s, Restore to Previous CC: %.2s",
regulat_info->alpha2, soc_reg->cur_country);
return status;
error:
reg_reset_ctry_pending_hints(soc_reg);
return status;
}
/**
* reg_ignore_default_country() - Ignore default country update
* @soc_reg: regulatory private object
* @regulat_info: regulatory info from firmware
*
* During SSR or restart of wlan modules after interface change timer phase,
* this function is used to ignore default country code from firmware.
*
* Return: If default country needs to be ignored return true else false.
*/
static bool
reg_ignore_default_country(struct wlan_regulatory_psoc_priv_obj *soc_reg,
struct cur_regulatory_info *regulat_info)
{
uint8_t phy_num;
if (!soc_reg->offload_enabled)
return false;
if (soc_reg->cc_src == SOURCE_UNKNOWN)
return false;
for (phy_num = 0; phy_num < regulat_info->num_phy; phy_num++) {
if (soc_reg->new_user_ctry_pending[phy_num] ||
soc_reg->new_init_ctry_pending[phy_num] ||
soc_reg->new_11d_ctry_pending[phy_num] ||
soc_reg->world_country_pending[phy_num])
return false;
}
return true;
}
QDF_STATUS reg_process_master_chan_list(struct cur_regulatory_info
*regulat_info)
{
struct wlan_regulatory_psoc_priv_obj *soc_reg;
uint32_t num_2g_reg_rules, num_5g_reg_rules;
struct cur_reg_rule *reg_rule_2g, *reg_rule_5g;
uint16_t min_bw_2g, max_bw_2g, min_bw_5g, max_bw_5g;
struct regulatory_channel *mas_chan_list;
struct wlan_objmgr_psoc *psoc;
enum channel_enum chan_enum;
wlan_objmgr_ref_dbgid dbg_id;
enum direction dir;
uint8_t phy_id;
struct wlan_objmgr_pdev *pdev;
struct wlan_lmac_if_reg_tx_ops *tx_ops;
struct reg_rule_info *reg_rules;
QDF_STATUS status;
psoc = regulat_info->psoc;
soc_reg = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(soc_reg)) {
reg_err("psoc reg component is NULL");
return QDF_STATUS_E_FAILURE;
}
tx_ops = reg_get_psoc_tx_ops(psoc);
phy_id = regulat_info->phy_id;
if (reg_ignore_default_country(soc_reg, regulat_info)) {
status = reg_set_curr_country(soc_reg, regulat_info, tx_ops);
if (QDF_IS_STATUS_SUCCESS(status)) {
reg_debug("WLAN restart - Ignore default CC for phy_id: %u",
phy_id);
return QDF_STATUS_SUCCESS;
}
}
reg_debug("process reg master chan list");
if (soc_reg->offload_enabled) {
dbg_id = WLAN_REGULATORY_NB_ID;
dir = NORTHBOUND;
} else {
dbg_id = WLAN_REGULATORY_SB_ID;
dir = SOUTHBOUND;
}
if (regulat_info->status_code != REG_SET_CC_STATUS_PASS) {
reg_err("Setting country code failed, status code is %d",
regulat_info->status_code);
pdev = wlan_objmgr_get_pdev_by_id(psoc, phy_id, dbg_id);
if (!pdev) {
reg_err("pdev is NULL");
return QDF_STATUS_E_FAILURE;
}
if (tx_ops->set_country_failed)
tx_ops->set_country_failed(pdev);
wlan_objmgr_pdev_release_ref(pdev, dbg_id);
if (regulat_info->status_code != REG_CURRENT_ALPHA2_NOT_FOUND)
return QDF_STATUS_E_FAILURE;
soc_reg->new_user_ctry_pending[phy_id] = false;
soc_reg->new_11d_ctry_pending[phy_id] = false;
soc_reg->world_country_pending[phy_id] = true;
}
mas_chan_list = soc_reg->mas_chan_params[phy_id].mas_chan_list;
reg_init_channel_map(regulat_info->dfs_region);
for (chan_enum = 0; chan_enum < NUM_CHANNELS;
chan_enum++) {
mas_chan_list[chan_enum].chan_num =
channel_map[chan_enum].chan_num;
mas_chan_list[chan_enum].center_freq =
channel_map[chan_enum].center_freq;
mas_chan_list[chan_enum].chan_flags =
REGULATORY_CHAN_DISABLED;
mas_chan_list[chan_enum].state =
CHANNEL_STATE_DISABLE;
mas_chan_list[chan_enum].nol_chan = false;
}
soc_reg->num_phy = regulat_info->num_phy;
soc_reg->mas_chan_params[phy_id].phybitmap =
regulat_info->phybitmap;
soc_reg->mas_chan_params[phy_id].dfs_region =
regulat_info->dfs_region;
soc_reg->mas_chan_params[phy_id].ctry_code =
regulat_info->ctry_code;
soc_reg->mas_chan_params[phy_id].reg_dmn_pair =
regulat_info->reg_dmn_pair;
qdf_mem_copy(soc_reg->mas_chan_params[phy_id].current_country,
regulat_info->alpha2,
REG_ALPHA2_LEN + 1);
qdf_mem_copy(soc_reg->cur_country,
regulat_info->alpha2,
REG_ALPHA2_LEN + 1);
reg_debug("set cur_country %.2s", soc_reg->cur_country);
min_bw_2g = regulat_info->min_bw_2g;
max_bw_2g = regulat_info->max_bw_2g;
reg_rule_2g = regulat_info->reg_rules_2g_ptr;
num_2g_reg_rules = regulat_info->num_2g_reg_rules;
reg_update_max_bw_per_rule(num_2g_reg_rules,
reg_rule_2g, max_bw_2g);
min_bw_5g = regulat_info->min_bw_5g;
max_bw_5g = regulat_info->max_bw_5g;
reg_rule_5g = regulat_info->reg_rules_5g_ptr;
num_5g_reg_rules = regulat_info->num_5g_reg_rules;
reg_update_max_bw_per_rule(num_5g_reg_rules,
reg_rule_5g, max_bw_5g);
reg_rules = &soc_reg->mas_chan_params[phy_id].reg_rules;
reg_reset_reg_rules(reg_rules);
reg_rules->num_of_reg_rules = num_5g_reg_rules + num_2g_reg_rules;
if (reg_rules->num_of_reg_rules > MAX_REG_RULES) {
reg_err("number of reg rules exceeds limit");
return QDF_STATUS_E_FAILURE;
}
if (reg_rules->num_of_reg_rules) {
if (num_2g_reg_rules)
qdf_mem_copy(reg_rules->reg_rules,
reg_rule_2g, num_2g_reg_rules *
sizeof(struct cur_reg_rule));
if (num_5g_reg_rules)
qdf_mem_copy(reg_rules->reg_rules +
num_2g_reg_rules, reg_rule_5g,
num_5g_reg_rules *
sizeof(struct cur_reg_rule));
}
if (num_5g_reg_rules != 0)
reg_do_auto_bw_correction(num_5g_reg_rules,
reg_rule_5g, max_bw_5g);
if (num_2g_reg_rules != 0)
reg_populate_band_channels(MIN_24GHZ_CHANNEL, MAX_24GHZ_CHANNEL,
reg_rule_2g, num_2g_reg_rules,
min_bw_2g, mas_chan_list);
if (num_5g_reg_rules != 0)
reg_populate_band_channels(MIN_5GHZ_CHANNEL, MAX_5GHZ_CHANNEL,
reg_rule_5g, num_5g_reg_rules,
min_bw_5g, mas_chan_list);
if (num_5g_reg_rules != 0)
reg_populate_band_channels(MIN_49GHZ_CHANNEL,
MAX_49GHZ_CHANNEL,
reg_rule_5g, num_5g_reg_rules,
min_bw_5g, mas_chan_list);
if (soc_reg->new_user_ctry_pending[phy_id]) {
soc_reg->new_user_ctry_pending[phy_id] = false;
soc_reg->cc_src = SOURCE_USERSPACE;
soc_reg->user_ctry_set = true;
reg_debug("new user country is set");
reg_run_11d_state_machine(psoc);
} else if (soc_reg->new_init_ctry_pending[phy_id]) {
soc_reg->new_init_ctry_pending[phy_id] = false;
soc_reg->cc_src = SOURCE_USERSPACE;
reg_debug("new init country is set");
} else if (soc_reg->new_11d_ctry_pending[phy_id]) {
soc_reg->new_11d_ctry_pending[phy_id] = false;
soc_reg->cc_src = SOURCE_11D;
soc_reg->user_ctry_set = false;
reg_run_11d_state_machine(psoc);
} else if (soc_reg->world_country_pending[phy_id]) {
soc_reg->world_country_pending[phy_id] = false;
soc_reg->cc_src = SOURCE_CORE;
soc_reg->user_ctry_set = false;
reg_run_11d_state_machine(psoc);
} else {
if (soc_reg->cc_src == SOURCE_UNKNOWN &&
soc_reg->num_phy == phy_id + 1)
soc_reg->cc_src = SOURCE_DRIVER;
qdf_mem_copy(soc_reg->mas_chan_params[phy_id].default_country,
regulat_info->alpha2,
REG_ALPHA2_LEN + 1);
soc_reg->mas_chan_params[phy_id].def_country_code =
regulat_info->ctry_code;
soc_reg->mas_chan_params[phy_id].def_region_domain =
regulat_info->reg_dmn_pair;
if (soc_reg->cc_src == SOURCE_DRIVER) {
qdf_mem_copy(soc_reg->def_country,
regulat_info->alpha2,
REG_ALPHA2_LEN + 1);
soc_reg->def_country_code = regulat_info->ctry_code;
soc_reg->def_region_domain =
regulat_info->reg_dmn_pair;
if (reg_is_world_alpha2(regulat_info->alpha2)) {
soc_reg->cc_src = SOURCE_CORE;
reg_run_11d_state_machine(psoc);
}
}
}
pdev = wlan_objmgr_get_pdev_by_id(psoc, phy_id, dbg_id);
if (pdev != NULL) {
reg_propagate_mas_chan_list_to_pdev(psoc, pdev, &dir);
wlan_objmgr_pdev_release_ref(pdev, dbg_id);
}
return QDF_STATUS_SUCCESS;
}
/**
* wlan_regulatory_psoc_obj_created_notification() - PSOC obj create callback
* @psoc: PSOC object
* @arg_list: Variable argument list
*
* This callback is registered with object manager during initialization to
* get notified when the object is created.
*
* Return: Success or Failure
*/
QDF_STATUS wlan_regulatory_psoc_obj_created_notification(
struct wlan_objmgr_psoc *psoc, void *arg_list)
{
struct wlan_regulatory_psoc_priv_obj *soc_reg_obj;
struct regulatory_channel *mas_chan_list;
enum channel_enum chan_enum;
QDF_STATUS status;
uint8_t i;
uint8_t pdev_cnt;
soc_reg_obj = qdf_mem_malloc(sizeof(*soc_reg_obj));
if (NULL == soc_reg_obj) {
reg_alert("Mem alloc failed for reg psoc priv obj");
return QDF_STATUS_E_NOMEM;
}
soc_reg_obj->offload_enabled = false;
soc_reg_obj->psoc_ptr = psoc;
soc_reg_obj->dfs_enabled = true;
soc_reg_obj->band_capability = BAND_ALL;
soc_reg_obj->enable_11d_supp = false;
soc_reg_obj->indoor_chan_enabled = true;
soc_reg_obj->force_ssc_disable_indoor_channel = false;
soc_reg_obj->master_vdev_cnt = 0;
soc_reg_obj->vdev_cnt_11d = 0;
soc_reg_obj->vdev_id_for_11d_scan = INVALID_VDEV_ID;
soc_reg_obj->restart_beaconing = CH_AVOID_RULE_RESTART;
soc_reg_obj->enable_srd_chan_in_master_mode = true;
soc_reg_obj->enable_11d_in_world_mode = false;
soc_reg_obj->def_pdev_id = -1;
for (i = 0; i < MAX_STA_VDEV_CNT; i++)
soc_reg_obj->vdev_ids_11d[i] = INVALID_VDEV_ID;
qdf_spinlock_create(&soc_reg_obj->cbk_list_lock);
for (pdev_cnt = 0; pdev_cnt < PSOC_MAX_PHY_REG_CAP; pdev_cnt++) {
mas_chan_list =
soc_reg_obj->mas_chan_params[pdev_cnt].mas_chan_list;
for (chan_enum = 0; chan_enum < NUM_CHANNELS;
chan_enum++) {
mas_chan_list[chan_enum].chan_flags |=
REGULATORY_CHAN_DISABLED;
mas_chan_list[chan_enum].state =
CHANNEL_STATE_DISABLE;
mas_chan_list[chan_enum].nol_chan = false;
}
}
status = wlan_objmgr_psoc_component_obj_attach(psoc,
WLAN_UMAC_COMP_REGULATORY, soc_reg_obj,
QDF_STATUS_SUCCESS);
if (QDF_IS_STATUS_ERROR(status)) {
qdf_spinlock_destroy(&soc_reg_obj->cbk_list_lock);
qdf_mem_free(soc_reg_obj);
reg_err("Obj attach failed");
return status;
}
reg_debug("reg psoc obj created with status %d", status);
return status;
}
/**
* wlan_regulatory_psoc_obj_destroyed_notification() - PSOC obj delete callback
* @psoc: PSOC object
* @arg_list: Variable argument list
*
* This callback is registered with object manager during initialization to
* get notified when the object is deleted.
*
* Return: Success or Failure
*/
QDF_STATUS wlan_regulatory_psoc_obj_destroyed_notification(
struct wlan_objmgr_psoc *psoc, void *arg_list)
{
QDF_STATUS status;
struct wlan_regulatory_psoc_priv_obj *soc_reg;
soc_reg = wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_REGULATORY);
if (NULL == soc_reg) {
reg_err("reg psoc private obj is NULL");
return QDF_STATUS_E_FAULT;
}
soc_reg->psoc_ptr = NULL;
qdf_spinlock_destroy(&soc_reg->cbk_list_lock);
status = wlan_objmgr_psoc_component_obj_detach(psoc,
WLAN_UMAC_COMP_REGULATORY,
soc_reg);
if (status != QDF_STATUS_SUCCESS)
reg_err("soc_reg private obj detach failed");
reg_debug("reg psoc obj detached with status %d", status);
qdf_mem_free(soc_reg);
return status;
}
QDF_STATUS reg_set_band(struct wlan_objmgr_pdev *pdev,
enum band_info band)
{
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
struct wlan_objmgr_psoc *psoc;
QDF_STATUS status;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("pdev reg component is NULL");
return QDF_STATUS_E_INVAL;
}
if (pdev_priv_obj->band_capability == band) {
reg_info("band is already set to %d", band);
return QDF_STATUS_SUCCESS;
}
psoc = wlan_pdev_get_psoc(pdev);
if (!psoc) {
reg_err("psoc is NULL");
return QDF_STATUS_E_INVAL;
}
psoc_priv_obj = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(psoc_priv_obj)) {
reg_err("psoc reg component is NULL");
return QDF_STATUS_E_INVAL;
}
reg_info("setting band_info: %d", band);
pdev_priv_obj->band_capability = band;
reg_compute_pdev_current_chan_list(pdev_priv_obj);
status = reg_send_scheduler_msg_sb(psoc, pdev);
return status;
}
#ifdef DISABLE_CHANNEL_LIST
QDF_STATUS reg_restore_cached_channels(struct wlan_objmgr_pdev *pdev)
{
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
struct wlan_objmgr_psoc *psoc;
QDF_STATUS status;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("pdev reg component is NULL");
return QDF_STATUS_E_INVAL;
}
psoc = wlan_pdev_get_psoc(pdev);
if (!psoc) {
reg_err("psoc is NULL");
return QDF_STATUS_E_INVAL;
}
psoc_priv_obj = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(psoc_priv_obj)) {
reg_err("psoc reg component is NULL");
return QDF_STATUS_E_INVAL;
}
pdev_priv_obj->disable_cached_channels = false;
reg_compute_pdev_current_chan_list(pdev_priv_obj);
status = reg_send_scheduler_msg_sb(psoc, pdev);
return status;
}
QDF_STATUS reg_cache_channel_state(struct wlan_objmgr_pdev *pdev,
uint32_t *channel_list,
uint32_t num_channels)
{
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
struct wlan_objmgr_psoc *psoc;
uint8_t i, j;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("pdev reg component is NULL");
return QDF_STATUS_E_INVAL;
}
psoc = wlan_pdev_get_psoc(pdev);
if (!psoc) {
reg_err("psoc is NULL");
return QDF_STATUS_E_INVAL;
}
psoc_priv_obj = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(psoc_priv_obj)) {
reg_err("psoc reg component is NULL");
return QDF_STATUS_E_INVAL;
}
if (pdev_priv_obj->num_cache_channels > 0) {
pdev_priv_obj->num_cache_channels = 0;
qdf_mem_set(&pdev_priv_obj->cache_disable_chan_list,
sizeof(pdev_priv_obj->cache_disable_chan_list), 0);
}
for (i = 0; i < num_channels; i++) {
for (j = 0; j < NUM_CHANNELS; j++) {
if (channel_list[i] == pdev_priv_obj->
cur_chan_list[j].chan_num) {
pdev_priv_obj->
cache_disable_chan_list[i].chan_num =
channel_list[i];
pdev_priv_obj->
cache_disable_chan_list[i].state =
pdev_priv_obj->cur_chan_list[j].state;
pdev_priv_obj->
cache_disable_chan_list[i].chan_flags =
pdev_priv_obj->
cur_chan_list[j].chan_flags;
}
}
}
pdev_priv_obj->num_cache_channels = num_channels;
return QDF_STATUS_SUCCESS;
}
static void set_disable_channel_state(
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj)
{
pdev_priv_obj->disable_cached_channels = pdev_priv_obj->sap_state;
}
#else
static void set_disable_channel_state(
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj)
{
}
#endif
QDF_STATUS reg_notify_sap_event(struct wlan_objmgr_pdev *pdev,
bool sap_state)
{
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
struct wlan_objmgr_psoc *psoc;
QDF_STATUS status;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("pdev reg component is NULL");
return QDF_STATUS_E_INVAL;
}
psoc = wlan_pdev_get_psoc(pdev);
if (!psoc) {
reg_err("psoc is NULL");
return QDF_STATUS_E_INVAL;
}
psoc_priv_obj = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(psoc_priv_obj)) {
reg_err("psoc reg component is NULL");
return QDF_STATUS_E_INVAL;
}
reg_info("sap_state: %d", sap_state);
if (pdev_priv_obj->sap_state == sap_state)
return QDF_STATUS_SUCCESS;
pdev_priv_obj->sap_state = sap_state;
set_disable_channel_state(pdev_priv_obj);
reg_compute_pdev_current_chan_list(pdev_priv_obj);
status = reg_send_scheduler_msg_sb(psoc, pdev);
return status;
}
QDF_STATUS reg_set_fcc_constraint(struct wlan_objmgr_pdev *pdev,
bool fcc_constraint)
{
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
struct wlan_objmgr_psoc *psoc;
QDF_STATUS status;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("pdev reg component is NULL");
return QDF_STATUS_E_INVAL;
}
if (pdev_priv_obj->set_fcc_channel == fcc_constraint) {
reg_info("fcc_constraint is already set to %d", fcc_constraint);
return QDF_STATUS_SUCCESS;
}
reg_info("setting set_fcc_channel: %d", fcc_constraint);
pdev_priv_obj->set_fcc_channel = fcc_constraint;
psoc = wlan_pdev_get_psoc(pdev);
if (!psoc) {
reg_err("psoc is NULL");
return QDF_STATUS_E_INVAL;
}
psoc_priv_obj = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(psoc_priv_obj)) {
reg_err("psoc reg component is NULL");
return QDF_STATUS_E_INVAL;
}
reg_compute_pdev_current_chan_list(pdev_priv_obj);
status = reg_send_scheduler_msg_sb(psoc, pdev);
return status;
}
bool reg_get_fcc_constraint(struct wlan_objmgr_pdev *pdev, uint32_t freq)
{
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("pdev reg component is NULL");
return false;
}
if (freq != CHAN_12_CENT_FREQ && freq != CHAN_13_CENT_FREQ)
return false;
if (!pdev_priv_obj->set_fcc_channel)
return false;
return true;
}
QDF_STATUS reg_enable_dfs_channels(struct wlan_objmgr_pdev *pdev,
bool enable)
{
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
struct wlan_objmgr_psoc *psoc;
QDF_STATUS status;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("pdev reg component is NULL");
return QDF_STATUS_E_INVAL;
}
if (pdev_priv_obj->dfs_enabled == enable) {
reg_info("dfs_enabled is already set to %d", enable);
return QDF_STATUS_SUCCESS;
}
psoc = wlan_pdev_get_psoc(pdev);
if (!psoc) {
reg_err("psoc is NULL");
return QDF_STATUS_E_INVAL;
}
psoc_priv_obj = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(psoc_priv_obj)) {
reg_err("psoc reg component is NULL");
return QDF_STATUS_E_INVAL;
}
reg_info("setting dfs_enabled: %d", enable);
pdev_priv_obj->dfs_enabled = enable;
reg_compute_pdev_current_chan_list(pdev_priv_obj);
status = reg_send_scheduler_msg_sb(psoc, pdev);
return status;
}
/**
* wlan_regulatory_pdev_obj_created_notification() - PDEV obj create callback
* @pdev: pdev object
* @arg_list: Variable argument list
*
* This callback is registered with object manager during initialization to
* get notified when the pdev object is created.
*
* Return: Success or Failure
*/
QDF_STATUS wlan_regulatory_pdev_obj_created_notification(
struct wlan_objmgr_pdev *pdev, void *arg_list)
{
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap_ptr;
struct wlan_objmgr_psoc *parent_psoc;
uint32_t pdev_id;
uint32_t cnt;
uint32_t range_2g_low, range_2g_high;
uint32_t range_5g_low, range_5g_high;
QDF_STATUS status;
struct reg_rule_info *psoc_reg_rules;
pdev_priv_obj = qdf_mem_malloc(sizeof(*pdev_priv_obj));
if (NULL == pdev_priv_obj) {
reg_alert("Mem alloc failed for pdev priv obj");
return QDF_STATUS_E_NOMEM;
}
parent_psoc = wlan_pdev_get_psoc(pdev);
pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
psoc_priv_obj = (struct wlan_regulatory_psoc_priv_obj *)
wlan_objmgr_psoc_get_comp_private_obj(parent_psoc,
WLAN_UMAC_COMP_REGULATORY);
if (NULL == psoc_priv_obj) {
reg_err("reg psoc private obj is NULL");
qdf_mem_free(pdev_priv_obj);
return QDF_STATUS_E_FAULT;
}
if (psoc_priv_obj->def_pdev_id == -1) {
reg_debug("marking pdev with id %d", pdev_id);
psoc_priv_obj->def_pdev_id = pdev_id;
} else
reg_debug("not marking this pdev");
pdev_priv_obj->pdev_ptr = pdev;
pdev_priv_obj->dfs_enabled = psoc_priv_obj->dfs_enabled;
pdev_priv_obj->set_fcc_channel = false;
pdev_priv_obj->band_capability = psoc_priv_obj->band_capability;
pdev_priv_obj->indoor_chan_enabled =
psoc_priv_obj->indoor_chan_enabled;
pdev_priv_obj->en_chan_144 = true;
qdf_spinlock_create(&pdev_priv_obj->reg_rules_lock);
reg_cap_ptr = psoc_priv_obj->reg_cap;
pdev_priv_obj->force_ssc_disable_indoor_channel =
psoc_priv_obj->force_ssc_disable_indoor_channel;
for (cnt = 0; cnt < PSOC_MAX_PHY_REG_CAP; cnt++) {
if (reg_cap_ptr == NULL) {
qdf_mem_free(pdev_priv_obj);
reg_err(" reg cap ptr is NULL");
return QDF_STATUS_E_FAULT;
}
if (reg_cap_ptr->phy_id == pdev_id)
break;
reg_cap_ptr++;
}
if (cnt == PSOC_MAX_PHY_REG_CAP) {
qdf_mem_free(pdev_priv_obj);
reg_err("extended capabilities not found for pdev");
return QDF_STATUS_E_FAULT;
}
range_2g_low = reg_cap_ptr->low_2ghz_chan;
range_2g_high = reg_cap_ptr->high_2ghz_chan;
range_5g_low = reg_cap_ptr->low_5ghz_chan;
range_5g_high = reg_cap_ptr->high_5ghz_chan;
pdev_priv_obj->range_2g_low = range_2g_low;
pdev_priv_obj->range_2g_high = range_2g_high;
pdev_priv_obj->range_5g_low = range_5g_low;
pdev_priv_obj->range_5g_high = range_5g_high;
pdev_priv_obj->wireless_modes = reg_cap_ptr->wireless_modes;
reg_init_pdev_mas_chan_list(pdev_priv_obj,
&psoc_priv_obj->mas_chan_params[pdev_id]);
psoc_reg_rules = &psoc_priv_obj->mas_chan_params[pdev_id].reg_rules;
reg_save_reg_rules_to_pdev(psoc_reg_rules, pdev_priv_obj);
status = wlan_objmgr_pdev_component_obj_attach(pdev,
WLAN_UMAC_COMP_REGULATORY,
pdev_priv_obj,
QDF_STATUS_SUCCESS);
reg_compute_pdev_current_chan_list(pdev_priv_obj);
if (QDF_IS_STATUS_ERROR(status)) {
reg_err("Obj attach failed");
qdf_mem_free(pdev_priv_obj);
return status;
}
reg_debug("reg pdev obj created with status %d", status);
return status;
}
QDF_STATUS wlan_regulatory_pdev_obj_destroyed_notification(
struct wlan_objmgr_pdev *pdev, void *arg_list)
{
QDF_STATUS status;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
uint32_t pdev_id;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("reg pdev private obj is NULL");
return QDF_STATUS_E_FAILURE;
}
pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
psoc_priv_obj = reg_get_psoc_obj(wlan_pdev_get_psoc(pdev));
if (!IS_VALID_PSOC_REG_OBJ(psoc_priv_obj)) {
reg_err("reg psoc private obj is NULL");
return QDF_STATUS_E_FAILURE;
}
pdev_priv_obj->pdev_ptr = NULL;
if (psoc_priv_obj->def_pdev_id == pdev_id) {
reg_debug("deleting marked pdev");
psoc_priv_obj->def_pdev_id = -1;
} else
reg_debug("deleting unmarked pdev");
status = wlan_objmgr_pdev_component_obj_detach(pdev,
WLAN_UMAC_COMP_REGULATORY,
pdev_priv_obj);
if (status != QDF_STATUS_SUCCESS)
reg_err("reg pdev private obj detach failed");
reg_debug("reg pdev obj deleted with status %d", status);
qdf_spin_lock_bh(&pdev_priv_obj->reg_rules_lock);
reg_reset_reg_rules(&pdev_priv_obj->reg_rules);
qdf_spin_unlock_bh(&pdev_priv_obj->reg_rules_lock);
qdf_spinlock_destroy(&pdev_priv_obj->reg_rules_lock);
qdf_mem_free(pdev_priv_obj);
return status;
}
/**
* reg_11d_vdev_created_update() - vdev obj create callback
* @vdev: vdev pointer
*
* updates 11d state when a vdev is created.
*
* Return: Success or Failure
*/
QDF_STATUS reg_11d_vdev_created_update(struct wlan_objmgr_vdev *vdev)
{
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
struct wlan_objmgr_pdev *parent_pdev;
struct wlan_objmgr_psoc *parent_psoc;
uint32_t vdev_id;
enum QDF_OPMODE op_mode;
uint8_t i;
op_mode = wlan_vdev_mlme_get_opmode(vdev);
parent_pdev = wlan_vdev_get_pdev(vdev);
parent_psoc = wlan_pdev_get_psoc(parent_pdev);
psoc_priv_obj = (struct wlan_regulatory_psoc_priv_obj *)
wlan_objmgr_psoc_get_comp_private_obj(parent_psoc,
WLAN_UMAC_COMP_REGULATORY);
if (!psoc_priv_obj) {
reg_err("reg psoc private obj is NULL");
return QDF_STATUS_E_FAULT;
}
if ((op_mode == QDF_STA_MODE) ||
(op_mode == QDF_P2P_DEVICE_MODE) ||
(op_mode == QDF_P2P_CLIENT_MODE)) {
vdev_id = wlan_vdev_get_id(vdev);
if (!psoc_priv_obj->vdev_cnt_11d) {
psoc_priv_obj->vdev_id_for_11d_scan = vdev_id;
reg_debug("running 11d state machine, opmode %d",
op_mode);
reg_run_11d_state_machine(parent_psoc);
}
for (i = 0; i < MAX_STA_VDEV_CNT; i++) {
if (psoc_priv_obj->vdev_ids_11d[i] ==
INVALID_VDEV_ID) {
psoc_priv_obj->vdev_ids_11d[i] = vdev_id;
break;
}
}
psoc_priv_obj->vdev_cnt_11d++;
}
if ((op_mode == QDF_P2P_GO_MODE) ||
(op_mode == QDF_SAP_MODE)) {
reg_debug("running 11d state machine, opmode %d", op_mode);
psoc_priv_obj->master_vdev_cnt++;
reg_run_11d_state_machine(parent_psoc);
}
return QDF_STATUS_SUCCESS;
}
/**
* reg_11d_vdev_delete_update() - update 11d state upon vdev delete
* @vdev: vdev pointer
*
* Return: Success or Failure
*/
QDF_STATUS reg_11d_vdev_delete_update(struct wlan_objmgr_vdev *vdev)
{
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
struct wlan_objmgr_pdev *parent_pdev;
struct wlan_objmgr_psoc *parent_psoc;
enum QDF_OPMODE op_mode;
uint32_t vdev_id;
uint8_t i;
if (!vdev) {
reg_err("vdev is NULL");
return QDF_STATUS_E_INVAL;
}
op_mode = wlan_vdev_mlme_get_opmode(vdev);
parent_pdev = wlan_vdev_get_pdev(vdev);
parent_psoc = wlan_pdev_get_psoc(parent_pdev);
psoc_priv_obj = (struct wlan_regulatory_psoc_priv_obj *)
wlan_objmgr_psoc_get_comp_private_obj(parent_psoc,
WLAN_UMAC_COMP_REGULATORY);
if (!psoc_priv_obj) {
reg_err("reg psoc private obj is NULL");
return QDF_STATUS_E_FAULT;
}
if ((op_mode == QDF_P2P_GO_MODE) ||
(op_mode == QDF_SAP_MODE)) {
psoc_priv_obj->master_vdev_cnt--;
reg_debug("run 11d state machine, deleted opmode %d",
op_mode);
reg_run_11d_state_machine(parent_psoc);
return QDF_STATUS_SUCCESS;
}
if ((op_mode == QDF_STA_MODE) ||
(op_mode == QDF_P2P_DEVICE_MODE) ||
(op_mode == QDF_P2P_CLIENT_MODE)) {
vdev_id = wlan_vdev_get_id(vdev);
for (i = 0; i < MAX_STA_VDEV_CNT; i++) {
if (psoc_priv_obj->vdev_ids_11d[i] == vdev_id) {
psoc_priv_obj->vdev_ids_11d[i] =
INVALID_VDEV_ID;
psoc_priv_obj->vdev_cnt_11d--;
break;
}
}
if (psoc_priv_obj->vdev_id_for_11d_scan != vdev_id)
return QDF_STATUS_SUCCESS;
if (!psoc_priv_obj->vdev_cnt_11d) {
psoc_priv_obj->vdev_id_for_11d_scan = INVALID_VDEV_ID;
psoc_priv_obj->enable_11d_supp = false;
return QDF_STATUS_SUCCESS;
}
for (i = 0; i < MAX_STA_VDEV_CNT; i++) {
if (psoc_priv_obj->vdev_ids_11d[i] ==
INVALID_VDEV_ID)
continue;
psoc_priv_obj->vdev_id_for_11d_scan =
psoc_priv_obj->vdev_ids_11d[i];
psoc_priv_obj->enable_11d_supp = false;
reg_debug("running 11d state machine, vdev %d",
psoc_priv_obj->vdev_id_for_11d_scan);
reg_run_11d_state_machine(parent_psoc);
break;
}
}
return QDF_STATUS_SUCCESS;
}
QDF_STATUS reg_get_current_chan_list(struct wlan_objmgr_pdev *pdev,
struct regulatory_channel *chan_list)
{
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("reg pdev private obj is NULL");
return QDF_STATUS_E_FAILURE;
}
qdf_mem_copy(chan_list, pdev_priv_obj->cur_chan_list,
NUM_CHANNELS * sizeof(struct regulatory_channel));
return QDF_STATUS_SUCCESS;
}
/**
* reg_update_nol_ch () - Updates NOL channels in current channel list
* @pdev: pointer to pdev object
* @ch_list: pointer to NOL channel list
* @num_ch: No.of channels in list
* @update_nol: set/reset the NOL status
*
* Return: None
*/
void reg_update_nol_ch(struct wlan_objmgr_pdev *pdev,
uint8_t *chan_list,
uint8_t num_chan,
bool nol_chan)
{
enum channel_enum chan_enum;
struct regulatory_channel *mas_chan_list;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
uint16_t i;
if (!num_chan || !chan_list) {
reg_err("chan_list or num_ch is NULL");
return;
}
pdev_priv_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev,
WLAN_UMAC_COMP_REGULATORY);
if (NULL == pdev_priv_obj) {
reg_err("reg psoc private obj is NULL");
return;
}
mas_chan_list = pdev_priv_obj->mas_chan_list;
for (i = 0; i < num_chan; i++) {
chan_enum = reg_get_chan_enum(chan_list[i]);
if (chan_enum == INVALID_CHANNEL) {
reg_err("Invalid ch in nol list, chan %d",
chan_list[i]);
continue;
}
mas_chan_list[chan_enum].nol_chan = nol_chan;
}
reg_compute_pdev_current_chan_list(pdev_priv_obj);
}
static void reg_change_pdev_for_config(struct wlan_objmgr_psoc *psoc,
void *object, void *arg)
{
struct wlan_objmgr_pdev *pdev = (struct wlan_objmgr_pdev *)object;
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
psoc_priv_obj = (struct wlan_regulatory_psoc_priv_obj *)
wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_REGULATORY);
if (NULL == psoc_priv_obj) {
reg_err("psoc priv obj is NULL");
return;
}
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("reg pdev private obj is NULL");
return;
}
pdev_priv_obj->dfs_enabled =
psoc_priv_obj->dfs_enabled;
pdev_priv_obj->indoor_chan_enabled =
psoc_priv_obj->indoor_chan_enabled;
pdev_priv_obj->force_ssc_disable_indoor_channel =
psoc_priv_obj->force_ssc_disable_indoor_channel;
pdev_priv_obj->band_capability = psoc_priv_obj->band_capability;
reg_compute_pdev_current_chan_list(pdev_priv_obj);
reg_send_scheduler_msg_sb(psoc, pdev);
}
QDF_STATUS reg_set_config_vars(struct wlan_objmgr_psoc *psoc,
struct reg_config_vars config_vars)
{
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
QDF_STATUS status;
psoc_priv_obj = (struct wlan_regulatory_psoc_priv_obj *)
wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_REGULATORY);
if (NULL == psoc_priv_obj) {
reg_err("psoc priv obj is NULL");
return QDF_STATUS_E_FAILURE;
}
psoc_priv_obj->enable_11d_supp_original =
config_vars.enable_11d_support;
psoc_priv_obj->scan_11d_interval =
config_vars.scan_11d_interval;
psoc_priv_obj->user_ctry_priority =
config_vars.userspace_ctry_priority;
psoc_priv_obj->dfs_enabled =
config_vars.dfs_enabled;
psoc_priv_obj->indoor_chan_enabled =
config_vars.indoor_chan_enabled;
psoc_priv_obj->force_ssc_disable_indoor_channel =
config_vars.force_ssc_disable_indoor_channel;
psoc_priv_obj->band_capability = config_vars.band_capability;
psoc_priv_obj->restart_beaconing = config_vars.restart_beaconing;
psoc_priv_obj->enable_srd_chan_in_master_mode =
config_vars.enable_srd_chan_in_master_mode;
psoc_priv_obj->enable_11d_in_world_mode =
config_vars.enable_11d_in_world_mode;
status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_REGULATORY_SB_ID);
if (QDF_IS_STATUS_ERROR(status)) {
reg_err("error taking psoc ref cnt");
return status;
}
status = wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
reg_change_pdev_for_config,
NULL, 1, WLAN_REGULATORY_SB_ID);
wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID);
return status;
}
bool reg_is_disable_ch(struct wlan_objmgr_pdev *pdev, uint32_t chan)
{
enum channel_state ch_state;
ch_state = reg_get_channel_state(pdev, chan);
return ch_state == CHANNEL_STATE_DISABLE;
}
bool reg_is_regdb_offloaded(struct wlan_objmgr_psoc *psoc)
{
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
psoc_priv_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_REGULATORY);
if (NULL == psoc_priv_obj) {
reg_err("reg psoc private obj is NULL");
return false;
}
return psoc_priv_obj->offload_enabled;
}
void reg_program_mas_chan_list(struct wlan_objmgr_psoc *psoc,
struct regulatory_channel *reg_channels,
uint8_t *alpha2,
enum dfs_reg dfs_region)
{
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
QDF_STATUS status;
uint32_t count;
enum direction dir;
uint32_t pdev_cnt;
psoc_priv_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_REGULATORY);
if (NULL == psoc_priv_obj) {
reg_err("reg psoc private obj is NULL");
return;
}
qdf_mem_copy(psoc_priv_obj->cur_country, alpha2,
REG_ALPHA2_LEN);
reg_debug("set cur_country %.2s", psoc_priv_obj->cur_country);
for (count = 0; count < NUM_CHANNELS; count++) {
reg_channels[count].chan_num =
channel_map[count].chan_num;
reg_channels[count].center_freq =
channel_map[count].center_freq;
reg_channels[count].nol_chan = false;
}
for (pdev_cnt = 0; pdev_cnt < PSOC_MAX_PHY_REG_CAP; pdev_cnt++) {
qdf_mem_copy(psoc_priv_obj->mas_chan_params[pdev_cnt].
mas_chan_list,
reg_channels,
NUM_CHANNELS * sizeof(struct regulatory_channel));
psoc_priv_obj->mas_chan_params[pdev_cnt].dfs_region =
dfs_region;
}
dir = SOUTHBOUND;
status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_REGULATORY_SB_ID);
if (QDF_IS_STATUS_ERROR(status)) {
reg_err("error taking psoc ref cnt");
return;
}
status = wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
reg_propagate_mas_chan_list_to_pdev,
&dir, 1, WLAN_REGULATORY_SB_ID);
wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID);
}
void reg_register_chan_change_callback(struct wlan_objmgr_psoc *psoc,
reg_chan_change_callback cbk,
void *arg)
{
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
uint32_t count;
psoc_priv_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_REGULATORY);
if (NULL == psoc_priv_obj) {
reg_err("reg psoc private obj is NULL");
return;
}
qdf_spin_lock_bh(&psoc_priv_obj->cbk_list_lock);
for (count = 0; count < REG_MAX_CHAN_CHANGE_CBKS; count++)
if (psoc_priv_obj->cbk_list[count].cbk == NULL) {
psoc_priv_obj->cbk_list[count].cbk = cbk;
psoc_priv_obj->cbk_list[count].arg = arg;
psoc_priv_obj->num_chan_change_cbks++;
break;
}
qdf_spin_unlock_bh(&psoc_priv_obj->cbk_list_lock);
if (count == REG_MAX_CHAN_CHANGE_CBKS)
reg_err("callback list is full, could not add the cbk");
}
void reg_unregister_chan_change_callback(struct wlan_objmgr_psoc *psoc,
reg_chan_change_callback cbk)
{
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
uint32_t count;
psoc_priv_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_REGULATORY);
if (NULL == psoc_priv_obj) {
reg_err("reg psoc private obj is NULL");
return;
}
qdf_spin_lock_bh(&psoc_priv_obj->cbk_list_lock);
for (count = 0; count < REG_MAX_CHAN_CHANGE_CBKS; count++)
if (psoc_priv_obj->cbk_list[count].cbk == cbk) {
psoc_priv_obj->cbk_list[count].cbk = NULL;
psoc_priv_obj->num_chan_change_cbks--;
break;
}
qdf_spin_unlock_bh(&psoc_priv_obj->cbk_list_lock);
if (count == REG_MAX_CHAN_CHANGE_CBKS)
reg_err("callback not found in the list");
}
enum country_src reg_get_cc_and_src(struct wlan_objmgr_psoc *psoc,
uint8_t *alpha2)
{
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
psoc_priv_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_REGULATORY);
if (NULL == psoc_priv_obj) {
reg_err("reg psoc private obj is NULL");
return SOURCE_UNKNOWN;
}
qdf_mem_copy(alpha2, psoc_priv_obj->cur_country,
REG_ALPHA2_LEN + 1);
return psoc_priv_obj->cc_src;
}
QDF_STATUS reg_program_default_cc(struct wlan_objmgr_pdev *pdev,
uint16_t regdmn)
{
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
struct cur_regulatory_info *reg_info;
uint16_t cc = -1;
uint16_t country_index = -1, regdmn_pair = -1;
struct wlan_objmgr_psoc *psoc;
QDF_STATUS err;
pdev_priv_obj = (struct wlan_regulatory_pdev_priv_obj *)
wlan_objmgr_pdev_get_comp_private_obj(pdev,
WLAN_UMAC_COMP_REGULATORY);
if (NULL == pdev_priv_obj) {
reg_err("reg soc is NULL");
return QDF_STATUS_E_FAILURE;
}
reg_info = (struct cur_regulatory_info *)qdf_mem_malloc
(sizeof(struct cur_regulatory_info));
if (reg_info == NULL) {
reg_err("reg info is NULL");
return QDF_STATUS_E_NOMEM;
}
psoc = wlan_pdev_get_psoc(pdev);
if (!psoc) {
reg_err("psoc is NULL");
return QDF_STATUS_E_INVAL;
}
reg_info->psoc = psoc;
reg_info->phy_id = wlan_objmgr_pdev_get_pdev_id(pdev);
if (regdmn == 0) {
reg_get_default_country(&regdmn);
regdmn |= COUNTRY_ERD_FLAG;
}
if (regdmn & COUNTRY_ERD_FLAG) {
cc = regdmn & ~COUNTRY_ERD_FLAG;
reg_get_rdpair_from_country_code(cc,
&country_index,
&regdmn_pair);
err = reg_get_cur_reginfo(reg_info, country_index, regdmn_pair);
if (err == QDF_STATUS_E_FAILURE) {
reg_err("%s : Unable to set country code\n", __func__);
qdf_mem_free(reg_info->reg_rules_2g_ptr);
qdf_mem_free(reg_info->reg_rules_5g_ptr);
qdf_mem_free(reg_info);
return QDF_STATUS_E_FAILURE;
}
pdev_priv_obj->ctry_code = cc;
} else {
reg_get_rdpair_from_regdmn_id(regdmn,
&regdmn_pair);
err = reg_get_cur_reginfo(reg_info, country_index, regdmn_pair);
if (err == QDF_STATUS_E_FAILURE) {
reg_err("%s : Unable to set country code\n", __func__);
qdf_mem_free(reg_info->reg_rules_2g_ptr);
qdf_mem_free(reg_info->reg_rules_5g_ptr);
qdf_mem_free(reg_info);
return QDF_STATUS_E_FAILURE;
}
pdev_priv_obj->reg_dmn_pair = regdmn;
}
reg_info->offload_enabled = false;
reg_process_master_chan_list(reg_info);
qdf_mem_free(reg_info->reg_rules_2g_ptr);
qdf_mem_free(reg_info->reg_rules_5g_ptr);
qdf_mem_free(reg_info);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS reg_get_regd_rules(struct wlan_objmgr_pdev *pdev,
struct reg_rule_info *reg_rules)
{
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
if (!pdev) {
reg_err("pdev is NULL");
return QDF_STATUS_E_FAILURE;
}
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!pdev_priv_obj) {
reg_err("pdev priv obj is NULL");
return QDF_STATUS_E_FAILURE;
}
qdf_spin_lock_bh(&pdev_priv_obj->reg_rules_lock);
qdf_mem_copy(reg_rules, &pdev_priv_obj->reg_rules,
sizeof(struct reg_rule_info));
qdf_spin_unlock_bh(&pdev_priv_obj->reg_rules_lock);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS reg_program_chan_list(struct wlan_objmgr_pdev *pdev,
struct cc_regdmn_s *rd)
{
struct cur_regulatory_info *reg_info;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
uint16_t country_index = -1, regdmn_pair = -1;
struct wlan_objmgr_psoc *psoc;
struct wlan_lmac_if_reg_tx_ops *tx_ops;
struct wlan_regulatory_psoc_priv_obj *soc_reg;
uint8_t pdev_id;
QDF_STATUS err;
pdev_priv_obj = (struct wlan_regulatory_pdev_priv_obj *)
wlan_objmgr_pdev_get_comp_private_obj(pdev,
WLAN_UMAC_COMP_REGULATORY);
if (NULL == pdev_priv_obj) {
reg_err(" pdev priv obj is NULL");
return QDF_STATUS_E_FAILURE;
}
psoc = wlan_pdev_get_psoc(pdev);
if (!psoc) {
reg_err("psoc is NULL");
return QDF_STATUS_E_INVAL;
}
soc_reg = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(soc_reg)) {
reg_err("psoc reg component is NULL");
return QDF_STATUS_E_FAILURE;
}
if (soc_reg->offload_enabled) {
if ((rd->flags == ALPHA_IS_SET) && (rd->cc.alpha[2] == 'O'))
pdev_priv_obj->indoor_chan_enabled = false;
else
pdev_priv_obj->indoor_chan_enabled = true;
pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
tx_ops = reg_get_psoc_tx_ops(psoc);
if (tx_ops->set_user_country_code) {
soc_reg->new_init_ctry_pending[pdev_id] = true;
return tx_ops->set_user_country_code(psoc, pdev_id, rd);
}
return QDF_STATUS_E_FAILURE;
}
reg_info = (struct cur_regulatory_info *)qdf_mem_malloc
(sizeof(struct cur_regulatory_info));
if (reg_info == NULL) {
reg_err("reg info is NULL");
return QDF_STATUS_E_NOMEM;
}
reg_info->psoc = psoc;
reg_info->phy_id = wlan_objmgr_pdev_get_pdev_id(pdev);
if (rd->flags == CC_IS_SET) {
reg_get_rdpair_from_country_code(rd->cc.country_code,
&country_index,
&regdmn_pair);
} else if (rd->flags == ALPHA_IS_SET) {
reg_get_rdpair_from_country_iso(rd->cc.alpha,
&country_index,
&regdmn_pair);
} else if (rd->flags == REGDMN_IS_SET) {
reg_get_rdpair_from_regdmn_id(rd->cc.regdmn_id,
&regdmn_pair);
}
err = reg_get_cur_reginfo(reg_info, country_index, regdmn_pair);
if (err == QDF_STATUS_E_FAILURE) {
reg_err("%s : Unable to set country code\n", __func__);
qdf_mem_free(reg_info->reg_rules_2g_ptr);
qdf_mem_free(reg_info->reg_rules_5g_ptr);
qdf_mem_free(reg_info);
return QDF_STATUS_E_FAILURE;
}
reg_info->offload_enabled = false;
reg_process_master_chan_list(reg_info);
qdf_mem_free(reg_info->reg_rules_2g_ptr);
qdf_mem_free(reg_info->reg_rules_5g_ptr);
qdf_mem_free(reg_info);
return QDF_STATUS_SUCCESS;
}
bool reg_is_11d_scan_inprogress(struct wlan_objmgr_psoc *psoc)
{
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
psoc_priv_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_REGULATORY);
if (!psoc_priv_obj) {
reg_err("reg psoc private obj is NULL");
return false;
}
return psoc_priv_obj->enable_11d_supp;
}
QDF_STATUS reg_get_current_cc(struct wlan_objmgr_pdev *pdev,
struct cc_regdmn_s *rd)
{
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
pdev_priv_obj = (struct wlan_regulatory_pdev_priv_obj *)
wlan_objmgr_pdev_get_comp_private_obj(pdev,
WLAN_UMAC_COMP_REGULATORY);
if (NULL == pdev_priv_obj) {
reg_err("reg pdev priv is NULL");
return QDF_STATUS_E_FAILURE;
}
if (rd->flags == CC_IS_SET) {
rd->cc.country_code = pdev_priv_obj->ctry_code;
} else if (rd->flags == ALPHA_IS_SET) {
qdf_mem_copy(rd->cc.alpha, pdev_priv_obj->current_country,
sizeof(rd->cc.alpha));
} else if (rd->flags == REGDMN_IS_SET) {
rd->cc.regdmn_id = pdev_priv_obj->reg_dmn_pair;
}
return QDF_STATUS_SUCCESS;
}
static QDF_STATUS reg_process_ch_avoid_freq(struct wlan_objmgr_psoc *psoc,
struct wlan_objmgr_pdev *pdev)
{
enum channel_enum ch_loop;
enum channel_enum start_ch_idx;
enum channel_enum end_ch_idx;
uint16_t start_channel;
uint16_t end_channel;
uint32_t i;
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
struct ch_avoid_freq_type *range;
psoc_priv_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_REGULATORY);
if (!psoc_priv_obj) {
reg_err("reg psoc private obj is NULL");
return QDF_STATUS_E_FAILURE;
}
for (i = 0; i < psoc_priv_obj->avoid_freq_list.ch_avoid_range_cnt;
i++) {
if (psoc_priv_obj->unsafe_chan_list.ch_cnt >= NUM_CHANNELS) {
reg_warn("LTE Coex unsafe channel list full");
break;
}
start_ch_idx = INVALID_CHANNEL;
end_ch_idx = INVALID_CHANNEL;
range = &psoc_priv_obj->avoid_freq_list.avoid_freq_range[i];
start_channel = reg_freq_to_chan(pdev, range->start_freq);
end_channel = reg_freq_to_chan(pdev, range->end_freq);
reg_debug("start: freq %d, ch %d, end: freq %d, ch %d",
range->start_freq, start_channel, range->end_freq,
end_channel);
/* do not process frequency bands that are not mapped to
* predefined channels
*/
if (start_channel == 0 || end_channel == 0)
continue;
for (ch_loop = 0; ch_loop < NUM_CHANNELS;
ch_loop++) {
if (REG_CH_TO_FREQ(ch_loop) >= range->start_freq) {
start_ch_idx = ch_loop;
break;
}
}
for (ch_loop = 0; ch_loop < NUM_CHANNELS;
ch_loop++) {
if (REG_CH_TO_FREQ(ch_loop) >= range->end_freq) {
end_ch_idx = ch_loop;
if (REG_CH_TO_FREQ(ch_loop) > range->end_freq)
end_ch_idx--;
break;
}
}
if (start_ch_idx == INVALID_CHANNEL ||
end_ch_idx == INVALID_CHANNEL)
continue;
for (ch_loop = start_ch_idx; ch_loop <= end_ch_idx;
ch_loop++) {
psoc_priv_obj->unsafe_chan_list.ch_list[
psoc_priv_obj->unsafe_chan_list.ch_cnt++] =
REG_CH_NUM(ch_loop);
if (psoc_priv_obj->unsafe_chan_list.ch_cnt >=
NUM_CHANNELS) {
reg_warn("LTECoex unsafe ch list full");
break;
}
}
}
reg_debug("number of unsafe channels is %d ",
psoc_priv_obj->unsafe_chan_list.ch_cnt);
if (!psoc_priv_obj->unsafe_chan_list.ch_cnt) {
reg_debug("No valid ch are present in avoid freq event");
return QDF_STATUS_SUCCESS;
}
for (ch_loop = 0; ch_loop < psoc_priv_obj->unsafe_chan_list.ch_cnt;
ch_loop++) {
if (ch_loop >= NUM_CHANNELS)
break;
reg_debug("channel %d is not safe",
psoc_priv_obj->unsafe_chan_list.
ch_list[ch_loop]);
}
return QDF_STATUS_SUCCESS;
}
/**
* reg_update_unsafe_ch () - Updates unsafe channels in current channel list
* @pdev: pointer to pdev object
* @ch_avoid_list: pointer to unsafe channel list
*
* Return: None
*/
static void reg_update_unsafe_ch(struct wlan_objmgr_psoc *psoc,
void *object, void *arg)
{
struct wlan_objmgr_pdev *pdev = (struct wlan_objmgr_pdev *)object;
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
QDF_STATUS status;
psoc_priv_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_REGULATORY);
if (!psoc_priv_obj) {
reg_err("reg psoc private obj is NULL");
return;
}
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("reg pdev priv obj is NULL");
return;
}
if (psoc_priv_obj->ch_avoid_ind) {
status = reg_process_ch_avoid_freq(psoc, pdev);
if (QDF_IS_STATUS_ERROR(status))
psoc_priv_obj->ch_avoid_ind = false;
}
reg_compute_pdev_current_chan_list(pdev_priv_obj);
status = reg_send_scheduler_msg_nb(psoc, pdev);
if (QDF_IS_STATUS_ERROR(status))
reg_err("channel change msg schedule failed");
}
QDF_STATUS reg_process_ch_avoid_event(struct wlan_objmgr_psoc *psoc,
struct ch_avoid_ind_type *ch_avoid_event)
{
uint32_t i;
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
QDF_STATUS status;
psoc_priv_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_REGULATORY);
if (!psoc_priv_obj) {
reg_err("reg psoc private obj is NULL");
return QDF_STATUS_E_FAILURE;
}
/* Make unsafe channel list */
reg_debug("band count %d", ch_avoid_event->ch_avoid_range_cnt);
/* generate vendor specific event */
qdf_mem_zero((void *)&psoc_priv_obj->avoid_freq_list,
sizeof(struct ch_avoid_ind_type));
qdf_mem_zero((void *)&psoc_priv_obj->unsafe_chan_list,
sizeof(struct unsafe_ch_list));
for (i = 0; i < ch_avoid_event->ch_avoid_range_cnt; i++) {
if ((CH_AVOID_RULE_RESTART_24G_ONLY ==
psoc_priv_obj->restart_beaconing) &&
REG_IS_5GHZ_FREQ(ch_avoid_event->
avoid_freq_range[i].start_freq)) {
reg_debug("skipping 5Ghz LTE Coex unsafe channel range");
continue;
}
psoc_priv_obj->avoid_freq_list.avoid_freq_range[i].start_freq =
ch_avoid_event->avoid_freq_range[i].start_freq;
psoc_priv_obj->avoid_freq_list.avoid_freq_range[i].end_freq =
ch_avoid_event->avoid_freq_range[i].end_freq;
}
psoc_priv_obj->avoid_freq_list.ch_avoid_range_cnt =
ch_avoid_event->ch_avoid_range_cnt;
psoc_priv_obj->ch_avoid_ind = true;
status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_REGULATORY_NB_ID);
if (QDF_IS_STATUS_ERROR(status)) {
reg_err("error taking psoc ref cnt");
return status;
}
status = wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
reg_update_unsafe_ch, NULL, 1,
WLAN_REGULATORY_NB_ID);
wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_NB_ID);
return status;
}
QDF_STATUS reg_save_new_11d_country(struct wlan_objmgr_psoc *psoc,
uint8_t *country)
{
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
struct wlan_lmac_if_reg_tx_ops *tx_ops;
struct set_country country_code;
uint8_t pdev_id;
psoc_priv_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_REGULATORY);
if (!psoc_priv_obj) {
reg_err("reg psoc private obj is NULL");
return QDF_STATUS_E_FAILURE;
}
pdev_id = psoc_priv_obj->def_pdev_id;
psoc_priv_obj->new_11d_ctry_pending[pdev_id] = true;
qdf_mem_copy(country_code.country, country, REG_ALPHA2_LEN + 1);
country_code.pdev_id = pdev_id;
if (psoc_priv_obj->offload_enabled) {
tx_ops = reg_get_psoc_tx_ops(psoc);
if (tx_ops->set_country_code) {
tx_ops->set_country_code(psoc, &country_code);
} else {
reg_err("country set handler is not present");
psoc_priv_obj->new_11d_ctry_pending[pdev_id] = false;
return QDF_STATUS_E_FAULT;
}
}
return QDF_STATUS_SUCCESS;
}
bool reg_11d_original_enabled_on_host(struct wlan_objmgr_psoc *psoc)
{
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
psoc_priv_obj =
wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_REGULATORY);
if (NULL == psoc_priv_obj) {
reg_err("reg psoc private obj is NULL");
return QDF_STATUS_E_FAILURE;
}
return (psoc_priv_obj->enable_11d_supp_original &&
!psoc_priv_obj->is_11d_offloaded);
}
bool reg_11d_enabled_on_host(struct wlan_objmgr_psoc *psoc)
{
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
psoc_priv_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_REGULATORY);
if (NULL == psoc_priv_obj) {
reg_err("reg psoc private obj is NULL");
return QDF_STATUS_E_FAILURE;
}
return (psoc_priv_obj->enable_11d_supp &&
!psoc_priv_obj->is_11d_offloaded);
}
QDF_STATUS reg_set_regdb_offloaded(struct wlan_objmgr_psoc *psoc,
bool val)
{
struct wlan_regulatory_psoc_priv_obj *soc_reg;
soc_reg = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(soc_reg)) {
reg_err("psoc reg component is NULL");
return QDF_STATUS_E_FAILURE;
}
soc_reg->offload_enabled = val;
return QDF_STATUS_SUCCESS;
}
QDF_STATUS reg_set_11d_offloaded(struct wlan_objmgr_psoc *psoc,
bool val)
{
struct wlan_regulatory_psoc_priv_obj *soc_reg;
soc_reg = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(soc_reg)) {
reg_err("psoc reg component is NULL");
return QDF_STATUS_E_FAILURE;
}
soc_reg->is_11d_offloaded = val;
return QDF_STATUS_SUCCESS;
}
QDF_STATUS reg_get_curr_regdomain(struct wlan_objmgr_pdev *pdev,
struct cur_regdmn_info *cur_regdmn)
{
struct wlan_objmgr_psoc *psoc;
struct wlan_regulatory_psoc_priv_obj *soc_reg;
uint16_t index;
int num_reg_dmn;
uint8_t phy_id;
psoc = wlan_pdev_get_psoc(pdev);
soc_reg = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(soc_reg)) {
reg_err("soc reg component is NULL");
return QDF_STATUS_E_INVAL;
}
phy_id = wlan_objmgr_pdev_get_pdev_id(pdev);
cur_regdmn->regdmn_pair_id =
soc_reg->mas_chan_params[phy_id].reg_dmn_pair;
reg_get_num_reg_dmn_pairs(&num_reg_dmn);
for (index = 0; index < num_reg_dmn; index++) {
if (g_reg_dmn_pairs[index].reg_dmn_pair_id ==
cur_regdmn->regdmn_pair_id)
break;
}
if (index == num_reg_dmn) {
reg_debug("invalid regdomain");
return QDF_STATUS_E_FAILURE;
}
cur_regdmn->dmn_id_2g = g_reg_dmn_pairs[index].dmn_id_2g;
cur_regdmn->dmn_id_5g = g_reg_dmn_pairs[index].dmn_id_5g;
cur_regdmn->ctl_2g = regdomains_2g[cur_regdmn->dmn_id_2g].ctl_val;
cur_regdmn->ctl_5g = regdomains_5g[cur_regdmn->dmn_id_5g].ctl_val;
cur_regdmn->dfs_region =
regdomains_5g[cur_regdmn->dmn_id_5g].dfs_region;
return QDF_STATUS_SUCCESS;
}
QDF_STATUS reg_modify_chan_144(struct wlan_objmgr_pdev *pdev,
bool enable_ch_144)
{
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
struct wlan_objmgr_psoc *psoc;
struct wlan_lmac_if_reg_tx_ops *reg_tx_ops;
QDF_STATUS status;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("pdev reg component is NULL");
return QDF_STATUS_E_INVAL;
}
if (pdev_priv_obj->en_chan_144 == enable_ch_144) {
reg_info("chan 144 is already %d", enable_ch_144);
return QDF_STATUS_SUCCESS;
}
psoc = wlan_pdev_get_psoc(pdev);
if (!psoc) {
reg_err("psoc is NULL");
return QDF_STATUS_E_INVAL;
}
psoc_priv_obj = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(psoc_priv_obj)) {
reg_err("psoc reg component is NULL");
return QDF_STATUS_E_INVAL;
}
reg_debug("setting chan 144: %d", enable_ch_144);
pdev_priv_obj->en_chan_144 = enable_ch_144;
reg_compute_pdev_current_chan_list(pdev_priv_obj);
reg_tx_ops = reg_get_psoc_tx_ops(psoc);
if (reg_tx_ops->fill_umac_legacy_chanlist)
reg_tx_ops->fill_umac_legacy_chanlist(pdev,
pdev_priv_obj->cur_chan_list);
status = reg_send_scheduler_msg_sb(psoc, pdev);
return status;
}
bool reg_get_en_chan_144(struct wlan_objmgr_pdev *pdev)
{
struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
pdev_priv_obj = reg_get_pdev_obj(pdev);
if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
reg_err("pdev reg component is NULL");
return false;
}
return pdev_priv_obj->en_chan_144;
}
struct wlan_psoc_host_hal_reg_capabilities_ext *reg_get_hal_reg_cap(
struct wlan_objmgr_psoc *psoc)
{
struct wlan_regulatory_psoc_priv_obj *soc_reg;
soc_reg = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(soc_reg)) {
reg_err("psoc reg component is NULL");
return NULL;
}
return soc_reg->reg_cap;
}
QDF_STATUS reg_set_hal_reg_cap(struct wlan_objmgr_psoc *psoc,
struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap,
uint16_t phy_cnt)
{
struct wlan_regulatory_psoc_priv_obj *soc_reg;
soc_reg = reg_get_psoc_obj(psoc);
if (!IS_VALID_PSOC_REG_OBJ(soc_reg)) {
reg_err("psoc reg component is NULL");
return QDF_STATUS_E_FAILURE;
}
if (phy_cnt > PSOC_MAX_PHY_REG_CAP) {
reg_err("phy cnt:%d is more than %d", phy_cnt,
PSOC_MAX_PHY_REG_CAP);
return QDF_STATUS_E_FAILURE;
}
qdf_mem_copy(soc_reg->reg_cap, reg_cap,
phy_cnt *
sizeof(struct wlan_psoc_host_hal_reg_capabilities_ext));
return QDF_STATUS_SUCCESS;
}