1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3 * Copyright (C) 2005-2014, 2020-2021 Intel Corporation
4 * Copyright (C) 2016 Intel Deutschland GmbH
5 */
6 #include <linux/slab.h>
7 #include <linux/string.h>
8 #include <linux/export.h>
9
10 #include "iwl-drv.h"
11 #include "iwl-phy-db.h"
12 #include "iwl-debug.h"
13 #include "iwl-op-mode.h"
14 #include "iwl-trans.h"
15
16 struct iwl_phy_db_entry {
17 u16 size;
18 u8 *data;
19 };
20
21 /**
22 * struct iwl_phy_db - stores phy configuration and calibration data.
23 *
24 * @cfg: phy configuration.
25 * @calib_nch: non channel specific calibration data.
26 * @n_group_papd: number of entries in papd channel group.
27 * @calib_ch_group_papd: calibration data related to papd channel group.
28 * @n_group_txp: number of entries in tx power channel group.
29 * @calib_ch_group_txp: calibration data related to tx power chanel group.
30 * @trans: transport layer
31 */
32 struct iwl_phy_db {
33 struct iwl_phy_db_entry cfg;
34 struct iwl_phy_db_entry calib_nch;
35 int n_group_papd;
36 struct iwl_phy_db_entry *calib_ch_group_papd;
37 int n_group_txp;
38 struct iwl_phy_db_entry *calib_ch_group_txp;
39
40 struct iwl_trans *trans;
41 };
42
43 enum iwl_phy_db_section_type {
44 IWL_PHY_DB_CFG = 1,
45 IWL_PHY_DB_CALIB_NCH,
46 IWL_PHY_DB_UNUSED,
47 IWL_PHY_DB_CALIB_CHG_PAPD,
48 IWL_PHY_DB_CALIB_CHG_TXP,
49 IWL_PHY_DB_MAX
50 };
51
52 #define PHY_DB_CMD 0x6c
53
54 /* for parsing of tx power channel group data that comes from the firmware*/
55 struct iwl_phy_db_chg_txp {
56 __le32 space;
57 __le16 max_channel_idx;
58 } __packed;
59
iwl_phy_db_init(struct iwl_trans * trans)60 struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans)
61 {
62 struct iwl_phy_db *phy_db = kzalloc_obj(struct iwl_phy_db);
63
64 if (!phy_db)
65 return phy_db;
66
67 phy_db->trans = trans;
68
69 phy_db->n_group_txp = -1;
70 phy_db->n_group_papd = -1;
71
72 /* TODO: add default values of the phy db. */
73 return phy_db;
74 }
75 IWL_EXPORT_SYMBOL(iwl_phy_db_init);
76
77 /*
78 * get phy db section: returns a pointer to a phy db section specified by
79 * type and channel group id.
80 */
81 static struct iwl_phy_db_entry *
iwl_phy_db_get_section(struct iwl_phy_db * phy_db,enum iwl_phy_db_section_type type,u16 chg_id)82 iwl_phy_db_get_section(struct iwl_phy_db *phy_db,
83 enum iwl_phy_db_section_type type,
84 u16 chg_id)
85 {
86 if (!phy_db || type >= IWL_PHY_DB_MAX)
87 return NULL;
88
89 switch (type) {
90 case IWL_PHY_DB_CFG:
91 return &phy_db->cfg;
92 case IWL_PHY_DB_CALIB_NCH:
93 return &phy_db->calib_nch;
94 case IWL_PHY_DB_CALIB_CHG_PAPD:
95 if (chg_id >= phy_db->n_group_papd)
96 return NULL;
97 return &phy_db->calib_ch_group_papd[chg_id];
98 case IWL_PHY_DB_CALIB_CHG_TXP:
99 if (chg_id >= phy_db->n_group_txp)
100 return NULL;
101 return &phy_db->calib_ch_group_txp[chg_id];
102 default:
103 return NULL;
104 }
105 return NULL;
106 }
107
iwl_phy_db_free_section(struct iwl_phy_db * phy_db,enum iwl_phy_db_section_type type,u16 chg_id)108 static void iwl_phy_db_free_section(struct iwl_phy_db *phy_db,
109 enum iwl_phy_db_section_type type,
110 u16 chg_id)
111 {
112 struct iwl_phy_db_entry *entry =
113 iwl_phy_db_get_section(phy_db, type, chg_id);
114 if (!entry)
115 return;
116
117 kfree(entry->data);
118 entry->data = NULL;
119 entry->size = 0;
120 }
121
iwl_phy_db_free(struct iwl_phy_db * phy_db)122 void iwl_phy_db_free(struct iwl_phy_db *phy_db)
123 {
124 int i;
125
126 if (!phy_db)
127 return;
128
129 iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CFG, 0);
130 iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_NCH, 0);
131
132 for (i = 0; i < phy_db->n_group_papd; i++)
133 iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_PAPD, i);
134 kfree(phy_db->calib_ch_group_papd);
135
136 for (i = 0; i < phy_db->n_group_txp; i++)
137 iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_TXP, i);
138 kfree(phy_db->calib_ch_group_txp);
139
140 kfree(phy_db);
141 }
142 IWL_EXPORT_SYMBOL(iwl_phy_db_free);
143
iwl_phy_db_set_section(struct iwl_phy_db * phy_db,struct iwl_rx_packet * pkt)144 int iwl_phy_db_set_section(struct iwl_phy_db *phy_db,
145 struct iwl_rx_packet *pkt)
146 {
147 unsigned int pkt_len = iwl_rx_packet_payload_len(pkt);
148 struct iwl_calib_res_notif_phy_db *phy_db_notif =
149 (struct iwl_calib_res_notif_phy_db *)pkt->data;
150 enum iwl_phy_db_section_type type;
151 u16 size;
152 struct iwl_phy_db_entry *entry;
153 u16 chg_id = 0;
154
155 if (pkt_len < sizeof(*phy_db_notif))
156 return -EINVAL;
157
158 type = le16_to_cpu(phy_db_notif->type);
159 size = le16_to_cpu(phy_db_notif->length);
160
161 if (pkt_len < sizeof(*phy_db_notif) + size)
162 return -EINVAL;
163
164 if (!phy_db)
165 return -EINVAL;
166
167 if (type == IWL_PHY_DB_CALIB_CHG_PAPD) {
168 chg_id = le16_to_cpup((__le16 *)phy_db_notif->data);
169 if (phy_db && !phy_db->calib_ch_group_papd) {
170 /*
171 * Firmware sends the largest index first, so we can use
172 * it to know how much we should allocate.
173 */
174 phy_db->calib_ch_group_papd = kzalloc_objs(struct iwl_phy_db_entry,
175 chg_id + 1,
176 GFP_ATOMIC);
177 if (!phy_db->calib_ch_group_papd)
178 return -ENOMEM;
179 phy_db->n_group_papd = chg_id + 1;
180 }
181 } else if (type == IWL_PHY_DB_CALIB_CHG_TXP) {
182 chg_id = le16_to_cpup((__le16 *)phy_db_notif->data);
183 if (phy_db && !phy_db->calib_ch_group_txp) {
184 /*
185 * Firmware sends the largest index first, so we can use
186 * it to know how much we should allocate.
187 */
188 phy_db->calib_ch_group_txp = kzalloc_objs(struct iwl_phy_db_entry,
189 chg_id + 1,
190 GFP_ATOMIC);
191 if (!phy_db->calib_ch_group_txp)
192 return -ENOMEM;
193 phy_db->n_group_txp = chg_id + 1;
194 }
195 }
196
197 entry = iwl_phy_db_get_section(phy_db, type, chg_id);
198 if (!entry)
199 return -EINVAL;
200
201 kfree(entry->data);
202 entry->data = kmemdup(phy_db_notif->data, size, GFP_ATOMIC);
203 if (!entry->data) {
204 entry->size = 0;
205 return -ENOMEM;
206 }
207
208 entry->size = size;
209
210 IWL_DEBUG_INFO(phy_db->trans,
211 "%s(%d): [PHYDB]SET: Type %d , Size: %d\n",
212 __func__, __LINE__, type, size);
213
214 return 0;
215 }
216 IWL_EXPORT_SYMBOL(iwl_phy_db_set_section);
217
is_valid_channel(u16 ch_id)218 static int is_valid_channel(u16 ch_id)
219 {
220 if (ch_id <= 14 ||
221 (36 <= ch_id && ch_id <= 64 && ch_id % 4 == 0) ||
222 (100 <= ch_id && ch_id <= 140 && ch_id % 4 == 0) ||
223 (145 <= ch_id && ch_id <= 165 && ch_id % 4 == 1))
224 return 1;
225 return 0;
226 }
227
ch_id_to_ch_index(u16 ch_id)228 static u8 ch_id_to_ch_index(u16 ch_id)
229 {
230 if (WARN_ON(!is_valid_channel(ch_id)))
231 return 0xff;
232
233 if (ch_id <= 14)
234 return ch_id - 1;
235 if (ch_id <= 64)
236 return (ch_id + 20) / 4;
237 if (ch_id <= 140)
238 return (ch_id - 12) / 4;
239 return (ch_id - 13) / 4;
240 }
241
242
channel_id_to_papd(u16 ch_id)243 static u16 channel_id_to_papd(u16 ch_id)
244 {
245 if (WARN_ON(!is_valid_channel(ch_id)))
246 return 0xff;
247
248 if (1 <= ch_id && ch_id <= 14)
249 return 0;
250 if (36 <= ch_id && ch_id <= 64)
251 return 1;
252 if (100 <= ch_id && ch_id <= 140)
253 return 2;
254 return 3;
255 }
256
channel_id_to_txp(struct iwl_phy_db * phy_db,u16 ch_id)257 static u16 channel_id_to_txp(struct iwl_phy_db *phy_db, u16 ch_id)
258 {
259 struct iwl_phy_db_chg_txp *txp_chg;
260 int i;
261 u8 ch_index = ch_id_to_ch_index(ch_id);
262 if (ch_index == 0xff)
263 return 0xff;
264
265 for (i = 0; i < phy_db->n_group_txp; i++) {
266 txp_chg = (void *)phy_db->calib_ch_group_txp[i].data;
267 if (!txp_chg)
268 return 0xff;
269 /*
270 * Looking for the first channel group that its max channel is
271 * higher then wanted channel.
272 */
273 if (le16_to_cpu(txp_chg->max_channel_idx) >= ch_index)
274 return i;
275 }
276 return 0xff;
277 }
278 static
iwl_phy_db_get_section_data(struct iwl_phy_db * phy_db,u32 type,u8 ** data,u16 * size,u16 ch_id)279 int iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db,
280 u32 type, u8 **data, u16 *size, u16 ch_id)
281 {
282 struct iwl_phy_db_entry *entry;
283 u16 ch_group_id = 0;
284
285 if (!phy_db)
286 return -EINVAL;
287
288 /* find wanted channel group */
289 if (type == IWL_PHY_DB_CALIB_CHG_PAPD)
290 ch_group_id = channel_id_to_papd(ch_id);
291 else if (type == IWL_PHY_DB_CALIB_CHG_TXP)
292 ch_group_id = channel_id_to_txp(phy_db, ch_id);
293
294 entry = iwl_phy_db_get_section(phy_db, type, ch_group_id);
295 if (!entry)
296 return -EINVAL;
297
298 *data = entry->data;
299 *size = entry->size;
300
301 IWL_DEBUG_INFO(phy_db->trans,
302 "%s(%d): [PHYDB] GET: Type %d , Size: %d\n",
303 __func__, __LINE__, type, *size);
304
305 return 0;
306 }
307
iwl_send_phy_db_cmd(struct iwl_phy_db * phy_db,u16 type,u16 length,void * data)308 static int iwl_send_phy_db_cmd(struct iwl_phy_db *phy_db, u16 type,
309 u16 length, void *data)
310 {
311 struct iwl_phy_db_cmd phy_db_cmd;
312 struct iwl_host_cmd cmd = {
313 .id = PHY_DB_CMD,
314 };
315
316 IWL_DEBUG_INFO(phy_db->trans,
317 "Sending PHY-DB hcmd of type %d, of length %d\n",
318 type, length);
319
320 /* Set phy db cmd variables */
321 phy_db_cmd.type = cpu_to_le16(type);
322 phy_db_cmd.length = cpu_to_le16(length);
323
324 /* Set hcmd variables */
325 cmd.data[0] = &phy_db_cmd;
326 cmd.len[0] = sizeof(struct iwl_phy_db_cmd);
327 cmd.data[1] = data;
328 cmd.len[1] = length;
329 cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY;
330
331 return iwl_trans_send_cmd(phy_db->trans, &cmd);
332 }
333
iwl_phy_db_send_all_channel_groups(struct iwl_phy_db * phy_db,enum iwl_phy_db_section_type type,u8 max_ch_groups)334 static int iwl_phy_db_send_all_channel_groups(
335 struct iwl_phy_db *phy_db,
336 enum iwl_phy_db_section_type type,
337 u8 max_ch_groups)
338 {
339 u16 i;
340 int err;
341 struct iwl_phy_db_entry *entry;
342
343 /* Send all the channel specific groups to operational fw */
344 for (i = 0; i < max_ch_groups; i++) {
345 entry = iwl_phy_db_get_section(phy_db,
346 type,
347 i);
348 if (!entry)
349 return -EINVAL;
350
351 if (!entry->size)
352 continue;
353
354 /* Send the requested PHY DB section */
355 err = iwl_send_phy_db_cmd(phy_db,
356 type,
357 entry->size,
358 entry->data);
359 if (err) {
360 IWL_ERR(phy_db->trans,
361 "Can't SEND phy_db section %d (%d), err %d\n",
362 type, i, err);
363 return err;
364 }
365
366 IWL_DEBUG_INFO(phy_db->trans,
367 "Sent PHY_DB HCMD, type = %d num = %d\n",
368 type, i);
369 }
370
371 return 0;
372 }
373
iwl_send_phy_db_data(struct iwl_phy_db * phy_db)374 int iwl_send_phy_db_data(struct iwl_phy_db *phy_db)
375 {
376 u8 *data = NULL;
377 u16 size = 0;
378 int err;
379
380 IWL_DEBUG_INFO(phy_db->trans,
381 "Sending phy db data and configuration to runtime image\n");
382
383 /* Send PHY DB CFG section */
384 err = iwl_phy_db_get_section_data(phy_db, IWL_PHY_DB_CFG,
385 &data, &size, 0);
386 if (err) {
387 IWL_ERR(phy_db->trans, "Cannot get Phy DB cfg section\n");
388 return err;
389 }
390
391 err = iwl_send_phy_db_cmd(phy_db, IWL_PHY_DB_CFG, size, data);
392 if (err) {
393 IWL_ERR(phy_db->trans,
394 "Cannot send HCMD of Phy DB cfg section\n");
395 return err;
396 }
397
398 err = iwl_phy_db_get_section_data(phy_db, IWL_PHY_DB_CALIB_NCH,
399 &data, &size, 0);
400 if (err) {
401 IWL_ERR(phy_db->trans,
402 "Cannot get Phy DB non specific channel section\n");
403 return err;
404 }
405
406 err = iwl_send_phy_db_cmd(phy_db, IWL_PHY_DB_CALIB_NCH, size, data);
407 if (err) {
408 IWL_ERR(phy_db->trans,
409 "Cannot send HCMD of Phy DB non specific channel section\n");
410 return err;
411 }
412
413 /* Send all the TXP channel specific data */
414 err = iwl_phy_db_send_all_channel_groups(phy_db,
415 IWL_PHY_DB_CALIB_CHG_PAPD,
416 phy_db->n_group_papd);
417 if (err) {
418 IWL_ERR(phy_db->trans,
419 "Cannot send channel specific PAPD groups\n");
420 return err;
421 }
422
423 /* Send all the TXP channel specific data */
424 err = iwl_phy_db_send_all_channel_groups(phy_db,
425 IWL_PHY_DB_CALIB_CHG_TXP,
426 phy_db->n_group_txp);
427 if (err) {
428 IWL_ERR(phy_db->trans,
429 "Cannot send channel specific TX power groups\n");
430 return err;
431 }
432
433 IWL_DEBUG_INFO(phy_db->trans,
434 "Finished sending phy db non channel data\n");
435 return 0;
436 }
437 IWL_EXPORT_SYMBOL(iwl_send_phy_db_data);
438