diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-sv-open.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sv-open.c | 177 |
1 files changed, 174 insertions, 3 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-sv-open.c b/drivers/net/wireless/iwlwifi/iwl-sv-open.c index 89b6696622c1..69b7e6bf2d6f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sv-open.c +++ b/drivers/net/wireless/iwlwifi/iwl-sv-open.c | |||
@@ -97,6 +97,13 @@ struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = { | |||
97 | 97 | ||
98 | [IWL_TM_ATTR_SYNC_RSP] = { .type = NLA_UNSPEC, }, | 98 | [IWL_TM_ATTR_SYNC_RSP] = { .type = NLA_UNSPEC, }, |
99 | [IWL_TM_ATTR_UCODE_RX_PKT] = { .type = NLA_UNSPEC, }, | 99 | [IWL_TM_ATTR_UCODE_RX_PKT] = { .type = NLA_UNSPEC, }, |
100 | |||
101 | [IWL_TM_ATTR_EEPROM] = { .type = NLA_UNSPEC, }, | ||
102 | |||
103 | [IWL_TM_ATTR_TRACE_ADDR] = { .type = NLA_UNSPEC, }, | ||
104 | [IWL_TM_ATTR_TRACE_DATA] = { .type = NLA_UNSPEC, }, | ||
105 | |||
106 | [IWL_TM_ATTR_FIXRATE] = { .type = NLA_U32, }, | ||
100 | }; | 107 | }; |
101 | 108 | ||
102 | /* | 109 | /* |
@@ -167,6 +174,31 @@ nla_put_failure: | |||
167 | void iwl_testmode_init(struct iwl_priv *priv) | 174 | void iwl_testmode_init(struct iwl_priv *priv) |
168 | { | 175 | { |
169 | priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt; | 176 | priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt; |
177 | priv->testmode_trace.trace_enabled = false; | ||
178 | } | ||
179 | |||
180 | static void iwl_trace_cleanup(struct iwl_priv *priv) | ||
181 | { | ||
182 | struct device *dev = &priv->pci_dev->dev; | ||
183 | |||
184 | if (priv->testmode_trace.trace_enabled) { | ||
185 | if (priv->testmode_trace.cpu_addr && | ||
186 | priv->testmode_trace.dma_addr) | ||
187 | dma_free_coherent(dev, | ||
188 | TRACE_TOTAL_SIZE, | ||
189 | priv->testmode_trace.cpu_addr, | ||
190 | priv->testmode_trace.dma_addr); | ||
191 | priv->testmode_trace.trace_enabled = false; | ||
192 | priv->testmode_trace.cpu_addr = NULL; | ||
193 | priv->testmode_trace.trace_addr = NULL; | ||
194 | priv->testmode_trace.dma_addr = 0; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | |||
199 | void iwl_testmode_cleanup(struct iwl_priv *priv) | ||
200 | { | ||
201 | iwl_trace_cleanup(priv); | ||
170 | } | 202 | } |
171 | 203 | ||
172 | /* | 204 | /* |
@@ -198,10 +230,11 @@ static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb) | |||
198 | } | 230 | } |
199 | 231 | ||
200 | cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]); | 232 | cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]); |
201 | cmd.data = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]); | 233 | cmd.data[0] = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]); |
202 | cmd.len = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]); | 234 | cmd.len[0] = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]); |
235 | cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY; | ||
203 | IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x," | 236 | IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x," |
204 | " len %d\n", cmd.id, cmd.flags, cmd.len); | 237 | " len %d\n", cmd.id, cmd.flags, cmd.len[0]); |
205 | /* ok, let's submit the command to ucode */ | 238 | /* ok, let's submit the command to ucode */ |
206 | return iwl_send_cmd(priv, &cmd); | 239 | return iwl_send_cmd(priv, &cmd); |
207 | } | 240 | } |
@@ -388,6 +421,38 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) | |||
388 | "Error starting the device: %d\n", status); | 421 | "Error starting the device: %d\n", status); |
389 | break; | 422 | break; |
390 | 423 | ||
424 | case IWL_TM_CMD_APP2DEV_GET_EEPROM: | ||
425 | if (priv->eeprom) { | ||
426 | skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, | ||
427 | priv->cfg->base_params->eeprom_size + 20); | ||
428 | if (!skb) { | ||
429 | IWL_DEBUG_INFO(priv, | ||
430 | "Error allocating memory\n"); | ||
431 | return -ENOMEM; | ||
432 | } | ||
433 | NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, | ||
434 | IWL_TM_CMD_DEV2APP_EEPROM_RSP); | ||
435 | NLA_PUT(skb, IWL_TM_ATTR_EEPROM, | ||
436 | priv->cfg->base_params->eeprom_size, | ||
437 | priv->eeprom); | ||
438 | status = cfg80211_testmode_reply(skb); | ||
439 | if (status < 0) | ||
440 | IWL_DEBUG_INFO(priv, | ||
441 | "Error sending msg : %d\n", | ||
442 | status); | ||
443 | } else | ||
444 | return -EFAULT; | ||
445 | break; | ||
446 | |||
447 | case IWL_TM_CMD_APP2DEV_FIXRATE_REQ: | ||
448 | if (!tb[IWL_TM_ATTR_FIXRATE]) { | ||
449 | IWL_DEBUG_INFO(priv, | ||
450 | "Error finding fixrate setting\n"); | ||
451 | return -ENOMSG; | ||
452 | } | ||
453 | priv->dbg_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]); | ||
454 | break; | ||
455 | |||
391 | default: | 456 | default: |
392 | IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n"); | 457 | IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n"); |
393 | return -ENOSYS; | 458 | return -ENOSYS; |
@@ -399,6 +464,102 @@ nla_put_failure: | |||
399 | return -EMSGSIZE; | 464 | return -EMSGSIZE; |
400 | } | 465 | } |
401 | 466 | ||
467 | |||
468 | /* | ||
469 | * This function handles the user application commands for uCode trace | ||
470 | * | ||
471 | * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the | ||
472 | * handlers respectively. | ||
473 | * | ||
474 | * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned | ||
475 | * value of the actual command execution is replied to the user application. | ||
476 | * | ||
477 | * @hw: ieee80211_hw object that represents the device | ||
478 | * @tb: gnl message fields from the user space | ||
479 | */ | ||
480 | static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb) | ||
481 | { | ||
482 | struct iwl_priv *priv = hw->priv; | ||
483 | struct sk_buff *skb; | ||
484 | int status = 0; | ||
485 | struct device *dev = &priv->pci_dev->dev; | ||
486 | |||
487 | switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { | ||
488 | case IWL_TM_CMD_APP2DEV_BEGIN_TRACE: | ||
489 | if (priv->testmode_trace.trace_enabled) | ||
490 | return -EBUSY; | ||
491 | |||
492 | priv->testmode_trace.cpu_addr = | ||
493 | dma_alloc_coherent(dev, | ||
494 | TRACE_TOTAL_SIZE, | ||
495 | &priv->testmode_trace.dma_addr, | ||
496 | GFP_KERNEL); | ||
497 | if (!priv->testmode_trace.cpu_addr) | ||
498 | return -ENOMEM; | ||
499 | priv->testmode_trace.trace_enabled = true; | ||
500 | priv->testmode_trace.trace_addr = (u8 *)PTR_ALIGN( | ||
501 | priv->testmode_trace.cpu_addr, 0x100); | ||
502 | memset(priv->testmode_trace.trace_addr, 0x03B, | ||
503 | TRACE_BUFF_SIZE); | ||
504 | skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, | ||
505 | sizeof(priv->testmode_trace.dma_addr) + 20); | ||
506 | if (!skb) { | ||
507 | IWL_DEBUG_INFO(priv, | ||
508 | "Error allocating memory\n"); | ||
509 | iwl_trace_cleanup(priv); | ||
510 | return -ENOMEM; | ||
511 | } | ||
512 | NLA_PUT(skb, IWL_TM_ATTR_TRACE_ADDR, | ||
513 | sizeof(priv->testmode_trace.dma_addr), | ||
514 | (u64 *)&priv->testmode_trace.dma_addr); | ||
515 | status = cfg80211_testmode_reply(skb); | ||
516 | if (status < 0) { | ||
517 | IWL_DEBUG_INFO(priv, | ||
518 | "Error sending msg : %d\n", | ||
519 | status); | ||
520 | } | ||
521 | break; | ||
522 | |||
523 | case IWL_TM_CMD_APP2DEV_END_TRACE: | ||
524 | iwl_trace_cleanup(priv); | ||
525 | break; | ||
526 | |||
527 | case IWL_TM_CMD_APP2DEV_READ_TRACE: | ||
528 | if (priv->testmode_trace.trace_enabled && | ||
529 | priv->testmode_trace.trace_addr) { | ||
530 | skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, | ||
531 | 20 + TRACE_BUFF_SIZE); | ||
532 | if (skb == NULL) { | ||
533 | IWL_DEBUG_INFO(priv, | ||
534 | "Error allocating memory\n"); | ||
535 | return -ENOMEM; | ||
536 | } | ||
537 | NLA_PUT(skb, IWL_TM_ATTR_TRACE_DATA, | ||
538 | TRACE_BUFF_SIZE, | ||
539 | priv->testmode_trace.trace_addr); | ||
540 | status = cfg80211_testmode_reply(skb); | ||
541 | if (status < 0) { | ||
542 | IWL_DEBUG_INFO(priv, | ||
543 | "Error sending msg : %d\n", status); | ||
544 | } | ||
545 | } else | ||
546 | return -EFAULT; | ||
547 | break; | ||
548 | |||
549 | default: | ||
550 | IWL_DEBUG_INFO(priv, "Unknown testmode mem command ID\n"); | ||
551 | return -ENOSYS; | ||
552 | } | ||
553 | return status; | ||
554 | |||
555 | nla_put_failure: | ||
556 | kfree_skb(skb); | ||
557 | if (nla_get_u32(tb[IWL_TM_ATTR_COMMAND]) == | ||
558 | IWL_TM_CMD_APP2DEV_BEGIN_TRACE) | ||
559 | iwl_trace_cleanup(priv); | ||
560 | return -EMSGSIZE; | ||
561 | } | ||
562 | |||
402 | /* The testmode gnl message handler that takes the gnl message from the | 563 | /* The testmode gnl message handler that takes the gnl message from the |
403 | * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then | 564 | * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then |
404 | * invoke the corresponding handlers. | 565 | * invoke the corresponding handlers. |
@@ -455,9 +616,19 @@ int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) | |||
455 | case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW: | 616 | case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW: |
456 | case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB: | 617 | case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB: |
457 | case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW: | 618 | case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW: |
619 | case IWL_TM_CMD_APP2DEV_GET_EEPROM: | ||
620 | case IWL_TM_CMD_APP2DEV_FIXRATE_REQ: | ||
458 | IWL_DEBUG_INFO(priv, "testmode cmd to driver\n"); | 621 | IWL_DEBUG_INFO(priv, "testmode cmd to driver\n"); |
459 | result = iwl_testmode_driver(hw, tb); | 622 | result = iwl_testmode_driver(hw, tb); |
460 | break; | 623 | break; |
624 | |||
625 | case IWL_TM_CMD_APP2DEV_BEGIN_TRACE: | ||
626 | case IWL_TM_CMD_APP2DEV_END_TRACE: | ||
627 | case IWL_TM_CMD_APP2DEV_READ_TRACE: | ||
628 | IWL_DEBUG_INFO(priv, "testmode uCode trace cmd to driver\n"); | ||
629 | result = iwl_testmode_trace(hw, tb); | ||
630 | break; | ||
631 | |||
461 | default: | 632 | default: |
462 | IWL_DEBUG_INFO(priv, "Unknown testmode command\n"); | 633 | IWL_DEBUG_INFO(priv, "Unknown testmode command\n"); |
463 | result = -ENOSYS; | 634 | result = -ENOSYS; |