]> git.ipfire.org Git - ipfire-2.x.git/blob - src/patches/suse-2.6.27.39/patches.drivers/ibmvfc_tasklet.patch
Add a patch to fix Intel E100 wake-on-lan problems.
[ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.drivers / ibmvfc_tasklet.patch
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 };