Hi Brian, Thanks for your quick response!
>>Should we perhaps use add_timer_on so the timer fires on the same core as the >>HRRQ is >>bound to? Actually the original pure_poll prototype has add_timer_on but it is commented out. I will try it. Thanks, Wendy From: Brian King <brk...@linux.vnet.ibm.com> To: wenxi...@linux.vnet.ibm.com, iprdd-devel@lists.sourceforge.net Date: 11/17/2015 05:31 PM Subject: Re: [Iprdd-devel] [PATCH 3/3] Add interrupt pure poller support A few quick comments below... On 11/17/2015 11:20 AM, wenxi...@linux.vnet.ibm.com wrote: > 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); Should we perhaps use add_timer_on so the timer fires on the same core as the HRRQ is bound to? > + } > + > + 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); Seems like a bug if we call this function for SIS-32. I'm find not supporting polling mode for SIS-32, but let's remove this if check and just comment that this is SIS-64 only. > + > + /* 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); Same comment here as above. > + > + /* 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) Should be static > +{ > + 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); Same comment as above regarding using add_timer_on > + > + > 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 { > -- Brian King Power Linux I/O IBM Linux Technology Center ------------------------------------------------------------------------------ Give your users amazing mobile app experiences with Intel XDK. Use one codebase in this all-in-one HTML5 development environment. Design, debug & build mobile apps & 2-D/3-D games for multiple OSs. Then get your creation into app stores sooner, with many ways to monetize. http://pubads.g.doubleclick.net/gampad/clk?id=254741551&iu=/4140 _______________________________________________ Iprdd-devel mailing list Iprdd-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/iprdd-devel
------------------------------------------------------------------------------
_______________________________________________ Iprdd-devel mailing list Iprdd-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/iprdd-devel