diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2015-01-24 05:14:47 -0500 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2015-01-27 08:50:50 -0500 |
commit | 04de6c6ce612ad159d44572b6ed566e57ecefcab (patch) | |
tree | 89fac868dea93ae40d468a20130cc982ff5e28bd /drivers/net/wireless/ath | |
parent | 6d48161678dcbeb1ac1736aaf11d10c55ed9a314 (diff) |
ath10k: implement diag data container event
Some firmware revisions may report this event as
part of their diagnostics.
This avoids `unknown event` warnings and adds
tracing for the event.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r-- | drivers/net/wireless/ath/ath10k/trace.h | 41 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi-tlv.c | 68 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi-tlv.h | 19 |
3 files changed, 128 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h index b289378b6e3e..1c541f73370d 100644 --- a/drivers/net/wireless/ath/ath10k/trace.h +++ b/drivers/net/wireless/ath/ath10k/trace.h | |||
@@ -453,6 +453,47 @@ TRACE_EVENT(ath10k_htt_rx_desc, | |||
453 | ) | 453 | ) |
454 | ); | 454 | ); |
455 | 455 | ||
456 | TRACE_EVENT(ath10k_wmi_diag_container, | ||
457 | TP_PROTO(struct ath10k *ar, | ||
458 | u8 type, | ||
459 | u32 timestamp, | ||
460 | u32 code, | ||
461 | u16 len, | ||
462 | const void *data), | ||
463 | |||
464 | TP_ARGS(ar, type, timestamp, code, len, data), | ||
465 | |||
466 | TP_STRUCT__entry( | ||
467 | __string(device, dev_name(ar->dev)) | ||
468 | __string(driver, dev_driver_string(ar->dev)) | ||
469 | __field(u8, type) | ||
470 | __field(u32, timestamp) | ||
471 | __field(u32, code) | ||
472 | __field(u16, len) | ||
473 | __dynamic_array(u8, data, len) | ||
474 | ), | ||
475 | |||
476 | TP_fast_assign( | ||
477 | __assign_str(device, dev_name(ar->dev)); | ||
478 | __assign_str(driver, dev_driver_string(ar->dev)); | ||
479 | __entry->type = type; | ||
480 | __entry->timestamp = timestamp; | ||
481 | __entry->code = code; | ||
482 | __entry->len = len; | ||
483 | memcpy(__get_dynamic_array(data), data, len); | ||
484 | ), | ||
485 | |||
486 | TP_printk( | ||
487 | "%s %s diag container type %hhu timestamp %u code %u len %d", | ||
488 | __get_str(driver), | ||
489 | __get_str(device), | ||
490 | __entry->type, | ||
491 | __entry->timestamp, | ||
492 | __entry->code, | ||
493 | __entry->len | ||
494 | ) | ||
495 | ); | ||
496 | |||
456 | #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/ | 497 | #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/ |
457 | 498 | ||
458 | /* we don't want to use include/trace/events */ | 499 | /* we don't want to use include/trace/events */ |
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 6f34fc7d663e..56cd51d0ac93 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c | |||
@@ -60,6 +60,8 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = { | |||
60 | = { .min_len = sizeof(struct wmi_tlv_rdy_ev) }, | 60 | = { .min_len = sizeof(struct wmi_tlv_rdy_ev) }, |
61 | [WMI_TLV_TAG_STRUCT_OFFLOAD_BCN_TX_STATUS_EVENT] | 61 | [WMI_TLV_TAG_STRUCT_OFFLOAD_BCN_TX_STATUS_EVENT] |
62 | = { .min_len = sizeof(struct wmi_tlv_bcn_tx_status_ev) }, | 62 | = { .min_len = sizeof(struct wmi_tlv_bcn_tx_status_ev) }, |
63 | [WMI_TLV_TAG_STRUCT_DIAG_DATA_CONTAINER_EVENT] | ||
64 | = { .min_len = sizeof(struct wmi_tlv_diag_data_ev) }, | ||
63 | }; | 65 | }; |
64 | 66 | ||
65 | static int | 67 | static int |
@@ -203,6 +205,69 @@ static int ath10k_wmi_tlv_event_bcn_tx_status(struct ath10k *ar, | |||
203 | return 0; | 205 | return 0; |
204 | } | 206 | } |
205 | 207 | ||
208 | static int ath10k_wmi_tlv_event_diag_data(struct ath10k *ar, | ||
209 | struct sk_buff *skb) | ||
210 | { | ||
211 | const void **tb; | ||
212 | const struct wmi_tlv_diag_data_ev *ev; | ||
213 | const struct wmi_tlv_diag_item *item; | ||
214 | const void *data; | ||
215 | int ret, num_items, len; | ||
216 | |||
217 | tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); | ||
218 | if (IS_ERR(tb)) { | ||
219 | ret = PTR_ERR(tb); | ||
220 | ath10k_warn(ar, "failed to parse tlv: %d\n", ret); | ||
221 | return ret; | ||
222 | } | ||
223 | |||
224 | ev = tb[WMI_TLV_TAG_STRUCT_DIAG_DATA_CONTAINER_EVENT]; | ||
225 | data = tb[WMI_TLV_TAG_ARRAY_BYTE]; | ||
226 | if (!ev || !data) { | ||
227 | kfree(tb); | ||
228 | return -EPROTO; | ||
229 | } | ||
230 | |||
231 | num_items = __le32_to_cpu(ev->num_items); | ||
232 | len = ath10k_wmi_tlv_len(data); | ||
233 | |||
234 | while (num_items--) { | ||
235 | if (len == 0) | ||
236 | break; | ||
237 | if (len < sizeof(*item)) { | ||
238 | ath10k_warn(ar, "failed to parse diag data: can't fit item header\n"); | ||
239 | break; | ||
240 | } | ||
241 | |||
242 | item = data; | ||
243 | |||
244 | if (len < sizeof(*item) + __le16_to_cpu(item->len)) { | ||
245 | ath10k_warn(ar, "failed to parse diag data: item is too long\n"); | ||
246 | break; | ||
247 | } | ||
248 | |||
249 | trace_ath10k_wmi_diag_container(ar, | ||
250 | item->type, | ||
251 | __le32_to_cpu(item->timestamp), | ||
252 | __le32_to_cpu(item->code), | ||
253 | __le16_to_cpu(item->len), | ||
254 | item->payload); | ||
255 | |||
256 | len -= sizeof(*item); | ||
257 | len -= roundup(__le16_to_cpu(item->len), 4); | ||
258 | |||
259 | data += sizeof(*item); | ||
260 | data += roundup(__le16_to_cpu(item->len), 4); | ||
261 | } | ||
262 | |||
263 | if (num_items != -1 || len != 0) | ||
264 | ath10k_warn(ar, "failed to parse diag data event: num_items %d len %d\n", | ||
265 | num_items, len); | ||
266 | |||
267 | kfree(tb); | ||
268 | return 0; | ||
269 | } | ||
270 | |||
206 | /***********/ | 271 | /***********/ |
207 | /* TLV ops */ | 272 | /* TLV ops */ |
208 | /***********/ | 273 | /***********/ |
@@ -318,6 +383,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) | |||
318 | case WMI_TLV_OFFLOAD_BCN_TX_STATUS_EVENTID: | 383 | case WMI_TLV_OFFLOAD_BCN_TX_STATUS_EVENTID: |
319 | ath10k_wmi_tlv_event_bcn_tx_status(ar, skb); | 384 | ath10k_wmi_tlv_event_bcn_tx_status(ar, skb); |
320 | break; | 385 | break; |
386 | case WMI_TLV_DIAG_DATA_CONTAINER_EVENTID: | ||
387 | ath10k_wmi_tlv_event_diag_data(ar, skb); | ||
388 | break; | ||
321 | default: | 389 | default: |
322 | ath10k_warn(ar, "Unknown eventid: %d\n", id); | 390 | ath10k_warn(ar, "Unknown eventid: %d\n", id); |
323 | break; | 391 | break; |
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index eb02290075a7..87db762ac1a2 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h | |||
@@ -1409,6 +1409,25 @@ struct wmi_tlv_p2p_go_bcn_ie { | |||
1409 | __le32 ie_len; | 1409 | __le32 ie_len; |
1410 | } __packed; | 1410 | } __packed; |
1411 | 1411 | ||
1412 | enum wmi_tlv_diag_item_type { | ||
1413 | WMI_TLV_DIAG_ITEM_TYPE_FW_EVENT, | ||
1414 | WMI_TLV_DIAG_ITEM_TYPE_FW_LOG, | ||
1415 | WMI_TLV_DIAG_ITEM_TYPE_FW_DEBUG_MSG, | ||
1416 | }; | ||
1417 | |||
1418 | struct wmi_tlv_diag_item { | ||
1419 | u8 type; | ||
1420 | u8 reserved; | ||
1421 | __le16 len; | ||
1422 | __le32 timestamp; | ||
1423 | __le32 code; | ||
1424 | u8 payload[0]; | ||
1425 | } __packed; | ||
1426 | |||
1427 | struct wmi_tlv_diag_data_ev { | ||
1428 | __le32 num_items; | ||
1429 | } __packed; | ||
1430 | |||
1412 | void ath10k_wmi_tlv_attach(struct ath10k *ar); | 1431 | void ath10k_wmi_tlv_attach(struct ath10k *ar); |
1413 | 1432 | ||
1414 | #endif | 1433 | #endif |