]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/4.11.2/crypto-ccp-change-isr-handler-method-for-a-v5-ccp.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.11.2 / crypto-ccp-change-isr-handler-method-for-a-v5-ccp.patch
1 From 6263b51eb3190d30351360fd168959af7e3a49a9 Mon Sep 17 00:00:00 2001
2 From: Gary R Hook <gary.hook@amd.com>
3 Date: Fri, 21 Apr 2017 10:50:14 -0500
4 Subject: crypto: ccp - Change ISR handler method for a v5 CCP
5
6 From: Gary R Hook <gary.hook@amd.com>
7
8 commit 6263b51eb3190d30351360fd168959af7e3a49a9 upstream.
9
10 The CCP has the ability to perform several operations simultaneously,
11 but only one interrupt. When implemented as a PCI device and using
12 MSI-X/MSI interrupts, use a tasklet model to service interrupts. By
13 disabling and enabling interrupts from the CCP, coupled with the
14 queuing that tasklets provide, we can ensure that all events
15 (occurring on the device) are recognized and serviced.
16
17 This change fixes a problem wherein 2 or more busy queues can cause
18 notification bits to change state while a (CCP) interrupt is being
19 serviced, but after the queue state has been evaluated. This results
20 in the event being 'lost' and the queue hanging, waiting to be
21 serviced. Since the status bits are never fully de-asserted, the
22 CCP never generates another interrupt (all bits zero -> one or more
23 bits one), and no further CCP operations will be executed.
24
25 Signed-off-by: Gary R Hook <gary.hook@amd.com>
26 Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
27 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
28
29 ---
30 drivers/crypto/ccp/ccp-dev-v5.c | 111 ++++++++++++++++++++++++----------------
31 1 file changed, 67 insertions(+), 44 deletions(-)
32
33 --- a/drivers/crypto/ccp/ccp-dev-v5.c
34 +++ b/drivers/crypto/ccp/ccp-dev-v5.c
35 @@ -653,6 +653,65 @@ static int ccp_assign_lsbs(struct ccp_de
36 return rc;
37 }
38
39 +static void ccp5_disable_queue_interrupts(struct ccp_device *ccp)
40 +{
41 + unsigned int i;
42 +
43 + for (i = 0; i < ccp->cmd_q_count; i++)
44 + iowrite32(0x0, ccp->cmd_q[i].reg_int_enable);
45 +}
46 +
47 +static void ccp5_enable_queue_interrupts(struct ccp_device *ccp)
48 +{
49 + unsigned int i;
50 +
51 + for (i = 0; i < ccp->cmd_q_count; i++)
52 + iowrite32(SUPPORTED_INTERRUPTS, ccp->cmd_q[i].reg_int_enable);
53 +}
54 +
55 +static void ccp5_irq_bh(unsigned long data)
56 +{
57 + struct ccp_device *ccp = (struct ccp_device *)data;
58 + u32 status;
59 + unsigned int i;
60 +
61 + for (i = 0; i < ccp->cmd_q_count; i++) {
62 + struct ccp_cmd_queue *cmd_q = &ccp->cmd_q[i];
63 +
64 + status = ioread32(cmd_q->reg_interrupt_status);
65 +
66 + if (status) {
67 + cmd_q->int_status = status;
68 + cmd_q->q_status = ioread32(cmd_q->reg_status);
69 + cmd_q->q_int_status = ioread32(cmd_q->reg_int_status);
70 +
71 + /* On error, only save the first error value */
72 + if ((status & INT_ERROR) && !cmd_q->cmd_error)
73 + cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status);
74 +
75 + cmd_q->int_rcvd = 1;
76 +
77 + /* Acknowledge the interrupt and wake the kthread */
78 + iowrite32(status, cmd_q->reg_interrupt_status);
79 + wake_up_interruptible(&cmd_q->int_queue);
80 + }
81 + }
82 + ccp5_enable_queue_interrupts(ccp);
83 +}
84 +
85 +static irqreturn_t ccp5_irq_handler(int irq, void *data)
86 +{
87 + struct device *dev = data;
88 + struct ccp_device *ccp = dev_get_drvdata(dev);
89 +
90 + ccp5_disable_queue_interrupts(ccp);
91 + if (ccp->use_tasklet)
92 + tasklet_schedule(&ccp->irq_tasklet);
93 + else
94 + ccp5_irq_bh((unsigned long)ccp);
95 + return IRQ_HANDLED;
96 +}
97 +
98 static int ccp5_init(struct ccp_device *ccp)
99 {
100 struct device *dev = ccp->dev;
101 @@ -736,18 +795,17 @@ static int ccp5_init(struct ccp_device *
102 }
103
104 /* Turn off the queues and disable interrupts until ready */
105 + ccp5_disable_queue_interrupts(ccp);
106 for (i = 0; i < ccp->cmd_q_count; i++) {
107 cmd_q = &ccp->cmd_q[i];
108
109 cmd_q->qcontrol = 0; /* Start with nothing */
110 iowrite32(cmd_q->qcontrol, cmd_q->reg_control);
111
112 - /* Disable the interrupts */
113 - iowrite32(0x00, cmd_q->reg_int_enable);
114 ioread32(cmd_q->reg_int_status);
115 ioread32(cmd_q->reg_status);
116
117 - /* Clear the interrupts */
118 + /* Clear the interrupt status */
119 iowrite32(SUPPORTED_INTERRUPTS, cmd_q->reg_interrupt_status);
120 }
121
122 @@ -758,6 +816,10 @@ static int ccp5_init(struct ccp_device *
123 dev_err(dev, "unable to allocate an IRQ\n");
124 goto e_pool;
125 }
126 + /* Initialize the ISR tasklet */
127 + if (ccp->use_tasklet)
128 + tasklet_init(&ccp->irq_tasklet, ccp5_irq_bh,
129 + (unsigned long)ccp);
130
131 dev_dbg(dev, "Loading LSB map...\n");
132 /* Copy the private LSB mask to the public registers */
133 @@ -826,11 +888,7 @@ static int ccp5_init(struct ccp_device *
134 }
135
136 dev_dbg(dev, "Enabling interrupts...\n");
137 - /* Enable interrupts */
138 - for (i = 0; i < ccp->cmd_q_count; i++) {
139 - cmd_q = &ccp->cmd_q[i];
140 - iowrite32(SUPPORTED_INTERRUPTS, cmd_q->reg_int_enable);
141 - }
142 + ccp5_enable_queue_interrupts(ccp);
143
144 dev_dbg(dev, "Registering device...\n");
145 /* Put this on the unit list to make it available */
146 @@ -882,15 +940,13 @@ static void ccp5_destroy(struct ccp_devi
147 ccp_del_device(ccp);
148
149 /* Disable and clear interrupts */
150 + ccp5_disable_queue_interrupts(ccp);
151 for (i = 0; i < ccp->cmd_q_count; i++) {
152 cmd_q = &ccp->cmd_q[i];
153
154 /* Turn off the run bit */
155 iowrite32(cmd_q->qcontrol & ~CMD5_Q_RUN, cmd_q->reg_control);
156
157 - /* Disable the interrupts */
158 - iowrite32(0x00, cmd_q->reg_int_enable);
159 -
160 /* Clear the interrupt status */
161 iowrite32(SUPPORTED_INTERRUPTS, cmd_q->reg_interrupt_status);
162 ioread32(cmd_q->reg_int_status);
163 @@ -925,39 +981,6 @@ static void ccp5_destroy(struct ccp_devi
164 }
165 }
166
167 -static irqreturn_t ccp5_irq_handler(int irq, void *data)
168 -{
169 - struct device *dev = data;
170 - struct ccp_device *ccp = dev_get_drvdata(dev);
171 - u32 status;
172 - unsigned int i;
173 -
174 - for (i = 0; i < ccp->cmd_q_count; i++) {
175 - struct ccp_cmd_queue *cmd_q = &ccp->cmd_q[i];
176 -
177 - status = ioread32(cmd_q->reg_interrupt_status);
178 -
179 - if (status) {
180 - cmd_q->int_status = status;
181 - cmd_q->q_status = ioread32(cmd_q->reg_status);
182 - cmd_q->q_int_status = ioread32(cmd_q->reg_int_status);
183 -
184 - /* On error, only save the first error value */
185 - if ((status & INT_ERROR) && !cmd_q->cmd_error)
186 - cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status);
187 -
188 - cmd_q->int_rcvd = 1;
189 -
190 - /* Acknowledge the interrupt and wake the kthread */
191 - iowrite32(SUPPORTED_INTERRUPTS,
192 - cmd_q->reg_interrupt_status);
193 - wake_up_interruptible(&cmd_q->int_queue);
194 - }
195 - }
196 -
197 - return IRQ_HANDLED;
198 -}
199 -
200 static void ccp5_config(struct ccp_device *ccp)
201 {
202 /* Public side */