aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/arcmsr
diff options
context:
space:
mode:
authorChing Huang <ching2048@areca.com.tw>2014-08-19 02:23:31 -0400
committerChristoph Hellwig <hch@lst.de>2014-09-16 12:39:28 -0400
commit1d1166ea16ac7047a1b01f20dcbcc6f7754c3c23 (patch)
treec78222ada649f6dbbeb8939beae1f1d4f4fb9a7d /drivers/scsi/arcmsr
parent6b3937227479e50032112faf74bd913f36dba2c6 (diff)
arcmsr: add code to support MSI-X and MSI interrupt
This patch adds code to support MSI and MSI-X interrupt. Signed-off-by: Ching Huang <ching2048@areca.com.tw> Reviewed-by: Tomas Henzl <thenzl@redhat.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'drivers/scsi/arcmsr')
-rw-r--r--drivers/scsi/arcmsr/arcmsr.h5
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c83
2 files changed, 76 insertions, 12 deletions
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
index 8f357933d8cb..1c64b60a3dcf 100644
--- a/drivers/scsi/arcmsr/arcmsr.h
+++ b/drivers/scsi/arcmsr/arcmsr.h
@@ -64,6 +64,7 @@ struct device_attribute;
64#define ARCMSR_MAX_HBB_POSTQUEUE 264 64#define ARCMSR_MAX_HBB_POSTQUEUE 264
65#define ARCMSR_MAX_XFER_LEN 0x26000 /* 152K */ 65#define ARCMSR_MAX_XFER_LEN 0x26000 /* 152K */
66#define ARCMSR_CDB_SG_PAGE_LENGTH 256 66#define ARCMSR_CDB_SG_PAGE_LENGTH 256
67#define ARCMST_NUM_MSIX_VECTORS 4
67#ifndef PCI_DEVICE_ID_ARECA_1880 68#ifndef PCI_DEVICE_ID_ARECA_1880
68#define PCI_DEVICE_ID_ARECA_1880 0x1880 69#define PCI_DEVICE_ID_ARECA_1880 0x1880
69 #endif 70 #endif
@@ -508,6 +509,7 @@ struct AdapterControlBlock
508 struct pci_dev * pdev; 509 struct pci_dev * pdev;
509 struct Scsi_Host * host; 510 struct Scsi_Host * host;
510 unsigned long vir2phy_offset; 511 unsigned long vir2phy_offset;
512 struct msix_entry entries[ARCMST_NUM_MSIX_VECTORS];
511 /* Offset is used in making arc cdb physical to virtual calculations */ 513 /* Offset is used in making arc cdb physical to virtual calculations */
512 uint32_t outbound_int_enable; 514 uint32_t outbound_int_enable;
513 uint32_t cdb_phyaddr_hi32; 515 uint32_t cdb_phyaddr_hi32;
@@ -544,6 +546,8 @@ struct AdapterControlBlock
544 /* iop init */ 546 /* iop init */
545 #define ACB_F_ABORT 0x0200 547 #define ACB_F_ABORT 0x0200
546 #define ACB_F_FIRMWARE_TRAP 0x0400 548 #define ACB_F_FIRMWARE_TRAP 0x0400
549 #define ACB_F_MSI_ENABLED 0x1000
550 #define ACB_F_MSIX_ENABLED 0x2000
547 struct CommandControlBlock * pccb_pool[ARCMSR_MAX_FREECCB_NUM]; 551 struct CommandControlBlock * pccb_pool[ARCMSR_MAX_FREECCB_NUM];
548 /* used for memory free */ 552 /* used for memory free */
549 struct list_head ccb_free_list; 553 struct list_head ccb_free_list;
@@ -594,6 +598,7 @@ struct AdapterControlBlock
594 #define FW_DEADLOCK 0x0010 598 #define FW_DEADLOCK 0x0010
595 atomic_t rq_map_token; 599 atomic_t rq_map_token;
596 atomic_t ante_token_value; 600 atomic_t ante_token_value;
601 int msix_vector_count;
597};/* HW_DEVICE_EXTENSION */ 602};/* HW_DEVICE_EXTENSION */
598/* 603/*
599******************************************************************************* 604*******************************************************************************
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 506fe7b851bc..60227d56bd39 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -603,6 +603,56 @@ static void arcmsr_message_isr_bh_fn(struct work_struct *work)
603 } 603 }
604} 604}
605 605
606static int
607arcmsr_request_irq(struct pci_dev *pdev, struct AdapterControlBlock *acb)
608{
609 int i, j, r;
610 struct msix_entry entries[ARCMST_NUM_MSIX_VECTORS];
611
612 for (i = 0; i < ARCMST_NUM_MSIX_VECTORS; i++)
613 entries[i].entry = i;
614 r = pci_enable_msix_range(pdev, entries, 1, ARCMST_NUM_MSIX_VECTORS);
615 if (r < 0)
616 goto msi_int;
617 acb->msix_vector_count = r;
618 for (i = 0; i < r; i++) {
619 if (request_irq(entries[i].vector,
620 arcmsr_do_interrupt, 0, "arcmsr", acb)) {
621 pr_warn("arcmsr%d: request_irq =%d failed!\n",
622 acb->host->host_no, entries[i].vector);
623 for (j = 0 ; j < i ; j++)
624 free_irq(entries[j].vector, acb);
625 pci_disable_msix(pdev);
626 goto msi_int;
627 }
628 acb->entries[i] = entries[i];
629 }
630 acb->acb_flags |= ACB_F_MSIX_ENABLED;
631 pr_info("arcmsr%d: msi-x enabled\n", acb->host->host_no);
632 return SUCCESS;
633msi_int:
634 if (pci_enable_msi_exact(pdev, 1) < 0)
635 goto legacy_int;
636 if (request_irq(pdev->irq, arcmsr_do_interrupt,
637 IRQF_SHARED, "arcmsr", acb)) {
638 pr_warn("arcmsr%d: request_irq =%d failed!\n",
639 acb->host->host_no, pdev->irq);
640 pci_disable_msi(pdev);
641 goto legacy_int;
642 }
643 acb->acb_flags |= ACB_F_MSI_ENABLED;
644 pr_info("arcmsr%d: msi enabled\n", acb->host->host_no);
645 return SUCCESS;
646legacy_int:
647 if (request_irq(pdev->irq, arcmsr_do_interrupt,
648 IRQF_SHARED, "arcmsr", acb)) {
649 pr_warn("arcmsr%d: request_irq = %d failed!\n",
650 acb->host->host_no, pdev->irq);
651 return FAILED;
652 }
653 return SUCCESS;
654}
655
606static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) 656static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
607{ 657{
608 struct Scsi_Host *host; 658 struct Scsi_Host *host;
@@ -667,16 +717,13 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
667 if(error){ 717 if(error){
668 goto free_hbb_mu; 718 goto free_hbb_mu;
669 } 719 }
670 arcmsr_iop_init(acb);
671 error = scsi_add_host(host, &pdev->dev); 720 error = scsi_add_host(host, &pdev->dev);
672 if(error){ 721 if(error){
673 goto RAID_controller_stop; 722 goto RAID_controller_stop;
674 } 723 }
675 error = request_irq(pdev->irq, arcmsr_do_interrupt, IRQF_SHARED, "arcmsr", acb); 724 if (arcmsr_request_irq(pdev, acb) == FAILED)
676 if(error){
677 goto scsi_host_remove; 725 goto scsi_host_remove;
678 } 726 arcmsr_iop_init(acb);
679 host->irq = pdev->irq;
680 scsi_scan_host(host); 727 scsi_scan_host(host);
681 INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn); 728 INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn);
682 atomic_set(&acb->rq_map_token, 16); 729 atomic_set(&acb->rq_map_token, 16);
@@ -710,6 +757,22 @@ pci_disable_dev:
710 return -ENODEV; 757 return -ENODEV;
711} 758}
712 759
760static void arcmsr_free_irq(struct pci_dev *pdev,
761 struct AdapterControlBlock *acb)
762{
763 int i;
764
765 if (acb->acb_flags & ACB_F_MSI_ENABLED) {
766 free_irq(pdev->irq, acb);
767 pci_disable_msi(pdev);
768 } else if (acb->acb_flags & ACB_F_MSIX_ENABLED) {
769 for (i = 0; i < acb->msix_vector_count; i++)
770 free_irq(acb->entries[i].vector, acb);
771 pci_disable_msix(pdev);
772 } else
773 free_irq(pdev->irq, acb);
774}
775
713static uint8_t arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb) 776static uint8_t arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb)
714{ 777{
715 struct MessageUnit_A __iomem *reg = acb->pmuA; 778 struct MessageUnit_A __iomem *reg = acb->pmuA;
@@ -992,6 +1055,7 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
992 } 1055 }
993 } 1056 }
994} 1057}
1058
995static void arcmsr_remove(struct pci_dev *pdev) 1059static void arcmsr_remove(struct pci_dev *pdev)
996{ 1060{
997 struct Scsi_Host *host = pci_get_drvdata(pdev); 1061 struct Scsi_Host *host = pci_get_drvdata(pdev);
@@ -1029,7 +1093,7 @@ static void arcmsr_remove(struct pci_dev *pdev)
1029 } 1093 }
1030 } 1094 }
1031 } 1095 }
1032 free_irq(pdev->irq, acb); 1096 arcmsr_free_irq(pdev, acb);
1033 arcmsr_free_ccb_pool(acb); 1097 arcmsr_free_ccb_pool(acb);
1034 arcmsr_free_hbb_mu(acb); 1098 arcmsr_free_hbb_mu(acb);
1035 arcmsr_unmap_pciregion(acb); 1099 arcmsr_unmap_pciregion(acb);
@@ -1045,6 +1109,7 @@ static void arcmsr_shutdown(struct pci_dev *pdev)
1045 (struct AdapterControlBlock *)host->hostdata; 1109 (struct AdapterControlBlock *)host->hostdata;
1046 del_timer_sync(&acb->eternal_timer); 1110 del_timer_sync(&acb->eternal_timer);
1047 arcmsr_disable_outbound_ints(acb); 1111 arcmsr_disable_outbound_ints(acb);
1112 arcmsr_free_irq(pdev, acb);
1048 flush_work(&acb->arcmsr_do_message_isr_bh); 1113 flush_work(&acb->arcmsr_do_message_isr_bh);
1049 arcmsr_stop_adapter_bgrb(acb); 1114 arcmsr_stop_adapter_bgrb(acb);
1050 arcmsr_flush_adapter_cache(acb); 1115 arcmsr_flush_adapter_cache(acb);
@@ -2516,8 +2581,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
2516 case ACB_ADAPTER_TYPE_A: { 2581 case ACB_ADAPTER_TYPE_A: {
2517 if (cdb_phyaddr_hi32 != 0) { 2582 if (cdb_phyaddr_hi32 != 0) {
2518 struct MessageUnit_A __iomem *reg = acb->pmuA; 2583 struct MessageUnit_A __iomem *reg = acb->pmuA;
2519 uint32_t intmask_org;
2520 intmask_org = arcmsr_disable_outbound_ints(acb);
2521 writel(ARCMSR_SIGNATURE_SET_CONFIG, \ 2584 writel(ARCMSR_SIGNATURE_SET_CONFIG, \
2522 &reg->message_rwbuffer[0]); 2585 &reg->message_rwbuffer[0]);
2523 writel(cdb_phyaddr_hi32, &reg->message_rwbuffer[1]); 2586 writel(cdb_phyaddr_hi32, &reg->message_rwbuffer[1]);
@@ -2529,7 +2592,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
2529 acb->host->host_no); 2592 acb->host->host_no);
2530 return 1; 2593 return 1;
2531 } 2594 }
2532 arcmsr_enable_outbound_ints(acb, intmask_org);
2533 } 2595 }
2534 } 2596 }
2535 break; 2597 break;
@@ -2539,8 +2601,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
2539 uint32_t __iomem *rwbuffer; 2601 uint32_t __iomem *rwbuffer;
2540 2602
2541 struct MessageUnit_B *reg = acb->pmuB; 2603 struct MessageUnit_B *reg = acb->pmuB;
2542 uint32_t intmask_org;
2543 intmask_org = arcmsr_disable_outbound_ints(acb);
2544 reg->postq_index = 0; 2604 reg->postq_index = 0;
2545 reg->doneq_index = 0; 2605 reg->doneq_index = 0;
2546 writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell); 2606 writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell);
@@ -2569,7 +2629,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
2569 return 1; 2629 return 1;
2570 } 2630 }
2571 arcmsr_hbb_enable_driver_mode(acb); 2631 arcmsr_hbb_enable_driver_mode(acb);
2572 arcmsr_enable_outbound_ints(acb, intmask_org);
2573 } 2632 }
2574 break; 2633 break;
2575 case ACB_ADAPTER_TYPE_C: { 2634 case ACB_ADAPTER_TYPE_C: {