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

Reply via email to