mirror of https://gitee.com/openkylin/linux.git
spi: bcm2835: add driver stats to debugfs
To estimate efficiency add statistics on transfer types (polling, interrupt and dma) used to debugfs. Signed-off-by: Martin Sperl <kernel@martin.sperl.org> Changelog: V1 -> V2: applied feedback by Stefan Wahren reorganized patchset added extra rational, descriptions fixed compile issue when CONFIG_DEBUG_FS is unset Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
ff245d90eb
commit
154f7da56f
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmaengine.h>
|
||||
|
@ -101,6 +102,15 @@ MODULE_PARM_DESC(polling_limit_us,
|
|||
* length is not a multiple of 4 (to overcome hardware limitation)
|
||||
* @tx_spillover: whether @tx_prologue spills over to second TX sglist entry
|
||||
* @dma_pending: whether a DMA transfer is in progress
|
||||
* @debugfs_dir: the debugfs directory - neede to remove debugfs when
|
||||
* unloading the module
|
||||
* @count_transfer_polling: count of how often polling mode is used
|
||||
* @count_transfer_irq: count of how often interrupt mode is used
|
||||
* @count_transfer_irq_after_polling: count of how often we fall back to
|
||||
* interrupt mode after starting in polling mode.
|
||||
* These are counted as well in @count_transfer_polling and
|
||||
* @count_transfer_irq
|
||||
* @count_transfer_dma: count how often dma mode is used
|
||||
*/
|
||||
struct bcm2835_spi {
|
||||
void __iomem *regs;
|
||||
|
@ -115,8 +125,55 @@ struct bcm2835_spi {
|
|||
int rx_prologue;
|
||||
unsigned int tx_spillover;
|
||||
unsigned int dma_pending;
|
||||
|
||||
struct dentry *debugfs_dir;
|
||||
u64 count_transfer_polling;
|
||||
u64 count_transfer_irq;
|
||||
u64 count_transfer_irq_after_polling;
|
||||
u64 count_transfer_dma;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
static void bcm2835_debugfs_create(struct bcm2835_spi *bs,
|
||||
const char *dname)
|
||||
{
|
||||
char name[64];
|
||||
struct dentry *dir;
|
||||
|
||||
/* get full name */
|
||||
snprintf(name, sizeof(name), "spi-bcm2835-%s", dname);
|
||||
|
||||
/* the base directory */
|
||||
dir = debugfs_create_dir(name, NULL);
|
||||
bs->debugfs_dir = dir;
|
||||
|
||||
/* the counters */
|
||||
debugfs_create_u64("count_transfer_polling", 0444, dir,
|
||||
&bs->count_transfer_polling);
|
||||
debugfs_create_u64("count_transfer_irq", 0444, dir,
|
||||
&bs->count_transfer_irq);
|
||||
debugfs_create_u64("count_transfer_irq_after_polling", 0444, dir,
|
||||
&bs->count_transfer_irq_after_polling);
|
||||
debugfs_create_u64("count_transfer_dma", 0444, dir,
|
||||
&bs->count_transfer_dma);
|
||||
}
|
||||
|
||||
static void bcm2835_debugfs_remove(struct bcm2835_spi *bs)
|
||||
{
|
||||
debugfs_remove_recursive(bs->debugfs_dir);
|
||||
bs->debugfs_dir = NULL;
|
||||
}
|
||||
#else
|
||||
static void bcm2835_debugfs_create(struct bcm2835_spi *bs,
|
||||
const char *dname)
|
||||
{
|
||||
}
|
||||
|
||||
static void bcm2835_debugfs_remove(struct bcm2835_spi *bs)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
||||
static inline u32 bcm2835_rd(struct bcm2835_spi *bs, unsigned reg)
|
||||
{
|
||||
return readl(bs->regs + reg);
|
||||
|
@ -320,6 +377,9 @@ static int bcm2835_spi_transfer_one_irq(struct spi_master *master,
|
|||
{
|
||||
struct bcm2835_spi *bs = spi_master_get_devdata(master);
|
||||
|
||||
/* update usage statistics */
|
||||
bs->count_transfer_irq++;
|
||||
|
||||
/*
|
||||
* Enable HW block, but with interrupts still disabled.
|
||||
* Otherwise the empty TX FIFO would immediately trigger an interrupt.
|
||||
|
@ -564,6 +624,9 @@ static int bcm2835_spi_transfer_one_dma(struct spi_master *master,
|
|||
struct bcm2835_spi *bs = spi_master_get_devdata(master);
|
||||
int ret;
|
||||
|
||||
/* update usage statistics */
|
||||
bs->count_transfer_dma++;
|
||||
|
||||
/*
|
||||
* Transfer first few bytes without DMA if length of first TX or RX
|
||||
* sglist entry is not a multiple of 4 bytes (hardware limitation).
|
||||
|
@ -706,6 +769,9 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
|
|||
struct bcm2835_spi *bs = spi_master_get_devdata(master);
|
||||
unsigned long timeout;
|
||||
|
||||
/* update usage statistics */
|
||||
bs->count_transfer_polling++;
|
||||
|
||||
/* enable HW block without interrupts */
|
||||
bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA);
|
||||
|
||||
|
@ -735,6 +801,10 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
|
|||
jiffies - timeout,
|
||||
bs->tx_len, bs->rx_len);
|
||||
/* fall back to interrupt mode */
|
||||
|
||||
/* update usage statistics */
|
||||
bs->count_transfer_irq_after_polling++;
|
||||
|
||||
return bcm2835_spi_transfer_one_irq(master, spi,
|
||||
tfr, cs, false);
|
||||
}
|
||||
|
@ -982,6 +1052,8 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
|
|||
goto out_clk_disable;
|
||||
}
|
||||
|
||||
bcm2835_debugfs_create(bs, dev_name(&pdev->dev));
|
||||
|
||||
return 0;
|
||||
|
||||
out_clk_disable:
|
||||
|
@ -996,6 +1068,8 @@ static int bcm2835_spi_remove(struct platform_device *pdev)
|
|||
struct spi_master *master = platform_get_drvdata(pdev);
|
||||
struct bcm2835_spi *bs = spi_master_get_devdata(master);
|
||||
|
||||
bcm2835_debugfs_remove(bs);
|
||||
|
||||
/* Clear FIFOs, and disable the HW block */
|
||||
bcm2835_wr(bs, BCM2835_SPI_CS,
|
||||
BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
|
||||
|
|
Loading…
Reference in New Issue