From: Wen Xiong <wenxi...@linux.vnet.ibm.com> --- drivers/scsi/ipr.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++- drivers/scsi/ipr.h | 3 + 2 files changed, 159 insertions(+), 1 deletions(-)
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 1248d27..3ae9ead 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -102,6 +102,8 @@ static unsigned int ipr_number_of_msix = 2; static unsigned int ipr_fast_reboot; static unsigned int ipr_cpu_map = 0; static unsigned int ipr_use_blk_mq = 0; +static unsigned int ipr_poll_mode = 0; +static unsigned int ipr_poll_timer = 10; static unsigned int *ipr_used_cpu; static unsigned int ipr_possible_cpu_cnt; @@ -234,7 +236,10 @@ module_param_named(cpu_map, ipr_cpu_map, int, 0); MODULE_PARM_DESC(cpu_map, "Defines how to map CPUs to IRQ vectors per adapter"); module_param_named(use_blk_mq, ipr_use_blk_mq, uint, S_IRUGO); MODULE_PARM_DESC(use_blk_mq, "ipr use block mq enable/disable. (default: disable(0))"); - +module_param_named(poll_mode, ipr_poll_mode, uint, S_IRUGO); +MODULE_PARM_DESC(poll_mode, "ipr polling mode enable/disable. (default: disable(0))"); +module_param_named(poll_timer, ipr_poll_timer, uint, S_IRUGO); +MODULE_PARM_DESC(poll_timer, "Milliseconds between polling. (default: 10)"); MODULE_LICENSE("GPL"); MODULE_VERSION(IPR_DRIVER_VERSION); @@ -3749,6 +3754,69 @@ static struct device_attribute ipr_iopoll_weight_attr = { }; /** + * ipr_show_poll_mode - Show ipr polling mode + * @dev: class device struct + * @buf: buffer + * + * Return value: + * number of bytes printed to buffer + **/ +static ssize_t ipr_show_poll_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; + unsigned long lock_flags = 0; + int len; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + len = snprintf(buf, PAGE_SIZE, "%d\n", ioa_cfg->poll_mode); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return len; +} + +static void ipr_disable_hrrq_interrupt(struct ipr_ioa_cfg *ioa_cfg); +/** + * ipr_store_poll_mode - Change the adapter's polling mode + * @dev: class device struct + * @buf: buffer + * + * Return value: + * number of bytes printed to buffer + **/ +static ssize_t ipr_store_poll_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; + unsigned long lock_flags; + int i; + + if (kstrtoul(buf, 10, &ioa_cfg->poll_mode)) + return -EINVAL; + + if (ioa_cfg->poll_mode && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) { + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + ipr_disable_hrrq_interrupt(ioa_cfg); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + for (i = 0; i < IPR_MAX_HRRQ_NUM; i++) + add_timer(&ioa_cfg->hrrq[i].hrrq_poll_timer); + } + + return strlen(buf); +} + +static struct device_attribute ipr_poll_mode_attr = { + .attr = { + .name = "poll_mode", + .mode = S_IRUGO | S_IWUSR, + }, + .show = ipr_show_poll_mode, + .store = ipr_store_poll_mode +}; + +/** * ipr_alloc_ucode_buffer - Allocates a microcode download buffer * @buf_len: buffer length * @@ -4190,6 +4258,7 @@ static struct device_attribute *ipr_ioa_attrs[] = { &ipr_ioa_fw_type_attr, &ipr_iopoll_weight_attr, &ipr_cpu_map_attr, + &ipr_poll_mode_attr, NULL, }; @@ -5597,6 +5666,47 @@ static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg, } /** + * ipr_disable_hrrq_interrupt - Disable HRRQ interrupt + * @ioa_cfg pointer to ioa config struct + * +**/ +static void ipr_disable_hrrq_interrupt(struct ipr_ioa_cfg *ioa_cfg) +{ + u32 int_reg; + + /* Mask HRRQ interrupt */ + if (ioa_cfg->sis64) + writeq(IPR_PCII_HRRQ_UPDATED, + ioa_cfg->regs.set_interrupt_mask_reg); + + /* MMIO read to flush the write */ + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32); +} + +/** + * ipr_enable_hrrq_interrupt - Enable HRRQ interrupt + * @ioa_cfg pointer to ioa config struct + * + **/ +static void ipr_enable_hrrq_interrupt(struct ipr_ioa_cfg *ioa_cfg) +{ + u32 int_reg; + int i; + + for (i = 0; i < IPR_MAX_HRRQ_NUM; i++) + if (!ioa_cfg->hrrq[i].allow_interrupts) + return; + + /* Enable HRRQ interrupt */ + if (ioa_cfg->sis64) + writeq(IPR_PCII_HRRQ_UPDATED, + ioa_cfg->regs.clr_interrupt_mask_reg); + + /* MMIO read to flush the write */ + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32); +} + +/** * ipr_isr_eh - Interrupt service routine error handler * @ioa_cfg: ioa config struct * @msg: message to log @@ -5692,6 +5802,29 @@ static int ipr_iopoll(struct blk_iopoll *iop, int budget) return completed_ops; } +void ipr_hrrq_poll_timeout(unsigned long ptr) +{ + struct ipr_hrr_queue *hrrq = (struct ipr_hrr_queue *) ptr; + struct ipr_ioa_cfg *ioa_cfg = hrrq->ioa_cfg; + struct ipr_cmnd *ipr_cmd, *temp; + unsigned long hrrq_flags; + LIST_HEAD(doneq); + + if (ioa_cfg->poll_mode && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) { + spin_lock_irqsave(hrrq->lock, hrrq_flags); + ipr_process_hrrq(hrrq, -1, &doneq); + spin_unlock_irqrestore(hrrq->lock, hrrq_flags); + + list_for_each_entry_safe(ipr_cmd, temp, &doneq, queue) { + list_del(&ipr_cmd->queue); + del_timer(&ipr_cmd->timer); + ipr_cmd->fast_done(ipr_cmd); + } + mod_timer(&hrrq->hrrq_poll_timer, + (jiffies + msecs_to_jiffies(ipr_poll_timer))); + } +} + /** * ipr_isr - Interrupt service routine * @irq: irq number @@ -9880,6 +10013,11 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg, ioa_cfg->hrrq[i].lock = ioa_cfg->host->host_lock; else ioa_cfg->hrrq[i].lock = &ioa_cfg->hrrq[i]._lock; + + init_timer(&ioa_cfg->hrrq[i].hrrq_poll_timer); + ioa_cfg->hrrq[i].hrrq_poll_timer.function = ipr_hrrq_poll_timeout; + ioa_cfg->hrrq[i].hrrq_poll_timer.data = (unsigned long) &ioa_cfg->hrrq[i]; + ioa_cfg->hrrq[i].hrrq_poll_timer.expires = jiffies + msecs_to_jiffies(ipr_poll_timer); } } @@ -10547,6 +10685,12 @@ static void __ipr_remove(struct pci_dev *pdev) ipr_free_all_resources(ioa_cfg); + if (ioa_cfg->poll_mode && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) { + for (i = 0; i < IPR_MAX_HRRQ_NUM; i++) + del_timer(&ioa_cfg->hrrq[i].hrrq_poll_timer); + ipr_enable_hrrq_interrupt(ioa_cfg); + } + LEAVE; } @@ -10585,6 +10729,7 @@ static void ipr_remove(struct pci_dev *pdev) static int ipr_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) { struct ipr_ioa_cfg *ioa_cfg; + unsigned long lock_flags = 0; int rc, i; rc = ipr_probe_ioa(pdev, dev_id); @@ -10630,6 +10775,7 @@ static int ipr_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) scsi_scan_host(ioa_cfg->host); ioa_cfg->iopoll_weight = ioa_cfg->chip_cfg->iopoll_weight; ioa_cfg->use_blk_mq = ipr_use_blk_mq; + ioa_cfg->poll_mode = ipr_poll_mode; if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) { for (i = 1; i < ioa_cfg->hrrq_num; i++) { @@ -10639,6 +10785,15 @@ static int ipr_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) } } + if (ioa_cfg->poll_mode && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) { + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + ipr_disable_hrrq_interrupt(ioa_cfg); + for (i = 0; i < ioa_cfg->hrrq_num; i++) + add_timer(&ioa_cfg->hrrq[i].hrrq_poll_timer); + + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + } + schedule_work(&ioa_cfg->work_q); return 0; } diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index c28a673..caa747c 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -518,6 +518,7 @@ struct ipr_hrr_queue { u8 removing_ioa:1; struct blk_iopoll iopoll; + struct timer_list hrrq_poll_timer; }; /* Command packet structure */ @@ -1612,6 +1613,8 @@ struct ipr_ioa_cfg { u32 use_blk_mq; + u32 poll_mode; + }; /* struct ipr_ioa_cfg */ struct ipr_cmnd { -- 1.7.1 ------------------------------------------------------------------------------ _______________________________________________ Iprdd-devel mailing list Iprdd-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/iprdd-devel