#include <linux/mutex.h>
#include <linux/poll.h>
#include <linux/vmalloc.h>
+#include <linux/irq_poll.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
return 1;
}
+static
+void megasas_setup_irq_poll(struct megasas_instance *instance)
+{
+ struct megasas_irq_context *irq_ctx;
+ u32 count, i;
+
+ count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+
+ /* Initialize IRQ poll */
+ for (i = 0; i < count; i++) {
+ irq_ctx = &instance->irq_context[i];
+ irq_ctx->os_irq = pci_irq_vector(instance->pdev, i);
+ irq_ctx->irq_poll_scheduled = false;
+ irq_poll_init(&irq_ctx->irqpoll,
+ instance->threshold_reply_count,
+ megasas_irqpoll);
+ }
+}
+
/*
* megasas_setup_irqs_ioapic - register legacy interrupts.
* @instance: Adapter soft state
megasas_destroy_irqs(struct megasas_instance *instance) {
int i;
+ int count;
+ struct megasas_irq_context *irq_ctx;
+
+ count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+ if (instance->adapter_type != MFI_SERIES) {
+ for (i = 0; i < count; i++) {
+ irq_ctx = &instance->irq_context[i];
+ irq_poll_disable(&irq_ctx->irqpoll);
+ }
+ }
if (instance->msix_vectors)
for (i = 0; i < instance->msix_vectors; i++) {
megasas_setup_irqs_ioapic(instance))
goto fail_init_adapter;
+ if (instance->adapter_type != MFI_SERIES)
+ megasas_setup_irq_poll(instance);
+
instance->instancet->enable_intr(instance);
dev_info(&instance->pdev->dev, "INIT adapter done\n");
megasas_setup_irqs_ioapic(instance))
goto fail_init_mfi;
+ if (instance->adapter_type != MFI_SERIES)
+ megasas_setup_irq_poll(instance);
+
/* Re-launch SR-IOV heartbeat timer */
if (instance->requestorId) {
if (!megasas_sriov_start_heartbeat(instance, 0))
#include <linux/poll.h>
#include <linux/vmalloc.h>
#include <linux/workqueue.h>
+#include <linux/irq_poll.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
instance->flag_ieee = 1;
instance->r1_ldio_hint_default = MR_R1_LDIO_PIGGYBACK_DEFAULT;
+ instance->threshold_reply_count = instance->max_fw_cmds / 4;
fusion->fast_path_io = 0;
if (megasas_allocate_raid_maps(instance))
* Completes all commands that is in reply descriptor queue
*/
int
-complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
+complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex,
+ struct megasas_irq_context *irq_context)
{
union MPI2_REPLY_DESCRIPTORS_UNION *desc;
struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *reply_desc;
* number of reply counts and still there are more replies in reply queue
* pending to be completed
*/
- if (threshold_reply_count >= THRESHOLD_REPLY_COUNT) {
+ if (threshold_reply_count >= instance->threshold_reply_count) {
if (instance->msix_combined)
writel(((MSIxIndex & 0x7) << 24) |
fusion->last_reply_idx[MSIxIndex],
fusion->last_reply_idx[MSIxIndex],
instance->reply_post_host_index_addr[0]);
threshold_reply_count = 0;
+ if (irq_context) {
+ if (!irq_context->irq_poll_scheduled) {
+ irq_context->irq_poll_scheduled = true;
+ disable_irq_nosync(irq_context->os_irq);
+ irq_poll_sched(&irq_context->irqpoll);
+ }
+ return num_completed;
+ }
}
}
- if (!num_completed)
- return IRQ_NONE;
+ if (num_completed) {
+ wmb();
+ if (instance->msix_combined)
+ writel(((MSIxIndex & 0x7) << 24) |
+ fusion->last_reply_idx[MSIxIndex],
+ instance->reply_post_host_index_addr[MSIxIndex/8]);
+ else
+ writel((MSIxIndex << 24) |
+ fusion->last_reply_idx[MSIxIndex],
+ instance->reply_post_host_index_addr[0]);
+ megasas_check_and_restore_queue_depth(instance);
+ }
+ return num_completed;
+}
- wmb();
- if (instance->msix_combined)
- writel(((MSIxIndex & 0x7) << 24) |
- fusion->last_reply_idx[MSIxIndex],
- instance->reply_post_host_index_addr[MSIxIndex/8]);
- else
- writel((MSIxIndex << 24) |
- fusion->last_reply_idx[MSIxIndex],
- instance->reply_post_host_index_addr[0]);
- megasas_check_and_restore_queue_depth(instance);
- return IRQ_HANDLED;
+/**
+ * megasas_enable_irq_poll() - enable irqpoll
+ */
+static void megasas_enable_irq_poll(struct megasas_instance *instance)
+{
+ u32 count, i;
+ struct megasas_irq_context *irq_ctx;
+
+ count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+
+ for (i = 0; i < count; i++) {
+ irq_ctx = &instance->irq_context[i];
+ irq_poll_enable(&irq_ctx->irqpoll);
+ }
}
/**
u32 count, i;
struct megasas_instance *instance =
(struct megasas_instance *)instance_addr;
+ struct megasas_irq_context *irq_ctx;
count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
- for (i = 0; i < count; i++)
+ for (i = 0; i < count; i++) {
synchronize_irq(pci_irq_vector(instance->pdev, i));
+ irq_ctx = &instance->irq_context[i];
+ irq_poll_disable(&irq_ctx->irqpoll);
+ if (irq_ctx->irq_poll_scheduled) {
+ irq_ctx->irq_poll_scheduled = false;
+ enable_irq(irq_ctx->os_irq);
+ }
+ }
+}
+
+/**
+ * megasas_irqpoll() - process a queue for completed reply descriptors
+ * @irqpoll: IRQ poll structure associated with queue to poll.
+ * @budget: Threshold of reply descriptors to process per poll.
+ *
+ * Return: The number of entries processed.
+ */
+
+int megasas_irqpoll(struct irq_poll *irqpoll, int budget)
+{
+ struct megasas_irq_context *irq_ctx;
+ struct megasas_instance *instance;
+ int num_entries;
+
+ irq_ctx = container_of(irqpoll, struct megasas_irq_context, irqpoll);
+ instance = irq_ctx->instance;
+
+ num_entries = complete_cmd_fusion(instance, irq_ctx->MSIxIndex, irq_ctx);
+ if (num_entries < budget) {
+ irq_poll_complete(irqpoll);
+ irq_ctx->irq_poll_scheduled = false;
+ enable_irq(irq_ctx->os_irq);
+ }
+
+ return num_entries;
}
/**
return;
for (MSIxIndex = 0 ; MSIxIndex < count; MSIxIndex++)
- complete_cmd_fusion(instance, MSIxIndex);
+ complete_cmd_fusion(instance, MSIxIndex, NULL);
}
/**
return IRQ_HANDLED;
}
- return complete_cmd_fusion(instance, irq_context->MSIxIndex);
+ return complete_cmd_fusion(instance, irq_context->MSIxIndex, irq_context)
+ ? IRQ_HANDLED : IRQ_NONE;
}
/**
instance->instancet->disable_intr(instance);
megasas_sync_irqs((unsigned long)instance);
instance->instancet->enable_intr(instance);
+ megasas_enable_irq_poll(instance);
if (scsi_lookup->scmd == NULL)
break;
}
megasas_sync_irqs((unsigned long)instance);
rc = megasas_track_scsiio(instance, id, channel);
instance->instancet->enable_intr(instance);
+ megasas_enable_irq_poll(instance);
break;
case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
dev_warn(&instance->pdev->dev, "Reset not supported"
", killing adapter scsi%d.\n",
instance->host->host_no);
- megaraid_sas_kill_hba(instance);
- instance->skip_heartbeat_timer_del = 1;
- retval = FAILED;
- goto out;
+ goto kill_hba;
}
/* Let SR-IOV VF & PF sync up if there was a HB failure */
dev_info(&instance->pdev->dev,
"Failed from %s %d\n",
__func__, __LINE__);
- megaraid_sas_kill_hba(instance);
- retval = FAILED;
- goto out;
+ goto kill_hba;
}
megasas_refire_mgmt_cmd(instance);
clear_bit(MEGASAS_FUSION_IN_RESET,
&instance->reset_flags);
instance->instancet->enable_intr(instance);
-
+ megasas_enable_irq_poll(instance);
shost_for_each_device(sdev, shost) {
if ((instance->tgt_prop) &&
(instance->nvme_page_size))
/* Reset failed, kill the adapter */
dev_warn(&instance->pdev->dev, "Reset failed, killing "
"adapter scsi%d.\n", instance->host->host_no);
- megaraid_sas_kill_hba(instance);
- instance->skip_heartbeat_timer_del = 1;
- retval = FAILED;
+ goto kill_hba;
} else {
/* For VF: Restart HB timer if we didn't OCR */
if (instance->requestorId) {
}
clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
instance->instancet->enable_intr(instance);
+ megasas_enable_irq_poll(instance);
atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
+ goto out;
}
+kill_hba:
+ megaraid_sas_kill_hba(instance);
+ megasas_enable_irq_poll(instance);
+ instance->skip_heartbeat_timer_del = 1;
+ retval = FAILED;
out:
clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
mutex_unlock(&instance->reset_mutex);