Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
e28d2af4 IT |
2 | /* |
3 | * Copyright IBM Corp. 2016 | |
4 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> | |
5 | * | |
6 | * Adjunct processor bus, queue related code. | |
7 | */ | |
8 | ||
9 | #define KMSG_COMPONENT "ap" | |
10 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | |
11 | ||
12 | #include <linux/init.h> | |
13 | #include <linux/slab.h> | |
14 | #include <asm/facility.h> | |
15 | ||
16 | #include "ap_bus.h" | |
17 | #include "ap_asm.h" | |
18 | ||
46fde9a9 HF |
19 | /** |
20 | * ap_queue_irq_ctrl(): Control interruption on a AP queue. | |
21 | * @qirqctrl: struct ap_qirq_ctrl (64 bit value) | |
22 | * @ind: The notification indicator byte | |
23 | * | |
24 | * Returns AP queue status. | |
25 | * | |
26 | * Control interruption on the given AP queue. | |
27 | * Just a simple wrapper function for the low level PQAP(AQIC) | |
28 | * instruction available for other kernel modules. | |
29 | */ | |
30 | struct ap_queue_status ap_queue_irq_ctrl(ap_qid_t qid, | |
31 | struct ap_qirq_ctrl qirqctrl, | |
32 | void *ind) | |
33 | { | |
34 | return ap_aqic(qid, qirqctrl, ind); | |
35 | } | |
36 | EXPORT_SYMBOL(ap_queue_irq_ctrl); | |
37 | ||
e28d2af4 IT |
38 | /** |
39 | * ap_queue_enable_interruption(): Enable interruption on an AP queue. | |
40 | * @qid: The AP queue number | |
41 | * @ind: the notification indicator byte | |
42 | * | |
43 | * Enables interruption on AP queue via ap_aqic(). Based on the return | |
44 | * value it waits a while and tests the AP queue if interrupts | |
45 | * have been switched on using ap_test_queue(). | |
46 | */ | |
47 | static int ap_queue_enable_interruption(struct ap_queue *aq, void *ind) | |
48 | { | |
49 | struct ap_queue_status status; | |
46fde9a9 | 50 | struct ap_qirq_ctrl qirqctrl = { 0 }; |
e28d2af4 | 51 | |
46fde9a9 HF |
52 | qirqctrl.ir = 1; |
53 | qirqctrl.isc = AP_ISC; | |
54 | status = ap_aqic(aq->qid, qirqctrl, ind); | |
e28d2af4 IT |
55 | switch (status.response_code) { |
56 | case AP_RESPONSE_NORMAL: | |
57 | case AP_RESPONSE_OTHERWISE_CHANGED: | |
58 | return 0; | |
59 | case AP_RESPONSE_Q_NOT_AVAIL: | |
60 | case AP_RESPONSE_DECONFIGURED: | |
61 | case AP_RESPONSE_CHECKSTOPPED: | |
62 | case AP_RESPONSE_INVALID_ADDRESS: | |
63 | pr_err("Registering adapter interrupts for AP device %02x.%04x failed\n", | |
64 | AP_QID_CARD(aq->qid), | |
65 | AP_QID_QUEUE(aq->qid)); | |
66 | return -EOPNOTSUPP; | |
67 | case AP_RESPONSE_RESET_IN_PROGRESS: | |
68 | case AP_RESPONSE_BUSY: | |
69 | default: | |
70 | return -EBUSY; | |
71 | } | |
72 | } | |
73 | ||
74 | /** | |
75 | * __ap_send(): Send message to adjunct processor queue. | |
76 | * @qid: The AP queue number | |
77 | * @psmid: The program supplied message identifier | |
78 | * @msg: The message text | |
79 | * @length: The message length | |
80 | * @special: Special Bit | |
81 | * | |
82 | * Returns AP queue status structure. | |
83 | * Condition code 1 on NQAP can't happen because the L bit is 1. | |
84 | * Condition code 2 on NQAP also means the send is incomplete, | |
85 | * because a segment boundary was reached. The NQAP is repeated. | |
86 | */ | |
87 | static inline struct ap_queue_status | |
88 | __ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length, | |
89 | unsigned int special) | |
90 | { | |
91 | if (special == 1) | |
92 | qid |= 0x400000UL; | |
93 | return ap_nqap(qid, psmid, msg, length); | |
94 | } | |
95 | ||
96 | int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) | |
97 | { | |
98 | struct ap_queue_status status; | |
99 | ||
100 | status = __ap_send(qid, psmid, msg, length, 0); | |
101 | switch (status.response_code) { | |
102 | case AP_RESPONSE_NORMAL: | |
103 | return 0; | |
104 | case AP_RESPONSE_Q_FULL: | |
105 | case AP_RESPONSE_RESET_IN_PROGRESS: | |
106 | return -EBUSY; | |
107 | case AP_RESPONSE_REQ_FAC_NOT_INST: | |
108 | return -EINVAL; | |
109 | default: /* Device is gone. */ | |
110 | return -ENODEV; | |
111 | } | |
112 | } | |
113 | EXPORT_SYMBOL(ap_send); | |
114 | ||
115 | int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length) | |
116 | { | |
117 | struct ap_queue_status status; | |
118 | ||
119 | if (msg == NULL) | |
120 | return -EINVAL; | |
121 | status = ap_dqap(qid, psmid, msg, length); | |
122 | switch (status.response_code) { | |
123 | case AP_RESPONSE_NORMAL: | |
124 | return 0; | |
125 | case AP_RESPONSE_NO_PENDING_REPLY: | |
126 | if (status.queue_empty) | |
127 | return -ENOENT; | |
128 | return -EBUSY; | |
129 | case AP_RESPONSE_RESET_IN_PROGRESS: | |
130 | return -EBUSY; | |
131 | default: | |
132 | return -ENODEV; | |
133 | } | |
134 | } | |
135 | EXPORT_SYMBOL(ap_recv); | |
136 | ||
137 | /* State machine definitions and helpers */ | |
138 | ||
139 | static enum ap_wait ap_sm_nop(struct ap_queue *aq) | |
140 | { | |
141 | return AP_WAIT_NONE; | |
142 | } | |
143 | ||
144 | /** | |
145 | * ap_sm_recv(): Receive pending reply messages from an AP queue but do | |
146 | * not change the state of the device. | |
147 | * @aq: pointer to the AP queue | |
148 | * | |
149 | * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT | |
150 | */ | |
151 | static struct ap_queue_status ap_sm_recv(struct ap_queue *aq) | |
152 | { | |
153 | struct ap_queue_status status; | |
154 | struct ap_message *ap_msg; | |
155 | ||
156 | status = ap_dqap(aq->qid, &aq->reply->psmid, | |
157 | aq->reply->message, aq->reply->length); | |
158 | switch (status.response_code) { | |
159 | case AP_RESPONSE_NORMAL: | |
160 | aq->queue_count--; | |
161 | if (aq->queue_count > 0) | |
162 | mod_timer(&aq->timeout, | |
163 | jiffies + aq->request_timeout); | |
164 | list_for_each_entry(ap_msg, &aq->pendingq, list) { | |
165 | if (ap_msg->psmid != aq->reply->psmid) | |
166 | continue; | |
167 | list_del_init(&ap_msg->list); | |
168 | aq->pendingq_count--; | |
169 | ap_msg->receive(aq, ap_msg, aq->reply); | |
170 | break; | |
171 | } | |
172 | case AP_RESPONSE_NO_PENDING_REPLY: | |
173 | if (!status.queue_empty || aq->queue_count <= 0) | |
174 | break; | |
175 | /* The card shouldn't forget requests but who knows. */ | |
176 | aq->queue_count = 0; | |
177 | list_splice_init(&aq->pendingq, &aq->requestq); | |
178 | aq->requestq_count += aq->pendingq_count; | |
179 | aq->pendingq_count = 0; | |
180 | break; | |
181 | default: | |
182 | break; | |
183 | } | |
184 | return status; | |
185 | } | |
186 | ||
187 | /** | |
188 | * ap_sm_read(): Receive pending reply messages from an AP queue. | |
189 | * @aq: pointer to the AP queue | |
190 | * | |
191 | * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT | |
192 | */ | |
193 | static enum ap_wait ap_sm_read(struct ap_queue *aq) | |
194 | { | |
195 | struct ap_queue_status status; | |
196 | ||
197 | if (!aq->reply) | |
198 | return AP_WAIT_NONE; | |
199 | status = ap_sm_recv(aq); | |
200 | switch (status.response_code) { | |
201 | case AP_RESPONSE_NORMAL: | |
202 | if (aq->queue_count > 0) { | |
203 | aq->state = AP_STATE_WORKING; | |
204 | return AP_WAIT_AGAIN; | |
205 | } | |
206 | aq->state = AP_STATE_IDLE; | |
207 | return AP_WAIT_NONE; | |
208 | case AP_RESPONSE_NO_PENDING_REPLY: | |
209 | if (aq->queue_count > 0) | |
210 | return AP_WAIT_INTERRUPT; | |
211 | aq->state = AP_STATE_IDLE; | |
212 | return AP_WAIT_NONE; | |
213 | default: | |
214 | aq->state = AP_STATE_BORKED; | |
215 | return AP_WAIT_NONE; | |
216 | } | |
217 | } | |
218 | ||
219 | /** | |
220 | * ap_sm_suspend_read(): Receive pending reply messages from an AP queue | |
221 | * without changing the device state in between. In suspend mode we don't | |
222 | * allow sending new requests, therefore just fetch pending replies. | |
223 | * @aq: pointer to the AP queue | |
224 | * | |
225 | * Returns AP_WAIT_NONE or AP_WAIT_AGAIN | |
226 | */ | |
227 | static enum ap_wait ap_sm_suspend_read(struct ap_queue *aq) | |
228 | { | |
229 | struct ap_queue_status status; | |
230 | ||
231 | if (!aq->reply) | |
232 | return AP_WAIT_NONE; | |
233 | status = ap_sm_recv(aq); | |
234 | switch (status.response_code) { | |
235 | case AP_RESPONSE_NORMAL: | |
236 | if (aq->queue_count > 0) | |
237 | return AP_WAIT_AGAIN; | |
238 | /* fall through */ | |
239 | default: | |
240 | return AP_WAIT_NONE; | |
241 | } | |
242 | } | |
243 | ||
244 | /** | |
245 | * ap_sm_write(): Send messages from the request queue to an AP queue. | |
246 | * @aq: pointer to the AP queue | |
247 | * | |
248 | * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT | |
249 | */ | |
250 | static enum ap_wait ap_sm_write(struct ap_queue *aq) | |
251 | { | |
252 | struct ap_queue_status status; | |
253 | struct ap_message *ap_msg; | |
254 | ||
255 | if (aq->requestq_count <= 0) | |
256 | return AP_WAIT_NONE; | |
257 | /* Start the next request on the queue. */ | |
258 | ap_msg = list_entry(aq->requestq.next, struct ap_message, list); | |
259 | status = __ap_send(aq->qid, ap_msg->psmid, | |
260 | ap_msg->message, ap_msg->length, ap_msg->special); | |
261 | switch (status.response_code) { | |
262 | case AP_RESPONSE_NORMAL: | |
263 | aq->queue_count++; | |
264 | if (aq->queue_count == 1) | |
265 | mod_timer(&aq->timeout, jiffies + aq->request_timeout); | |
266 | list_move_tail(&ap_msg->list, &aq->pendingq); | |
267 | aq->requestq_count--; | |
268 | aq->pendingq_count++; | |
269 | if (aq->queue_count < aq->card->queue_depth) { | |
270 | aq->state = AP_STATE_WORKING; | |
271 | return AP_WAIT_AGAIN; | |
272 | } | |
273 | /* fall through */ | |
274 | case AP_RESPONSE_Q_FULL: | |
275 | aq->state = AP_STATE_QUEUE_FULL; | |
276 | return AP_WAIT_INTERRUPT; | |
277 | case AP_RESPONSE_RESET_IN_PROGRESS: | |
278 | aq->state = AP_STATE_RESET_WAIT; | |
279 | return AP_WAIT_TIMEOUT; | |
280 | case AP_RESPONSE_MESSAGE_TOO_BIG: | |
281 | case AP_RESPONSE_REQ_FAC_NOT_INST: | |
282 | list_del_init(&ap_msg->list); | |
283 | aq->requestq_count--; | |
284 | ap_msg->rc = -EINVAL; | |
285 | ap_msg->receive(aq, ap_msg, NULL); | |
286 | return AP_WAIT_AGAIN; | |
287 | default: | |
288 | aq->state = AP_STATE_BORKED; | |
289 | return AP_WAIT_NONE; | |
290 | } | |
291 | } | |
292 | ||
293 | /** | |
294 | * ap_sm_read_write(): Send and receive messages to/from an AP queue. | |
295 | * @aq: pointer to the AP queue | |
296 | * | |
297 | * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT | |
298 | */ | |
299 | static enum ap_wait ap_sm_read_write(struct ap_queue *aq) | |
300 | { | |
301 | return min(ap_sm_read(aq), ap_sm_write(aq)); | |
302 | } | |
303 | ||
304 | /** | |
305 | * ap_sm_reset(): Reset an AP queue. | |
306 | * @qid: The AP queue number | |
307 | * | |
308 | * Submit the Reset command to an AP queue. | |
309 | */ | |
310 | static enum ap_wait ap_sm_reset(struct ap_queue *aq) | |
311 | { | |
312 | struct ap_queue_status status; | |
313 | ||
314 | status = ap_rapq(aq->qid); | |
315 | switch (status.response_code) { | |
316 | case AP_RESPONSE_NORMAL: | |
317 | case AP_RESPONSE_RESET_IN_PROGRESS: | |
318 | aq->state = AP_STATE_RESET_WAIT; | |
319 | aq->interrupt = AP_INTR_DISABLED; | |
320 | return AP_WAIT_TIMEOUT; | |
321 | case AP_RESPONSE_BUSY: | |
322 | return AP_WAIT_TIMEOUT; | |
323 | case AP_RESPONSE_Q_NOT_AVAIL: | |
324 | case AP_RESPONSE_DECONFIGURED: | |
325 | case AP_RESPONSE_CHECKSTOPPED: | |
326 | default: | |
327 | aq->state = AP_STATE_BORKED; | |
328 | return AP_WAIT_NONE; | |
329 | } | |
330 | } | |
331 | ||
332 | /** | |
333 | * ap_sm_reset_wait(): Test queue for completion of the reset operation | |
334 | * @aq: pointer to the AP queue | |
335 | * | |
336 | * Returns AP_POLL_IMMEDIATELY, AP_POLL_AFTER_TIMEROUT or 0. | |
337 | */ | |
338 | static enum ap_wait ap_sm_reset_wait(struct ap_queue *aq) | |
339 | { | |
340 | struct ap_queue_status status; | |
341 | void *lsi_ptr; | |
342 | ||
343 | if (aq->queue_count > 0 && aq->reply) | |
344 | /* Try to read a completed message and get the status */ | |
345 | status = ap_sm_recv(aq); | |
346 | else | |
347 | /* Get the status with TAPQ */ | |
348 | status = ap_tapq(aq->qid, NULL); | |
349 | ||
350 | switch (status.response_code) { | |
351 | case AP_RESPONSE_NORMAL: | |
352 | lsi_ptr = ap_airq_ptr(); | |
353 | if (lsi_ptr && ap_queue_enable_interruption(aq, lsi_ptr) == 0) | |
354 | aq->state = AP_STATE_SETIRQ_WAIT; | |
355 | else | |
356 | aq->state = (aq->queue_count > 0) ? | |
357 | AP_STATE_WORKING : AP_STATE_IDLE; | |
358 | return AP_WAIT_AGAIN; | |
359 | case AP_RESPONSE_BUSY: | |
360 | case AP_RESPONSE_RESET_IN_PROGRESS: | |
361 | return AP_WAIT_TIMEOUT; | |
362 | case AP_RESPONSE_Q_NOT_AVAIL: | |
363 | case AP_RESPONSE_DECONFIGURED: | |
364 | case AP_RESPONSE_CHECKSTOPPED: | |
365 | default: | |
366 | aq->state = AP_STATE_BORKED; | |
367 | return AP_WAIT_NONE; | |
368 | } | |
369 | } | |
370 | ||
371 | /** | |
372 | * ap_sm_setirq_wait(): Test queue for completion of the irq enablement | |
373 | * @aq: pointer to the AP queue | |
374 | * | |
375 | * Returns AP_POLL_IMMEDIATELY, AP_POLL_AFTER_TIMEROUT or 0. | |
376 | */ | |
377 | static enum ap_wait ap_sm_setirq_wait(struct ap_queue *aq) | |
378 | { | |
379 | struct ap_queue_status status; | |
380 | ||
381 | if (aq->queue_count > 0 && aq->reply) | |
382 | /* Try to read a completed message and get the status */ | |
383 | status = ap_sm_recv(aq); | |
384 | else | |
385 | /* Get the status with TAPQ */ | |
386 | status = ap_tapq(aq->qid, NULL); | |
387 | ||
e7fc5146 | 388 | if (status.irq_enabled == 1) { |
e28d2af4 IT |
389 | /* Irqs are now enabled */ |
390 | aq->interrupt = AP_INTR_ENABLED; | |
391 | aq->state = (aq->queue_count > 0) ? | |
392 | AP_STATE_WORKING : AP_STATE_IDLE; | |
393 | } | |
394 | ||
395 | switch (status.response_code) { | |
396 | case AP_RESPONSE_NORMAL: | |
397 | if (aq->queue_count > 0) | |
398 | return AP_WAIT_AGAIN; | |
399 | /* fallthrough */ | |
400 | case AP_RESPONSE_NO_PENDING_REPLY: | |
401 | return AP_WAIT_TIMEOUT; | |
402 | default: | |
403 | aq->state = AP_STATE_BORKED; | |
404 | return AP_WAIT_NONE; | |
405 | } | |
406 | } | |
407 | ||
408 | /* | |
409 | * AP state machine jump table | |
410 | */ | |
411 | static ap_func_t *ap_jumptable[NR_AP_STATES][NR_AP_EVENTS] = { | |
412 | [AP_STATE_RESET_START] = { | |
413 | [AP_EVENT_POLL] = ap_sm_reset, | |
414 | [AP_EVENT_TIMEOUT] = ap_sm_nop, | |
415 | }, | |
416 | [AP_STATE_RESET_WAIT] = { | |
417 | [AP_EVENT_POLL] = ap_sm_reset_wait, | |
418 | [AP_EVENT_TIMEOUT] = ap_sm_nop, | |
419 | }, | |
420 | [AP_STATE_SETIRQ_WAIT] = { | |
421 | [AP_EVENT_POLL] = ap_sm_setirq_wait, | |
422 | [AP_EVENT_TIMEOUT] = ap_sm_nop, | |
423 | }, | |
424 | [AP_STATE_IDLE] = { | |
425 | [AP_EVENT_POLL] = ap_sm_write, | |
426 | [AP_EVENT_TIMEOUT] = ap_sm_nop, | |
427 | }, | |
428 | [AP_STATE_WORKING] = { | |
429 | [AP_EVENT_POLL] = ap_sm_read_write, | |
430 | [AP_EVENT_TIMEOUT] = ap_sm_reset, | |
431 | }, | |
432 | [AP_STATE_QUEUE_FULL] = { | |
433 | [AP_EVENT_POLL] = ap_sm_read, | |
434 | [AP_EVENT_TIMEOUT] = ap_sm_reset, | |
435 | }, | |
436 | [AP_STATE_SUSPEND_WAIT] = { | |
437 | [AP_EVENT_POLL] = ap_sm_suspend_read, | |
438 | [AP_EVENT_TIMEOUT] = ap_sm_nop, | |
439 | }, | |
440 | [AP_STATE_BORKED] = { | |
441 | [AP_EVENT_POLL] = ap_sm_nop, | |
442 | [AP_EVENT_TIMEOUT] = ap_sm_nop, | |
443 | }, | |
444 | }; | |
445 | ||
446 | enum ap_wait ap_sm_event(struct ap_queue *aq, enum ap_event event) | |
447 | { | |
448 | return ap_jumptable[aq->state][event](aq); | |
449 | } | |
450 | ||
451 | enum ap_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_event event) | |
452 | { | |
453 | enum ap_wait wait; | |
454 | ||
455 | while ((wait = ap_sm_event(aq, event)) == AP_WAIT_AGAIN) | |
456 | ; | |
457 | return wait; | |
458 | } | |
459 | ||
460 | /* | |
461 | * Power management for queue devices | |
462 | */ | |
463 | void ap_queue_suspend(struct ap_device *ap_dev) | |
464 | { | |
465 | struct ap_queue *aq = to_ap_queue(&ap_dev->device); | |
466 | ||
467 | /* Poll on the device until all requests are finished. */ | |
468 | spin_lock_bh(&aq->lock); | |
469 | aq->state = AP_STATE_SUSPEND_WAIT; | |
470 | while (ap_sm_event(aq, AP_EVENT_POLL) != AP_WAIT_NONE) | |
471 | ; | |
472 | aq->state = AP_STATE_BORKED; | |
473 | spin_unlock_bh(&aq->lock); | |
474 | } | |
475 | EXPORT_SYMBOL(ap_queue_suspend); | |
476 | ||
477 | void ap_queue_resume(struct ap_device *ap_dev) | |
478 | { | |
479 | } | |
480 | EXPORT_SYMBOL(ap_queue_resume); | |
481 | ||
482 | /* | |
483 | * AP queue related attributes. | |
484 | */ | |
d0360d7b HF |
485 | static ssize_t ap_req_count_show(struct device *dev, |
486 | struct device_attribute *attr, | |
487 | char *buf) | |
e28d2af4 IT |
488 | { |
489 | struct ap_queue *aq = to_ap_queue(dev); | |
490 | unsigned int req_cnt; | |
491 | ||
492 | spin_lock_bh(&aq->lock); | |
493 | req_cnt = aq->total_request_count; | |
494 | spin_unlock_bh(&aq->lock); | |
495 | return snprintf(buf, PAGE_SIZE, "%d\n", req_cnt); | |
496 | } | |
497 | ||
d0360d7b HF |
498 | static ssize_t ap_req_count_store(struct device *dev, |
499 | struct device_attribute *attr, | |
500 | const char *buf, size_t count) | |
501 | { | |
502 | struct ap_queue *aq = to_ap_queue(dev); | |
503 | ||
504 | spin_lock_bh(&aq->lock); | |
505 | aq->total_request_count = 0; | |
506 | spin_unlock_bh(&aq->lock); | |
507 | ||
508 | return count; | |
509 | } | |
510 | ||
511 | static DEVICE_ATTR(request_count, 0644, ap_req_count_show, ap_req_count_store); | |
e28d2af4 IT |
512 | |
513 | static ssize_t ap_requestq_count_show(struct device *dev, | |
514 | struct device_attribute *attr, char *buf) | |
515 | { | |
516 | struct ap_queue *aq = to_ap_queue(dev); | |
517 | unsigned int reqq_cnt = 0; | |
518 | ||
519 | spin_lock_bh(&aq->lock); | |
520 | reqq_cnt = aq->requestq_count; | |
521 | spin_unlock_bh(&aq->lock); | |
522 | return snprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt); | |
523 | } | |
524 | ||
525 | static DEVICE_ATTR(requestq_count, 0444, ap_requestq_count_show, NULL); | |
526 | ||
527 | static ssize_t ap_pendingq_count_show(struct device *dev, | |
528 | struct device_attribute *attr, char *buf) | |
529 | { | |
530 | struct ap_queue *aq = to_ap_queue(dev); | |
531 | unsigned int penq_cnt = 0; | |
532 | ||
533 | spin_lock_bh(&aq->lock); | |
534 | penq_cnt = aq->pendingq_count; | |
535 | spin_unlock_bh(&aq->lock); | |
536 | return snprintf(buf, PAGE_SIZE, "%d\n", penq_cnt); | |
537 | } | |
538 | ||
539 | static DEVICE_ATTR(pendingq_count, 0444, ap_pendingq_count_show, NULL); | |
540 | ||
541 | static ssize_t ap_reset_show(struct device *dev, | |
542 | struct device_attribute *attr, char *buf) | |
543 | { | |
544 | struct ap_queue *aq = to_ap_queue(dev); | |
545 | int rc = 0; | |
546 | ||
547 | spin_lock_bh(&aq->lock); | |
548 | switch (aq->state) { | |
549 | case AP_STATE_RESET_START: | |
550 | case AP_STATE_RESET_WAIT: | |
551 | rc = snprintf(buf, PAGE_SIZE, "Reset in progress.\n"); | |
552 | break; | |
553 | case AP_STATE_WORKING: | |
554 | case AP_STATE_QUEUE_FULL: | |
555 | rc = snprintf(buf, PAGE_SIZE, "Reset Timer armed.\n"); | |
556 | break; | |
557 | default: | |
558 | rc = snprintf(buf, PAGE_SIZE, "No Reset Timer set.\n"); | |
559 | } | |
560 | spin_unlock_bh(&aq->lock); | |
561 | return rc; | |
562 | } | |
563 | ||
564 | static DEVICE_ATTR(reset, 0444, ap_reset_show, NULL); | |
565 | ||
566 | static ssize_t ap_interrupt_show(struct device *dev, | |
567 | struct device_attribute *attr, char *buf) | |
568 | { | |
569 | struct ap_queue *aq = to_ap_queue(dev); | |
570 | int rc = 0; | |
571 | ||
572 | spin_lock_bh(&aq->lock); | |
573 | if (aq->state == AP_STATE_SETIRQ_WAIT) | |
574 | rc = snprintf(buf, PAGE_SIZE, "Enable Interrupt pending.\n"); | |
575 | else if (aq->interrupt == AP_INTR_ENABLED) | |
576 | rc = snprintf(buf, PAGE_SIZE, "Interrupts enabled.\n"); | |
577 | else | |
578 | rc = snprintf(buf, PAGE_SIZE, "Interrupts disabled.\n"); | |
579 | spin_unlock_bh(&aq->lock); | |
580 | return rc; | |
581 | } | |
582 | ||
583 | static DEVICE_ATTR(interrupt, 0444, ap_interrupt_show, NULL); | |
584 | ||
585 | static struct attribute *ap_queue_dev_attrs[] = { | |
586 | &dev_attr_request_count.attr, | |
587 | &dev_attr_requestq_count.attr, | |
588 | &dev_attr_pendingq_count.attr, | |
589 | &dev_attr_reset.attr, | |
590 | &dev_attr_interrupt.attr, | |
591 | NULL | |
592 | }; | |
593 | ||
594 | static struct attribute_group ap_queue_dev_attr_group = { | |
595 | .attrs = ap_queue_dev_attrs | |
596 | }; | |
597 | ||
598 | static const struct attribute_group *ap_queue_dev_attr_groups[] = { | |
599 | &ap_queue_dev_attr_group, | |
600 | NULL | |
601 | }; | |
602 | ||
227374b1 | 603 | static struct device_type ap_queue_type = { |
e28d2af4 IT |
604 | .name = "ap_queue", |
605 | .groups = ap_queue_dev_attr_groups, | |
606 | }; | |
607 | ||
608 | static void ap_queue_device_release(struct device *dev) | |
609 | { | |
e3850508 HF |
610 | struct ap_queue *aq = to_ap_queue(dev); |
611 | ||
612 | if (!list_empty(&aq->list)) { | |
613 | spin_lock_bh(&ap_list_lock); | |
614 | list_del_init(&aq->list); | |
615 | spin_unlock_bh(&ap_list_lock); | |
616 | } | |
617 | kfree(aq); | |
e28d2af4 IT |
618 | } |
619 | ||
620 | struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type) | |
621 | { | |
622 | struct ap_queue *aq; | |
623 | ||
624 | aq = kzalloc(sizeof(*aq), GFP_KERNEL); | |
625 | if (!aq) | |
626 | return NULL; | |
627 | aq->ap_dev.device.release = ap_queue_device_release; | |
628 | aq->ap_dev.device.type = &ap_queue_type; | |
629 | aq->ap_dev.device_type = device_type; | |
630 | /* CEX6 toleration: map to CEX5 */ | |
631 | if (device_type == AP_DEVICE_TYPE_CEX6) | |
632 | aq->ap_dev.device_type = AP_DEVICE_TYPE_CEX5; | |
633 | aq->qid = qid; | |
634 | aq->state = AP_STATE_RESET_START; | |
635 | aq->interrupt = AP_INTR_DISABLED; | |
636 | spin_lock_init(&aq->lock); | |
637 | INIT_LIST_HEAD(&aq->pendingq); | |
638 | INIT_LIST_HEAD(&aq->requestq); | |
639 | setup_timer(&aq->timeout, ap_request_timeout, (unsigned long) aq); | |
640 | ||
641 | return aq; | |
642 | } | |
643 | ||
644 | void ap_queue_init_reply(struct ap_queue *aq, struct ap_message *reply) | |
645 | { | |
646 | aq->reply = reply; | |
647 | ||
648 | spin_lock_bh(&aq->lock); | |
649 | ap_wait(ap_sm_event(aq, AP_EVENT_POLL)); | |
650 | spin_unlock_bh(&aq->lock); | |
651 | } | |
652 | EXPORT_SYMBOL(ap_queue_init_reply); | |
653 | ||
654 | /** | |
655 | * ap_queue_message(): Queue a request to an AP device. | |
656 | * @aq: The AP device to queue the message to | |
657 | * @ap_msg: The message that is to be added | |
658 | */ | |
659 | void ap_queue_message(struct ap_queue *aq, struct ap_message *ap_msg) | |
660 | { | |
661 | /* For asynchronous message handling a valid receive-callback | |
662 | * is required. | |
663 | */ | |
664 | BUG_ON(!ap_msg->receive); | |
665 | ||
666 | spin_lock_bh(&aq->lock); | |
667 | /* Queue the message. */ | |
668 | list_add_tail(&ap_msg->list, &aq->requestq); | |
669 | aq->requestq_count++; | |
670 | aq->total_request_count++; | |
e47de21d | 671 | atomic_inc(&aq->card->total_request_count); |
e28d2af4 IT |
672 | /* Send/receive as many request from the queue as possible. */ |
673 | ap_wait(ap_sm_event_loop(aq, AP_EVENT_POLL)); | |
674 | spin_unlock_bh(&aq->lock); | |
675 | } | |
676 | EXPORT_SYMBOL(ap_queue_message); | |
677 | ||
678 | /** | |
679 | * ap_cancel_message(): Cancel a crypto request. | |
680 | * @aq: The AP device that has the message queued | |
681 | * @ap_msg: The message that is to be removed | |
682 | * | |
683 | * Cancel a crypto request. This is done by removing the request | |
684 | * from the device pending or request queue. Note that the | |
685 | * request stays on the AP queue. When it finishes the message | |
686 | * reply will be discarded because the psmid can't be found. | |
687 | */ | |
688 | void ap_cancel_message(struct ap_queue *aq, struct ap_message *ap_msg) | |
689 | { | |
690 | struct ap_message *tmp; | |
691 | ||
692 | spin_lock_bh(&aq->lock); | |
693 | if (!list_empty(&ap_msg->list)) { | |
694 | list_for_each_entry(tmp, &aq->pendingq, list) | |
695 | if (tmp->psmid == ap_msg->psmid) { | |
696 | aq->pendingq_count--; | |
697 | goto found; | |
698 | } | |
699 | aq->requestq_count--; | |
700 | found: | |
701 | list_del_init(&ap_msg->list); | |
702 | } | |
703 | spin_unlock_bh(&aq->lock); | |
704 | } | |
705 | EXPORT_SYMBOL(ap_cancel_message); | |
706 | ||
707 | /** | |
708 | * __ap_flush_queue(): Flush requests. | |
709 | * @aq: Pointer to the AP queue | |
710 | * | |
711 | * Flush all requests from the request/pending queue of an AP device. | |
712 | */ | |
713 | static void __ap_flush_queue(struct ap_queue *aq) | |
714 | { | |
715 | struct ap_message *ap_msg, *next; | |
716 | ||
717 | list_for_each_entry_safe(ap_msg, next, &aq->pendingq, list) { | |
718 | list_del_init(&ap_msg->list); | |
719 | aq->pendingq_count--; | |
720 | ap_msg->rc = -EAGAIN; | |
721 | ap_msg->receive(aq, ap_msg, NULL); | |
722 | } | |
723 | list_for_each_entry_safe(ap_msg, next, &aq->requestq, list) { | |
724 | list_del_init(&ap_msg->list); | |
725 | aq->requestq_count--; | |
726 | ap_msg->rc = -EAGAIN; | |
727 | ap_msg->receive(aq, ap_msg, NULL); | |
728 | } | |
729 | } | |
730 | ||
731 | void ap_flush_queue(struct ap_queue *aq) | |
732 | { | |
733 | spin_lock_bh(&aq->lock); | |
734 | __ap_flush_queue(aq); | |
735 | spin_unlock_bh(&aq->lock); | |
736 | } | |
737 | EXPORT_SYMBOL(ap_flush_queue); | |
738 | ||
739 | void ap_queue_remove(struct ap_queue *aq) | |
740 | { | |
741 | ap_flush_queue(aq); | |
742 | del_timer_sync(&aq->timeout); | |
743 | } | |
744 | EXPORT_SYMBOL(ap_queue_remove); |