CMA: document cma=0
[firefly-linux-kernel-4.4.55.git] / net / wireless / reg.c
index 558b0e3a02d8284c49de58d14833c13b444db5a2..b725a31a475178ec99de0e9aabc4d89e2ebb7d40 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright 2007      Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2008-2011 Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -798,6 +799,57 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1,
        return 0;
 }
 
+/* check whether old rule contains new rule */
+static bool rule_contains(struct ieee80211_reg_rule *r1,
+                         struct ieee80211_reg_rule *r2)
+{
+       /* for simplicity, currently consider only same flags */
+       if (r1->flags != r2->flags)
+               return false;
+
+       /* verify r1 is more restrictive */
+       if ((r1->power_rule.max_antenna_gain >
+            r2->power_rule.max_antenna_gain) ||
+           r1->power_rule.max_eirp > r2->power_rule.max_eirp)
+               return false;
+
+       /* make sure r2's range is contained within r1 */
+       if (r1->freq_range.start_freq_khz > r2->freq_range.start_freq_khz ||
+           r1->freq_range.end_freq_khz < r2->freq_range.end_freq_khz)
+               return false;
+
+       /* and finally verify that r1.max_bw >= r2.max_bw */
+       if (r1->freq_range.max_bandwidth_khz <
+           r2->freq_range.max_bandwidth_khz)
+               return false;
+
+       return true;
+}
+
+/* add or extend current rules. do nothing if rule is already contained */
+static void add_rule(struct ieee80211_reg_rule *rule,
+                    struct ieee80211_reg_rule *reg_rules, u32 *n_rules)
+{
+       struct ieee80211_reg_rule *tmp_rule;
+       int i;
+
+       for (i = 0; i < *n_rules; i++) {
+               tmp_rule = &reg_rules[i];
+               /* rule is already contained - do nothing */
+               if (rule_contains(tmp_rule, rule))
+                       return;
+
+               /* extend rule if possible */
+               if (rule_contains(rule, tmp_rule)) {
+                       memcpy(tmp_rule, rule, sizeof(*rule));
+                       return;
+               }
+       }
+
+       memcpy(&reg_rules[*n_rules], rule, sizeof(*rule));
+       (*n_rules)++;
+}
+
 /**
  * regdom_intersect - do the intersection between two regulatory domains
  * @rd1: first regulatory domain
@@ -817,12 +869,10 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
 {
        int r, size_of_regd;
        unsigned int x, y;
-       unsigned int num_rules = 0, rule_idx = 0;
+       unsigned int num_rules = 0;
        const struct ieee80211_reg_rule *rule1, *rule2;
-       struct ieee80211_reg_rule *intersected_rule;
+       struct ieee80211_reg_rule intersected_rule;
        struct ieee80211_regdomain *rd;
-       /* This is just a dummy holder to help us count */
-       struct ieee80211_reg_rule dummy_rule;
 
        if (!rd1 || !rd2)
                return NULL;
@@ -840,7 +890,7 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
                for (y = 0; y < rd2->n_reg_rules; y++) {
                        rule2 = &rd2->reg_rules[y];
                        if (!reg_rules_intersect(rd1, rd2, rule1, rule2,
-                                                &dummy_rule))
+                                                &intersected_rule))
                                num_rules++;
                }
        }
@@ -855,34 +905,24 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
        if (!rd)
                return NULL;
 
-       for (x = 0; x < rd1->n_reg_rules && rule_idx < num_rules; x++) {
+       for (x = 0; x < rd1->n_reg_rules; x++) {
                rule1 = &rd1->reg_rules[x];
-               for (y = 0; y < rd2->n_reg_rules && rule_idx < num_rules; y++) {
+               for (y = 0; y < rd2->n_reg_rules; y++) {
                        rule2 = &rd2->reg_rules[y];
-                       /*
-                        * This time around instead of using the stack lets
-                        * write to the target rule directly saving ourselves
-                        * a memcpy()
-                        */
-                       intersected_rule = &rd->reg_rules[rule_idx];
                        r = reg_rules_intersect(rd1, rd2, rule1, rule2,
-                                               intersected_rule);
+                                               &intersected_rule);
                        /*
                         * No need to memset here the intersected rule here as
                         * we're not using the stack anymore
                         */
                        if (r)
                                continue;
-                       rule_idx++;
-               }
-       }
 
-       if (rule_idx != num_rules) {
-               kfree(rd);
-               return NULL;
+                       add_rule(&intersected_rule, rd->reg_rules,
+                                &rd->n_reg_rules);
+               }
        }
 
-       rd->n_reg_rules = num_rules;
        rd->alpha2[0] = '9';
        rd->alpha2[1] = '8';
        rd->dfs_region = reg_intersect_dfs_region(rd1->dfs_region,
@@ -935,7 +975,7 @@ freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq,
                if (!band_rule_found)
                        band_rule_found = freq_in_rule_band(fr, center_freq);
 
-               bw_fits = reg_does_bw_fit(fr, center_freq, MHZ_TO_KHZ(5));
+               bw_fits = reg_does_bw_fit(fr, center_freq, MHZ_TO_KHZ(20));
 
                if (band_rule_found && bw_fits)
                        return rr;
@@ -1019,10 +1059,10 @@ static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd,
 }
 #endif
 
-/* Find an ieee80211_reg_rule such that a 5MHz channel with frequency
- * chan->center_freq fits there.
- * If there is no such reg_rule, disable the channel, otherwise set the
- * flags corresponding to the bandwidths allowed in the particular reg_rule
+/*
+ * Note that right now we assume the desired channel bandwidth
+ * is always 20 MHz for each individual channel (HT40 uses 20 MHz
+ * per channel, the primary and the extension channel).
  */
 static void handle_channel(struct wiphy *wiphy,
                           enum nl80211_reg_initiator initiator,
@@ -1083,12 +1123,8 @@ static void handle_channel(struct wiphy *wiphy,
        if (reg_rule->flags & NL80211_RRF_AUTO_BW)
                max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
 
-       if (max_bandwidth_khz < MHZ_TO_KHZ(10))
-               bw_flags = IEEE80211_CHAN_NO_10MHZ;
-       if (max_bandwidth_khz < MHZ_TO_KHZ(20))
-               bw_flags |= IEEE80211_CHAN_NO_20MHZ;
        if (max_bandwidth_khz < MHZ_TO_KHZ(40))
-               bw_flags |= IEEE80211_CHAN_NO_HT40;
+               bw_flags = IEEE80211_CHAN_NO_HT40;
        if (max_bandwidth_khz < MHZ_TO_KHZ(80))
                bw_flags |= IEEE80211_CHAN_NO_80MHZ;
        if (max_bandwidth_khz < MHZ_TO_KHZ(160))
@@ -1522,12 +1558,8 @@ static void handle_channel_custom(struct wiphy *wiphy,
        if (reg_rule->flags & NL80211_RRF_AUTO_BW)
                max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
 
-       if (max_bandwidth_khz < MHZ_TO_KHZ(10))
-               bw_flags = IEEE80211_CHAN_NO_10MHZ;
-       if (max_bandwidth_khz < MHZ_TO_KHZ(20))
-               bw_flags |= IEEE80211_CHAN_NO_20MHZ;
        if (max_bandwidth_khz < MHZ_TO_KHZ(40))
-               bw_flags |= IEEE80211_CHAN_NO_HT40;
+               bw_flags = IEEE80211_CHAN_NO_HT40;
        if (max_bandwidth_khz < MHZ_TO_KHZ(80))
                bw_flags |= IEEE80211_CHAN_NO_80MHZ;
        if (max_bandwidth_khz < MHZ_TO_KHZ(160))