|
@@ -31,6 +31,7 @@
|
|
|
#include <linux/skbuff.h>
|
|
|
#include <linux/of_gpio.h>
|
|
|
#include <linux/ieee802154.h>
|
|
|
+#include <linux/debugfs.h>
|
|
|
|
|
|
#include <net/mac802154.h>
|
|
|
#include <net/cfg802154.h>
|
|
@@ -83,6 +84,15 @@ struct at86rf230_state_change {
|
|
|
bool irq_enable;
|
|
|
};
|
|
|
|
|
|
+struct at86rf230_trac {
|
|
|
+ u64 success;
|
|
|
+ u64 success_data_pending;
|
|
|
+ u64 success_wait_for_ack;
|
|
|
+ u64 channel_access_failure;
|
|
|
+ u64 no_ack;
|
|
|
+ u64 invalid;
|
|
|
+};
|
|
|
+
|
|
|
struct at86rf230_local {
|
|
|
struct spi_device *spi;
|
|
|
|
|
@@ -103,6 +113,8 @@ struct at86rf230_local {
|
|
|
u8 tx_retry;
|
|
|
struct sk_buff *tx_skb;
|
|
|
struct at86rf230_state_change tx;
|
|
|
+
|
|
|
+ struct at86rf230_trac trac;
|
|
|
};
|
|
|
|
|
|
#define AT86RF2XX_NUMREGS 0x3F
|
|
@@ -660,6 +672,31 @@ at86rf230_tx_trac_check(void *context)
|
|
|
struct at86rf230_state_change *ctx = context;
|
|
|
struct at86rf230_local *lp = ctx->lp;
|
|
|
|
|
|
+ if (IS_ENABLED(CONFIG_IEEE802154_AT86RF230_DEBUGFS)) {
|
|
|
+ u8 trac = TRAC_MASK(ctx->buf[1]);
|
|
|
+
|
|
|
+ switch (trac) {
|
|
|
+ case TRAC_SUCCESS:
|
|
|
+ lp->trac.success++;
|
|
|
+ break;
|
|
|
+ case TRAC_SUCCESS_DATA_PENDING:
|
|
|
+ lp->trac.success_data_pending++;
|
|
|
+ break;
|
|
|
+ case TRAC_CHANNEL_ACCESS_FAILURE:
|
|
|
+ lp->trac.channel_access_failure++;
|
|
|
+ break;
|
|
|
+ case TRAC_NO_ACK:
|
|
|
+ lp->trac.no_ack++;
|
|
|
+ break;
|
|
|
+ case TRAC_INVALID:
|
|
|
+ lp->trac.invalid++;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ WARN_ONCE(1, "received tx trac status %d\n", trac);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
at86rf230_async_state_change(lp, &lp->irq, STATE_TX_ON,
|
|
|
at86rf230_tx_on, true);
|
|
|
}
|
|
@@ -696,13 +733,32 @@ at86rf230_rx_read_frame_complete(void *context)
|
|
|
}
|
|
|
|
|
|
static void
|
|
|
-at86rf230_rx_read_frame(void *context)
|
|
|
+at86rf230_rx_trac_check(void *context)
|
|
|
{
|
|
|
struct at86rf230_state_change *ctx = context;
|
|
|
struct at86rf230_local *lp = ctx->lp;
|
|
|
u8 *buf = ctx->buf;
|
|
|
int rc;
|
|
|
|
|
|
+ if (IS_ENABLED(CONFIG_IEEE802154_AT86RF230_DEBUGFS)) {
|
|
|
+ u8 trac = TRAC_MASK(buf[1]);
|
|
|
+
|
|
|
+ switch (trac) {
|
|
|
+ case TRAC_SUCCESS:
|
|
|
+ lp->trac.success++;
|
|
|
+ break;
|
|
|
+ case TRAC_SUCCESS_WAIT_FOR_ACK:
|
|
|
+ lp->trac.success_wait_for_ack++;
|
|
|
+ break;
|
|
|
+ case TRAC_INVALID:
|
|
|
+ lp->trac.invalid++;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ WARN_ONCE(1, "received rx trac status %d\n", trac);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
buf[0] = CMD_FB;
|
|
|
ctx->trx.len = AT86RF2XX_MAX_BUF;
|
|
|
ctx->msg.complete = at86rf230_rx_read_frame_complete;
|
|
@@ -714,18 +770,6 @@ at86rf230_rx_read_frame(void *context)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void
|
|
|
-at86rf230_rx_trac_check(void *context)
|
|
|
-{
|
|
|
- /* Possible check on trac status here. This could be useful to make
|
|
|
- * some stats why receive is failed. Not used at the moment, but it's
|
|
|
- * maybe timing relevant. Datasheet doesn't say anything about this.
|
|
|
- * The programming guide say do it so.
|
|
|
- */
|
|
|
-
|
|
|
- at86rf230_rx_read_frame(context);
|
|
|
-}
|
|
|
-
|
|
|
static void
|
|
|
at86rf230_irq_trx_end(struct at86rf230_local *lp)
|
|
|
{
|
|
@@ -891,6 +935,10 @@ at86rf230_start(struct ieee802154_hw *hw)
|
|
|
{
|
|
|
struct at86rf230_local *lp = hw->priv;
|
|
|
|
|
|
+ /* reset trac stats on start */
|
|
|
+ if (IS_ENABLED(CONFIG_IEEE802154_AT86RF230_DEBUGFS))
|
|
|
+ memset(&lp->trac, 0, sizeof(struct at86rf230_trac));
|
|
|
+
|
|
|
at86rf230_awake(lp);
|
|
|
enable_irq(lp->spi->irq);
|
|
|
|
|
@@ -1591,6 +1639,81 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp)
|
|
|
lp->tx.timer.function = at86rf230_async_state_timer;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_IEEE802154_AT86RF230_DEBUGFS
|
|
|
+static struct dentry *at86rf230_debugfs_root;
|
|
|
+
|
|
|
+static int at86rf230_stats_show(struct seq_file *file, void *offset)
|
|
|
+{
|
|
|
+ struct at86rf230_local *lp = file->private;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = seq_printf(file, "SUCCESS:\t\t%8llu\n", lp->trac.success);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ ret = seq_printf(file, "SUCCESS_DATA_PENDING:\t%8llu\n",
|
|
|
+ lp->trac.success_data_pending);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ ret = seq_printf(file, "SUCCESS_WAIT_FOR_ACK:\t%8llu\n",
|
|
|
+ lp->trac.success_wait_for_ack);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ ret = seq_printf(file, "CHANNEL_ACCESS_FAILURE:\t%8llu\n",
|
|
|
+ lp->trac.channel_access_failure);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ ret = seq_printf(file, "NO_ACK:\t\t\t%8llu\n", lp->trac.no_ack);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ return seq_printf(file, "INVALID:\t\t%8llu\n", lp->trac.invalid);
|
|
|
+}
|
|
|
+
|
|
|
+static int at86rf230_stats_open(struct inode *inode, struct file *file)
|
|
|
+{
|
|
|
+ return single_open(file, at86rf230_stats_show, inode->i_private);
|
|
|
+}
|
|
|
+
|
|
|
+static const struct file_operations at86rf230_stats_fops = {
|
|
|
+ .open = at86rf230_stats_open,
|
|
|
+ .read = seq_read,
|
|
|
+ .llseek = seq_lseek,
|
|
|
+ .release = single_release,
|
|
|
+};
|
|
|
+
|
|
|
+static int at86rf230_debugfs_init(struct at86rf230_local *lp)
|
|
|
+{
|
|
|
+ char debugfs_dir_name[DNAME_INLINE_LEN + 1] = "at86rf230-";
|
|
|
+ struct dentry *stats;
|
|
|
+
|
|
|
+ strncat(debugfs_dir_name, dev_name(&lp->spi->dev), DNAME_INLINE_LEN);
|
|
|
+
|
|
|
+ at86rf230_debugfs_root = debugfs_create_dir(debugfs_dir_name, NULL);
|
|
|
+ if (!at86rf230_debugfs_root)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ stats = debugfs_create_file("trac_stats", S_IRUGO,
|
|
|
+ at86rf230_debugfs_root, lp,
|
|
|
+ &at86rf230_stats_fops);
|
|
|
+ if (!stats)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void at86rf230_debugfs_remove(void)
|
|
|
+{
|
|
|
+ debugfs_remove_recursive(at86rf230_debugfs_root);
|
|
|
+}
|
|
|
+#else
|
|
|
+static int at86rf230_debugfs_init(struct at86rf230_local *lp) { return 0; }
|
|
|
+static void at86rf230_debugfs_remove(void) { }
|
|
|
+#endif
|
|
|
+
|
|
|
static int at86rf230_probe(struct spi_device *spi)
|
|
|
{
|
|
|
struct ieee802154_hw *hw;
|
|
@@ -1686,12 +1809,18 @@ static int at86rf230_probe(struct spi_device *spi)
|
|
|
/* going into sleep by default */
|
|
|
at86rf230_sleep(lp);
|
|
|
|
|
|
- rc = ieee802154_register_hw(lp->hw);
|
|
|
+ rc = at86rf230_debugfs_init(lp);
|
|
|
if (rc)
|
|
|
goto free_dev;
|
|
|
|
|
|
+ rc = ieee802154_register_hw(lp->hw);
|
|
|
+ if (rc)
|
|
|
+ goto free_debugfs;
|
|
|
+
|
|
|
return rc;
|
|
|
|
|
|
+free_debugfs:
|
|
|
+ at86rf230_debugfs_remove();
|
|
|
free_dev:
|
|
|
ieee802154_free_hw(lp->hw);
|
|
|
|
|
@@ -1706,6 +1835,7 @@ static int at86rf230_remove(struct spi_device *spi)
|
|
|
at86rf230_write_subreg(lp, SR_IRQ_MASK, 0);
|
|
|
ieee802154_unregister_hw(lp->hw);
|
|
|
ieee802154_free_hw(lp->hw);
|
|
|
+ at86rf230_debugfs_remove();
|
|
|
dev_dbg(&spi->dev, "unregistered at86rf230\n");
|
|
|
|
|
|
return 0;
|