From: Jérôme Pouiller <jerome.pouil...@silabs.com>

Add traces when debug events happen and allow to ask internal
information to chip.

These features work independently from mac80211.

Signed-off-by: Jérôme Pouiller <jerome.pouil...@silabs.com>
---
 drivers/staging/wfx/debug.c  | 105 +++++++++++++++++++++++++++++++++++
 drivers/staging/wfx/hif_rx.c |  80 ++++++++++++++++++++++++++
 drivers/staging/wfx/main.c   |   2 +
 drivers/staging/wfx/wfx.h    |  16 ++++++
 4 files changed, 203 insertions(+)

diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c
index 0619c7d1cf79..1e23bb5bde3e 100644
--- a/drivers/staging/wfx/debug.c
+++ b/drivers/staging/wfx/debug.c
@@ -6,11 +6,13 @@
  * Copyright (c) 2010, ST-Ericsson
  */
 #include <linux/debugfs.h>
+#include <linux/seq_file.h>
 #include <linux/crc32.h>
 
 #include "debug.h"
 #include "wfx.h"
 #include "main.h"
+#include "hif_tx_mib.h"
 
 #define CREATE_TRACE_POINTS
 #include "traces.h"
@@ -55,6 +57,107 @@ const char *get_reg_name(unsigned long id)
        return get_symbol(id, wfx_reg_print_map);
 }
 
+static int wfx_counters_show(struct seq_file *seq, void *v)
+{
+       int ret;
+       struct wfx_dev *wdev = seq->private;
+       struct hif_mib_extended_count_table counters;
+
+       ret = hif_get_counters_table(wdev, &counters);
+       if (ret < 0)
+               return ret;
+       if (ret > 0)
+               return -EIO;
+
+#define PUT_COUNTER(name) \
+       seq_printf(seq, "%24s %d\n", #name ":", 
le32_to_cpu(counters.count_##name))
+
+       PUT_COUNTER(tx_packets);
+       PUT_COUNTER(tx_multicast_frames);
+       PUT_COUNTER(tx_frames_success);
+       PUT_COUNTER(tx_frame_failures);
+       PUT_COUNTER(tx_frames_retried);
+       PUT_COUNTER(tx_frames_multi_retried);
+
+       PUT_COUNTER(rts_success);
+       PUT_COUNTER(rts_failures);
+       PUT_COUNTER(ack_failures);
+
+       PUT_COUNTER(rx_packets);
+       PUT_COUNTER(rx_frames_success);
+       PUT_COUNTER(rx_packet_errors);
+       PUT_COUNTER(plcp_errors);
+       PUT_COUNTER(fcs_errors);
+       PUT_COUNTER(rx_decryption_failures);
+       PUT_COUNTER(rx_mic_failures);
+       PUT_COUNTER(rx_no_key_failures);
+       PUT_COUNTER(rx_frame_duplicates);
+       PUT_COUNTER(rx_multicast_frames);
+       PUT_COUNTER(rx_cmacicv_errors);
+       PUT_COUNTER(rx_cmac_replays);
+       PUT_COUNTER(rx_mgmt_ccmp_replays);
+
+       PUT_COUNTER(rx_beacon);
+       PUT_COUNTER(miss_beacon);
+
+#undef PUT_COUNTER
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(wfx_counters);
+
+static const char * const channel_names[] = {
+       [0] = "1M",
+       [1] = "2M",
+       [2] = "5.5M",
+       [3] = "11M",
+       /* Entries 4 and 5 does not exist */
+       [6] = "6M",
+       [7] = "9M",
+       [8] = "12M",
+       [9] = "18M",
+       [10] = "24M",
+       [11] = "36M",
+       [12] = "48M",
+       [13] = "54M",
+       [14] = "MCS0",
+       [15] = "MCS1",
+       [16] = "MCS2",
+       [17] = "MCS3",
+       [18] = "MCS4",
+       [19] = "MCS5",
+       [20] = "MCS6",
+       [21] = "MCS7",
+};
+
+static int wfx_rx_stats_show(struct seq_file *seq, void *v)
+{
+       struct wfx_dev *wdev = seq->private;
+       struct hif_rx_stats *st = &wdev->rx_stats;
+       int i;
+
+       mutex_lock(&wdev->rx_stats_lock);
+       seq_printf(seq, "Timestamp: %dus\n", st->date);
+       seq_printf(seq, "Low power clock: frequency %uHz, external %s\n",
+               st->pwr_clk_freq,
+               st->is_ext_pwr_clk ? "yes" : "no");
+       seq_printf(seq, "Num. of frames: %d, PER (x10e4): %d, Throughput: 
%dKbps/s\n",
+               st->nb_rx_frame, st->per_total, st->throughput);
+       seq_puts(seq, "       Num. of      PER     RSSI      SNR      CFO\n");
+       seq_puts(seq, "        frames  (x10e4)    (dBm)     (dB)    (kHz)\n");
+       for (i = 0; i < ARRAY_SIZE(channel_names); i++) {
+               if (channel_names[i])
+                       seq_printf(seq, "%5s %8d %8d %8d %8d %8d\n",
+                                  channel_names[i], st->nb_rx_by_rate[i],
+                                  st->per[i], st->rssi[i] / 100,
+                                  st->snr[i] / 100, st->cfo[i]);
+       }
+       mutex_unlock(&wdev->rx_stats_lock);
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(wfx_rx_stats);
+
 static ssize_t wfx_send_pds_write(struct file *file, const char __user 
*user_buf,
                             size_t count, loff_t *ppos)
 {
@@ -190,6 +293,8 @@ int wfx_debug_init(struct wfx_dev *wdev)
        struct dentry *d;
 
        d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir);
+       debugfs_create_file("counters", 0444, d, wdev, &wfx_counters_fops);
+       debugfs_create_file("rx_stats", 0444, d, wdev, &wfx_rx_stats_fops);
        debugfs_create_file("send_pds", 0200, d, wdev, &wfx_send_pds_fops);
        debugfs_create_file("burn_slk_key", 0200, d, wdev, 
&wfx_burn_slk_key_fops);
        debugfs_create_file("send_hif_msg", 0600, d, wdev, 
&wfx_send_hif_msg_fops);
diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c
index 6b9683d69a3f..c93bae1b6acf 100644
--- a/drivers/staging/wfx/hif_rx.c
+++ b/drivers/staging/wfx/hif_rx.c
@@ -94,13 +94,93 @@ static int hif_keys_indication(struct wfx_dev *wdev, struct 
hif_msg *hif, void *
        return 0;
 }
 
+static int hif_join_complete_indication(struct wfx_dev *wdev, struct hif_msg 
*hif, void *buf)
+{
+       struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
+
+       WARN_ON(!wvif);
+       dev_warn(wdev->dev, "unattended JoinCompleteInd\n");
+
+       return 0;
+}
+
+static int hif_error_indication(struct wfx_dev *wdev, struct hif_msg *hif, 
void *buf)
+{
+       struct hif_ind_error *body = buf;
+       u8 *pRollback = (u8 *) body->data;
+       u32 *pStatus = (u32 *) body->data;
+
+       switch (body->type) {
+       case HIF_ERROR_FIRMWARE_ROLLBACK:
+               dev_err(wdev->dev, "asynchronous error: firmware rollback error 
%d\n", *pRollback);
+               break;
+       case HIF_ERROR_FIRMWARE_DEBUG_ENABLED:
+               dev_err(wdev->dev, "asynchronous error: firmware debug feature 
enabled\n");
+               break;
+       case HIF_ERROR_OUTDATED_SESSION_KEY:
+               dev_err(wdev->dev, "asynchronous error: secure link outdated 
key: %#.8x\n", *pStatus);
+               break;
+       case HIF_ERROR_INVALID_SESSION_KEY:
+               dev_err(wdev->dev, "asynchronous error: invalid session key\n");
+               break;
+       case HIF_ERROR_OOR_VOLTAGE:
+               dev_err(wdev->dev, "asynchronous error: out-of-range 
overvoltage: %#.8x\n", *pStatus);
+               break;
+       case HIF_ERROR_PDS_VERSION:
+               dev_err(wdev->dev, "asynchronous error: wrong PDS payload or 
version: %#.8x\n", *pStatus);
+               break;
+       default:
+               dev_err(wdev->dev, "asynchronous error: unknown (%d)\n", 
body->type);
+               break;
+       }
+       return 0;
+}
+
+static int hif_generic_indication(struct wfx_dev *wdev, struct hif_msg *hif, 
void *buf)
+{
+       struct hif_ind_generic *body = buf;
+
+       switch (body->indication_type) {
+       case HIF_GENERIC_INDICATION_TYPE_RAW:
+               return 0;
+       case HIF_GENERIC_INDICATION_TYPE_STRING:
+               dev_info(wdev->dev, "firmware says: %s\n", (char *) 
body->indication_data.raw_data);
+               return 0;
+       case HIF_GENERIC_INDICATION_TYPE_RX_STATS:
+               mutex_lock(&wdev->rx_stats_lock);
+               // Older firmware send a generic indication beside RxStats
+               if (!wfx_api_older_than(wdev, 1, 4))
+                       dev_info(wdev->dev, "Rx test ongoing. Temperature: 
%d°C\n", body->indication_data.rx_stats.current_temp);
+               memcpy(&wdev->rx_stats, &body->indication_data.rx_stats, 
sizeof(wdev->rx_stats));
+               mutex_unlock(&wdev->rx_stats_lock);
+               return 0;
+       default:
+               dev_err(wdev->dev, "generic_indication: unknown indication 
type: %#.8x\n", body->indication_type);
+               return -EIO;
+       }
+}
+
+static int hif_exception_indication(struct wfx_dev *wdev, struct hif_msg *hif, 
void *buf)
+{
+       size_t len = hif->len - 4; // drop header
+       dev_err(wdev->dev, "firmware exception\n");
+       print_hex_dump_bytes("Dump: ", DUMP_PREFIX_NONE, buf, len);
+       wdev->chip_frozen = 1;
+
+       return -1;
+}
+
 static const struct {
        int msg_id;
        int (*handler)(struct wfx_dev *wdev, struct hif_msg *hif, void *buf);
 } hif_handlers[] = {
        { HIF_IND_ID_STARTUP,              hif_startup_indication },
        { HIF_IND_ID_WAKEUP,               hif_wakeup_indication },
+       { HIF_IND_ID_JOIN_COMPLETE,        hif_join_complete_indication },
        { HIF_IND_ID_SL_EXCHANGE_PUB_KEYS, hif_keys_indication },
+       { HIF_IND_ID_GENERIC,              hif_generic_indication },
+       { HIF_IND_ID_ERROR,                hif_error_indication },
+       { HIF_IND_ID_EXCEPTION,            hif_exception_indication },
 };
 
 void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb)
diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c
index 5b04ea5f4353..2e71f446d4d4 100644
--- a/drivers/staging/wfx/main.c
+++ b/drivers/staging/wfx/main.c
@@ -212,6 +212,7 @@ struct wfx_dev *wfx_init_common(struct device *dev,
        wdev->pdata.gpio_wakeup = wfx_get_gpio(dev, gpio_wakeup, "wakeup");
        wfx_fill_sl_key(dev, &wdev->pdata);
 
+       mutex_init(&wdev->rx_stats_lock);
        init_completion(&wdev->firmware_ready);
        wfx_init_hif_cmd(&wdev->hif_cmd);
 
@@ -220,6 +221,7 @@ struct wfx_dev *wfx_init_common(struct device *dev,
 
 void wfx_free_common(struct wfx_dev *wdev)
 {
+       mutex_destroy(&wdev->rx_stats_lock);
        ieee80211_free_hw(wdev->hw);
 }
 
diff --git a/drivers/staging/wfx/wfx.h b/drivers/staging/wfx/wfx.h
index 7adb5bf67e90..49b776a07515 100644
--- a/drivers/staging/wfx/wfx.h
+++ b/drivers/staging/wfx/wfx.h
@@ -38,6 +38,9 @@ struct wfx_dev {
        int                     chip_frozen;
 
        struct wfx_hif_cmd      hif_cmd;
+
+       struct hif_rx_stats     rx_stats;
+       struct mutex            rx_stats_lock;
 };
 
 struct wfx_vif {
@@ -46,4 +49,17 @@ struct wfx_vif {
        int                     id;
 };
 
+static inline struct wfx_vif *wdev_to_wvif(struct wfx_dev *wdev, int vif_id)
+{
+       if (vif_id >= ARRAY_SIZE(wdev->vif)) {
+               dev_dbg(wdev->dev, "requesting non-existent vif: %d\n", vif_id);
+               return NULL;
+       }
+       if (!wdev->vif[vif_id]) {
+               dev_dbg(wdev->dev, "requesting non-allocated vif: %d\n", 
vif_id);
+               return NULL;
+       }
+       return (struct wfx_vif *) wdev->vif[vif_id]->drv_priv;
+}
+
 #endif /* WFX_H */
-- 
2.20.1
_______________________________________________
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

Reply via email to