[SCSI] mvsas: Add driver version and interrupt coalescing to device attributes in...
authorXiangliang Yu <yuxiangl@marvell.com>
Tue, 24 May 2011 14:31:47 +0000 (22:31 +0800)
committerJames Bottomley <JBottomley@Parallels.com>
Tue, 26 Jul 2011 06:33:11 +0000 (10:33 +0400)
Signed-off-by: Xiangliang Yu <yuxiangl@marvell.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/mvsas/mv_64xx.c
drivers/scsi/mvsas/mv_94xx.c
drivers/scsi/mvsas/mv_init.c
drivers/scsi/mvsas/mv_sas.h

index 0e13e64..c88b8a7 100644 (file)
@@ -402,7 +402,7 @@ static int __devinit mvs_64xx_init(struct mvs_info *mvi)
        tmp = 0;
        mw32(MVS_INT_COAL, tmp);
 
-       tmp = 0x100;
+       tmp = 0x10000 | interrupt_coalescing;
        mw32(MVS_INT_COAL_TMOUT, tmp);
 
        /* ladies and gentlemen, start your engines */
@@ -758,6 +758,28 @@ void mvs_64xx_fix_dma(dma_addr_t buf_dma, int buf_len, int from, void *prd)
 }
 #endif
 
+static void mvs_64xx_tune_interrupt(struct mvs_info *mvi, u32 time)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp = 0;
+       /* interrupt coalescing may cause missing HW interrput in some case,
+        * and the max count is 0x1ff, while our max slot is 0x200,
+        * it will make count 0.
+        */
+       if (time == 0) {
+               mw32(MVS_INT_COAL, 0);
+               mw32(MVS_INT_COAL_TMOUT, 0x10000);
+       } else {
+               if (MVS_CHIP_SLOT_SZ > 0x1ff)
+                       mw32(MVS_INT_COAL, 0x1ff|COAL_EN);
+               else
+                       mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ|COAL_EN);
+
+               tmp = 0x10000 | time;
+               mw32(MVS_INT_COAL_TMOUT, tmp);
+       }
+}
+
 const struct mvs_dispatch mvs_64xx_dispatch = {
        "mv64xx",
        mvs_64xx_init,
@@ -811,6 +833,7 @@ const struct mvs_dispatch mvs_64xx_dispatch = {
 #ifndef DISABLE_HOTPLUG_DMA_FIX
        mvs_64xx_fix_dma,
 #endif
+       mvs_64xx_tune_interrupt,
        NULL,
 };
 
index 3f2ad93..e589f31 100644 (file)
@@ -475,7 +475,7 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi)
        tmp = 0;
        mw32(MVS_INT_COAL, tmp);
 
-       tmp = 0x100;
+       tmp = 0x10000 | interrupt_coalescing;
        mw32(MVS_INT_COAL_TMOUT, tmp);
 
        /* ladies and gentlemen, start your engines */
@@ -894,6 +894,29 @@ static void mvs_94xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set,
 {
 }
 
+static void mvs_94xx_tune_interrupt(struct mvs_info *mvi, u32 time)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp = 0;
+       /* interrupt coalescing may cause missing HW interrput in some case,
+        * and the max count is 0x1ff, while our max slot is 0x200,
+        * it will make count 0.
+        */
+       if (time == 0) {
+               mw32(MVS_INT_COAL, 0);
+               mw32(MVS_INT_COAL_TMOUT, 0x10000);
+       } else {
+               if (MVS_CHIP_SLOT_SZ > 0x1ff)
+                       mw32(MVS_INT_COAL, 0x1ff|COAL_EN);
+               else
+                       mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ|COAL_EN);
+
+               tmp = 0x10000 | time;
+               mw32(MVS_INT_COAL_TMOUT, tmp);
+       }
+
+}
+
 const struct mvs_dispatch mvs_94xx_dispatch = {
        "mv94xx",
        mvs_94xx_init,
@@ -947,6 +970,7 @@ const struct mvs_dispatch mvs_94xx_dispatch = {
 #ifndef DISABLE_HOTPLUG_DMA_FIX
        mvs_94xx_fix_dma,
 #endif
+       mvs_94xx_tune_interrupt,
        mvs_94xx_non_spec_ncq_error,
 };
 
index 9f1cccc..531093d 100644 (file)
@@ -34,6 +34,8 @@ MODULE_PARM_DESC(collector, "\n"
        "\tThe mvsas SAS LLDD supports both modes.\n"
        "\tDefault: 1 (Direct Mode).\n");
 
+int interrupt_coalescing = 0x80;
+
 static struct scsi_transport_template *mvs_stt;
 struct kmem_cache *mvs_task_list_cache;
 static const struct mvs_chip_info mvs_chips[] = {
@@ -48,6 +50,8 @@ static const struct mvs_chip_info mvs_chips[] = {
        [chip_1320] =   { 2, 4, 0x800, 17, 64,  9, &mvs_94xx_dispatch, },
 };
 
+struct device_attribute *mvst_host_attrs[];
+
 #define SOC_SAS_NUM 2
 #define SG_MX 64
 
@@ -74,6 +78,7 @@ static struct scsi_host_template mvs_sht = {
        .slave_alloc            = mvs_slave_alloc,
        .target_destroy         = sas_target_destroy,
        .ioctl                  = sas_ioctl,
+       .shost_attrs            = mvst_host_attrs,
 };
 
 static struct sas_domain_function_template mvs_transport_ops = {
@@ -706,6 +711,70 @@ static struct pci_driver mvs_pci_driver = {
        .remove         = __devexit_p(mvs_pci_remove),
 };
 
+static ssize_t
+mvs_show_driver_version(struct device *cdev,
+               struct device_attribute *attr,  char *buffer)
+{
+       return snprintf(buffer, PAGE_SIZE, "%s\n", DRV_VERSION);
+}
+
+static DEVICE_ATTR(driver_version,
+                        S_IRUGO,
+                        mvs_show_driver_version,
+                        NULL);
+
+static ssize_t
+mvs_store_interrupt_coalescing(struct device *cdev,
+                       struct device_attribute *attr,
+                       const char *buffer, size_t size)
+{
+       int val = 0;
+       struct mvs_info *mvi = NULL;
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+       u8 i, core_nr;
+       if (buffer == NULL)
+               return size;
+
+       if (sscanf(buffer, "%d", &val) != 1)
+               return -EINVAL;
+
+       if (val >= 0x10000) {
+               mv_dprintk("interrupt coalescing timer %d us is"
+                       "too long\n", val);
+               return strlen(buffer);
+       }
+
+       interrupt_coalescing = val;
+
+       core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
+       mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0];
+
+       if (unlikely(!mvi))
+               return -EINVAL;
+
+       for (i = 0; i < core_nr; i++) {
+               mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i];
+               if (MVS_CHIP_DISP->tune_interrupt)
+                       MVS_CHIP_DISP->tune_interrupt(mvi,
+                               interrupt_coalescing);
+       }
+       mv_dprintk("set interrupt coalescing time to %d us\n",
+               interrupt_coalescing);
+       return strlen(buffer);
+}
+
+static ssize_t mvs_show_interrupt_coalescing(struct device *cdev,
+                       struct device_attribute *attr, char *buffer)
+{
+       return snprintf(buffer, PAGE_SIZE, "%d\n", interrupt_coalescing);
+}
+
+static DEVICE_ATTR(interrupt_coalescing,
+                        S_IRUGO|S_IWUSR,
+                        mvs_show_interrupt_coalescing,
+                        mvs_store_interrupt_coalescing);
+
 /* task handler */
 struct task_struct *mvs_th;
 static int __init mvs_init(void)
@@ -742,6 +811,12 @@ static void __exit mvs_exit(void)
        kmem_cache_destroy(mvs_task_list_cache);
 }
 
+struct device_attribute *mvst_host_attrs[] = {
+       &dev_attr_driver_version,
+       &dev_attr_interrupt_coalescing,
+       NULL,
+};
+
 module_init(mvs_init);
 module_exit(mvs_exit);
 
index ccd622f..089ef1e 100644 (file)
@@ -64,6 +64,7 @@
 #endif
 #define MV_MAX_U32                     0xffffffff
 
+extern int interrupt_coalescing;
 extern struct mvs_tgt_initiator mvs_tgt;
 extern struct mvs_info *tgt_mvi;
 extern const struct mvs_dispatch mvs_64xx_dispatch;
@@ -170,6 +171,7 @@ struct mvs_dispatch {
 #ifndef DISABLE_HOTPLUG_DMA_FIX
        void (*dma_fix)(dma_addr_t buf_dma, int buf_len, int from, void *prd);
 #endif
+       void (*tune_interrupt)(struct mvs_info *mvi, u32 time);
        void (*non_spec_ncq_error)(struct mvs_info *mvi);
 
 };