Adds support for interrupt coalescing feature to reduce interrupt events.
Provides a mechanism of adjusting coalescing count and timeout tick by sysfs
at runtime, so that tradeoff of latency and CPU load can be made depending
on different applications.
Signed-off-by: Qiang Liu qiang@freescale.com
---
change for V3
change the title and comments according the feedback
support dynamic config interrupt coalescing register by /sysfs
test random small file with iometer
adjust kernel source baseline for apply upstream
Description:
1. fsl-sata interrupt will be raised 130 thousand times when write 8G file
(dd if=/dev/zero of=/dev/sda2 bs=128K count=65536);
2. most of interrupts raised because of only 1-4 commands completed;
3. only 30 thousand times will be raised after set max interrupt threshold,
more interrupts are coalesced as the description of ICC;
Test methods and results:
1. test sequential large file performance,
[root@p2020ds root]# echo 31 524287 \
/sys/devices/soc.0/ffe18000.sata/intr_coalescing
[root@p2020ds root]# dd if=/dev/zero of=/dev/sda2 bs=128K count=65536
[root@p2020ds root]# top
CPU % | dd | flush-8:0 | softirq
---
before | 20-22 |17-19 |7
---
after | 18-21 |15-16 |5
---
2. test random small file with iometer,
iometer paramters:
4 I/Os burst length, 1MB transfer request size, 100% write, 2MB file size
as default configuration of interrupt coalescing register, 1 interrupts and
no timeout config, total write performance is 119MB per second,
after config with the maximum value, write performance is 110MB per second.
After compare the test results, a configuable interrupt coalescing should be
better when cope with flexible context.
drivers/ata/sata_fsl.c | 111 ++--
1 files changed, 107 insertions(+), 4 deletions(-)
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index 0120b0d..d6577b9 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -6,7 +6,7 @@
* Author: Ashish Kalra ashish.ka...@freescale.com
* Li Yang le...@freescale.com
*
- * Copyright (c) 2006-2007, 2011 Freescale Semiconductor, Inc.
+ * Copyright (c) 2006-2007, 2011-2012 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -26,6 +26,15 @@
#include asm/io.h
#include linux/of_platform.h
+static unsigned int intr_coalescing_count;
+module_param(intr_coalescing_count, int, S_IRUGO);
+MODULE_PARM_DESC(intr_coalescing_count,
+INT coalescing count threshold (1..31));
+
+static unsigned int intr_coalescing_ticks;
+module_param(intr_coalescing_ticks, int, S_IRUGO);
+MODULE_PARM_DESC(intr_coalescing_ticks,
+INT coalescing timer threshold in AHB ticks);
/* Controller information */
enum {
SATA_FSL_QUEUE_DEPTH= 16,
@@ -83,6 +92,16 @@ enum {
};
/*
+ * Interrupt Coalescing Control Register bitdefs */
+enum {
+ ICC_MIN_INT_COUNT_THRESHOLD = 1,
+ ICC_MAX_INT_COUNT_THRESHOLD = ((1 5) - 1),
+ ICC_MIN_INT_TICKS_THRESHOLD = 0,
+ ICC_MAX_INT_TICKS_THRESHOLD = ((1 19) - 1),
+ ICC_SAFE_INT_TICKS = 1,
+};
+
+/*
* Host Controller command register set - per port
*/
enum {
@@ -263,8 +282,65 @@ struct sata_fsl_host_priv {
void __iomem *csr_base;
int irq;
int data_snoop;
+ struct device_attribute intr_coalescing;
};
+static void fsl_sata_set_irq_coalescing(struct ata_host *host,
+ unsigned int count, unsigned int ticks)
+{
+ struct sata_fsl_host_priv *host_priv = host-private_data;
+ void __iomem *hcr_base = host_priv-hcr_base;
+
+ if (count ICC_MAX_INT_COUNT_THRESHOLD)
+ count = ICC_MAX_INT_COUNT_THRESHOLD;
+ else if (count ICC_MIN_INT_COUNT_THRESHOLD)
+ count = ICC_MIN_INT_COUNT_THRESHOLD;
+
+ if (ticks ICC_MAX_INT_TICKS_THRESHOLD)
+ ticks = ICC_MAX_INT_TICKS_THRESHOLD;
+ else if ((ICC_MIN_INT_TICKS_THRESHOLD == ticks)
+ (count ICC_MIN_INT_COUNT_THRESHOLD))
+ ticks = ICC_SAFE_INT_TICKS;
+
+ spin_lock(host-lock);
+ iowrite32((count 24 | ticks), hcr_base + ICC);
+
+ intr_coalescing_count = count;
+ intr_coalescing_ticks = ticks;
+ spin_unlock(host-lock);
+
+ DPRINTK(intrrupt coalescing, count = 0x%x, ticks = %x\n,
+ intr_coalescing_count, intr_coalescing_ticks);
+ DPRINTK(ICC register status: (hcr base: 0x%x) = 0x%x\n,
+ hcr_base, ioread32(hcr_base + ICC));
+}
+
+static ssize_t