diff options
author | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2011-05-06 13:21:28 -0400 |
---|---|---|
committer | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2011-05-13 15:02:02 -0400 |
commit | 7a4e5281d1b3335a3dc90841415390473cccebf3 (patch) | |
tree | bc6731ec17596e5e5f90dc64f0472567971854ad | |
parent | 5065054790b111bf677b1eccf3f8f76f20cc0ae6 (diff) |
iwlagn: add testmode trace command
Adding testmode trace/debug capability
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.h | 5 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 11 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sv-open.c | 133 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-testmode.h | 15 |
5 files changed, 165 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index a7054a5ee34a..e027f99f18a5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -3659,6 +3659,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) | |||
3659 | */ | 3659 | */ |
3660 | set_bit(STATUS_EXIT_PENDING, &priv->status); | 3660 | set_bit(STATUS_EXIT_PENDING, &priv->status); |
3661 | 3661 | ||
3662 | iwl_testmode_cleanup(priv); | ||
3662 | iwl_leds_exit(priv); | 3663 | iwl_leds_exit(priv); |
3663 | 3664 | ||
3664 | if (priv->mac80211_registered) { | 3665 | if (priv->mac80211_registered) { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index fc7dc0628316..2495fe7a58cb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h | |||
@@ -343,6 +343,7 @@ extern int iwl_alive_start(struct iwl_priv *priv); | |||
343 | #ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL | 343 | #ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL |
344 | extern int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len); | 344 | extern int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len); |
345 | extern void iwl_testmode_init(struct iwl_priv *priv); | 345 | extern void iwl_testmode_init(struct iwl_priv *priv); |
346 | extern void iwl_testmode_cleanup(struct iwl_priv *priv); | ||
346 | #else | 347 | #else |
347 | static inline | 348 | static inline |
348 | int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) | 349 | int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) |
@@ -353,6 +354,10 @@ static inline | |||
353 | void iwl_testmode_init(struct iwl_priv *priv) | 354 | void iwl_testmode_init(struct iwl_priv *priv) |
354 | { | 355 | { |
355 | } | 356 | } |
357 | static inline | ||
358 | void iwl_testmode_cleanup(struct iwl_priv *priv) | ||
359 | { | ||
360 | } | ||
356 | #endif | 361 | #endif |
357 | 362 | ||
358 | #endif /* __iwl_agn_h__ */ | 363 | #endif /* __iwl_agn_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 3e3b8b8939d6..12fb2f4ca0b1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -1179,6 +1179,14 @@ enum iwl_scan_type { | |||
1179 | IWL_SCAN_OFFCH_TX, | 1179 | IWL_SCAN_OFFCH_TX, |
1180 | }; | 1180 | }; |
1181 | 1181 | ||
1182 | #ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL | ||
1183 | struct iwl_testmode_trace { | ||
1184 | u8 *cpu_addr; | ||
1185 | u8 *trace_addr; | ||
1186 | dma_addr_t dma_addr; | ||
1187 | bool trace_enabled; | ||
1188 | }; | ||
1189 | #endif | ||
1182 | struct iwl_priv { | 1190 | struct iwl_priv { |
1183 | 1191 | ||
1184 | /* ieee device used by generic ieee processing code */ | 1192 | /* ieee device used by generic ieee processing code */ |
@@ -1510,6 +1518,9 @@ struct iwl_priv { | |||
1510 | struct led_classdev led; | 1518 | struct led_classdev led; |
1511 | unsigned long blink_on, blink_off; | 1519 | unsigned long blink_on, blink_off; |
1512 | bool led_registered; | 1520 | bool led_registered; |
1521 | #ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL | ||
1522 | struct iwl_testmode_trace testmode_trace; | ||
1523 | #endif | ||
1513 | }; /*iwl_priv */ | 1524 | }; /*iwl_priv */ |
1514 | 1525 | ||
1515 | static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id) | 1526 | static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-sv-open.c b/drivers/net/wireless/iwlwifi/iwl-sv-open.c index dd2904aa9be2..b778c3f4b84d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sv-open.c +++ b/drivers/net/wireless/iwlwifi/iwl-sv-open.c | |||
@@ -97,6 +97,10 @@ 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_TRACE_ADDR] = { .type = NLA_UNSPEC, }, | ||
102 | [IWL_TM_ATTR_TRACE_DATA] = { .type = NLA_UNSPEC, }, | ||
103 | |||
100 | }; | 104 | }; |
101 | 105 | ||
102 | /* | 106 | /* |
@@ -167,6 +171,31 @@ nla_put_failure: | |||
167 | void iwl_testmode_init(struct iwl_priv *priv) | 171 | void iwl_testmode_init(struct iwl_priv *priv) |
168 | { | 172 | { |
169 | priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt; | 173 | priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt; |
174 | priv->testmode_trace.trace_enabled = false; | ||
175 | } | ||
176 | |||
177 | static void iwl_trace_cleanup(struct iwl_priv *priv) | ||
178 | { | ||
179 | struct device *dev = &priv->pci_dev->dev; | ||
180 | |||
181 | if (priv->testmode_trace.trace_enabled) { | ||
182 | if (priv->testmode_trace.cpu_addr && | ||
183 | priv->testmode_trace.dma_addr) | ||
184 | dma_free_coherent(dev, | ||
185 | TRACE_TOTAL_SIZE, | ||
186 | priv->testmode_trace.cpu_addr, | ||
187 | priv->testmode_trace.dma_addr); | ||
188 | priv->testmode_trace.trace_enabled = false; | ||
189 | priv->testmode_trace.cpu_addr = NULL; | ||
190 | priv->testmode_trace.trace_addr = NULL; | ||
191 | priv->testmode_trace.dma_addr = 0; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | |||
196 | void iwl_testmode_cleanup(struct iwl_priv *priv) | ||
197 | { | ||
198 | iwl_trace_cleanup(priv); | ||
170 | } | 199 | } |
171 | 200 | ||
172 | /* | 201 | /* |
@@ -400,6 +429,102 @@ nla_put_failure: | |||
400 | return -EMSGSIZE; | 429 | return -EMSGSIZE; |
401 | } | 430 | } |
402 | 431 | ||
432 | |||
433 | /* | ||
434 | * This function handles the user application commands for uCode trace | ||
435 | * | ||
436 | * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the | ||
437 | * handlers respectively. | ||
438 | * | ||
439 | * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned | ||
440 | * value of the actual command execution is replied to the user application. | ||
441 | * | ||
442 | * @hw: ieee80211_hw object that represents the device | ||
443 | * @tb: gnl message fields from the user space | ||
444 | */ | ||
445 | static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb) | ||
446 | { | ||
447 | struct iwl_priv *priv = hw->priv; | ||
448 | struct sk_buff *skb; | ||
449 | int status = 0; | ||
450 | struct device *dev = &priv->pci_dev->dev; | ||
451 | |||
452 | switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { | ||
453 | case IWL_TM_CMD_APP2DEV_BEGIN_TRACE: | ||
454 | if (priv->testmode_trace.trace_enabled) | ||
455 | return -EBUSY; | ||
456 | |||
457 | priv->testmode_trace.cpu_addr = | ||
458 | dma_alloc_coherent(dev, | ||
459 | TRACE_TOTAL_SIZE, | ||
460 | &priv->testmode_trace.dma_addr, | ||
461 | GFP_KERNEL); | ||
462 | if (!priv->testmode_trace.cpu_addr) | ||
463 | return -ENOMEM; | ||
464 | priv->testmode_trace.trace_enabled = true; | ||
465 | priv->testmode_trace.trace_addr = (u8 *)PTR_ALIGN( | ||
466 | priv->testmode_trace.cpu_addr, 0x100); | ||
467 | memset(priv->testmode_trace.trace_addr, 0x03B, | ||
468 | TRACE_BUFF_SIZE); | ||
469 | skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, | ||
470 | sizeof(priv->testmode_trace.dma_addr) + 20); | ||
471 | if (!skb) { | ||
472 | IWL_DEBUG_INFO(priv, | ||
473 | "Error allocating memory\n"); | ||
474 | iwl_trace_cleanup(priv); | ||
475 | return -ENOMEM; | ||
476 | } | ||
477 | NLA_PUT(skb, IWL_TM_ATTR_TRACE_ADDR, | ||
478 | sizeof(priv->testmode_trace.dma_addr), | ||
479 | (u64 *)&priv->testmode_trace.dma_addr); | ||
480 | status = cfg80211_testmode_reply(skb); | ||
481 | if (status < 0) { | ||
482 | IWL_DEBUG_INFO(priv, | ||
483 | "Error sending msg : %d\n", | ||
484 | status); | ||
485 | } | ||
486 | break; | ||
487 | |||
488 | case IWL_TM_CMD_APP2DEV_END_TRACE: | ||
489 | iwl_trace_cleanup(priv); | ||
490 | break; | ||
491 | |||
492 | case IWL_TM_CMD_APP2DEV_READ_TRACE: | ||
493 | if (priv->testmode_trace.trace_enabled && | ||
494 | priv->testmode_trace.trace_addr) { | ||
495 | skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, | ||
496 | 20 + TRACE_BUFF_SIZE); | ||
497 | if (skb == NULL) { | ||
498 | IWL_DEBUG_INFO(priv, | ||
499 | "Error allocating memory\n"); | ||
500 | return -ENOMEM; | ||
501 | } | ||
502 | NLA_PUT(skb, IWL_TM_ATTR_TRACE_DATA, | ||
503 | TRACE_BUFF_SIZE, | ||
504 | priv->testmode_trace.trace_addr); | ||
505 | status = cfg80211_testmode_reply(skb); | ||
506 | if (status < 0) { | ||
507 | IWL_DEBUG_INFO(priv, | ||
508 | "Error sending msg : %d\n", status); | ||
509 | } | ||
510 | } else | ||
511 | return -EFAULT; | ||
512 | break; | ||
513 | |||
514 | default: | ||
515 | IWL_DEBUG_INFO(priv, "Unknown testmode mem command ID\n"); | ||
516 | return -ENOSYS; | ||
517 | } | ||
518 | return status; | ||
519 | |||
520 | nla_put_failure: | ||
521 | kfree_skb(skb); | ||
522 | if (nla_get_u32(tb[IWL_TM_ATTR_COMMAND]) == | ||
523 | IWL_TM_CMD_APP2DEV_BEGIN_TRACE) | ||
524 | iwl_trace_cleanup(priv); | ||
525 | return -EMSGSIZE; | ||
526 | } | ||
527 | |||
403 | /* The testmode gnl message handler that takes the gnl message from the | 528 | /* The testmode gnl message handler that takes the gnl message from the |
404 | * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then | 529 | * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then |
405 | * invoke the corresponding handlers. | 530 | * invoke the corresponding handlers. |
@@ -459,6 +584,14 @@ int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) | |||
459 | IWL_DEBUG_INFO(priv, "testmode cmd to driver\n"); | 584 | IWL_DEBUG_INFO(priv, "testmode cmd to driver\n"); |
460 | result = iwl_testmode_driver(hw, tb); | 585 | result = iwl_testmode_driver(hw, tb); |
461 | break; | 586 | break; |
587 | |||
588 | case IWL_TM_CMD_APP2DEV_BEGIN_TRACE: | ||
589 | case IWL_TM_CMD_APP2DEV_END_TRACE: | ||
590 | case IWL_TM_CMD_APP2DEV_READ_TRACE: | ||
591 | IWL_DEBUG_INFO(priv, "testmode uCode trace cmd to driver\n"); | ||
592 | result = iwl_testmode_trace(hw, tb); | ||
593 | break; | ||
594 | |||
462 | default: | 595 | default: |
463 | IWL_DEBUG_INFO(priv, "Unknown testmode command\n"); | 596 | IWL_DEBUG_INFO(priv, "Unknown testmode command\n"); |
464 | result = -ENOSYS; | 597 | result = -ENOSYS; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.h b/drivers/net/wireless/iwlwifi/iwl-testmode.h index 31f8949f2801..34634eca94ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-testmode.h +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.h | |||
@@ -91,6 +91,10 @@ enum iwl_tm_cmd_t { | |||
91 | /* if there is other new command for the driver layer operation, | 91 | /* if there is other new command for the driver layer operation, |
92 | * append them here */ | 92 | * append them here */ |
93 | 93 | ||
94 | /* commands fom user space for uCode trace operations */ | ||
95 | IWL_TM_CMD_APP2DEV_BEGIN_TRACE, | ||
96 | IWL_TM_CMD_APP2DEV_END_TRACE, | ||
97 | IWL_TM_CMD_APP2DEV_READ_TRACE, | ||
94 | 98 | ||
95 | /* commands from kernel space to carry the synchronous response | 99 | /* commands from kernel space to carry the synchronous response |
96 | * to user application */ | 100 | * to user application */ |
@@ -144,8 +148,19 @@ enum iwl_tm_attr_t { | |||
144 | * application */ | 148 | * application */ |
145 | IWL_TM_ATTR_UCODE_RX_PKT, | 149 | IWL_TM_ATTR_UCODE_RX_PKT, |
146 | 150 | ||
151 | /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_XXX_TRACE, | ||
152 | * The mandatory fields are: | ||
153 | * IWL_TM_ATTR_MEM_TRACE_ADDR for the trace address | ||
154 | */ | ||
155 | IWL_TM_ATTR_TRACE_ADDR, | ||
156 | IWL_TM_ATTR_TRACE_DATA, | ||
157 | |||
147 | IWL_TM_ATTR_MAX, | 158 | IWL_TM_ATTR_MAX, |
148 | }; | 159 | }; |
149 | 160 | ||
161 | /* uCode trace buffer */ | ||
162 | #define TRACE_BUFF_SIZE 0x20000 | ||
163 | #define TRACE_BUFF_PADD 0x2000 | ||
164 | #define TRACE_TOTAL_SIZE (TRACE_BUFF_SIZE + TRACE_BUFF_PADD) | ||
150 | 165 | ||
151 | #endif | 166 | #endif |