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

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
...@@ -64,6 +64,7 @@ struct device_attribute; ...@@ -64,6 +64,7 @@ struct device_attribute;
#define ARCMSR_MAX_HBB_POSTQUEUE 264 #define ARCMSR_MAX_HBB_POSTQUEUE 264
#define ARCMSR_MAX_XFER_LEN 0x26000 /* 152K */ #define ARCMSR_MAX_XFER_LEN 0x26000 /* 152K */
#define ARCMSR_CDB_SG_PAGE_LENGTH 256 #define ARCMSR_CDB_SG_PAGE_LENGTH 256
#define ARCMST_NUM_MSIX_VECTORS 4
#ifndef PCI_DEVICE_ID_ARECA_1880 #ifndef PCI_DEVICE_ID_ARECA_1880
#define PCI_DEVICE_ID_ARECA_1880 0x1880 #define PCI_DEVICE_ID_ARECA_1880 0x1880
#endif #endif
...@@ -508,6 +509,7 @@ struct AdapterControlBlock ...@@ -508,6 +509,7 @@ struct AdapterControlBlock
struct pci_dev * pdev; struct pci_dev * pdev;
struct Scsi_Host * host; struct Scsi_Host * host;
unsigned long vir2phy_offset; unsigned long vir2phy_offset;
struct msix_entry entries[ARCMST_NUM_MSIX_VECTORS];
/* Offset is used in making arc cdb physical to virtual calculations */ /* Offset is used in making arc cdb physical to virtual calculations */
uint32_t outbound_int_enable; uint32_t outbound_int_enable;
uint32_t cdb_phyaddr_hi32; uint32_t cdb_phyaddr_hi32;
...@@ -544,6 +546,8 @@ struct AdapterControlBlock ...@@ -544,6 +546,8 @@ struct AdapterControlBlock
/* iop init */ /* iop init */
#define ACB_F_ABORT 0x0200 #define ACB_F_ABORT 0x0200
#define ACB_F_FIRMWARE_TRAP 0x0400 #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]; struct CommandControlBlock * pccb_pool[ARCMSR_MAX_FREECCB_NUM];
/* used for memory free */ /* used for memory free */
struct list_head ccb_free_list; struct list_head ccb_free_list;
...@@ -594,6 +598,7 @@ struct AdapterControlBlock ...@@ -594,6 +598,7 @@ struct AdapterControlBlock
#define FW_DEADLOCK 0x0010 #define FW_DEADLOCK 0x0010
atomic_t rq_map_token; atomic_t rq_map_token;
atomic_t ante_token_value; atomic_t ante_token_value;
int msix_vector_count;
};/* HW_DEVICE_EXTENSION */ };/* HW_DEVICE_EXTENSION */
/* /*
******************************************************************************* *******************************************************************************
......
...@@ -603,6 +603,56 @@ static void arcmsr_message_isr_bh_fn(struct work_struct *work) ...@@ -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) static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{ {
struct Scsi_Host *host; struct Scsi_Host *host;
...@@ -667,16 +717,13 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -667,16 +717,13 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if(error){ if(error){
goto free_hbb_mu; goto free_hbb_mu;
} }
arcmsr_iop_init(acb);
error = scsi_add_host(host, &pdev->dev); error = scsi_add_host(host, &pdev->dev);
if(error){ if(error){
goto RAID_controller_stop; goto RAID_controller_stop;
} }
error = request_irq(pdev->irq, arcmsr_do_interrupt, IRQF_SHARED, "arcmsr", acb); if (arcmsr_request_irq(pdev, acb) == FAILED)
if(error){
goto scsi_host_remove; goto scsi_host_remove;
} arcmsr_iop_init(acb);
host->irq = pdev->irq;
scsi_scan_host(host); scsi_scan_host(host);
INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn); INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn);
atomic_set(&acb->rq_map_token, 16); atomic_set(&acb->rq_map_token, 16);
...@@ -710,6 +757,22 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -710,6 +757,22 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return -ENODEV; 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) static uint8_t arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb)
{ {
struct MessageUnit_A __iomem *reg = acb->pmuA; struct MessageUnit_A __iomem *reg = acb->pmuA;
...@@ -992,6 +1055,7 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) ...@@ -992,6 +1055,7 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
} }
} }
} }
static void arcmsr_remove(struct pci_dev *pdev) static void arcmsr_remove(struct pci_dev *pdev)
{ {
struct Scsi_Host *host = pci_get_drvdata(pdev); struct Scsi_Host *host = pci_get_drvdata(pdev);
...@@ -1029,7 +1093,7 @@ static void arcmsr_remove(struct pci_dev *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_ccb_pool(acb);
arcmsr_free_hbb_mu(acb); arcmsr_free_hbb_mu(acb);
arcmsr_unmap_pciregion(acb); arcmsr_unmap_pciregion(acb);
...@@ -1045,6 +1109,7 @@ static void arcmsr_shutdown(struct pci_dev *pdev) ...@@ -1045,6 +1109,7 @@ static void arcmsr_shutdown(struct pci_dev *pdev)
(struct AdapterControlBlock *)host->hostdata; (struct AdapterControlBlock *)host->hostdata;
del_timer_sync(&acb->eternal_timer); del_timer_sync(&acb->eternal_timer);
arcmsr_disable_outbound_ints(acb); arcmsr_disable_outbound_ints(acb);
arcmsr_free_irq(pdev, acb);
flush_work(&acb->arcmsr_do_message_isr_bh); flush_work(&acb->arcmsr_do_message_isr_bh);
arcmsr_stop_adapter_bgrb(acb); arcmsr_stop_adapter_bgrb(acb);
arcmsr_flush_adapter_cache(acb); arcmsr_flush_adapter_cache(acb);
...@@ -2516,8 +2581,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) ...@@ -2516,8 +2581,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_A: { case ACB_ADAPTER_TYPE_A: {
if (cdb_phyaddr_hi32 != 0) { if (cdb_phyaddr_hi32 != 0) {
struct MessageUnit_A __iomem *reg = acb->pmuA; struct MessageUnit_A __iomem *reg = acb->pmuA;
uint32_t intmask_org;
intmask_org = arcmsr_disable_outbound_ints(acb);
writel(ARCMSR_SIGNATURE_SET_CONFIG, \ writel(ARCMSR_SIGNATURE_SET_CONFIG, \
&reg->message_rwbuffer[0]); &reg->message_rwbuffer[0]);
writel(cdb_phyaddr_hi32, &reg->message_rwbuffer[1]); writel(cdb_phyaddr_hi32, &reg->message_rwbuffer[1]);
...@@ -2529,7 +2592,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) ...@@ -2529,7 +2592,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
acb->host->host_no); acb->host->host_no);
return 1; return 1;
} }
arcmsr_enable_outbound_ints(acb, intmask_org);
} }
} }
break; break;
...@@ -2539,8 +2601,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) ...@@ -2539,8 +2601,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
uint32_t __iomem *rwbuffer; uint32_t __iomem *rwbuffer;
struct MessageUnit_B *reg = acb->pmuB; struct MessageUnit_B *reg = acb->pmuB;
uint32_t intmask_org;
intmask_org = arcmsr_disable_outbound_ints(acb);
reg->postq_index = 0; reg->postq_index = 0;
reg->doneq_index = 0; reg->doneq_index = 0;
writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell); writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell);
...@@ -2569,7 +2629,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) ...@@ -2569,7 +2629,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
return 1; return 1;
} }
arcmsr_hbb_enable_driver_mode(acb); arcmsr_hbb_enable_driver_mode(acb);
arcmsr_enable_outbound_ints(acb, intmask_org);
} }
break; break;
case ACB_ADAPTER_TYPE_C: { case ACB_ADAPTER_TYPE_C: {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment