diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/mvsas/mv_64xx.c | 25 | ||||
-rw-r--r-- | drivers/scsi/mvsas/mv_94xx.c | 26 | ||||
-rw-r--r-- | drivers/scsi/mvsas/mv_init.c | 75 | ||||
-rw-r--r-- | drivers/scsi/mvsas/mv_sas.h | 2 |
4 files changed, 126 insertions, 2 deletions
diff --git a/drivers/scsi/mvsas/mv_64xx.c b/drivers/scsi/mvsas/mv_64xx.c index 0e13e6441da7..c88b8a7ed398 100644 --- a/drivers/scsi/mvsas/mv_64xx.c +++ b/drivers/scsi/mvsas/mv_64xx.c @@ -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, }; diff --git a/drivers/scsi/mvsas/mv_94xx.c b/drivers/scsi/mvsas/mv_94xx.c index 3f2ad934c917..e589f31cb2b4 100644 --- a/drivers/scsi/mvsas/mv_94xx.c +++ b/drivers/scsi/mvsas/mv_94xx.c @@ -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, }; diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index 9f1cccc2a3ed..531093ddc418 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -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); diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h index ccd622f7f841..089ef1ef3865 100644 --- a/drivers/scsi/mvsas/mv_sas.h +++ b/drivers/scsi/mvsas/mv_sas.h @@ -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); }; |