Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / net / wireless / broadcom / b43 / ppr.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Broadcom B43 wireless driver
4  * PPR (Power Per Rate) management
5  *
6  * Copyright (c) 2014 Rafał Miłecki <zajec5@gmail.com>
7  */
8
9 #include "ppr.h"
10 #include "b43.h"
11
12 #define ppr_for_each_entry(ppr, i, entry)                               \
13         for (i = 0, entry = &(ppr)->__all_rates[i];                     \
14              i < B43_PPR_RATES_NUM;                                     \
15              i++, entry++)
16
17 void b43_ppr_clear(struct b43_wldev *dev, struct b43_ppr *ppr)
18 {
19         memset(ppr, 0, sizeof(*ppr));
20
21         /* Compile-time PPR check */
22         BUILD_BUG_ON(sizeof(struct b43_ppr) != B43_PPR_RATES_NUM * sizeof(u8));
23 }
24
25 void b43_ppr_add(struct b43_wldev *dev, struct b43_ppr *ppr, int diff)
26 {
27         int i;
28         u8 *rate;
29
30         ppr_for_each_entry(ppr, i, rate) {
31                 *rate = clamp_val(*rate + diff, 0, 127);
32         }
33 }
34
35 void b43_ppr_apply_max(struct b43_wldev *dev, struct b43_ppr *ppr, u8 max)
36 {
37         int i;
38         u8 *rate;
39
40         ppr_for_each_entry(ppr, i, rate) {
41                 *rate = min(*rate, max);
42         }
43 }
44
45 void b43_ppr_apply_min(struct b43_wldev *dev, struct b43_ppr *ppr, u8 min)
46 {
47         int i;
48         u8 *rate;
49
50         ppr_for_each_entry(ppr, i, rate) {
51                 *rate = max(*rate, min);
52         }
53 }
54
55 u8 b43_ppr_get_max(struct b43_wldev *dev, struct b43_ppr *ppr)
56 {
57         u8 res = 0;
58         int i;
59         u8 *rate;
60
61         ppr_for_each_entry(ppr, i, rate) {
62                 res = max(*rate, res);
63         }
64
65         return res;
66 }
67
68 bool b43_ppr_load_max_from_sprom(struct b43_wldev *dev, struct b43_ppr *ppr,
69                                  enum b43_band band)
70 {
71         struct b43_ppr_rates *rates = &ppr->rates;
72         struct ssb_sprom *sprom = dev->dev->bus_sprom;
73         struct b43_phy *phy = &dev->phy;
74         u8 maxpwr, off;
75         u32 sprom_ofdm_po;
76         u16 *sprom_mcs_po;
77         u8 extra_cdd_po, extra_stbc_po;
78         int i;
79
80         switch (band) {
81         case B43_BAND_2G:
82                 maxpwr = min(sprom->core_pwr_info[0].maxpwr_2g,
83                              sprom->core_pwr_info[1].maxpwr_2g);
84                 sprom_ofdm_po = sprom->ofdm2gpo;
85                 sprom_mcs_po = sprom->mcs2gpo;
86                 extra_cdd_po = (sprom->cddpo >> 0) & 0xf;
87                 extra_stbc_po = (sprom->stbcpo >> 0) & 0xf;
88                 break;
89         case B43_BAND_5G_LO:
90                 maxpwr = min(sprom->core_pwr_info[0].maxpwr_5gl,
91                              sprom->core_pwr_info[1].maxpwr_5gl);
92                 sprom_ofdm_po = sprom->ofdm5glpo;
93                 sprom_mcs_po = sprom->mcs5glpo;
94                 extra_cdd_po = (sprom->cddpo >> 8) & 0xf;
95                 extra_stbc_po = (sprom->stbcpo >> 8) & 0xf;
96                 break;
97         case B43_BAND_5G_MI:
98                 maxpwr = min(sprom->core_pwr_info[0].maxpwr_5g,
99                              sprom->core_pwr_info[1].maxpwr_5g);
100                 sprom_ofdm_po = sprom->ofdm5gpo;
101                 sprom_mcs_po = sprom->mcs5gpo;
102                 extra_cdd_po = (sprom->cddpo >> 4) & 0xf;
103                 extra_stbc_po = (sprom->stbcpo >> 4) & 0xf;
104                 break;
105         case B43_BAND_5G_HI:
106                 maxpwr = min(sprom->core_pwr_info[0].maxpwr_5gh,
107                              sprom->core_pwr_info[1].maxpwr_5gh);
108                 sprom_ofdm_po = sprom->ofdm5ghpo;
109                 sprom_mcs_po = sprom->mcs5ghpo;
110                 extra_cdd_po = (sprom->cddpo >> 12) & 0xf;
111                 extra_stbc_po = (sprom->stbcpo >> 12) & 0xf;
112                 break;
113         default:
114                 WARN_ON_ONCE(1);
115                 return false;
116         }
117
118         if (band == B43_BAND_2G) {
119                 for (i = 0; i < 4; i++) {
120                         off = ((sprom->cck2gpo >> (i * 4)) & 0xf) * 2;
121                         rates->cck[i] = maxpwr - off;
122                 }
123         }
124
125         /* OFDM */
126         for (i = 0; i < 8; i++) {
127                 off = ((sprom_ofdm_po >> (i * 4)) & 0xf) * 2;
128                 rates->ofdm[i] = maxpwr - off;
129         }
130
131         /* MCS 20 SISO */
132         rates->mcs_20[0] = rates->ofdm[0];
133         rates->mcs_20[1] = rates->ofdm[2];
134         rates->mcs_20[2] = rates->ofdm[3];
135         rates->mcs_20[3] = rates->ofdm[4];
136         rates->mcs_20[4] = rates->ofdm[5];
137         rates->mcs_20[5] = rates->ofdm[6];
138         rates->mcs_20[6] = rates->ofdm[7];
139         rates->mcs_20[7] = rates->ofdm[7];
140
141         /* MCS 20 CDD */
142         for (i = 0; i < 4; i++) {
143                 off = ((sprom_mcs_po[0] >> (i * 4)) & 0xf) * 2;
144                 rates->mcs_20_cdd[i] = maxpwr - off;
145                 if (phy->type == B43_PHYTYPE_N && phy->rev >= 3)
146                         rates->mcs_20_cdd[i] -= extra_cdd_po;
147         }
148         for (i = 0; i < 4; i++) {
149                 off = ((sprom_mcs_po[1] >> (i * 4)) & 0xf) * 2;
150                 rates->mcs_20_cdd[4 + i] = maxpwr - off;
151                 if (phy->type == B43_PHYTYPE_N && phy->rev >= 3)
152                         rates->mcs_20_cdd[4 + i] -= extra_cdd_po;
153         }
154
155         /* OFDM 20 CDD */
156         rates->ofdm_20_cdd[0] = rates->mcs_20_cdd[0];
157         rates->ofdm_20_cdd[1] = rates->mcs_20_cdd[0];
158         rates->ofdm_20_cdd[2] = rates->mcs_20_cdd[1];
159         rates->ofdm_20_cdd[3] = rates->mcs_20_cdd[2];
160         rates->ofdm_20_cdd[4] = rates->mcs_20_cdd[3];
161         rates->ofdm_20_cdd[5] = rates->mcs_20_cdd[4];
162         rates->ofdm_20_cdd[6] = rates->mcs_20_cdd[5];
163         rates->ofdm_20_cdd[7] = rates->mcs_20_cdd[6];
164
165         /* MCS 20 STBC */
166         for (i = 0; i < 4; i++) {
167                 off = ((sprom_mcs_po[0] >> (i * 4)) & 0xf) * 2;
168                 rates->mcs_20_stbc[i] = maxpwr - off;
169                 if (phy->type == B43_PHYTYPE_N && phy->rev >= 3)
170                         rates->mcs_20_stbc[i] -= extra_stbc_po;
171         }
172         for (i = 0; i < 4; i++) {
173                 off = ((sprom_mcs_po[1] >> (i * 4)) & 0xf) * 2;
174                 rates->mcs_20_stbc[4 + i] = maxpwr - off;
175                 if (phy->type == B43_PHYTYPE_N && phy->rev >= 3)
176                         rates->mcs_20_stbc[4 + i] -= extra_stbc_po;
177         }
178
179         /* MCS 20 SDM */
180         for (i = 0; i < 4; i++) {
181                 off = ((sprom_mcs_po[2] >> (i * 4)) & 0xf) * 2;
182                 rates->mcs_20_sdm[i] = maxpwr - off;
183         }
184         for (i = 0; i < 4; i++) {
185                 off = ((sprom_mcs_po[3] >> (i * 4)) & 0xf) * 2;
186                 rates->mcs_20_sdm[4 + i] = maxpwr - off;
187         }
188
189         return true;
190 }