|
@@ -2536,7 +2536,7 @@ megasas_deplete_reply_queue(struct megasas_instance *instance,
|
|
|
instance->reg_set)
|
|
|
) == 0) {
|
|
|
/* Hardware may not set outbound_intr_status in MSI-X mode */
|
|
|
- if (!instance->msi_flag)
|
|
|
+ if (!instance->msix_vectors)
|
|
|
return IRQ_NONE;
|
|
|
}
|
|
|
|
|
@@ -2594,16 +2594,14 @@ megasas_deplete_reply_queue(struct megasas_instance *instance,
|
|
|
*/
|
|
|
static irqreturn_t megasas_isr(int irq, void *devp)
|
|
|
{
|
|
|
- struct megasas_instance *instance;
|
|
|
+ struct megasas_irq_context *irq_context = devp;
|
|
|
+ struct megasas_instance *instance = irq_context->instance;
|
|
|
unsigned long flags;
|
|
|
irqreturn_t rc;
|
|
|
|
|
|
- if (atomic_read(
|
|
|
- &(((struct megasas_instance *)devp)->fw_reset_no_pci_access)))
|
|
|
+ if (atomic_read(&instance->fw_reset_no_pci_access))
|
|
|
return IRQ_HANDLED;
|
|
|
|
|
|
- instance = (struct megasas_instance *)devp;
|
|
|
-
|
|
|
spin_lock_irqsave(&instance->hba_lock, flags);
|
|
|
rc = megasas_deplete_reply_queue(instance, DID_OK);
|
|
|
spin_unlock_irqrestore(&instance->hba_lock, flags);
|
|
@@ -3488,6 +3486,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
|
|
|
struct megasas_register_set __iomem *reg_set;
|
|
|
struct megasas_ctrl_info *ctrl_info;
|
|
|
unsigned long bar_list;
|
|
|
+ int i;
|
|
|
|
|
|
/* Find first memory bar */
|
|
|
bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM);
|
|
@@ -3541,9 +3540,33 @@ static int megasas_init_fw(struct megasas_instance *instance)
|
|
|
/* Check if MSI-X is supported while in ready state */
|
|
|
msix_enable = (instance->instancet->read_fw_status_reg(reg_set) &
|
|
|
0x4000000) >> 0x1a;
|
|
|
- if (msix_enable && !msix_disable &&
|
|
|
- !pci_enable_msix(instance->pdev, &instance->msixentry, 1))
|
|
|
- instance->msi_flag = 1;
|
|
|
+ if (msix_enable && !msix_disable) {
|
|
|
+ /* Check max MSI-X vectors */
|
|
|
+ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
|
|
|
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER)) {
|
|
|
+ instance->msix_vectors = (readl(&instance->reg_set->
|
|
|
+ outbound_scratch_pad_2
|
|
|
+ ) & 0x1F) + 1;
|
|
|
+ } else
|
|
|
+ instance->msix_vectors = 1;
|
|
|
+ /* Don't bother allocating more MSI-X vectors than cpus */
|
|
|
+ instance->msix_vectors = min(instance->msix_vectors,
|
|
|
+ (unsigned int)num_online_cpus());
|
|
|
+ for (i = 0; i < instance->msix_vectors; i++)
|
|
|
+ instance->msixentry[i].entry = i;
|
|
|
+ i = pci_enable_msix(instance->pdev, instance->msixentry,
|
|
|
+ instance->msix_vectors);
|
|
|
+ if (i >= 0) {
|
|
|
+ if (i) {
|
|
|
+ if (!pci_enable_msix(instance->pdev,
|
|
|
+ instance->msixentry, i))
|
|
|
+ instance->msix_vectors = i;
|
|
|
+ else
|
|
|
+ instance->msix_vectors = 0;
|
|
|
+ }
|
|
|
+ } else
|
|
|
+ instance->msix_vectors = 0;
|
|
|
+ }
|
|
|
|
|
|
/* Get operational params, sge flags, send init cmd to controller */
|
|
|
if (instance->instancet->init_adapter(instance))
|
|
@@ -3958,7 +3981,7 @@ fail_set_dma_mask:
|
|
|
static int __devinit
|
|
|
megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
|
{
|
|
|
- int rval, pos;
|
|
|
+ int rval, pos, i, j;
|
|
|
struct Scsi_Host *host;
|
|
|
struct megasas_instance *instance;
|
|
|
u16 control = 0;
|
|
@@ -4126,11 +4149,32 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
|
/*
|
|
|
* Register IRQ
|
|
|
*/
|
|
|
- if (request_irq(instance->msi_flag ? instance->msixentry.vector :
|
|
|
- pdev->irq, instance->instancet->service_isr,
|
|
|
- IRQF_SHARED, "megasas", instance)) {
|
|
|
- printk(KERN_DEBUG "megasas: Failed to register IRQ\n");
|
|
|
- goto fail_irq;
|
|
|
+ if (instance->msix_vectors) {
|
|
|
+ for (i = 0 ; i < instance->msix_vectors; i++) {
|
|
|
+ instance->irq_context[i].instance = instance;
|
|
|
+ instance->irq_context[i].MSIxIndex = i;
|
|
|
+ if (request_irq(instance->msixentry[i].vector,
|
|
|
+ instance->instancet->service_isr, 0,
|
|
|
+ "megasas",
|
|
|
+ &instance->irq_context[i])) {
|
|
|
+ printk(KERN_DEBUG "megasas: Failed to "
|
|
|
+ "register IRQ for vector %d.\n", i);
|
|
|
+ for (j = 0 ; j < i ; j++)
|
|
|
+ free_irq(
|
|
|
+ instance->msixentry[j].vector,
|
|
|
+ &instance->irq_context[j]);
|
|
|
+ goto fail_irq;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ instance->irq_context[0].instance = instance;
|
|
|
+ instance->irq_context[0].MSIxIndex = 0;
|
|
|
+ if (request_irq(pdev->irq, instance->instancet->service_isr,
|
|
|
+ IRQF_SHARED, "megasas",
|
|
|
+ &instance->irq_context[0])) {
|
|
|
+ printk(KERN_DEBUG "megasas: Failed to register IRQ\n");
|
|
|
+ goto fail_irq;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
instance->instancet->enable_intr(instance->reg_set);
|
|
@@ -4174,8 +4218,12 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
|
|
|
|
pci_set_drvdata(pdev, NULL);
|
|
|
instance->instancet->disable_intr(instance->reg_set);
|
|
|
- free_irq(instance->msi_flag ? instance->msixentry.vector :
|
|
|
- instance->pdev->irq, instance);
|
|
|
+ if (instance->msix_vectors)
|
|
|
+ for (i = 0 ; i < instance->msix_vectors; i++)
|
|
|
+ free_irq(instance->msixentry[i].vector,
|
|
|
+ &instance->irq_context[i]);
|
|
|
+ else
|
|
|
+ free_irq(instance->pdev->irq, &instance->irq_context[0]);
|
|
|
fail_irq:
|
|
|
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
|
|
|
(instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER))
|
|
@@ -4183,7 +4231,7 @@ fail_irq:
|
|
|
else
|
|
|
megasas_release_mfi(instance);
|
|
|
fail_init_mfi:
|
|
|
- if (instance->msi_flag)
|
|
|
+ if (instance->msix_vectors)
|
|
|
pci_disable_msix(instance->pdev);
|
|
|
fail_alloc_dma_buf:
|
|
|
if (instance->evt_detail)
|
|
@@ -4299,6 +4347,7 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
|
|
|
{
|
|
|
struct Scsi_Host *host;
|
|
|
struct megasas_instance *instance;
|
|
|
+ int i;
|
|
|
|
|
|
instance = pci_get_drvdata(pdev);
|
|
|
host = instance->host;
|
|
@@ -4322,9 +4371,14 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
|
|
|
|
|
|
pci_set_drvdata(instance->pdev, instance);
|
|
|
instance->instancet->disable_intr(instance->reg_set);
|
|
|
- free_irq(instance->msi_flag ? instance->msixentry.vector :
|
|
|
- instance->pdev->irq, instance);
|
|
|
- if (instance->msi_flag)
|
|
|
+
|
|
|
+ if (instance->msix_vectors)
|
|
|
+ for (i = 0 ; i < instance->msix_vectors; i++)
|
|
|
+ free_irq(instance->msixentry[i].vector,
|
|
|
+ &instance->irq_context[i]);
|
|
|
+ else
|
|
|
+ free_irq(instance->pdev->irq, &instance->irq_context[0]);
|
|
|
+ if (instance->msix_vectors)
|
|
|
pci_disable_msix(instance->pdev);
|
|
|
|
|
|
pci_save_state(pdev);
|
|
@@ -4342,7 +4396,7 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
|
|
|
static int
|
|
|
megasas_resume(struct pci_dev *pdev)
|
|
|
{
|
|
|
- int rval;
|
|
|
+ int rval, i, j;
|
|
|
struct Scsi_Host *host;
|
|
|
struct megasas_instance *instance;
|
|
|
|
|
@@ -4380,8 +4434,9 @@ megasas_resume(struct pci_dev *pdev)
|
|
|
goto fail_ready_state;
|
|
|
|
|
|
/* Now re-enable MSI-X */
|
|
|
- if (instance->msi_flag)
|
|
|
- pci_enable_msix(instance->pdev, &instance->msixentry, 1);
|
|
|
+ if (instance->msix_vectors)
|
|
|
+ pci_enable_msix(instance->pdev, instance->msixentry,
|
|
|
+ instance->msix_vectors);
|
|
|
|
|
|
switch (instance->pdev->device) {
|
|
|
case PCI_DEVICE_ID_LSI_FUSION:
|
|
@@ -4411,11 +4466,32 @@ megasas_resume(struct pci_dev *pdev)
|
|
|
/*
|
|
|
* Register IRQ
|
|
|
*/
|
|
|
- if (request_irq(instance->msi_flag ? instance->msixentry.vector :
|
|
|
- pdev->irq, instance->instancet->service_isr,
|
|
|
- IRQF_SHARED, "megasas", instance)) {
|
|
|
- printk(KERN_ERR "megasas: Failed to register IRQ\n");
|
|
|
- goto fail_irq;
|
|
|
+ if (instance->msix_vectors) {
|
|
|
+ for (i = 0 ; i < instance->msix_vectors; i++) {
|
|
|
+ instance->irq_context[i].instance = instance;
|
|
|
+ instance->irq_context[i].MSIxIndex = i;
|
|
|
+ if (request_irq(instance->msixentry[i].vector,
|
|
|
+ instance->instancet->service_isr, 0,
|
|
|
+ "megasas",
|
|
|
+ &instance->irq_context[i])) {
|
|
|
+ printk(KERN_DEBUG "megasas: Failed to "
|
|
|
+ "register IRQ for vector %d.\n", i);
|
|
|
+ for (j = 0 ; j < i ; j++)
|
|
|
+ free_irq(
|
|
|
+ instance->msixentry[j].vector,
|
|
|
+ &instance->irq_context[j]);
|
|
|
+ goto fail_irq;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ instance->irq_context[0].instance = instance;
|
|
|
+ instance->irq_context[0].MSIxIndex = 0;
|
|
|
+ if (request_irq(pdev->irq, instance->instancet->service_isr,
|
|
|
+ IRQF_SHARED, "megasas",
|
|
|
+ &instance->irq_context[0])) {
|
|
|
+ printk(KERN_DEBUG "megasas: Failed to register IRQ\n");
|
|
|
+ goto fail_irq;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
instance->instancet->enable_intr(instance->reg_set);
|
|
@@ -4512,9 +4588,13 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
|
|
|
|
|
|
instance->instancet->disable_intr(instance->reg_set);
|
|
|
|
|
|
- free_irq(instance->msi_flag ? instance->msixentry.vector :
|
|
|
- instance->pdev->irq, instance);
|
|
|
- if (instance->msi_flag)
|
|
|
+ if (instance->msix_vectors)
|
|
|
+ for (i = 0 ; i < instance->msix_vectors; i++)
|
|
|
+ free_irq(instance->msixentry[i].vector,
|
|
|
+ &instance->irq_context[i]);
|
|
|
+ else
|
|
|
+ free_irq(instance->pdev->irq, &instance->irq_context[0]);
|
|
|
+ if (instance->msix_vectors)
|
|
|
pci_disable_msix(instance->pdev);
|
|
|
|
|
|
switch (instance->pdev->device) {
|
|
@@ -4560,14 +4640,20 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
|
|
|
*/
|
|
|
static void megasas_shutdown(struct pci_dev *pdev)
|
|
|
{
|
|
|
+ int i;
|
|
|
struct megasas_instance *instance = pci_get_drvdata(pdev);
|
|
|
+
|
|
|
instance->unload = 1;
|
|
|
megasas_flush_cache(instance);
|
|
|
megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
|
|
|
instance->instancet->disable_intr(instance->reg_set);
|
|
|
- free_irq(instance->msi_flag ? instance->msixentry.vector :
|
|
|
- instance->pdev->irq, instance);
|
|
|
- if (instance->msi_flag)
|
|
|
+ if (instance->msix_vectors)
|
|
|
+ for (i = 0 ; i < instance->msix_vectors; i++)
|
|
|
+ free_irq(instance->msixentry[i].vector,
|
|
|
+ &instance->irq_context[i]);
|
|
|
+ else
|
|
|
+ free_irq(instance->pdev->irq, &instance->irq_context[0]);
|
|
|
+ if (instance->msix_vectors)
|
|
|
pci_disable_msix(instance->pdev);
|
|
|
}
|
|
|
|