unsigned int retry_count;
unsigned int excessive_retries;
+
+ unsigned int tx_to_fw;
+ unsigned int tx_timeouts;
+ unsigned int tx_other_err;
};
struct wl1251_debugfs {
return 0;
}
+int wl1251_acx_error_counters(struct wl1251 *wl, struct acx_error_counters *counts)
+{
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx error counters");
+
+ ret = wl1251_cmd_interrogate(wl, ACX_ERROR_CNT, counts,
+ sizeof(*counts));
+ if (ret < 0) {
+ wl1251_warning("acx error counters failed: %d", ret);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
int wl1251_acx_rate_policies(struct wl1251 *wl)
{
struct acx_rate_policy *acx;
struct acx_rxpipe_statistics rxpipe;
} __packed;
+struct acx_error_counters
+{
+ struct acx_header header;
+ u32 plcp_error_count; /* PLCP error count, clears on read */
+ u32 fcs_error_count; /* FCS error count, clears on read */
+ u32 valid_frame_count; /* number of MPDUs without PLCP header errors */
+ /* auto clear */
+ u32 seq_num_miss_count; /* missed sequence numbers in the squentially */
+ /* values of frames seq numbers */
+} __packed;
+
#define ACX_MAX_RATE_CLASSES 8
#define ACX_RATE_MASK_UNSPECIFIED 0
#define ACX_RATE_RETRY_LIMIT 10
int wl1251_acx_cts_protect(struct wl1251 *wl,
enum acx_ctsprotect_type ctsprotect);
int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats);
+int wl1251_acx_error_counters(struct wl1251 *wl, struct acx_error_counters *counts);
int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime);
int wl1251_acx_rate_policies(struct wl1251 *wl);
int wl1251_acx_mem_cfg(struct wl1251 *wl);
return 0;
}
+static ssize_t wl1251_sysfs_show_wl_stats(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct wl1251 *wl = dev_get_drvdata(dev);
+ struct acx_error_counters counts;
+ struct acx_statistics stats;
+ ssize_t len;
+ int ret;
+
+ memset(&counts, 0, sizeof(counts));
+ memset(&stats, 0, sizeof(stats));
+
+ mutex_lock(&wl->mutex);
+
+ if (wl->state != WL1251_STATE_ON)
+ goto out;
+
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ wl1251_acx_error_counters(wl, &counts);
+ //wl1251_acx_statistics(wl, &stats);
+
+ wl1251_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+
+ len = snprintf(buf, PAGE_SIZE, "%u %u %u %u "
+ "%u %u %u %u\n",
+ counts.fcs_error_count, counts.plcp_error_count,
+ counts.seq_num_miss_count, counts.valid_frame_count,
+ wl->stats.retry_count, wl->stats.tx_timeouts,
+ wl->stats.tx_other_err, wl->stats.tx_to_fw);
+
+ return len;
+}
+
+static DEVICE_ATTR(wl_stats, S_IRUGO | S_IWUSR,
+ wl1251_sysfs_show_wl_stats,
+ NULL);
+
int wl1251_init_ieee80211(struct wl1251 *wl)
{
int ret;
if (ret)
goto out;
+ ret = device_create_file(wiphy_dev(wl->hw->wiphy), &dev_attr_wl_stats);
+ if (ret < 0)
+ wl1251_error("failed to create sysfs file");
+
wl1251_debugfs_init(wl);
wl1251_notice("initialized");
int wl1251_free_hw(struct wl1251 *wl)
{
+ device_remove_file(wiphy_dev(wl->hw->wiphy), &dev_attr_wl_stats);
ieee80211_unregister_hw(wl->hw);
wl1251_debugfs_exit(wl);
wl1251_tx_trigger(wl);
+ wl->stats.tx_to_fw++;
+
return ret;
}
info->status.rates[0].count = result->ack_failures + 1;
wl->stats.retry_count += result->ack_failures;
+ if (result->status != TX_SUCCESS) {
+ if (result->status & TX_TIMEOUT)
+ wl->stats.tx_timeouts++;
+ else
+ wl->stats.tx_other_err++;
+ }
+
/*
* We have to remove our private TX header before pushing
* the skb back to mac80211.