1 /******************************************************************************
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.
8 * Copyright(c) 2017 Intel Deutschland GmbH
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of version 2 of the GNU General Public License as
12 * published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
21 * Copyright(c) 2017 Intel Deutschland GmbH
22 * All rights reserved.
24 * Redistribution and use in source and binary forms, with or without
25 * modification, are permitted provided that the following conditions
28 * * Redistributions of source code must retain the above copyright
29 * notice, this list of conditions and the following disclaimer.
30 * * Redistributions in binary form must reproduce the above copyright
31 * notice, this list of conditions and the following disclaimer in
32 * the documentation and/or other materials provided with the
34 * * Neither the name Intel Corporation nor the names of its
35 * contributors may be used to endorse or promote products derived
36 * from this software without specific prior written permission.
38 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
39 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
40 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
41 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
42 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
44 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
45 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
46 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
47 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
48 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50 *****************************************************************************/
52 #include "iwl-trans.h"
54 #include "iwl-context-info.h"
58 static int iwl_pcie_get_num_sections(const struct fw_img
*fw
,
63 while (start
< fw
->num_sec
&&
64 fw
->sec
[start
].offset
!= CPU1_CPU2_SEPARATOR_SECTION
&&
65 fw
->sec
[start
].offset
!= PAGING_SEPARATOR_SECTION
) {
73 static int iwl_pcie_ctxt_info_alloc_dma(struct iwl_trans
*trans
,
74 const struct fw_desc
*sec
,
75 struct iwl_dram_data
*dram
)
77 dram
->block
= dma_alloc_coherent(trans
->dev
, sec
->len
,
83 dram
->size
= sec
->len
;
84 memcpy(dram
->block
, sec
->data
, sec
->len
);
89 static void iwl_pcie_ctxt_info_free_fw_img(struct iwl_trans
*trans
)
91 struct iwl_trans_pcie
*trans_pcie
= IWL_TRANS_GET_PCIE_TRANS(trans
);
92 struct iwl_self_init_dram
*dram
= &trans_pcie
->init_dram
;
96 WARN_ON(dram
->fw_cnt
);
100 for (i
= 0; i
< dram
->fw_cnt
; i
++)
101 dma_free_coherent(trans
->dev
, dram
->fw
[i
].size
,
102 dram
->fw
[i
].block
, dram
->fw
[i
].physical
);
109 void iwl_pcie_ctxt_info_free_paging(struct iwl_trans
*trans
)
111 struct iwl_trans_pcie
*trans_pcie
= IWL_TRANS_GET_PCIE_TRANS(trans
);
112 struct iwl_self_init_dram
*dram
= &trans_pcie
->init_dram
;
116 WARN_ON(dram
->paging_cnt
);
121 for (i
= 0; i
< dram
->paging_cnt
; i
++)
122 dma_free_coherent(trans
->dev
, dram
->paging
[i
].size
,
123 dram
->paging
[i
].block
,
124 dram
->paging
[i
].physical
);
127 dram
->paging_cnt
= 0;
131 static int iwl_pcie_ctxt_info_init_fw_sec(struct iwl_trans
*trans
,
132 const struct fw_img
*fw
,
133 struct iwl_context_info
*ctxt_info
)
135 struct iwl_trans_pcie
*trans_pcie
= IWL_TRANS_GET_PCIE_TRANS(trans
);
136 struct iwl_self_init_dram
*dram
= &trans_pcie
->init_dram
;
137 struct iwl_context_info_dram
*ctxt_dram
= &ctxt_info
->dram
;
138 int i
, ret
, lmac_cnt
, umac_cnt
, paging_cnt
;
140 if (WARN(dram
->paging
,
141 "paging shouldn't already be initialized (%d pages)\n",
143 iwl_pcie_ctxt_info_free_paging(trans
);
145 lmac_cnt
= iwl_pcie_get_num_sections(fw
, 0);
146 /* add 1 due to separator */
147 umac_cnt
= iwl_pcie_get_num_sections(fw
, lmac_cnt
+ 1);
148 /* add 2 due to separators */
149 paging_cnt
= iwl_pcie_get_num_sections(fw
, lmac_cnt
+ umac_cnt
+ 2);
151 dram
->fw
= kcalloc(umac_cnt
+ lmac_cnt
, sizeof(*dram
->fw
), GFP_KERNEL
);
154 dram
->paging
= kcalloc(paging_cnt
, sizeof(*dram
->paging
), GFP_KERNEL
);
158 /* initialize lmac sections */
159 for (i
= 0; i
< lmac_cnt
; i
++) {
160 ret
= iwl_pcie_ctxt_info_alloc_dma(trans
, &fw
->sec
[i
],
161 &dram
->fw
[dram
->fw_cnt
]);
164 ctxt_dram
->lmac_img
[i
] =
165 cpu_to_le64(dram
->fw
[dram
->fw_cnt
].physical
);
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],
174 &dram
->fw
[dram
->fw_cnt
]);
177 ctxt_dram
->umac_img
[i
] =
178 cpu_to_le64(dram
->fw
[dram
->fw_cnt
].physical
);
184 * Paging memory isn't stored in dram->fw as the umac and lmac - it is
186 * This is since the timing of its release is different -
187 * while fw memory can be released on alive, the paging memory can be
188 * freed only when the device goes down.
189 * Given that, the logic here in accessing the fw image is a bit
190 * different - fw_cnt isn't changing so loop counter is added to it.
192 for (i
= 0; i
< paging_cnt
; i
++) {
193 /* access FW with +2 to make up for lmac & umac separators */
194 int fw_idx
= dram
->fw_cnt
+ i
+ 2;
196 ret
= iwl_pcie_ctxt_info_alloc_dma(trans
, &fw
->sec
[fw_idx
],
201 ctxt_dram
->virtual_img
[i
] =
202 cpu_to_le64(dram
->paging
[i
].physical
);
209 int iwl_pcie_ctxt_info_init(struct iwl_trans
*trans
,
210 const struct fw_img
*fw
)
212 struct iwl_trans_pcie
*trans_pcie
= IWL_TRANS_GET_PCIE_TRANS(trans
);
213 struct iwl_context_info
*ctxt_info
;
214 struct iwl_context_info_rbd_cfg
*rx_cfg
;
215 u32 control_flags
= 0;
218 ctxt_info
= dma_alloc_coherent(trans
->dev
, sizeof(*ctxt_info
),
219 &trans_pcie
->ctxt_info_dma_addr
,
224 ctxt_info
->version
.version
= 0;
225 ctxt_info
->version
.mac_id
=
226 cpu_to_le16((u16
)iwl_read32(trans
, CSR_HW_REV
));
228 ctxt_info
->version
.size
= cpu_to_le16(sizeof(*ctxt_info
) / 4);
230 BUILD_BUG_ON(RX_QUEUE_CB_SIZE(MQ_RX_TABLE_SIZE
) > 0xF);
231 control_flags
= IWL_CTXT_INFO_RB_SIZE_4K
|
232 IWL_CTXT_INFO_TFD_FORMAT_LONG
|
233 RX_QUEUE_CB_SIZE(MQ_RX_TABLE_SIZE
) <<
234 IWL_CTXT_INFO_RB_CB_SIZE_POS
;
235 ctxt_info
->control
.control_flags
= cpu_to_le32(control_flags
);
237 /* initialize RX default queue */
238 rx_cfg
= &ctxt_info
->rbd_cfg
;
239 rx_cfg
->free_rbd_addr
= cpu_to_le64(trans_pcie
->rxq
->bd_dma
);
240 rx_cfg
->used_rbd_addr
= cpu_to_le64(trans_pcie
->rxq
->used_bd_dma
);
241 rx_cfg
->status_wr_ptr
= cpu_to_le64(trans_pcie
->rxq
->rb_stts_dma
);
243 /* initialize TX command queue */
244 ctxt_info
->hcmd_cfg
.cmd_queue_addr
=
245 cpu_to_le64(trans_pcie
->txq
[trans_pcie
->cmd_queue
]->dma_addr
);
246 ctxt_info
->hcmd_cfg
.cmd_queue_size
=
247 TFD_QUEUE_CB_SIZE(trans_pcie
->tx_cmd_queue_size
);
249 /* allocate ucode sections in dram and set addresses */
250 ret
= iwl_pcie_ctxt_info_init_fw_sec(trans
, fw
, ctxt_info
);
252 dma_free_coherent(trans
->dev
, sizeof(*trans_pcie
->ctxt_info
),
253 ctxt_info
, trans_pcie
->ctxt_info_dma_addr
);
257 trans_pcie
->ctxt_info
= ctxt_info
;
259 iwl_enable_interrupts(trans
);
261 /* Configure debug, if exists */
262 if (trans
->dbg_dest_tlv
)
263 iwl_pcie_apply_destination(trans
);
265 /* kick FW self load */
266 iwl_write64(trans
, CSR_CTXT_INFO_BA
, trans_pcie
->ctxt_info_dma_addr
);
267 iwl_write_prph(trans
, UREG_CPU_INIT_RUN
, 1);
269 /* Context info will be released upon alive or failure to get one */
274 void iwl_pcie_ctxt_info_free(struct iwl_trans
*trans
)
276 struct iwl_trans_pcie
*trans_pcie
= IWL_TRANS_GET_PCIE_TRANS(trans
);
278 if (!trans_pcie
->ctxt_info
)
281 dma_free_coherent(trans
->dev
, sizeof(*trans_pcie
->ctxt_info
),
282 trans_pcie
->ctxt_info
,
283 trans_pcie
->ctxt_info_dma_addr
);
284 trans_pcie
->ctxt_info_dma_addr
= 0;
285 trans_pcie
->ctxt_info
= NULL
;
287 iwl_pcie_ctxt_info_free_fw_img(trans
);