hal.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  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 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. #include "trace.h"
  106. static int iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
  107. struct iwm_nonwifi_cmd *cmd,
  108. struct iwm_udma_nonwifi_cmd *udma_cmd)
  109. {
  110. INIT_LIST_HEAD(&cmd->pending);
  111. spin_lock(&iwm->cmd_lock);
  112. cmd->resp_received = 0;
  113. cmd->seq_num = iwm->nonwifi_seq_num;
  114. udma_cmd->seq_num = cpu_to_le16(cmd->seq_num);
  115. iwm->nonwifi_seq_num++;
  116. iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX;
  117. if (udma_cmd->resp)
  118. list_add_tail(&cmd->pending, &iwm->nonwifi_pending_cmd);
  119. spin_unlock(&iwm->cmd_lock);
  120. cmd->buf.start = cmd->buf.payload;
  121. cmd->buf.len = 0;
  122. memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd));
  123. return cmd->seq_num;
  124. }
  125. u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm)
  126. {
  127. u16 seq_num = iwm->wifi_seq_num;
  128. iwm->wifi_seq_num++;
  129. iwm->wifi_seq_num %= UMAC_WIFI_SEQ_NUM_MAX;
  130. return seq_num;
  131. }
  132. static void iwm_wifi_cmd_init(struct iwm_priv *iwm,
  133. struct iwm_wifi_cmd *cmd,
  134. struct iwm_udma_wifi_cmd *udma_cmd,
  135. struct iwm_umac_cmd *umac_cmd,
  136. struct iwm_lmac_cmd *lmac_cmd,
  137. u16 payload_size)
  138. {
  139. INIT_LIST_HEAD(&cmd->pending);
  140. spin_lock(&iwm->cmd_lock);
  141. cmd->seq_num = iwm_alloc_wifi_cmd_seq(iwm);
  142. umac_cmd->seq_num = cpu_to_le16(cmd->seq_num);
  143. if (umac_cmd->resp)
  144. list_add_tail(&cmd->pending, &iwm->wifi_pending_cmd);
  145. spin_unlock(&iwm->cmd_lock);
  146. cmd->buf.start = cmd->buf.payload;
  147. cmd->buf.len = 0;
  148. if (lmac_cmd) {
  149. cmd->buf.start -= sizeof(struct iwm_lmac_hdr);
  150. lmac_cmd->seq_num = cpu_to_le16(cmd->seq_num);
  151. lmac_cmd->count = cpu_to_le16(payload_size);
  152. memcpy(&cmd->lmac_cmd, lmac_cmd, sizeof(*lmac_cmd));
  153. umac_cmd->count = cpu_to_le16(sizeof(struct iwm_lmac_hdr));
  154. } else
  155. umac_cmd->count = 0;
  156. umac_cmd->count = cpu_to_le16(payload_size +
  157. le16_to_cpu(umac_cmd->count));
  158. udma_cmd->count = cpu_to_le16(sizeof(struct iwm_umac_fw_cmd_hdr) +
  159. le16_to_cpu(umac_cmd->count));
  160. memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd));
  161. memcpy(&cmd->umac_cmd, umac_cmd, sizeof(*umac_cmd));
  162. }
  163. void iwm_cmd_flush(struct iwm_priv *iwm)
  164. {
  165. struct iwm_wifi_cmd *wcmd, *wnext;
  166. struct iwm_nonwifi_cmd *nwcmd, *nwnext;
  167. list_for_each_entry_safe(wcmd, wnext, &iwm->wifi_pending_cmd, pending) {
  168. list_del(&wcmd->pending);
  169. kfree(wcmd);
  170. }
  171. list_for_each_entry_safe(nwcmd, nwnext, &iwm->nonwifi_pending_cmd,
  172. pending) {
  173. list_del(&nwcmd->pending);
  174. kfree(nwcmd);
  175. }
  176. }
  177. struct iwm_wifi_cmd *iwm_get_pending_wifi_cmd(struct iwm_priv *iwm, u16 seq_num)
  178. {
  179. struct iwm_wifi_cmd *cmd;
  180. list_for_each_entry(cmd, &iwm->wifi_pending_cmd, pending)
  181. if (cmd->seq_num == seq_num) {
  182. list_del(&cmd->pending);
  183. return cmd;
  184. }
  185. return NULL;
  186. }
  187. struct iwm_nonwifi_cmd *iwm_get_pending_nonwifi_cmd(struct iwm_priv *iwm,
  188. u8 seq_num, u8 cmd_opcode)
  189. {
  190. struct iwm_nonwifi_cmd *cmd;
  191. list_for_each_entry(cmd, &iwm->nonwifi_pending_cmd, pending)
  192. if ((cmd->seq_num == seq_num) &&
  193. (cmd->udma_cmd.opcode == cmd_opcode) &&
  194. (cmd->resp_received)) {
  195. list_del(&cmd->pending);
  196. return cmd;
  197. }
  198. return NULL;
  199. }
  200. static void iwm_build_udma_nonwifi_hdr(struct iwm_priv *iwm,
  201. struct iwm_udma_out_nonwifi_hdr *hdr,
  202. struct iwm_udma_nonwifi_cmd *cmd)
  203. {
  204. memset(hdr, 0, sizeof(*hdr));
  205. SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE, cmd->opcode);
  206. SET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_RESP, cmd->resp);
  207. SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, 1);
  208. SET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW,
  209. cmd->handle_by_hw);
  210. SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_SIGNATURE, UMAC_HDI_OUT_SIGNATURE);
  211. SET_VAL32(hdr->cmd, UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM,
  212. le16_to_cpu(cmd->seq_num));
  213. hdr->addr = cmd->addr;
  214. hdr->op1_sz = cmd->op1_sz;
  215. hdr->op2 = cmd->op2;
  216. }
  217. static int iwm_send_udma_nonwifi_cmd(struct iwm_priv *iwm,
  218. struct iwm_nonwifi_cmd *cmd)
  219. {
  220. struct iwm_udma_out_nonwifi_hdr *udma_hdr;
  221. struct iwm_nonwifi_cmd_buff *buf;
  222. struct iwm_udma_nonwifi_cmd *udma_cmd = &cmd->udma_cmd;
  223. buf = &cmd->buf;
  224. buf->start -= sizeof(struct iwm_umac_nonwifi_out_hdr);
  225. buf->len += sizeof(struct iwm_umac_nonwifi_out_hdr);
  226. udma_hdr = (struct iwm_udma_out_nonwifi_hdr *)(buf->start);
  227. iwm_build_udma_nonwifi_hdr(iwm, udma_hdr, udma_cmd);
  228. IWM_DBG_CMD(iwm, DBG,
  229. "Send UDMA nonwifi cmd: opcode = 0x%x, resp = 0x%x, "
  230. "hw = 0x%x, seqnum = %d, addr = 0x%x, op1_sz = 0x%x, "
  231. "op2 = 0x%x\n", udma_cmd->opcode, udma_cmd->resp,
  232. udma_cmd->handle_by_hw, cmd->seq_num, udma_cmd->addr,
  233. udma_cmd->op1_sz, udma_cmd->op2);
  234. trace_iwm_tx_nonwifi_cmd(iwm, udma_hdr);
  235. return iwm_bus_send_chunk(iwm, buf->start, buf->len);
  236. }
  237. void iwm_udma_wifi_hdr_set_eop(struct iwm_priv *iwm, u8 *buf, u8 eop)
  238. {
  239. struct iwm_udma_out_wifi_hdr *hdr = (struct iwm_udma_out_wifi_hdr *)buf;
  240. SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, eop);
  241. }
  242. void iwm_build_udma_wifi_hdr(struct iwm_priv *iwm,
  243. struct iwm_udma_out_wifi_hdr *hdr,
  244. struct iwm_udma_wifi_cmd *cmd)
  245. {
  246. memset(hdr, 0, sizeof(*hdr));
  247. SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE, UMAC_HDI_OUT_OPCODE_WIFI);
  248. SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, cmd->eop);
  249. SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_SIGNATURE, UMAC_HDI_OUT_SIGNATURE);
  250. SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_BYTE_COUNT,
  251. le16_to_cpu(cmd->count));
  252. SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_CREDIT_GRP, cmd->credit_group);
  253. SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_RATID, cmd->ra_tid);
  254. SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_LMAC_OFFSET, cmd->lmac_offset);
  255. }
  256. void iwm_build_umac_hdr(struct iwm_priv *iwm,
  257. struct iwm_umac_fw_cmd_hdr *hdr,
  258. struct iwm_umac_cmd *cmd)
  259. {
  260. memset(hdr, 0, sizeof(*hdr));
  261. SET_VAL32(hdr->meta_data, UMAC_FW_CMD_BYTE_COUNT,
  262. le16_to_cpu(cmd->count));
  263. SET_VAL32(hdr->meta_data, UMAC_FW_CMD_TX_STA_COLOR, cmd->color);
  264. SET_VAL8(hdr->cmd.flags, UMAC_DEV_CMD_FLAGS_RESP_REQ, cmd->resp);
  265. hdr->cmd.cmd = cmd->id;
  266. hdr->cmd.seq_num = cmd->seq_num;
  267. }
  268. static int iwm_send_udma_wifi_cmd(struct iwm_priv *iwm,
  269. struct iwm_wifi_cmd *cmd)
  270. {
  271. struct iwm_umac_wifi_out_hdr *umac_hdr;
  272. struct iwm_wifi_cmd_buff *buf;
  273. struct iwm_udma_wifi_cmd *udma_cmd = &cmd->udma_cmd;
  274. struct iwm_umac_cmd *umac_cmd = &cmd->umac_cmd;
  275. int ret;
  276. buf = &cmd->buf;
  277. buf->start -= sizeof(struct iwm_umac_wifi_out_hdr);
  278. buf->len += sizeof(struct iwm_umac_wifi_out_hdr);
  279. umac_hdr = (struct iwm_umac_wifi_out_hdr *)(buf->start);
  280. iwm_build_udma_wifi_hdr(iwm, &umac_hdr->hw_hdr, udma_cmd);
  281. iwm_build_umac_hdr(iwm, &umac_hdr->sw_hdr, umac_cmd);
  282. IWM_DBG_CMD(iwm, DBG,
  283. "Send UDMA wifi cmd: opcode = 0x%x, UMAC opcode = 0x%x, "
  284. "eop = 0x%x, count = 0x%x, credit_group = 0x%x, "
  285. "ra_tid = 0x%x, lmac_offset = 0x%x, seqnum = %d\n",
  286. UMAC_HDI_OUT_OPCODE_WIFI, umac_cmd->id,
  287. udma_cmd->eop, udma_cmd->count, udma_cmd->credit_group,
  288. udma_cmd->ra_tid, udma_cmd->lmac_offset, cmd->seq_num);
  289. if (umac_cmd->id == UMAC_CMD_OPCODE_WIFI_PASS_THROUGH)
  290. IWM_DBG_CMD(iwm, DBG, "\tLMAC opcode: 0x%x\n",
  291. cmd->lmac_cmd.id);
  292. ret = iwm_tx_credit_alloc(iwm, udma_cmd->credit_group, buf->len);
  293. /* We keep sending UMAC reset regardless of the command credits.
  294. * The UMAC is supposed to be reset anyway and the Tx credits are
  295. * reinitialized afterwards. If we are lucky, the reset could
  296. * still be done even though we have run out of credits for the
  297. * command pool at this moment.*/
  298. if (ret && (umac_cmd->id != UMAC_CMD_OPCODE_RESET)) {
  299. IWM_DBG_TX(iwm, DBG, "Failed to alloc tx credit for cmd %d\n",
  300. umac_cmd->id);
  301. return ret;
  302. }
  303. trace_iwm_tx_wifi_cmd(iwm, umac_hdr);
  304. return iwm_bus_send_chunk(iwm, buf->start, buf->len);
  305. }
  306. /* target_cmd a.k.a udma_nonwifi_cmd can be sent when UMAC is not available */
  307. int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
  308. struct iwm_udma_nonwifi_cmd *udma_cmd,
  309. const void *payload)
  310. {
  311. struct iwm_nonwifi_cmd *cmd;
  312. int ret, seq_num;
  313. cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL);
  314. if (!cmd) {
  315. IWM_ERR(iwm, "Couldn't alloc memory for hal cmd\n");
  316. return -ENOMEM;
  317. }
  318. seq_num = iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd);
  319. if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE ||
  320. cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) {
  321. cmd->buf.len = le32_to_cpu(cmd->udma_cmd.op1_sz);
  322. memcpy(&cmd->buf.payload, payload, cmd->buf.len);
  323. }
  324. ret = iwm_send_udma_nonwifi_cmd(iwm, cmd);
  325. if (!udma_cmd->resp)
  326. kfree(cmd);
  327. if (ret < 0)
  328. return ret;
  329. return seq_num;
  330. }
  331. static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr,
  332. struct iwm_lmac_cmd *cmd)
  333. {
  334. memset(hdr, 0, sizeof(*hdr));
  335. hdr->id = cmd->id;
  336. hdr->flags = 0; /* Is this ever used? */
  337. hdr->seq_num = cmd->seq_num;
  338. }
  339. /*
  340. * iwm_hal_send_host_cmd(): sends commands to the UMAC or the LMAC.
  341. * Sending command to the LMAC is equivalent to sending a
  342. * regular UMAC command with the LMAC passthrough or the LMAC
  343. * wrapper UMAC command IDs.
  344. */
  345. int iwm_hal_send_host_cmd(struct iwm_priv *iwm,
  346. struct iwm_udma_wifi_cmd *udma_cmd,
  347. struct iwm_umac_cmd *umac_cmd,
  348. struct iwm_lmac_cmd *lmac_cmd,
  349. const void *payload, u16 payload_size)
  350. {
  351. struct iwm_wifi_cmd *cmd;
  352. struct iwm_lmac_hdr *hdr;
  353. int lmac_hdr_len = 0;
  354. int ret;
  355. cmd = kzalloc(sizeof(struct iwm_wifi_cmd), GFP_KERNEL);
  356. if (!cmd) {
  357. IWM_ERR(iwm, "Couldn't alloc memory for wifi hal cmd\n");
  358. return -ENOMEM;
  359. }
  360. iwm_wifi_cmd_init(iwm, cmd, udma_cmd, umac_cmd, lmac_cmd, payload_size);
  361. if (lmac_cmd) {
  362. hdr = (struct iwm_lmac_hdr *)(cmd->buf.start);
  363. iwm_build_lmac_hdr(iwm, hdr, &cmd->lmac_cmd);
  364. lmac_hdr_len = sizeof(struct iwm_lmac_hdr);
  365. }
  366. memcpy(cmd->buf.payload, payload, payload_size);
  367. cmd->buf.len = le16_to_cpu(umac_cmd->count);
  368. ret = iwm_send_udma_wifi_cmd(iwm, cmd);
  369. /* We free the cmd if we're not expecting any response */
  370. if (!umac_cmd->resp)
  371. kfree(cmd);
  372. return ret;
  373. }
  374. /*
  375. * iwm_hal_send_umac_cmd(): This is a special case for
  376. * iwm_hal_send_host_cmd() to send direct UMAC cmd (without
  377. * LMAC involved).
  378. */
  379. int iwm_hal_send_umac_cmd(struct iwm_priv *iwm,
  380. struct iwm_udma_wifi_cmd *udma_cmd,
  381. struct iwm_umac_cmd *umac_cmd,
  382. const void *payload, u16 payload_size)
  383. {
  384. return iwm_hal_send_host_cmd(iwm, udma_cmd, umac_cmd, NULL,
  385. payload, payload_size);
  386. }