diff options
author | Ching Huang <ching2048@areca.com.tw> | 2014-08-19 02:23:31 -0400 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2014-09-16 12:39:28 -0400 |
commit | 1d1166ea16ac7047a1b01f20dcbcc6f7754c3c23 (patch) | |
tree | c78222ada649f6dbbeb8939beae1f1d4f4fb9a7d /drivers/scsi/arcmsr | |
parent | 6b3937227479e50032112faf74bd913f36dba2c6 (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.h | 5 | ||||
-rw-r--r-- | drivers/scsi/arcmsr/arcmsr_hba.c | 83 |
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 | ||
606 | static int | ||
607 | arcmsr_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; | ||
633 | msi_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; | ||
646 | legacy_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 | |||
606 | static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) | 656 | static 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 | ||
760 | static 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 | |||
713 | static uint8_t arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb) | 776 | static 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 | |||
995 | static void arcmsr_remove(struct pci_dev *pdev) | 1059 | static 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 | ®->message_rwbuffer[0]); | 2585 | ®->message_rwbuffer[0]); |
2523 | writel(cdb_phyaddr_hi32, ®->message_rwbuffer[1]); | 2586 | writel(cdb_phyaddr_hi32, ®->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: { |