]> git.ipfire.org Git - ipfire-2.x.git/blame - src/patches/suse-2.6.27.39/patches.drivers/ibmvfc_tasklet.patch
Fix oinkmaster patch.
[ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.drivers / ibmvfc_tasklet.patch
CommitLineData
2cb7cef9
BS
1Subject: Fix dropped interrupts
2From: Brian King <brking@linux.vnet.ibm.com>
3References: 473115 - LTC51485
4
5This patch fixes a problem of possible dropped interrupts. Currently, the ibmvfc
6driver has a race condition where after ibmvfc_interrupt gets run, the platform
7code clears the interrupt. This can result in lost interrupts and, in worst case
8scenarios, result in command timeouts. Fix this by implementing a tasklet
9similar to what the ibmvscsi driver does so that interrupt processing is no longer
10done in the actual interrupt handler, which eliminates the race.
11
12Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
13Signed-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 };