paging.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  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) 2012 - 2014 Intel Corporation. All rights reserved.
  9. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  10. * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
  11. * Copyright(c) 2018 Intel Corporation
  12. *
  13. * This program is free software; you can redistribute it and/or modify
  14. * it under the terms of version 2 of the GNU General Public License as
  15. * published by the Free Software Foundation.
  16. *
  17. * This program is distributed in the hope that it will be useful, but
  18. * WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  20. * General Public License for more details.
  21. *
  22. * The full GNU General Public License is included in this distribution
  23. * in the file called COPYING.
  24. *
  25. * Contact Information:
  26. * Intel Linux Wireless <linuxwifi@intel.com>
  27. * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  28. *
  29. * BSD LICENSE
  30. *
  31. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  32. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  33. * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
  34. * Copyright(c) 2018 Intel Corporation
  35. * All rights reserved.
  36. *
  37. * Redistribution and use in source and binary forms, with or without
  38. * modification, are permitted provided that the following conditions
  39. * are met:
  40. *
  41. * * Redistributions of source code must retain the above copyright
  42. * notice, this list of conditions and the following disclaimer.
  43. * * Redistributions in binary form must reproduce the above copyright
  44. * notice, this list of conditions and the following disclaimer in
  45. * the documentation and/or other materials provided with the
  46. * distribution.
  47. * * Neither the name Intel Corporation nor the names of its
  48. * contributors may be used to endorse or promote products derived
  49. * from this software without specific prior written permission.
  50. *
  51. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  52. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  53. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  54. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  55. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  56. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  57. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  58. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  59. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  60. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  61. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  62. *
  63. *****************************************************************************/
  64. #include "iwl-drv.h"
  65. #include "runtime.h"
  66. #include "fw/api/commands.h"
  67. void iwl_free_fw_paging(struct iwl_fw_runtime *fwrt)
  68. {
  69. int i;
  70. if (!fwrt->fw_paging_db[0].fw_paging_block)
  71. return;
  72. for (i = 0; i < NUM_OF_FW_PAGING_BLOCKS; i++) {
  73. struct iwl_fw_paging *paging = &fwrt->fw_paging_db[i];
  74. if (!paging->fw_paging_block) {
  75. IWL_DEBUG_FW(fwrt,
  76. "Paging: block %d already freed, continue to next page\n",
  77. i);
  78. continue;
  79. }
  80. dma_unmap_page(fwrt->trans->dev, paging->fw_paging_phys,
  81. paging->fw_paging_size, DMA_BIDIRECTIONAL);
  82. __free_pages(paging->fw_paging_block,
  83. get_order(paging->fw_paging_size));
  84. paging->fw_paging_block = NULL;
  85. }
  86. memset(fwrt->fw_paging_db, 0, sizeof(fwrt->fw_paging_db));
  87. }
  88. IWL_EXPORT_SYMBOL(iwl_free_fw_paging);
  89. static int iwl_alloc_fw_paging_mem(struct iwl_fw_runtime *fwrt,
  90. const struct fw_img *image)
  91. {
  92. struct page *block;
  93. dma_addr_t phys = 0;
  94. int blk_idx, order, num_of_pages, size;
  95. if (fwrt->fw_paging_db[0].fw_paging_block)
  96. return 0;
  97. /* ensure BLOCK_2_EXP_SIZE is power of 2 of PAGING_BLOCK_SIZE */
  98. BUILD_BUG_ON(BIT(BLOCK_2_EXP_SIZE) != PAGING_BLOCK_SIZE);
  99. num_of_pages = image->paging_mem_size / FW_PAGING_SIZE;
  100. fwrt->num_of_paging_blk =
  101. DIV_ROUND_UP(num_of_pages, NUM_OF_PAGE_PER_GROUP);
  102. fwrt->num_of_pages_in_last_blk =
  103. num_of_pages -
  104. NUM_OF_PAGE_PER_GROUP * (fwrt->num_of_paging_blk - 1);
  105. IWL_DEBUG_FW(fwrt,
  106. "Paging: allocating mem for %d paging blocks, each block holds 8 pages, last block holds %d pages\n",
  107. fwrt->num_of_paging_blk,
  108. fwrt->num_of_pages_in_last_blk);
  109. /*
  110. * Allocate CSS and paging blocks in dram.
  111. */
  112. for (blk_idx = 0; blk_idx < fwrt->num_of_paging_blk + 1; blk_idx++) {
  113. /* For CSS allocate 4KB, for others PAGING_BLOCK_SIZE (32K) */
  114. size = blk_idx ? PAGING_BLOCK_SIZE : FW_PAGING_SIZE;
  115. order = get_order(size);
  116. block = alloc_pages(GFP_KERNEL, order);
  117. if (!block) {
  118. /* free all the previous pages since we failed */
  119. iwl_free_fw_paging(fwrt);
  120. return -ENOMEM;
  121. }
  122. fwrt->fw_paging_db[blk_idx].fw_paging_block = block;
  123. fwrt->fw_paging_db[blk_idx].fw_paging_size = size;
  124. phys = dma_map_page(fwrt->trans->dev, block, 0,
  125. PAGE_SIZE << order,
  126. DMA_BIDIRECTIONAL);
  127. if (dma_mapping_error(fwrt->trans->dev, phys)) {
  128. /*
  129. * free the previous pages and the current one
  130. * since we failed to map_page.
  131. */
  132. iwl_free_fw_paging(fwrt);
  133. return -ENOMEM;
  134. }
  135. fwrt->fw_paging_db[blk_idx].fw_paging_phys = phys;
  136. if (!blk_idx)
  137. IWL_DEBUG_FW(fwrt,
  138. "Paging: allocated 4K(CSS) bytes (order %d) for firmware paging.\n",
  139. order);
  140. else
  141. IWL_DEBUG_FW(fwrt,
  142. "Paging: allocated 32K bytes (order %d) for firmware paging.\n",
  143. order);
  144. }
  145. return 0;
  146. }
  147. static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt,
  148. const struct fw_img *image)
  149. {
  150. int sec_idx, idx, ret;
  151. u32 offset = 0;
  152. /*
  153. * find where is the paging image start point:
  154. * if CPU2 exist and it's in paging format, then the image looks like:
  155. * CPU1 sections (2 or more)
  156. * CPU1_CPU2_SEPARATOR_SECTION delimiter - separate between CPU1 to CPU2
  157. * CPU2 sections (not paged)
  158. * PAGING_SEPARATOR_SECTION delimiter - separate between CPU2
  159. * non paged to CPU2 paging sec
  160. * CPU2 paging CSS
  161. * CPU2 paging image (including instruction and data)
  162. */
  163. for (sec_idx = 0; sec_idx < image->num_sec; sec_idx++) {
  164. if (image->sec[sec_idx].offset == PAGING_SEPARATOR_SECTION) {
  165. sec_idx++;
  166. break;
  167. }
  168. }
  169. /*
  170. * If paging is enabled there should be at least 2 more sections left
  171. * (one for CSS and one for Paging data)
  172. */
  173. if (sec_idx >= image->num_sec - 1) {
  174. IWL_ERR(fwrt, "Paging: Missing CSS and/or paging sections\n");
  175. ret = -EINVAL;
  176. goto err;
  177. }
  178. /* copy the CSS block to the dram */
  179. IWL_DEBUG_FW(fwrt, "Paging: load paging CSS to FW, sec = %d\n",
  180. sec_idx);
  181. if (image->sec[sec_idx].len > fwrt->fw_paging_db[0].fw_paging_size) {
  182. IWL_ERR(fwrt, "CSS block is larger than paging size\n");
  183. ret = -EINVAL;
  184. goto err;
  185. }
  186. memcpy(page_address(fwrt->fw_paging_db[0].fw_paging_block),
  187. image->sec[sec_idx].data,
  188. image->sec[sec_idx].len);
  189. dma_sync_single_for_device(fwrt->trans->dev,
  190. fwrt->fw_paging_db[0].fw_paging_phys,
  191. fwrt->fw_paging_db[0].fw_paging_size,
  192. DMA_BIDIRECTIONAL);
  193. IWL_DEBUG_FW(fwrt,
  194. "Paging: copied %d CSS bytes to first block\n",
  195. fwrt->fw_paging_db[0].fw_paging_size);
  196. sec_idx++;
  197. /*
  198. * Copy the paging blocks to the dram. The loop index starts
  199. * from 1 since the CSS block (index 0) was already copied to
  200. * dram. We use num_of_paging_blk + 1 to account for that.
  201. */
  202. for (idx = 1; idx < fwrt->num_of_paging_blk + 1; idx++) {
  203. struct iwl_fw_paging *block = &fwrt->fw_paging_db[idx];
  204. int remaining = image->sec[sec_idx].len - offset;
  205. int len = block->fw_paging_size;
  206. /*
  207. * For the last block, we copy all that is remaining,
  208. * for all other blocks, we copy fw_paging_size at a
  209. * time. */
  210. if (idx == fwrt->num_of_paging_blk) {
  211. len = remaining;
  212. if (remaining !=
  213. fwrt->num_of_pages_in_last_blk * FW_PAGING_SIZE) {
  214. IWL_ERR(fwrt,
  215. "Paging: last block contains more data than expected %d\n",
  216. remaining);
  217. ret = -EINVAL;
  218. goto err;
  219. }
  220. } else if (block->fw_paging_size > remaining) {
  221. IWL_ERR(fwrt,
  222. "Paging: not enough data in other in block %d (%d)\n",
  223. idx, remaining);
  224. ret = -EINVAL;
  225. goto err;
  226. }
  227. memcpy(page_address(block->fw_paging_block),
  228. image->sec[sec_idx].data + offset, len);
  229. dma_sync_single_for_device(fwrt->trans->dev,
  230. block->fw_paging_phys,
  231. block->fw_paging_size,
  232. DMA_BIDIRECTIONAL);
  233. IWL_DEBUG_FW(fwrt,
  234. "Paging: copied %d paging bytes to block %d\n",
  235. len, idx);
  236. offset += block->fw_paging_size;
  237. }
  238. return 0;
  239. err:
  240. iwl_free_fw_paging(fwrt);
  241. return ret;
  242. }
  243. static int iwl_save_fw_paging(struct iwl_fw_runtime *fwrt,
  244. const struct fw_img *fw)
  245. {
  246. int ret;
  247. ret = iwl_alloc_fw_paging_mem(fwrt, fw);
  248. if (ret)
  249. return ret;
  250. return iwl_fill_paging_mem(fwrt, fw);
  251. }
  252. /* send paging cmd to FW in case CPU2 has paging image */
  253. static int iwl_send_paging_cmd(struct iwl_fw_runtime *fwrt,
  254. const struct fw_img *fw)
  255. {
  256. struct iwl_fw_paging_cmd paging_cmd = {
  257. .flags = cpu_to_le32(PAGING_CMD_IS_SECURED |
  258. PAGING_CMD_IS_ENABLED |
  259. (fwrt->num_of_pages_in_last_blk <<
  260. PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS)),
  261. .block_size = cpu_to_le32(BLOCK_2_EXP_SIZE),
  262. .block_num = cpu_to_le32(fwrt->num_of_paging_blk),
  263. };
  264. struct iwl_host_cmd hcmd = {
  265. .id = iwl_cmd_id(FW_PAGING_BLOCK_CMD, IWL_ALWAYS_LONG_GROUP, 0),
  266. .len = { sizeof(paging_cmd), },
  267. .data = { &paging_cmd, },
  268. };
  269. int blk_idx;
  270. /* loop for for all paging blocks + CSS block */
  271. for (blk_idx = 0; blk_idx < fwrt->num_of_paging_blk + 1; blk_idx++) {
  272. dma_addr_t addr = fwrt->fw_paging_db[blk_idx].fw_paging_phys;
  273. __le32 phy_addr;
  274. addr = addr >> PAGE_2_EXP_SIZE;
  275. phy_addr = cpu_to_le32(addr);
  276. paging_cmd.device_phy_addr[blk_idx] = phy_addr;
  277. }
  278. return iwl_trans_send_cmd(fwrt->trans, &hcmd);
  279. }
  280. int iwl_init_paging(struct iwl_fw_runtime *fwrt, enum iwl_ucode_type type)
  281. {
  282. const struct fw_img *fw = &fwrt->fw->img[type];
  283. int ret;
  284. if (fwrt->trans->cfg->gen2)
  285. return 0;
  286. /*
  287. * Configure and operate fw paging mechanism.
  288. * The driver configures the paging flow only once.
  289. * The CPU2 paging image is included in the IWL_UCODE_INIT image.
  290. */
  291. if (!fw->paging_mem_size)
  292. return 0;
  293. ret = iwl_save_fw_paging(fwrt, fw);
  294. if (ret) {
  295. IWL_ERR(fwrt, "failed to save the FW paging image\n");
  296. return ret;
  297. }
  298. ret = iwl_send_paging_cmd(fwrt, fw);
  299. if (ret) {
  300. IWL_ERR(fwrt, "failed to send the paging cmd\n");
  301. iwl_free_fw_paging(fwrt);
  302. return ret;
  303. }
  304. return 0;
  305. }
  306. IWL_EXPORT_SYMBOL(iwl_init_paging);