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