Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1d1166ea authored by Ching Huang's avatar Ching Huang Committed by Christoph Hellwig
Browse files

arcmsr: add code to support MSI-X and MSI interrupt



This patch adds code to support MSI and MSI-X interrupt.

Signed-off-by: default avatarChing Huang <ching2048@areca.com.tw>
Reviewed-by: default avatarTomas Henzl <thenzl@redhat.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
parent 6b393722
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ struct device_attribute;
#define ARCMSR_MAX_HBB_POSTQUEUE						264
#define ARCMSR_MAX_XFER_LEN							0x26000 /* 152K */
#define ARCMSR_CDB_SG_PAGE_LENGTH						256 
#define ARCMST_NUM_MSIX_VECTORS		4
#ifndef PCI_DEVICE_ID_ARECA_1880
#define PCI_DEVICE_ID_ARECA_1880 0x1880
 #endif
@@ -508,6 +509,7 @@ struct AdapterControlBlock
	struct pci_dev *		pdev;
	struct Scsi_Host *		host;
	unsigned long			vir2phy_offset;
	struct msix_entry	entries[ARCMST_NUM_MSIX_VECTORS];
	/* Offset is used in making arc cdb physical to virtual calculations */
	uint32_t			outbound_int_enable;
	uint32_t			cdb_phyaddr_hi32;
@@ -544,6 +546,8 @@ struct AdapterControlBlock
	/* iop init */
	#define ACB_F_ABORT				0x0200
	#define ACB_F_FIRMWARE_TRAP           		0x0400
	#define ACB_F_MSI_ENABLED		0x1000
	#define ACB_F_MSIX_ENABLED		0x2000
	struct CommandControlBlock *			pccb_pool[ARCMSR_MAX_FREECCB_NUM];
	/* used for memory free */
	struct list_head		ccb_free_list;
@@ -594,6 +598,7 @@ struct AdapterControlBlock
				#define	FW_DEADLOCK	0x0010
	atomic_t 			rq_map_token;
	atomic_t			ante_token_value;
	int		msix_vector_count;
};/* HW_DEVICE_EXTENSION */
/*
*******************************************************************************
+71 −12
Original line number Diff line number Diff line
@@ -603,6 +603,56 @@ static void arcmsr_message_isr_bh_fn(struct work_struct *work)
	}
}

static int
arcmsr_request_irq(struct pci_dev *pdev, struct AdapterControlBlock *acb)
{
	int	i, j, r;
	struct msix_entry entries[ARCMST_NUM_MSIX_VECTORS];

	for (i = 0; i < ARCMST_NUM_MSIX_VECTORS; i++)
		entries[i].entry = i;
	r = pci_enable_msix_range(pdev, entries, 1, ARCMST_NUM_MSIX_VECTORS);
	if (r < 0)
		goto msi_int;
	acb->msix_vector_count = r;
	for (i = 0; i < r; i++) {
		if (request_irq(entries[i].vector,
			arcmsr_do_interrupt, 0, "arcmsr", acb)) {
			pr_warn("arcmsr%d: request_irq =%d failed!\n",
				acb->host->host_no, entries[i].vector);
			for (j = 0 ; j < i ; j++)
				free_irq(entries[j].vector, acb);
			pci_disable_msix(pdev);
			goto msi_int;
		}
		acb->entries[i] = entries[i];
	}
	acb->acb_flags |= ACB_F_MSIX_ENABLED;
	pr_info("arcmsr%d: msi-x enabled\n", acb->host->host_no);
	return SUCCESS;
msi_int:
	if (pci_enable_msi_exact(pdev, 1) < 0)
		goto legacy_int;
	if (request_irq(pdev->irq, arcmsr_do_interrupt,
		IRQF_SHARED, "arcmsr", acb)) {
		pr_warn("arcmsr%d: request_irq =%d failed!\n",
			acb->host->host_no, pdev->irq);
		pci_disable_msi(pdev);
		goto legacy_int;
	}
	acb->acb_flags |= ACB_F_MSI_ENABLED;
	pr_info("arcmsr%d: msi enabled\n", acb->host->host_no);
	return SUCCESS;
legacy_int:
	if (request_irq(pdev->irq, arcmsr_do_interrupt,
		IRQF_SHARED, "arcmsr", acb)) {
		pr_warn("arcmsr%d: request_irq = %d failed!\n",
			acb->host->host_no, pdev->irq);
		return FAILED;
	}
	return SUCCESS;
}

static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
	struct Scsi_Host *host;
@@ -667,16 +717,13 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	if(error){
		goto free_hbb_mu;
	}
	arcmsr_iop_init(acb);
	error = scsi_add_host(host, &pdev->dev);
	if(error){
		goto RAID_controller_stop;
	}
	error = request_irq(pdev->irq, arcmsr_do_interrupt, IRQF_SHARED, "arcmsr", acb);
	if(error){
	if (arcmsr_request_irq(pdev, acb) == FAILED)
		goto scsi_host_remove;
	}
	host->irq = pdev->irq;
	arcmsr_iop_init(acb);
    	scsi_scan_host(host);
	INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn);
	atomic_set(&acb->rq_map_token, 16);
@@ -710,6 +757,22 @@ pci_disable_dev:
	return -ENODEV;
}

static void arcmsr_free_irq(struct pci_dev *pdev,
		struct AdapterControlBlock *acb)
{
	int i;

	if (acb->acb_flags & ACB_F_MSI_ENABLED) {
		free_irq(pdev->irq, acb);
		pci_disable_msi(pdev);
	} else if (acb->acb_flags & ACB_F_MSIX_ENABLED) {
		for (i = 0; i < acb->msix_vector_count; i++)
			free_irq(acb->entries[i].vector, acb);
		pci_disable_msix(pdev);
	} else
		free_irq(pdev->irq, acb);
}

static uint8_t arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb)
{
	struct MessageUnit_A __iomem *reg = acb->pmuA;
@@ -992,6 +1055,7 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
	}
	}
}

static void arcmsr_remove(struct pci_dev *pdev)
{
	struct Scsi_Host *host = pci_get_drvdata(pdev);
@@ -1029,7 +1093,7 @@ static void arcmsr_remove(struct pci_dev *pdev)
			}
		}
	}
	free_irq(pdev->irq, acb);
	arcmsr_free_irq(pdev, acb);
	arcmsr_free_ccb_pool(acb);
	arcmsr_free_hbb_mu(acb);
	arcmsr_unmap_pciregion(acb);
@@ -1045,6 +1109,7 @@ static void arcmsr_shutdown(struct pci_dev *pdev)
		(struct AdapterControlBlock *)host->hostdata;
	del_timer_sync(&acb->eternal_timer);
	arcmsr_disable_outbound_ints(acb);
	arcmsr_free_irq(pdev, acb);
	flush_work(&acb->arcmsr_do_message_isr_bh);
	arcmsr_stop_adapter_bgrb(acb);
	arcmsr_flush_adapter_cache(acb);
@@ -2516,8 +2581,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
	case ACB_ADAPTER_TYPE_A: {
		if (cdb_phyaddr_hi32 != 0) {
			struct MessageUnit_A __iomem *reg = acb->pmuA;
			uint32_t intmask_org;
			intmask_org = arcmsr_disable_outbound_ints(acb);
			writel(ARCMSR_SIGNATURE_SET_CONFIG, \
						&reg->message_rwbuffer[0]);
			writel(cdb_phyaddr_hi32, &reg->message_rwbuffer[1]);
@@ -2529,7 +2592,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
				acb->host->host_no);
				return 1;
			}
			arcmsr_enable_outbound_ints(acb, intmask_org);
		}
		}
		break;
@@ -2539,8 +2601,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
		uint32_t __iomem *rwbuffer;

		struct MessageUnit_B *reg = acb->pmuB;
		uint32_t intmask_org;
		intmask_org = arcmsr_disable_outbound_ints(acb);
		reg->postq_index = 0;
		reg->doneq_index = 0;
		writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell);
@@ -2569,7 +2629,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
			return 1;
		}
		arcmsr_hbb_enable_driver_mode(acb);
		arcmsr_enable_outbound_ints(acb, intmask_org);
		}
		break;
	case ACB_ADAPTER_TYPE_C: {