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