diff options
author | Matthew Wilcox <matthew@wil.cx> | 2007-07-29 01:11:05 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.localdomain> | 2007-10-12 14:38:40 -0400 |
commit | 074c8fe4c0c0c7918d99bca34ea8e02a86997530 (patch) | |
tree | 3749b38af53c46df54a036cb8d9cfd740031eef3 | |
parent | 2a437959e963d98e04dbbcd26b69bfb1985567ce (diff) |
[SCSI] advansys: Improve interrupt handler
Pass the Scsi_Host to the interrupt handler, rather than polling all
hosts for each interrupt.
Return IRQ_NONE if we didn't handle this interrupt
Don't set the IRQF_DISABLED flag; this is not a fast-executing interrupt
handler.
Signed-off-by: Matthew Wilcox <matthew@wil.cx>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r-- | drivers/scsi/advansys.c | 172 |
1 files changed, 72 insertions, 100 deletions
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 6d11076bbd02..a407ff34199d 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c | |||
@@ -3951,7 +3951,6 @@ static PortAddr _asc_def_iop_base[]; | |||
3951 | * advansys.h contains function prototypes for functions global to Linux. | 3951 | * advansys.h contains function prototypes for functions global to Linux. |
3952 | */ | 3952 | */ |
3953 | 3953 | ||
3954 | static irqreturn_t advansys_interrupt(int, void *); | ||
3955 | static int advansys_slave_configure(struct scsi_device *); | 3954 | static int advansys_slave_configure(struct scsi_device *); |
3956 | static void asc_scsi_done_list(struct scsi_cmnd *); | 3955 | static void asc_scsi_done_list(struct scsi_cmnd *); |
3957 | static int asc_execute_scsi_cmnd(struct scsi_cmnd *); | 3956 | static int asc_execute_scsi_cmnd(struct scsi_cmnd *); |
@@ -4684,89 +4683,76 @@ static struct scsi_host_template driver_template = { | |||
4684 | */ | 4683 | */ |
4685 | static irqreturn_t advansys_interrupt(int irq, void *dev_id) | 4684 | static irqreturn_t advansys_interrupt(int irq, void *dev_id) |
4686 | { | 4685 | { |
4687 | ulong flags; | 4686 | unsigned long flags; |
4688 | int i; | ||
4689 | asc_board_t *boardp; | ||
4690 | struct scsi_cmnd *done_scp = NULL, *last_scp = NULL; | 4687 | struct scsi_cmnd *done_scp = NULL, *last_scp = NULL; |
4691 | struct scsi_cmnd *new_last_scp; | 4688 | struct scsi_cmnd *new_last_scp; |
4692 | struct Scsi_Host *shost; | 4689 | struct Scsi_Host *shost = dev_id; |
4690 | asc_board_t *boardp = ASC_BOARDP(shost); | ||
4691 | irqreturn_t result = IRQ_NONE; | ||
4693 | 4692 | ||
4694 | ASC_DBG(1, "advansys_interrupt: begin\n"); | 4693 | ASC_DBG1(2, "advansys_interrupt: boardp 0x%p\n", boardp); |
4694 | spin_lock_irqsave(&boardp->lock, flags); | ||
4695 | if (ASC_NARROW_BOARD(boardp)) { | ||
4696 | /* | ||
4697 | * Narrow Board | ||
4698 | */ | ||
4699 | if (AscIsIntPending(shost->io_port)) { | ||
4700 | result = IRQ_HANDLED; | ||
4701 | ASC_STATS(shost, interrupt); | ||
4702 | ASC_DBG(1, "advansys_interrupt: before AscISR()\n"); | ||
4703 | AscISR(&boardp->dvc_var.asc_dvc_var); | ||
4704 | } | ||
4705 | } else { | ||
4706 | /* | ||
4707 | * Wide Board | ||
4708 | */ | ||
4709 | ASC_DBG(1, "advansys_interrupt: before AdvISR()\n"); | ||
4710 | if (AdvISR(&boardp->dvc_var.adv_dvc_var)) { | ||
4711 | result = IRQ_HANDLED; | ||
4712 | ASC_STATS(shost, interrupt); | ||
4713 | } | ||
4714 | } | ||
4695 | 4715 | ||
4696 | /* | 4716 | /* |
4697 | * Check for interrupts on all boards. | 4717 | * Start waiting requests and create a list of completed requests. |
4698 | * AscISR() will call asc_isr_callback(). | 4718 | * |
4699 | */ | 4719 | * If a reset request is being performed for the board, the reset |
4700 | for (i = 0; i < asc_board_count; i++) { | 4720 | * handler will complete pending requests after it has completed. |
4701 | shost = asc_host[i]; | 4721 | */ |
4702 | boardp = ASC_BOARDP(shost); | 4722 | if ((boardp->flags & ASC_HOST_IN_RESET) == 0) { |
4703 | ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n", | 4723 | ASC_DBG2(1, "advansys_interrupt: done_scp 0x%p, " |
4704 | i, (ulong)boardp); | 4724 | "last_scp 0x%p\n", done_scp, last_scp); |
4705 | spin_lock_irqsave(&boardp->lock, flags); | 4725 | |
4706 | if (ASC_NARROW_BOARD(boardp)) { | 4726 | /* Start any waiting commands for the board. */ |
4707 | /* | 4727 | if (!ASC_QUEUE_EMPTY(&boardp->waiting)) { |
4708 | * Narrow Board | 4728 | ASC_DBG(1, "advansys_interrupt: before " |
4709 | */ | 4729 | "asc_execute_queue()\n"); |
4710 | if (AscIsIntPending(shost->io_port)) { | 4730 | asc_execute_queue(&boardp->waiting); |
4711 | ASC_STATS(shost, interrupt); | ||
4712 | ASC_DBG(1, | ||
4713 | "advansys_interrupt: before AscISR()\n"); | ||
4714 | AscISR(&boardp->dvc_var.asc_dvc_var); | ||
4715 | } | ||
4716 | } else { | ||
4717 | /* | ||
4718 | * Wide Board | ||
4719 | */ | ||
4720 | ASC_DBG(1, "advansys_interrupt: before AdvISR()\n"); | ||
4721 | if (AdvISR(&boardp->dvc_var.adv_dvc_var)) { | ||
4722 | ASC_STATS(shost, interrupt); | ||
4723 | } | ||
4724 | } | 4731 | } |
4725 | 4732 | ||
4726 | /* | 4733 | /* |
4727 | * Start waiting requests and create a list of completed requests. | 4734 | * Add to the list of requests that must be completed. |
4728 | * | 4735 | * |
4729 | * If a reset request is being performed for the board, the reset | 4736 | * 'done_scp' will always be NULL on the first iteration of |
4730 | * handler will complete pending requests after it has completed. | 4737 | * this loop. 'last_scp' is set at the same time as 'done_scp'. |
4731 | */ | 4738 | */ |
4732 | if ((boardp->flags & ASC_HOST_IN_RESET) == 0) { | 4739 | if (done_scp == NULL) { |
4733 | ASC_DBG2(1, | 4740 | done_scp = asc_dequeue_list(&boardp->done, |
4734 | "advansys_interrupt: done_scp 0x%lx, last_scp 0x%lx\n", | 4741 | &last_scp, ASC_TID_ALL); |
4735 | (ulong)done_scp, (ulong)last_scp); | 4742 | } else { |
4736 | 4743 | ASC_ASSERT(last_scp != NULL); | |
4737 | /* Start any waiting commands for the board. */ | 4744 | last_scp->host_scribble = |
4738 | if (!ASC_QUEUE_EMPTY(&boardp->waiting)) { | 4745 | (unsigned char *)asc_dequeue_list(&boardp-> |
4739 | ASC_DBG(1, | 4746 | done, |
4740 | "advansys_interrupt: before asc_execute_queue()\n"); | 4747 | &new_last_scp, |
4741 | asc_execute_queue(&boardp->waiting); | 4748 | ASC_TID_ALL); |
4742 | } | 4749 | if (new_last_scp != NULL) { |
4743 | 4750 | ASC_ASSERT(REQPNEXT(last_scp) != NULL); | |
4744 | /* | 4751 | last_scp = new_last_scp; |
4745 | * Add to the list of requests that must be completed. | ||
4746 | * | ||
4747 | * 'done_scp' will always be NULL on the first iteration | ||
4748 | * of this loop. 'last_scp' is set at the same time as | ||
4749 | * 'done_scp'. | ||
4750 | */ | ||
4751 | if (done_scp == NULL) { | ||
4752 | done_scp = | ||
4753 | asc_dequeue_list(&boardp->done, &last_scp, | ||
4754 | ASC_TID_ALL); | ||
4755 | } else { | ||
4756 | ASC_ASSERT(last_scp != NULL); | ||
4757 | last_scp->host_scribble = | ||
4758 | (unsigned char *)asc_dequeue_list(&boardp-> | ||
4759 | done, | ||
4760 | &new_last_scp, | ||
4761 | ASC_TID_ALL); | ||
4762 | if (new_last_scp != NULL) { | ||
4763 | ASC_ASSERT(REQPNEXT(last_scp) != NULL); | ||
4764 | last_scp = new_last_scp; | ||
4765 | } | ||
4766 | } | 4752 | } |
4767 | } | 4753 | } |
4768 | spin_unlock_irqrestore(&boardp->lock, flags); | ||
4769 | } | 4754 | } |
4755 | spin_unlock_irqrestore(&boardp->lock, flags); | ||
4770 | 4756 | ||
4771 | /* | 4757 | /* |
4772 | * If interrupts were enabled on entry, then they | 4758 | * If interrupts were enabled on entry, then they |
@@ -4778,7 +4764,7 @@ static irqreturn_t advansys_interrupt(int irq, void *dev_id) | |||
4778 | asc_scsi_done_list(done_scp); | 4764 | asc_scsi_done_list(done_scp); |
4779 | 4765 | ||
4780 | ASC_DBG(1, "advansys_interrupt: end\n"); | 4766 | ASC_DBG(1, "advansys_interrupt: end\n"); |
4781 | return IRQ_HANDLED; | 4767 | return result; |
4782 | } | 4768 | } |
4783 | 4769 | ||
4784 | /* | 4770 | /* |
@@ -17764,7 +17750,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type) | |||
17764 | ASC_DVC_VAR *asc_dvc_varp = NULL; | 17750 | ASC_DVC_VAR *asc_dvc_varp = NULL; |
17765 | ADV_DVC_VAR *adv_dvc_varp = NULL; | 17751 | ADV_DVC_VAR *adv_dvc_varp = NULL; |
17766 | adv_sgblk_t *sgp = NULL; | 17752 | adv_sgblk_t *sgp = NULL; |
17767 | int share_irq = FALSE; | 17753 | int share_irq; |
17768 | int iolen = 0; | 17754 | int iolen = 0; |
17769 | ADV_PADDR pci_memory_address; | 17755 | ADV_PADDR pci_memory_address; |
17770 | int warn_code, err_code; | 17756 | int warn_code, err_code; |
@@ -17918,15 +17904,15 @@ advansys_board_found(int iop, struct device *dev, int bus_type) | |||
17918 | #ifdef CONFIG_ISA | 17904 | #ifdef CONFIG_ISA |
17919 | case ASC_IS_ISA: | 17905 | case ASC_IS_ISA: |
17920 | shost->unchecked_isa_dma = TRUE; | 17906 | shost->unchecked_isa_dma = TRUE; |
17921 | share_irq = FALSE; | 17907 | share_irq = 0; |
17922 | break; | 17908 | break; |
17923 | case ASC_IS_VL: | 17909 | case ASC_IS_VL: |
17924 | shost->unchecked_isa_dma = FALSE; | 17910 | shost->unchecked_isa_dma = FALSE; |
17925 | share_irq = FALSE; | 17911 | share_irq = 0; |
17926 | break; | 17912 | break; |
17927 | case ASC_IS_EISA: | 17913 | case ASC_IS_EISA: |
17928 | shost->unchecked_isa_dma = FALSE; | 17914 | shost->unchecked_isa_dma = FALSE; |
17929 | share_irq = TRUE; | 17915 | share_irq = IRQF_SHARED; |
17930 | break; | 17916 | break; |
17931 | #endif /* CONFIG_ISA */ | 17917 | #endif /* CONFIG_ISA */ |
17932 | #ifdef CONFIG_PCI | 17918 | #ifdef CONFIG_PCI |
@@ -17937,7 +17923,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type) | |||
17937 | PCI_SLOT(pdev->devfn), | 17923 | PCI_SLOT(pdev->devfn), |
17938 | PCI_FUNC(pdev->devfn)); | 17924 | PCI_FUNC(pdev->devfn)); |
17939 | shost->unchecked_isa_dma = FALSE; | 17925 | shost->unchecked_isa_dma = FALSE; |
17940 | share_irq = TRUE; | 17926 | share_irq = IRQF_SHARED; |
17941 | break; | 17927 | break; |
17942 | #endif /* CONFIG_PCI */ | 17928 | #endif /* CONFIG_PCI */ |
17943 | default: | 17929 | default: |
@@ -17945,7 +17931,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type) | |||
17945 | ("advansys_board_found: board %d: unknown adapter type: %d\n", | 17931 | ("advansys_board_found: board %d: unknown adapter type: %d\n", |
17946 | boardp->id, asc_dvc_varp->bus_type); | 17932 | boardp->id, asc_dvc_varp->bus_type); |
17947 | shost->unchecked_isa_dma = TRUE; | 17933 | shost->unchecked_isa_dma = TRUE; |
17948 | share_irq = FALSE; | 17934 | share_irq = 0; |
17949 | break; | 17935 | break; |
17950 | } | 17936 | } |
17951 | } else { | 17937 | } else { |
@@ -17961,7 +17947,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type) | |||
17961 | PCI_SLOT(pdev->devfn), | 17947 | PCI_SLOT(pdev->devfn), |
17962 | PCI_FUNC(pdev->devfn)); | 17948 | PCI_FUNC(pdev->devfn)); |
17963 | shost->unchecked_isa_dma = FALSE; | 17949 | shost->unchecked_isa_dma = FALSE; |
17964 | share_irq = TRUE; | 17950 | share_irq = IRQF_SHARED; |
17965 | #endif /* CONFIG_PCI */ | 17951 | #endif /* CONFIG_PCI */ |
17966 | } | 17952 | } |
17967 | 17953 | ||
@@ -18425,25 +18411,11 @@ advansys_board_found(int iop, struct device *dev, int bus_type) | |||
18425 | 18411 | ||
18426 | /* Register IRQ Number. */ | 18412 | /* Register IRQ Number. */ |
18427 | ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq); | 18413 | ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq); |
18428 | /* | 18414 | |
18429 | * If request_irq() fails with the IRQF_DISABLED flag set, | 18415 | ret = request_irq(shost->irq, advansys_interrupt, share_irq, |
18430 | * then try again without the IRQF_DISABLED flag set. This | 18416 | "advansys", shost); |
18431 | * allows IRQ sharing to work even with other drivers that | 18417 | |
18432 | * do not set the IRQF_DISABLED flag. | 18418 | if (ret) { |
18433 | * | ||
18434 | * If IRQF_DISABLED is not set, then interrupts are enabled | ||
18435 | * before the driver interrupt function is called. | ||
18436 | */ | ||
18437 | if (((ret = request_irq(shost->irq, advansys_interrupt, | ||
18438 | IRQF_DISABLED | (share_irq == | ||
18439 | TRUE ? | ||
18440 | IRQF_SHARED : | ||
18441 | 0), "advansys", boardp)) != 0) | ||
18442 | && | ||
18443 | ((ret = | ||
18444 | request_irq(shost->irq, advansys_interrupt, | ||
18445 | (share_irq == TRUE ? IRQF_SHARED : 0), | ||
18446 | "advansys", boardp)) != 0)) { | ||
18447 | if (ret == -EBUSY) { | 18419 | if (ret == -EBUSY) { |
18448 | ASC_PRINT2 | 18420 | ASC_PRINT2 |
18449 | ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n", | 18421 | ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n", |
@@ -18644,7 +18616,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type) | |||
18644 | #ifdef CONFIG_PROC_FS | 18616 | #ifdef CONFIG_PROC_FS |
18645 | kfree(boardp->prtbuf); | 18617 | kfree(boardp->prtbuf); |
18646 | #endif /* CONFIG_PROC_FS */ | 18618 | #endif /* CONFIG_PROC_FS */ |
18647 | free_irq(shost->irq, boardp); | 18619 | free_irq(shost->irq, shost); |
18648 | scsi_unregister(shost); | 18620 | scsi_unregister(shost); |
18649 | asc_board_count--; | 18621 | asc_board_count--; |
18650 | return NULL; | 18622 | return NULL; |
@@ -18960,7 +18932,7 @@ static int advansys_release(struct Scsi_Host *shost) | |||
18960 | 18932 | ||
18961 | ASC_DBG(1, "advansys_release: begin\n"); | 18933 | ASC_DBG(1, "advansys_release: begin\n"); |
18962 | boardp = ASC_BOARDP(shost); | 18934 | boardp = ASC_BOARDP(shost); |
18963 | free_irq(shost->irq, boardp); | 18935 | free_irq(shost->irq, shost); |
18964 | if (shost->dma_channel != NO_ISA_DMA) { | 18936 | if (shost->dma_channel != NO_ISA_DMA) { |
18965 | ASC_DBG(1, "advansys_release: free_dma()\n"); | 18937 | ASC_DBG(1, "advansys_release: free_dma()\n"); |
18966 | free_dma(shost->dma_channel); | 18938 | free_dma(shost->dma_channel); |