Commit 074c8fe4 authored by Matthew Wilcox's avatar Matthew Wilcox Committed by James Bottomley

[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: default avatarMatthew Wilcox <matthew@wil.cx>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 2a437959
...@@ -3951,7 +3951,6 @@ static PortAddr _asc_def_iop_base[]; ...@@ -3951,7 +3951,6 @@ static PortAddr _asc_def_iop_base[];
* advansys.h contains function prototypes for functions global to Linux. * advansys.h contains function prototypes for functions global to Linux.
*/ */
static irqreturn_t advansys_interrupt(int, void *);
static int advansys_slave_configure(struct scsi_device *); static int advansys_slave_configure(struct scsi_device *);
static void asc_scsi_done_list(struct scsi_cmnd *); static void asc_scsi_done_list(struct scsi_cmnd *);
static int asc_execute_scsi_cmnd(struct scsi_cmnd *); static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
...@@ -4684,89 +4683,76 @@ static struct scsi_host_template driver_template = { ...@@ -4684,89 +4683,76 @@ static struct scsi_host_template driver_template = {
*/ */
static irqreturn_t advansys_interrupt(int irq, void *dev_id) static irqreturn_t advansys_interrupt(int irq, void *dev_id)
{ {
ulong flags; unsigned long flags;
int i;
asc_board_t *boardp;
struct scsi_cmnd *done_scp = NULL, *last_scp = NULL; struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
struct scsi_cmnd *new_last_scp; struct scsi_cmnd *new_last_scp;
struct Scsi_Host *shost; struct Scsi_Host *shost = dev_id;
asc_board_t *boardp = ASC_BOARDP(shost);
irqreturn_t result = IRQ_NONE;
ASC_DBG(1, "advansys_interrupt: begin\n"); ASC_DBG1(2, "advansys_interrupt: boardp 0x%p\n", boardp);
spin_lock_irqsave(&boardp->lock, flags);
if (ASC_NARROW_BOARD(boardp)) {
/*
* Narrow Board
*/
if (AscIsIntPending(shost->io_port)) {
result = IRQ_HANDLED;
ASC_STATS(shost, interrupt);
ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
AscISR(&boardp->dvc_var.asc_dvc_var);
}
} else {
/*
* Wide Board
*/
ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
result = IRQ_HANDLED;
ASC_STATS(shost, interrupt);
}
}
/* /*
* Check for interrupts on all boards. * Start waiting requests and create a list of completed requests.
* AscISR() will call asc_isr_callback(). *
*/ * If a reset request is being performed for the board, the reset
for (i = 0; i < asc_board_count; i++) { * handler will complete pending requests after it has completed.
shost = asc_host[i]; */
boardp = ASC_BOARDP(shost); if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n", ASC_DBG2(1, "advansys_interrupt: done_scp 0x%p, "
i, (ulong)boardp); "last_scp 0x%p\n", done_scp, last_scp);
spin_lock_irqsave(&boardp->lock, flags);
if (ASC_NARROW_BOARD(boardp)) { /* Start any waiting commands for the board. */
/* if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
* Narrow Board ASC_DBG(1, "advansys_interrupt: before "
*/ "asc_execute_queue()\n");
if (AscIsIntPending(shost->io_port)) { asc_execute_queue(&boardp->waiting);
ASC_STATS(shost, interrupt);
ASC_DBG(1,
"advansys_interrupt: before AscISR()\n");
AscISR(&boardp->dvc_var.asc_dvc_var);
}
} else {
/*
* Wide Board
*/
ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
ASC_STATS(shost, interrupt);
}
} }
/* /*
* Start waiting requests and create a list of completed requests. * Add to the list of requests that must be completed.
* *
* If a reset request is being performed for the board, the reset * 'done_scp' will always be NULL on the first iteration of
* handler will complete pending requests after it has completed. * this loop. 'last_scp' is set at the same time as 'done_scp'.
*/ */
if ((boardp->flags & ASC_HOST_IN_RESET) == 0) { if (done_scp == NULL) {
ASC_DBG2(1, done_scp = asc_dequeue_list(&boardp->done,
"advansys_interrupt: done_scp 0x%lx, last_scp 0x%lx\n", &last_scp, ASC_TID_ALL);
(ulong)done_scp, (ulong)last_scp); } else {
ASC_ASSERT(last_scp != NULL);
/* Start any waiting commands for the board. */ last_scp->host_scribble =
if (!ASC_QUEUE_EMPTY(&boardp->waiting)) { (unsigned char *)asc_dequeue_list(&boardp->
ASC_DBG(1, done,
"advansys_interrupt: before asc_execute_queue()\n"); &new_last_scp,
asc_execute_queue(&boardp->waiting); ASC_TID_ALL);
} if (new_last_scp != NULL) {
ASC_ASSERT(REQPNEXT(last_scp) != NULL);
/* last_scp = new_last_scp;
* Add to the list of requests that must be completed.
*
* 'done_scp' will always be NULL on the first iteration
* of this loop. 'last_scp' is set at the same time as
* 'done_scp'.
*/
if (done_scp == NULL) {
done_scp =
asc_dequeue_list(&boardp->done, &last_scp,
ASC_TID_ALL);
} else {
ASC_ASSERT(last_scp != NULL);
last_scp->host_scribble =
(unsigned char *)asc_dequeue_list(&boardp->
done,
&new_last_scp,
ASC_TID_ALL);
if (new_last_scp != NULL) {
ASC_ASSERT(REQPNEXT(last_scp) != NULL);
last_scp = new_last_scp;
}
} }
} }
spin_unlock_irqrestore(&boardp->lock, flags);
} }
spin_unlock_irqrestore(&boardp->lock, flags);
/* /*
* If interrupts were enabled on entry, then they * If interrupts were enabled on entry, then they
...@@ -4778,7 +4764,7 @@ static irqreturn_t advansys_interrupt(int irq, void *dev_id) ...@@ -4778,7 +4764,7 @@ static irqreturn_t advansys_interrupt(int irq, void *dev_id)
asc_scsi_done_list(done_scp); asc_scsi_done_list(done_scp);
ASC_DBG(1, "advansys_interrupt: end\n"); ASC_DBG(1, "advansys_interrupt: end\n");
return IRQ_HANDLED; return result;
} }
/* /*
...@@ -17764,7 +17750,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type) ...@@ -17764,7 +17750,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
ASC_DVC_VAR *asc_dvc_varp = NULL; ASC_DVC_VAR *asc_dvc_varp = NULL;
ADV_DVC_VAR *adv_dvc_varp = NULL; ADV_DVC_VAR *adv_dvc_varp = NULL;
adv_sgblk_t *sgp = NULL; adv_sgblk_t *sgp = NULL;
int share_irq = FALSE; int share_irq;
int iolen = 0; int iolen = 0;
ADV_PADDR pci_memory_address; ADV_PADDR pci_memory_address;
int warn_code, err_code; int warn_code, err_code;
...@@ -17918,15 +17904,15 @@ advansys_board_found(int iop, struct device *dev, int bus_type) ...@@ -17918,15 +17904,15 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
#ifdef CONFIG_ISA #ifdef CONFIG_ISA
case ASC_IS_ISA: case ASC_IS_ISA:
shost->unchecked_isa_dma = TRUE; shost->unchecked_isa_dma = TRUE;
share_irq = FALSE; share_irq = 0;
break; break;
case ASC_IS_VL: case ASC_IS_VL:
shost->unchecked_isa_dma = FALSE; shost->unchecked_isa_dma = FALSE;
share_irq = FALSE; share_irq = 0;
break; break;
case ASC_IS_EISA: case ASC_IS_EISA:
shost->unchecked_isa_dma = FALSE; shost->unchecked_isa_dma = FALSE;
share_irq = TRUE; share_irq = IRQF_SHARED;
break; break;
#endif /* CONFIG_ISA */ #endif /* CONFIG_ISA */
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
...@@ -17937,7 +17923,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type) ...@@ -17937,7 +17923,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
PCI_SLOT(pdev->devfn), PCI_SLOT(pdev->devfn),
PCI_FUNC(pdev->devfn)); PCI_FUNC(pdev->devfn));
shost->unchecked_isa_dma = FALSE; shost->unchecked_isa_dma = FALSE;
share_irq = TRUE; share_irq = IRQF_SHARED;
break; break;
#endif /* CONFIG_PCI */ #endif /* CONFIG_PCI */
default: default:
...@@ -17945,7 +17931,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type) ...@@ -17945,7 +17931,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
("advansys_board_found: board %d: unknown adapter type: %d\n", ("advansys_board_found: board %d: unknown adapter type: %d\n",
boardp->id, asc_dvc_varp->bus_type); boardp->id, asc_dvc_varp->bus_type);
shost->unchecked_isa_dma = TRUE; shost->unchecked_isa_dma = TRUE;
share_irq = FALSE; share_irq = 0;
break; break;
} }
} else { } else {
...@@ -17961,7 +17947,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type) ...@@ -17961,7 +17947,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
PCI_SLOT(pdev->devfn), PCI_SLOT(pdev->devfn),
PCI_FUNC(pdev->devfn)); PCI_FUNC(pdev->devfn));
shost->unchecked_isa_dma = FALSE; shost->unchecked_isa_dma = FALSE;
share_irq = TRUE; share_irq = IRQF_SHARED;
#endif /* CONFIG_PCI */ #endif /* CONFIG_PCI */
} }
...@@ -18425,25 +18411,11 @@ advansys_board_found(int iop, struct device *dev, int bus_type) ...@@ -18425,25 +18411,11 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
/* Register IRQ Number. */ /* Register IRQ Number. */
ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq); ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
/*
* If request_irq() fails with the IRQF_DISABLED flag set, ret = request_irq(shost->irq, advansys_interrupt, share_irq,
* then try again without the IRQF_DISABLED flag set. This "advansys", shost);
* allows IRQ sharing to work even with other drivers that
* do not set the IRQF_DISABLED flag. if (ret) {
*
* If IRQF_DISABLED is not set, then interrupts are enabled
* before the driver interrupt function is called.
*/
if (((ret = request_irq(shost->irq, advansys_interrupt,
IRQF_DISABLED | (share_irq ==
TRUE ?
IRQF_SHARED :
0), "advansys", boardp)) != 0)
&&
((ret =
request_irq(shost->irq, advansys_interrupt,
(share_irq == TRUE ? IRQF_SHARED : 0),
"advansys", boardp)) != 0)) {
if (ret == -EBUSY) { if (ret == -EBUSY) {
ASC_PRINT2 ASC_PRINT2
("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n", ("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,7 +18616,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
kfree(boardp->prtbuf); kfree(boardp->prtbuf);
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_PROC_FS */
free_irq(shost->irq, boardp); free_irq(shost->irq, shost);
scsi_unregister(shost); scsi_unregister(shost);
asc_board_count--; asc_board_count--;
return NULL; return NULL;
...@@ -18960,7 +18932,7 @@ static int advansys_release(struct Scsi_Host *shost) ...@@ -18960,7 +18932,7 @@ static int advansys_release(struct Scsi_Host *shost)
ASC_DBG(1, "advansys_release: begin\n"); ASC_DBG(1, "advansys_release: begin\n");
boardp = ASC_BOARDP(shost); boardp = ASC_BOARDP(shost);
free_irq(shost->irq, boardp); free_irq(shost->irq, shost);
if (shost->dma_channel != NO_ISA_DMA) { if (shost->dma_channel != NO_ISA_DMA) {
ASC_DBG(1, "advansys_release: free_dma()\n"); ASC_DBG(1, "advansys_release: free_dma()\n");
free_dma(shost->dma_channel); free_dma(shost->dma_channel);
......
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