1/******************************************************************************
2 *
3 * This file is provided under a dual BSD/GPLv2 license.  When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * GPL LICENSE SUMMARY
7 *
8 * Copyright(c) 2017 Intel Deutschland GmbH
9 * Copyright(c) 2018 - 2021 Intel Corporation
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of version 2 of the GNU General Public License as
13 * published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * BSD LICENSE
21 *
22 * Copyright(c) 2017 Intel Deutschland GmbH
23 * Copyright(c) 2018 - 2020 Intel Corporation
24 * All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 *
30 *  * Redistributions of source code must retain the above copyright
31 *    notice, this list of conditions and the following disclaimer.
32 *  * Redistributions in binary form must reproduce the above copyright
33 *    notice, this list of conditions and the following disclaimer in
34 *    the documentation and/or other materials provided with the
35 *    distribution.
36 *  * Neither the name Intel Corporation nor the names of its
37 *    contributors may be used to endorse or promote products derived
38 *    from this software without specific prior written permission.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
43 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
44 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51 *
52 *****************************************************************************/
53
54#include "iwl-trans.h"
55#include "iwl-fh.h"
56#include "iwl-context-info.h"
57#include "internal.h"
58#include "iwl-prph.h"
59
60static void *_iwl_pcie_ctxt_info_dma_alloc_coherent(struct iwl_trans *trans,
61						    size_t size,
62						    dma_addr_t *phys,
63						    int depth)
64{
65	void *result;
66
67	if (WARN(depth > 2,
68		 "failed to allocate DMA memory not crossing 2^32 boundary"))
69		return NULL;
70
71	result = dma_alloc_coherent(trans->dev, size, phys, GFP_KERNEL);
72
73	if (!result)
74		return NULL;
75
76	if (unlikely(iwl_txq_crosses_4g_boundary(*phys, size))) {
77		void *old = result;
78		dma_addr_t oldphys = *phys;
79
80		result = _iwl_pcie_ctxt_info_dma_alloc_coherent(trans, size,
81								phys,
82								depth + 1);
83		dma_free_coherent(trans->dev, size, old, oldphys);
84	}
85
86	return result;
87}
88
89static void *iwl_pcie_ctxt_info_dma_alloc_coherent(struct iwl_trans *trans,
90						   size_t size,
91						   dma_addr_t *phys)
92{
93	return _iwl_pcie_ctxt_info_dma_alloc_coherent(trans, size, phys, 0);
94}
95
96int iwl_pcie_ctxt_info_alloc_dma(struct iwl_trans *trans,
97				 const void *data, u32 len,
98				 struct iwl_dram_data *dram)
99{
100	dram->block = iwl_pcie_ctxt_info_dma_alloc_coherent(trans, len,
101							    &dram->physical);
102	if (!dram->block)
103		return -ENOMEM;
104
105	dram->size = len;
106	memcpy(dram->block, data, len);
107
108	return 0;
109}
110
111void iwl_pcie_ctxt_info_free_paging(struct iwl_trans *trans)
112{
113	struct iwl_self_init_dram *dram = &trans->init_dram;
114	int i;
115
116	if (!dram->paging) {
117		WARN_ON(dram->paging_cnt);
118		return;
119	}
120
121	/* free paging*/
122	for (i = 0; i < dram->paging_cnt; i++)
123		dma_free_coherent(trans->dev, dram->paging[i].size,
124				  dram->paging[i].block,
125				  dram->paging[i].physical);
126
127	kfree(dram->paging);
128	dram->paging_cnt = 0;
129	dram->paging = NULL;
130}
131
132int iwl_pcie_init_fw_sec(struct iwl_trans *trans,
133			 const struct fw_img *fw,
134			 struct iwl_context_info_dram *ctxt_dram)
135{
136	struct iwl_self_init_dram *dram = &trans->init_dram;
137	int i, ret, lmac_cnt, umac_cnt, paging_cnt;
138
139	if (WARN(dram->paging,
140		 "paging shouldn't already be initialized (%d pages)\n",
141		 dram->paging_cnt))
142		iwl_pcie_ctxt_info_free_paging(trans);
143
144	lmac_cnt = iwl_pcie_get_num_sections(fw, 0);
145	/* add 1 due to separator */
146	umac_cnt = iwl_pcie_get_num_sections(fw, lmac_cnt + 1);
147	/* add 2 due to separators */
148	paging_cnt = iwl_pcie_get_num_sections(fw, lmac_cnt + umac_cnt + 2);
149
150	dram->fw = kcalloc(umac_cnt + lmac_cnt, sizeof(*dram->fw), GFP_KERNEL);
151	if (!dram->fw)
152		return -ENOMEM;
153	dram->paging = kcalloc(paging_cnt, sizeof(*dram->paging), GFP_KERNEL);
154	if (!dram->paging)
155		return -ENOMEM;
156
157	/* initialize lmac sections */
158	for (i = 0; i < lmac_cnt; i++) {
159		ret = iwl_pcie_ctxt_info_alloc_dma(trans, fw->sec[i].data,
160						   fw->sec[i].len,
161						   &dram->fw[dram->fw_cnt]);
162		if (ret)
163			return ret;
164		ctxt_dram->lmac_img[i] =
165			cpu_to_le64(dram->fw[dram->fw_cnt].physical);
166		dram->fw_cnt++;
167	}
168
169	/* initialize umac sections */
170	for (i = 0; i < umac_cnt; i++) {
171		/* access FW with +1 to make up for lmac separator */
172		ret = iwl_pcie_ctxt_info_alloc_dma(trans,
173						   fw->sec[dram->fw_cnt + 1].data,
174						   fw->sec[dram->fw_cnt + 1].len,
175						   &dram->fw[dram->fw_cnt]);
176		if (ret)
177			return ret;
178		ctxt_dram->umac_img[i] =
179			cpu_to_le64(dram->fw[dram->fw_cnt].physical);
180		dram->fw_cnt++;
181	}
182
183	/*
184	 * Initialize paging.
185	 * Paging memory isn't stored in dram->fw as the umac and lmac - it is
186	 * stored separately.
187	 * This is since the timing of its release is different -
188	 * while fw memory can be released on alive, the paging memory can be
189	 * freed only when the device goes down.
190	 * Given that, the logic here in accessing the fw image is a bit
191	 * different - fw_cnt isn't changing so loop counter is added to it.
192	 */
193	for (i = 0; i < paging_cnt; i++) {
194		/* access FW with +2 to make up for lmac & umac separators */
195		int fw_idx = dram->fw_cnt + i + 2;
196
197		ret = iwl_pcie_ctxt_info_alloc_dma(trans, fw->sec[fw_idx].data,
198						   fw->sec[fw_idx].len,
199						   &dram->paging[i]);
200		if (ret)
201			return ret;
202
203		ctxt_dram->virtual_img[i] =
204			cpu_to_le64(dram->paging[i].physical);
205		dram->paging_cnt++;
206	}
207
208	return 0;
209}
210
211int iwl_pcie_ctxt_info_init(struct iwl_trans *trans,
212			    const struct fw_img *fw)
213{
214	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
215	struct iwl_context_info *ctxt_info;
216	struct iwl_context_info_rbd_cfg *rx_cfg;
217	u32 control_flags = 0, rb_size;
218	dma_addr_t phys;
219	int ret;
220
221	ctxt_info = iwl_pcie_ctxt_info_dma_alloc_coherent(trans,
222							  sizeof(*ctxt_info),
223							  &phys);
224	if (!ctxt_info)
225		return -ENOMEM;
226
227	trans_pcie->ctxt_info_dma_addr = phys;
228
229	ctxt_info->version.version = 0;
230	ctxt_info->version.mac_id =
231		cpu_to_le16((u16)iwl_read32(trans, CSR_HW_REV));
232	/* size is in DWs */
233	ctxt_info->version.size = cpu_to_le16(sizeof(*ctxt_info) / 4);
234
235	switch (trans_pcie->rx_buf_size) {
236	case IWL_AMSDU_2K:
237		rb_size = IWL_CTXT_INFO_RB_SIZE_2K;
238		break;
239	case IWL_AMSDU_4K:
240		rb_size = IWL_CTXT_INFO_RB_SIZE_4K;
241		break;
242	case IWL_AMSDU_8K:
243		rb_size = IWL_CTXT_INFO_RB_SIZE_8K;
244		break;
245	case IWL_AMSDU_12K:
246		rb_size = IWL_CTXT_INFO_RB_SIZE_12K;
247		break;
248	default:
249		WARN_ON(1);
250		rb_size = IWL_CTXT_INFO_RB_SIZE_4K;
251	}
252
253	WARN_ON(RX_QUEUE_CB_SIZE(trans->cfg->num_rbds) > 12);
254	control_flags = IWL_CTXT_INFO_TFD_FORMAT_LONG;
255	control_flags |=
256		u32_encode_bits(RX_QUEUE_CB_SIZE(trans->cfg->num_rbds),
257				IWL_CTXT_INFO_RB_CB_SIZE);
258	control_flags |= u32_encode_bits(rb_size, IWL_CTXT_INFO_RB_SIZE);
259	ctxt_info->control.control_flags = cpu_to_le32(control_flags);
260
261	/* initialize RX default queue */
262	rx_cfg = &ctxt_info->rbd_cfg;
263	rx_cfg->free_rbd_addr = cpu_to_le64(trans_pcie->rxq->bd_dma);
264	rx_cfg->used_rbd_addr = cpu_to_le64(trans_pcie->rxq->used_bd_dma);
265	rx_cfg->status_wr_ptr = cpu_to_le64(trans_pcie->rxq->rb_stts_dma);
266
267	/* initialize TX command queue */
268	ctxt_info->hcmd_cfg.cmd_queue_addr =
269		cpu_to_le64(trans->txqs.txq[trans->txqs.cmd.q_id]->dma_addr);
270	ctxt_info->hcmd_cfg.cmd_queue_size =
271		TFD_QUEUE_CB_SIZE(IWL_CMD_QUEUE_SIZE);
272
273	/* allocate ucode sections in dram and set addresses */
274	ret = iwl_pcie_init_fw_sec(trans, fw, &ctxt_info->dram);
275	if (ret) {
276		dma_free_coherent(trans->dev, sizeof(*trans_pcie->ctxt_info),
277				  ctxt_info, trans_pcie->ctxt_info_dma_addr);
278		return ret;
279	}
280
281	trans_pcie->ctxt_info = ctxt_info;
282
283	iwl_enable_fw_load_int_ctx_info(trans);
284
285	/* Configure debug, if exists */
286	if (iwl_pcie_dbg_on(trans))
287		iwl_pcie_apply_destination(trans);
288
289	/* kick FW self load */
290	iwl_write64(trans, CSR_CTXT_INFO_BA, trans_pcie->ctxt_info_dma_addr);
291
292	/* Context info will be released upon alive or failure to get one */
293
294	return 0;
295}
296
297void iwl_pcie_ctxt_info_free(struct iwl_trans *trans)
298{
299	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
300
301	if (!trans_pcie->ctxt_info)
302		return;
303
304	dma_free_coherent(trans->dev, sizeof(*trans_pcie->ctxt_info),
305			  trans_pcie->ctxt_info,
306			  trans_pcie->ctxt_info_dma_addr);
307	trans_pcie->ctxt_info_dma_addr = 0;
308	trans_pcie->ctxt_info = NULL;
309
310	iwl_pcie_ctxt_info_free_fw_img(trans);
311}
312