]>
Commit | Line | Data |
---|---|---|
1 | Subject: Fix dropped interrupts | |
2 | From: Brian King <brking@linux.vnet.ibm.com> | |
3 | References: 473115 - LTC51485 | |
4 | ||
5 | This patch fixes a problem of possible dropped interrupts. Currently, the ibmvfc | |
6 | driver has a race condition where after ibmvfc_interrupt gets run, the platform | |
7 | code clears the interrupt. This can result in lost interrupts and, in worst case | |
8 | scenarios, result in command timeouts. Fix this by implementing a tasklet | |
9 | similar to what the ibmvscsi driver does so that interrupt processing is no longer | |
10 | done in the actual interrupt handler, which eliminates the race. | |
11 | ||
12 | Signed-off-by: Brian King <brking@linux.vnet.ibm.com> | |
13 | Signed-off-by: Olaf Hering <olh@suse.de> | |
14 | --- | |
15 | ||
16 | drivers/scsi/ibmvscsi/ibmvfc.c | 25 +++++++++++++++++++++++-- | |
17 | drivers/scsi/ibmvscsi/ibmvfc.h | 1 + | |
18 | 2 files changed, 24 insertions(+), 2 deletions(-) | |
19 | ||
20 | --- a/drivers/scsi/ibmvscsi/ibmvfc.c | |
21 | +++ b/drivers/scsi/ibmvscsi/ibmvfc.c | |
22 | @@ -640,6 +640,7 @@ static void ibmvfc_release_crq_queue(str | |
23 | ||
24 | ibmvfc_dbg(vhost, "Releasing CRQ\n"); | |
25 | free_irq(vdev->irq, vhost); | |
26 | + tasklet_kill(&vhost->tasklet); | |
27 | do { | |
28 | rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); | |
29 | } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); | |
30 | @@ -2697,6 +2698,25 @@ static struct ibmvfc_crq *ibmvfc_next_cr | |
31 | static irqreturn_t ibmvfc_interrupt(int irq, void *dev_instance) | |
32 | { | |
33 | struct ibmvfc_host *vhost = (struct ibmvfc_host *)dev_instance; | |
34 | + unsigned long flags; | |
35 | + | |
36 | + spin_lock_irqsave(vhost->host->host_lock, flags); | |
37 | + vio_disable_interrupts(to_vio_dev(vhost->dev)); | |
38 | + tasklet_schedule(&vhost->tasklet); | |
39 | + spin_unlock_irqrestore(vhost->host->host_lock, flags); | |
40 | + return IRQ_HANDLED; | |
41 | +} | |
42 | + | |
43 | +/** | |
44 | + * ibmvfc_tasklet - Interrupt handler tasklet | |
45 | + * @data: ibmvfc host struct | |
46 | + * | |
47 | + * Returns: | |
48 | + * Nothing | |
49 | + **/ | |
50 | +static void ibmvfc_tasklet(void *data) | |
51 | +{ | |
52 | + struct ibmvfc_host *vhost = data; | |
53 | struct vio_dev *vdev = to_vio_dev(vhost->dev); | |
54 | struct ibmvfc_crq *crq; | |
55 | struct ibmvfc_async_crq *async; | |
56 | @@ -2704,7 +2724,6 @@ static irqreturn_t ibmvfc_interrupt(int | |
57 | int done = 0; | |
58 | ||
59 | spin_lock_irqsave(vhost->host->host_lock, flags); | |
60 | - vio_disable_interrupts(to_vio_dev(vhost->dev)); | |
61 | while (!done) { | |
62 | /* Pull all the valid messages off the CRQ */ | |
63 | while ((crq = ibmvfc_next_crq(vhost)) != NULL) { | |
64 | @@ -2732,7 +2751,6 @@ static irqreturn_t ibmvfc_interrupt(int | |
65 | } | |
66 | ||
67 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | |
68 | - return IRQ_HANDLED; | |
69 | } | |
70 | ||
71 | /** | |
72 | @@ -3857,6 +3875,8 @@ static int ibmvfc_init_crq(struct ibmvfc | |
73 | ||
74 | retrc = 0; | |
75 | ||
76 | + tasklet_init(&vhost->tasklet, (void *)ibmvfc_tasklet, (unsigned long)vhost); | |
77 | + | |
78 | if ((rc = request_irq(vdev->irq, ibmvfc_interrupt, 0, IBMVFC_NAME, vhost))) { | |
79 | dev_err(dev, "Couldn't register irq 0x%x. rc=%d\n", vdev->irq, rc); | |
80 | goto req_irq_failed; | |
81 | @@ -3872,6 +3892,7 @@ static int ibmvfc_init_crq(struct ibmvfc | |
82 | return retrc; | |
83 | ||
84 | req_irq_failed: | |
85 | + tasklet_kill(&vhost->tasklet); | |
86 | do { | |
87 | rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); | |
88 | } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); | |
89 | --- a/drivers/scsi/ibmvscsi/ibmvfc.h | |
90 | +++ b/drivers/scsi/ibmvscsi/ibmvfc.h | |
91 | @@ -684,6 +684,7 @@ struct ibmvfc_host { | |
92 | char partition_name[97]; | |
93 | void (*job_step) (struct ibmvfc_host *); | |
94 | struct task_struct *work_thread; | |
95 | + struct tasklet_struct tasklet; | |
96 | wait_queue_head_t init_wait_q; | |
97 | wait_queue_head_t work_wait_q; | |
98 | }; |