hal.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. /*
  2. * Intel Wireless Multicomm 3200 WiFi driver
  3. *
  4. * Copyright (C) 2009 Intel Corporation. All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * * Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * * Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in
  14. * the documentation and/or other materials provided with the
  15. * distribution.
  16. * * Neither the name of Intel Corporation nor the names of its
  17. * contributors may be used to endorse or promote products derived
  18. * from this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. *
  32. *
  33. * Intel Corporation <ilw@linux.intel.com>
  34. * Samuel Ortiz <samuel.ortiz@intel.com>
  35. * Zhu Yi <yi.zhu@intel.com>
  36. *
  37. */
  38. /*
  39. * Hardware Abstraction Layer for iwm.
  40. *
  41. * This file mostly defines an abstraction API for
  42. * sending various commands to the target.
  43. *
  44. * We have 2 types of commands: wifi and non-wifi ones.
  45. *
  46. * - wifi commands:
  47. * They are used for sending LMAC and UMAC commands,
  48. * and thus are the most commonly used ones.
  49. * There are 2 different wifi command types, the regular
  50. * one and the LMAC one. The former is used to send
  51. * UMAC commands (see UMAC_CMD_OPCODE_* from umac.h)
  52. * while the latter is used for sending commands to the
  53. * LMAC. If you look at LMAC commands you'll se that they
  54. * are actually regular iwlwifi target commands encapsulated
  55. * into a special UMAC command called UMAC passthrough.
  56. * This is due to the fact the the host talks exclusively
  57. * to the UMAC and so there needs to be a special UMAC
  58. * command for talking to the LMAC.
  59. * This is how a wifi command is layed out:
  60. * ------------------------
  61. * | iwm_udma_out_wifi_hdr |
  62. * ------------------------
  63. * | SW meta_data (32 bits) |
  64. * ------------------------
  65. * | iwm_dev_cmd_hdr |
  66. * ------------------------
  67. * | payload |
  68. * | .... |
  69. *
  70. * - non-wifi, or general commands:
  71. * Those commands are handled by the device's bootrom,
  72. * and are typically sent when the UMAC and the LMAC
  73. * are not yet available.
  74. * * This is how a non-wifi command is layed out:
  75. * ---------------------------
  76. * | iwm_udma_out_nonwifi_hdr |
  77. * ---------------------------
  78. * | payload |
  79. * | .... |
  80. *
  81. * All the commands start with a UDMA header, which is
  82. * basically a 32 bits field. The 4 LSB there define
  83. * an opcode that allows the target to differentiate
  84. * between wifi (opcode is 0xf) and non-wifi commands
  85. * (opcode is [0..0xe]).
  86. *
  87. * When a command (wifi or non-wifi) is supposed to receive
  88. * an answer, we queue the command buffer. When we do receive
  89. * a command response from the UMAC, we go through the list
  90. * of pending command, and pass both the command and the answer
  91. * to the rx handler. Each command is sent with a unique
  92. * sequence id, and the answer is sent with the same one. This
  93. * is how we're supposed to match an answer with its command.
  94. * See rx.c:iwm_rx_handle_[non]wifi() and iwm_get_pending_[non]wifi()
  95. * for the implementation details.
  96. */
  97. #include <linux/kernel.h>
  98. #include <linux/netdevice.h>
  99. #include <linux/slab.h>
  100. #include "iwm.h"
  101. #include "bus.h"
  102. #include "hal.h"
  103. #include "umac.h"
  104. #include "debug.h"
  105. static int iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
  106. struct iwm_nonwifi_cmd *cmd,
  107. struct iwm_udma_nonwifi_cmd *udma_cmd)
  108. {
  109. INIT_LIST_HEAD(&cmd->pending);
  110. spin_lock(&iwm->cmd_lock);
  111. cmd->resp_received = 0;
  112. cmd->seq_num = iwm->nonwifi_seq_num;
  113. udma_cmd->seq_num = cpu_to_le16(cmd->seq_num);
  114. iwm->nonwifi_seq_num++;
  115. iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX;
  116. if (udma_cmd->resp)
  117. list_add_tail(&cmd->pending, &iwm->nonwifi_pending_cmd);
  118. spin_unlock(&iwm->cmd_lock);
  119. cmd->buf.start = cmd->buf.payload;
  120. cmd->buf.len = 0;
  121. memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd));
  122. return cmd->seq_num;
  123. }
  124. u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm)
  125. {
  126. u16 seq_num = iwm->wifi_seq_num;
  127. iwm->wifi_seq_num++;
  128. iwm->wifi_seq_num %= UMAC_WIFI_SEQ_NUM_MAX;
  129. return seq_num;
  130. }
  131. static void iwm_wifi_cmd_init(struct iwm_priv *iwm,
  132. struct iwm_wifi_cmd *cmd,
  133. struct iwm_udma_wifi_cmd *udma_cmd,
  134. struct iwm_umac_cmd *umac_cmd,
  135. struct iwm_lmac_cmd *lmac_cmd,
  136. u16 payload_size)
  137. {
  138. INIT_LIST_HEAD(&cmd->pending);
  139. spin_lock(&iwm->cmd_lock);
  140. cmd->seq_num = iwm_alloc_wifi_cmd_seq(iwm);
  141. umac_cmd->seq_num = cpu_to_le16(cmd->seq_num);
  142. if (umac_cmd->resp)
  143. list_add_tail(&cmd->pending, &iwm->wifi_pending_cmd);
  144. spin_unlock(&iwm->cmd_lock);
  145. cmd->buf.start = cmd->buf.payload;
  146. cmd->buf.len = 0;
  147. if (lmac_cmd) {
  148. cmd->buf.start -= sizeof(struct iwm_lmac_hdr);
  149. lmac_cmd->seq_num = cpu_to_le16(cmd->seq_num);
  150. lmac_cmd->count = cpu_to_le16(payload_size);
  151. memcpy(&cmd->lmac_cmd, lmac_cmd, sizeof(*lmac_cmd));
  152. umac_cmd->count = cpu_to_le16(sizeof(struct iwm_lmac_hdr));
  153. } else
  154. umac_cmd->count = 0;
  155. umac_cmd->count = cpu_to_le16(payload_size +
  156. le16_to_cpu(umac_cmd->count));
  157. udma_cmd->count = cpu_to_le16(sizeof(struct iwm_umac_fw_cmd_hdr) +
  158. le16_to_cpu(umac_cmd->count));
  159. memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd));
  160. memcpy(&cmd->umac_cmd, umac_cmd, sizeof(*umac_cmd));
  161. }
  162. void iwm_cmd_flush(struct iwm_priv *iwm)
  163. {
  164. struct iwm_wifi_cmd *wcmd, *wnext;
  165. struct iwm_nonwifi_cmd *nwcmd, *nwnext;
  166. list_for_each_entry_safe(wcmd, wnext, &iwm->wifi_pending_cmd, pending) {
  167. list_del(&wcmd->pending);
  168. kfree(wcmd);
  169. }
  170. list_for_each_entry_safe(nwcmd, nwnext, &iwm->nonwifi_pending_cmd,
  171. pending) {
  172. list_del(&nwcmd->pending);
  173. kfree(nwcmd);
  174. }
  175. }
  176. struct iwm_wifi_cmd *iwm_get_pending_wifi_cmd(struct iwm_priv *iwm, u16 seq_num)
  177. {
  178. struct iwm_wifi_cmd *cmd, *next;
  179. list_for_each_entry_safe(cmd, next, &iwm->wifi_pending_cmd, pending)
  180. if (cmd->seq_num == seq_num) {
  181. list_del(&cmd->pending);
  182. return cmd;
  183. }
  184. return NULL;
  185. }
  186. struct iwm_nonwifi_cmd *
  187. iwm_get_pending_nonwifi_cmd(struct iwm_priv *iwm, u8 seq_num, u8 cmd_opcode)
  188. {
  189. struct iwm_nonwifi_cmd *cmd, *next;
  190. list_for_each_entry_safe(cmd, next, &iwm->nonwifi_pending_cmd, pending)
  191. if ((cmd->seq_num == seq_num) &&
  192. (cmd->udma_cmd.opcode == cmd_opcode) &&
  193. (cmd->resp_received)) {
  194. list_del(&cmd->pending);
  195. return cmd;
  196. }
  197. return NULL;
  198. }
  199. static void iwm_build_udma_nonwifi_hdr(struct iwm_priv *iwm,
  200. struct iwm_udma_out_nonwifi_hdr *hdr,
  201. struct iwm_udma_nonwifi_cmd *cmd)
  202. {
  203. memset(hdr, 0, sizeof(*hdr));
  204. SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE, cmd->opcode);
  205. SET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_RESP, cmd->resp);
  206. SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, 1);
  207. SET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW,
  208. cmd->handle_by_hw);
  209. SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_SIGNATURE, UMAC_HDI_OUT_SIGNATURE);
  210. SET_VAL32(hdr->cmd, UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM,
  211. le16_to_cpu(cmd->seq_num));
  212. hdr->addr = cmd->addr;
  213. hdr->op1_sz = cmd->op1_sz;
  214. hdr->op2 = cmd->op2;
  215. }
  216. static int iwm_send_udma_nonwifi_cmd(struct iwm_priv *iwm,
  217. struct iwm_nonwifi_cmd *cmd)
  218. {
  219. struct iwm_udma_out_nonwifi_hdr *udma_hdr;
  220. struct iwm_nonwifi_cmd_buff *buf;
  221. struct iwm_udma_nonwifi_cmd *udma_cmd = &cmd->udma_cmd;
  222. buf = &cmd->buf;
  223. buf->start -= sizeof(struct iwm_umac_nonwifi_out_hdr);
  224. buf->len += sizeof(struct iwm_umac_nonwifi_out_hdr);
  225. udma_hdr = (struct iwm_udma_out_nonwifi_hdr *)(buf->start);
  226. iwm_build_udma_nonwifi_hdr(iwm, udma_hdr, udma_cmd);
  227. IWM_DBG_CMD(iwm, DBG,
  228. "Send UDMA nonwifi cmd: opcode = 0x%x, resp = 0x%x, "
  229. "hw = 0x%x, seqnum = %d, addr = 0x%x, op1_sz = 0x%x, "
  230. "op2 = 0x%x\n", udma_cmd->opcode, udma_cmd->resp,
  231. udma_cmd->handle_by_hw, cmd->seq_num, udma_cmd->addr,
  232. udma_cmd->op1_sz, udma_cmd->op2);
  233. return iwm_bus_send_chunk(iwm, buf->start, buf->len);
  234. }
  235. void iwm_udma_wifi_hdr_set_eop(struct iwm_priv *iwm, u8 *buf, u8 eop)
  236. {
  237. struct iwm_udma_out_wifi_hdr *hdr = (struct iwm_udma_out_wifi_hdr *)buf;
  238. SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, eop);
  239. }
  240. void iwm_build_udma_wifi_hdr(struct iwm_priv *iwm,
  241. struct iwm_udma_out_wifi_hdr *hdr,
  242. struct iwm_udma_wifi_cmd *cmd)
  243. {
  244. memset(hdr, 0, sizeof(*hdr));
  245. SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE, UMAC_HDI_OUT_OPCODE_WIFI);
  246. SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, cmd->eop);
  247. SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_SIGNATURE, UMAC_HDI_OUT_SIGNATURE);
  248. SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_BYTE_COUNT,
  249. le16_to_cpu(cmd->count));
  250. SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_CREDIT_GRP, cmd->credit_group);
  251. SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_RATID, cmd->ra_tid);
  252. SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_LMAC_OFFSET, cmd->lmac_offset);
  253. }
  254. void iwm_build_umac_hdr(struct iwm_priv *iwm,
  255. struct iwm_umac_fw_cmd_hdr *hdr,
  256. struct iwm_umac_cmd *cmd)
  257. {
  258. memset(hdr, 0, sizeof(*hdr));
  259. SET_VAL32(hdr->meta_data, UMAC_FW_CMD_BYTE_COUNT,
  260. le16_to_cpu(cmd->count));
  261. SET_VAL32(hdr->meta_data, UMAC_FW_CMD_TX_STA_COLOR, cmd->color);
  262. SET_VAL8(hdr->cmd.flags, UMAC_DEV_CMD_FLAGS_RESP_REQ, cmd->resp);
  263. hdr->cmd.cmd = cmd->id;
  264. hdr->cmd.seq_num = cmd->seq_num;
  265. }
  266. static int iwm_send_udma_wifi_cmd(struct iwm_priv *iwm,
  267. struct iwm_wifi_cmd *cmd)
  268. {
  269. struct iwm_umac_wifi_out_hdr *umac_hdr;
  270. struct iwm_wifi_cmd_buff *buf;
  271. struct iwm_udma_wifi_cmd *udma_cmd = &cmd->udma_cmd;
  272. struct iwm_umac_cmd *umac_cmd = &cmd->umac_cmd;
  273. int ret;
  274. buf = &cmd->buf;
  275. buf->start -= sizeof(struct iwm_umac_wifi_out_hdr);
  276. buf->len += sizeof(struct iwm_umac_wifi_out_hdr);
  277. umac_hdr = (struct iwm_umac_wifi_out_hdr *)(buf->start);
  278. iwm_build_udma_wifi_hdr(iwm, &umac_hdr->hw_hdr, udma_cmd);
  279. iwm_build_umac_hdr(iwm, &umac_hdr->sw_hdr, umac_cmd);
  280. IWM_DBG_CMD(iwm, DBG,
  281. "Send UDMA wifi cmd: opcode = 0x%x, UMAC opcode = 0x%x, "
  282. "eop = 0x%x, count = 0x%x, credit_group = 0x%x, "
  283. "ra_tid = 0x%x, lmac_offset = 0x%x, seqnum = %d\n",
  284. UMAC_HDI_OUT_OPCODE_WIFI, umac_cmd->id,
  285. udma_cmd->eop, udma_cmd->count, udma_cmd->credit_group,
  286. udma_cmd->ra_tid, udma_cmd->lmac_offset, cmd->seq_num);
  287. if (umac_cmd->id == UMAC_CMD_OPCODE_WIFI_PASS_THROUGH)
  288. IWM_DBG_CMD(iwm, DBG, "\tLMAC opcode: 0x%x\n",
  289. cmd->lmac_cmd.id);
  290. ret = iwm_tx_credit_alloc(iwm, udma_cmd->credit_group, buf->len);
  291. /* We keep sending UMAC reset regardless of the command credits.
  292. * The UMAC is supposed to be reset anyway and the Tx credits are
  293. * reinitialized afterwards. If we are lucky, the reset could
  294. * still be done even though we have run out of credits for the
  295. * command pool at this moment.*/
  296. if (ret && (umac_cmd->id != UMAC_CMD_OPCODE_RESET)) {
  297. IWM_DBG_TX(iwm, DBG, "Failed to alloc tx credit for cmd %d\n",
  298. umac_cmd->id);
  299. return ret;
  300. }
  301. return iwm_bus_send_chunk(iwm, buf->start, buf->len);
  302. }
  303. /* target_cmd a.k.a udma_nonwifi_cmd can be sent when UMAC is not available */
  304. int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
  305. struct iwm_udma_nonwifi_cmd *udma_cmd,
  306. const void *payload)
  307. {
  308. struct iwm_nonwifi_cmd *cmd;
  309. int ret, seq_num;
  310. cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL);
  311. if (!cmd) {
  312. IWM_ERR(iwm, "Couldn't alloc memory for hal cmd\n");
  313. return -ENOMEM;
  314. }
  315. seq_num = iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd);
  316. if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE ||
  317. cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) {
  318. cmd->buf.len = le32_to_cpu(cmd->udma_cmd.op1_sz);
  319. memcpy(&cmd->buf.payload, payload, cmd->buf.len);
  320. }
  321. ret = iwm_send_udma_nonwifi_cmd(iwm, cmd);
  322. if (!udma_cmd->resp)
  323. kfree(cmd);
  324. if (ret < 0)
  325. return ret;
  326. return seq_num;
  327. }
  328. static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr,
  329. struct iwm_lmac_cmd *cmd)
  330. {
  331. memset(hdr, 0, sizeof(*hdr));
  332. hdr->id = cmd->id;
  333. hdr->flags = 0; /* Is this ever used? */
  334. hdr->seq_num = cmd->seq_num;
  335. }
  336. /*
  337. * iwm_hal_send_host_cmd(): sends commands to the UMAC or the LMAC.
  338. * Sending command to the LMAC is equivalent to sending a
  339. * regular UMAC command with the LMAC passthrough or the LMAC
  340. * wrapper UMAC command IDs.
  341. */
  342. int iwm_hal_send_host_cmd(struct iwm_priv *iwm,
  343. struct iwm_udma_wifi_cmd *udma_cmd,
  344. struct iwm_umac_cmd *umac_cmd,
  345. struct iwm_lmac_cmd *lmac_cmd,
  346. const void *payload, u16 payload_size)
  347. {
  348. struct iwm_wifi_cmd *cmd;
  349. struct iwm_lmac_hdr *hdr;
  350. int lmac_hdr_len = 0;
  351. int ret;
  352. cmd = kzalloc(sizeof(struct iwm_wifi_cmd), GFP_KERNEL);
  353. if (!cmd) {
  354. IWM_ERR(iwm, "Couldn't alloc memory for wifi hal cmd\n");
  355. return -ENOMEM;
  356. }
  357. iwm_wifi_cmd_init(iwm, cmd, udma_cmd, umac_cmd, lmac_cmd, payload_size);
  358. if (lmac_cmd) {
  359. hdr = (struct iwm_lmac_hdr *)(cmd->buf.start);
  360. iwm_build_lmac_hdr(iwm, hdr, &cmd->lmac_cmd);
  361. lmac_hdr_len = sizeof(struct iwm_lmac_hdr);
  362. }
  363. memcpy(cmd->buf.payload, payload, payload_size);
  364. cmd->buf.len = le16_to_cpu(umac_cmd->count);
  365. ret = iwm_send_udma_wifi_cmd(iwm, cmd);
  366. /* We free the cmd if we're not expecting any response */
  367. if (!umac_cmd->resp)
  368. kfree(cmd);
  369. return ret;
  370. }
  371. /*
  372. * iwm_hal_send_umac_cmd(): This is a special case for
  373. * iwm_hal_send_host_cmd() to send direct UMAC cmd (without
  374. * LMAC involved).
  375. */
  376. int iwm_hal_send_umac_cmd(struct iwm_priv *iwm,
  377. struct iwm_udma_wifi_cmd *udma_cmd,
  378. struct iwm_umac_cmd *umac_cmd,
  379. const void *payload, u16 payload_size)
  380. {
  381. return iwm_hal_send_host_cmd(iwm, udma_cmd, umac_cmd, NULL,
  382. payload, payload_size);
  383. }