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 * 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. 13 * 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. 18 * 19 * BSD LICENSE 20 * 21 * Copyright(c) 2017 Intel Deutschland GmbH 22 * All rights reserved. 23 * 24 * Redistribution and use in source and binary forms, with or without 25 * modification, are permitted provided that the following conditions 26 * are met: 27 * 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 33 * distribution. 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. 37 * 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. 49 * 50 *****************************************************************************/ 51 52 #include "iwl-trans.h" 53 #include "iwl-fh.h" 54 #include "iwl-context-info.h" 55 #include "internal.h" 56 #include "iwl-prph.h" 57 58 static int iwl_pcie_get_num_sections(const struct fw_img *fw, 59 int start) 60 { 61 int i = 0; 62 63 while (start < fw->num_sec && 64 fw->sec[start].offset != CPU1_CPU2_SEPARATOR_SECTION && 65 fw->sec[start].offset != PAGING_SEPARATOR_SECTION) { 66 start++; 67 i++; 68 } 69 70 return i; 71 } 72 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) 76 { 77 dram->block = dma_alloc_coherent(trans->dev, sec->len, 78 &dram->physical, 79 GFP_KERNEL); 80 if (!dram->block) 81 return -ENOMEM; 82 83 dram->size = sec->len; 84 memcpy(dram->block, sec->data, sec->len); 85 86 return 0; 87 } 88 89 static void iwl_pcie_ctxt_info_free_fw_img(struct iwl_trans *trans) 90 { 91 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 92 struct iwl_self_init_dram *dram = &trans_pcie->init_dram; 93 int i; 94 95 if (!dram->fw) { 96 WARN_ON(dram->fw_cnt); 97 return; 98 } 99 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); 103 104 kfree(dram->fw); 105 dram->fw_cnt = 0; 106 dram->fw = NULL; 107 } 108 109 void iwl_pcie_ctxt_info_free_paging(struct iwl_trans *trans) 110 { 111 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 112 struct iwl_self_init_dram *dram = &trans_pcie->init_dram; 113 int i; 114 115 if (!dram->paging) { 116 WARN_ON(dram->paging_cnt); 117 return; 118 } 119 120 /* free paging*/ 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); 125 126 kfree(dram->paging); 127 dram->paging_cnt = 0; 128 dram->paging = NULL; 129 } 130 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) 134 { 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; 139 140 if (WARN(dram->paging, 141 "paging shouldn't already be initialized (%d pages)\n", 142 dram->paging_cnt)) 143 iwl_pcie_ctxt_info_free_paging(trans); 144 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); 150 151 dram->fw = kcalloc(umac_cnt + lmac_cnt, sizeof(*dram->fw), GFP_KERNEL); 152 if (!dram->fw) 153 return -ENOMEM; 154 dram->paging = kcalloc(paging_cnt, sizeof(*dram->paging), GFP_KERNEL); 155 if (!dram->paging) 156 return -ENOMEM; 157 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]); 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], 174 &dram->fw[dram->fw_cnt]); 175 if (ret) 176 return ret; 177 ctxt_dram->umac_img[i] = 178 cpu_to_le64(dram->fw[dram->fw_cnt].physical); 179 dram->fw_cnt++; 180 } 181 182 /* 183 * Initialize paging. 184 * Paging memory isn't stored in dram->fw as the umac and lmac - it is 185 * stored separately. 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. 191 */ 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; 195 196 ret = iwl_pcie_ctxt_info_alloc_dma(trans, &fw->sec[fw_idx], 197 &dram->paging[i]); 198 if (ret) 199 return ret; 200 201 ctxt_dram->virtual_img[i] = 202 cpu_to_le64(dram->paging[i].physical); 203 dram->paging_cnt++; 204 } 205 206 return 0; 207 } 208 209 int iwl_pcie_ctxt_info_init(struct iwl_trans *trans, 210 const struct fw_img *fw) 211 { 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; 216 int ret; 217 218 ctxt_info = dma_alloc_coherent(trans->dev, sizeof(*ctxt_info), 219 &trans_pcie->ctxt_info_dma_addr, 220 GFP_KERNEL); 221 if (!ctxt_info) 222 return -ENOMEM; 223 224 ctxt_info->version.version = 0; 225 ctxt_info->version.mac_id = 226 cpu_to_le16((u16)iwl_read32(trans, CSR_HW_REV)); 227 /* size is in DWs */ 228 ctxt_info->version.size = cpu_to_le16(sizeof(*ctxt_info) / 4); 229 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); 236 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); 242 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); 248 249 /* allocate ucode sections in dram and set addresses */ 250 ret = iwl_pcie_ctxt_info_init_fw_sec(trans, fw, ctxt_info); 251 if (ret) { 252 dma_free_coherent(trans->dev, sizeof(*trans_pcie->ctxt_info), 253 ctxt_info, trans_pcie->ctxt_info_dma_addr); 254 return ret; 255 } 256 257 trans_pcie->ctxt_info = ctxt_info; 258 259 iwl_enable_interrupts(trans); 260 261 /* Configure debug, if exists */ 262 if (trans->dbg_dest_tlv) 263 iwl_pcie_apply_destination(trans); 264 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); 268 269 /* Context info will be released upon alive or failure to get one */ 270 271 return 0; 272 } 273 274 void iwl_pcie_ctxt_info_free(struct iwl_trans *trans) 275 { 276 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 277 278 if (!trans_pcie->ctxt_info) 279 return; 280 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; 286 287 iwl_pcie_ctxt_info_free_fw_img(trans); 288 } 289