|
@@ -857,6 +857,105 @@ int wlan_hdd_send_avoid_freq_event(struct hdd_context *hdd_ctx,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * define short names for the global vendor params
|
|
|
+ * used by QCA_NL80211_VENDOR_SUBCMD_HANG
|
|
|
+ */
|
|
|
+#define HANG_REASON_INDEX QCA_NL80211_VENDOR_SUBCMD_HANG_REASON_INDEX
|
|
|
+
|
|
|
+/**
|
|
|
+ * hdd_convert_hang_reason() - Convert cds recovery reason to vendor specific
|
|
|
+ * hang reason
|
|
|
+ * @reason: cds recovery reason
|
|
|
+ *
|
|
|
+ * Return: Vendor specific reason code
|
|
|
+ */
|
|
|
+static enum qca_wlan_vendor_hang_reason
|
|
|
+hdd_convert_hang_reason(enum qdf_hang_reason reason)
|
|
|
+{
|
|
|
+ uint32_t ret_val;
|
|
|
+
|
|
|
+ switch (reason) {
|
|
|
+ case QDF_RX_HASH_NO_ENTRY_FOUND:
|
|
|
+ ret_val = QCA_WLAN_HANG_RX_HASH_NO_ENTRY_FOUND;
|
|
|
+ break;
|
|
|
+ case QDF_PEER_DELETION_TIMEDOUT:
|
|
|
+ ret_val = QCA_WLAN_HANG_PEER_DELETION_TIMEDOUT;
|
|
|
+ break;
|
|
|
+ case QDF_PEER_UNMAP_TIMEDOUT:
|
|
|
+ ret_val = QCA_WLAN_HANG_PEER_UNMAP_TIMEDOUT;
|
|
|
+ break;
|
|
|
+ case QDF_SCAN_REQ_EXPIRED:
|
|
|
+ ret_val = QCA_WLAN_HANG_SCAN_REQ_EXPIRED;
|
|
|
+ break;
|
|
|
+ case QDF_SCAN_ATTEMPT_FAILURES:
|
|
|
+ ret_val = QCA_WLAN_HANG_SCAN_ATTEMPT_FAILURES;
|
|
|
+ break;
|
|
|
+ case QDF_GET_MSG_BUFF_FAILURE:
|
|
|
+ ret_val = QCA_WLAN_HANG_GET_MSG_BUFF_FAILURE;
|
|
|
+ break;
|
|
|
+ case QDF_ACTIVE_LIST_TIMEOUT:
|
|
|
+ ret_val = QCA_WLAN_HANG_ACTIVE_LIST_TIMEOUT;
|
|
|
+ break;
|
|
|
+ case QDF_SUSPEND_TIMEOUT:
|
|
|
+ ret_val = QCA_WLAN_HANG_SUSPEND_TIMEOUT;
|
|
|
+ break;
|
|
|
+ case QDF_RESUME_TIMEOUT:
|
|
|
+ ret_val = QCA_WLAN_HANG_RESUME_TIMEOUT;
|
|
|
+ break;
|
|
|
+ case QDF_REASON_UNSPECIFIED:
|
|
|
+ default:
|
|
|
+ ret_val = QCA_WLAN_HANG_REASON_UNSPECIFIED;
|
|
|
+ }
|
|
|
+ return ret_val;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * wlan_hdd_send_hang_reason_event() - Send hang reason to the userspace
|
|
|
+ * @hdd_ctx: Pointer to hdd context
|
|
|
+ * @reason: cds recovery reason
|
|
|
+ *
|
|
|
+ * Return: 0 on success or failure reason
|
|
|
+ */
|
|
|
+int wlan_hdd_send_hang_reason_event(struct hdd_context *hdd_ctx,
|
|
|
+ enum qdf_hang_reason reason)
|
|
|
+{
|
|
|
+ struct sk_buff *vendor_event;
|
|
|
+ enum qca_wlan_vendor_hang_reason hang_reason;
|
|
|
+
|
|
|
+ ENTER();
|
|
|
+
|
|
|
+ if (!hdd_ctx) {
|
|
|
+ hdd_err("HDD context is null");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
|
|
|
+ NULL,
|
|
|
+ sizeof(uint32_t),
|
|
|
+ HANG_REASON_INDEX,
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!vendor_event) {
|
|
|
+ hdd_err("cfg80211_vendor_event_alloc failed");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ hang_reason = hdd_convert_hang_reason(reason);
|
|
|
+
|
|
|
+ if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_HANG_REASON,
|
|
|
+ (uint32_t) hang_reason)) {
|
|
|
+ hdd_err("QCA_WLAN_VENDOR_ATTR_HANG_REASON put fail");
|
|
|
+ kfree_skb(vendor_event);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ cfg80211_vendor_event(vendor_event, GFP_KERNEL);
|
|
|
+
|
|
|
+ EXIT();
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+#undef HANG_REASON_INDEX
|
|
|
+
|
|
|
/**
|
|
|
* wlan_hdd_get_adjacent_chan(): Gets next/previous channel
|
|
|
* with respect to the channel passed.
|
|
@@ -1317,6 +1416,10 @@ static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] =
|
|
|
.vendor_id = QCA_NL80211_VENDOR_ID,
|
|
|
.subcmd = QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET,
|
|
|
},
|
|
|
+ [QCA_NL80211_VENDOR_SUBCMD_HANG_REASON_INDEX] = {
|
|
|
+ .vendor_id = QCA_NL80211_VENDOR_ID,
|
|
|
+ .subcmd = QCA_NL80211_VENDOR_SUBCMD_HANG,
|
|
|
+ },
|
|
|
|
|
|
#ifdef WLAN_UMAC_CONVERGENCE
|
|
|
COMMON_VENDOR_EVENTS
|