From: Wen Xiong <[email protected]>
---
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
[email protected]
https://lists.sourceforge.net/lists/listinfo/iprdd-devel