blob: fa5f05c643cbebf3995ea16587a7ce80df1c8041 [file] [log] [blame]
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001/*
2 * linux/drivers/s390/crypto/ap_bus.c
3 *
4 * Copyright (C) 2006 IBM Corporation
5 * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
6 * Martin Schwidefsky <schwidefsky@de.ibm.com>
7 * Ralph Wuerthner <rwuerthn@de.ibm.com>
Felix Beckcb17a632008-12-25 13:38:41 +01008 * Felix Beck <felix.beck@de.ibm.com>
Holger Dengler6bed05b2011-07-24 10:48:25 +02009 * Holger Dengler <hd@linux.vnet.ibm.com>
Martin Schwidefsky1534c382006-09-20 15:58:25 +020010 *
11 * Adjunct processor bus.
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2, or (at your option)
16 * any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 */
27
Martin Schwidefsky136f7a12008-12-25 13:39:46 +010028#define KMSG_COMPONENT "ap"
29#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
30
Holger Dengler62d146f2011-01-05 12:47:38 +010031#include <linux/kernel_stat.h>
Martin Schwidefsky1534c382006-09-20 15:58:25 +020032#include <linux/module.h>
33#include <linux/init.h>
34#include <linux/delay.h>
35#include <linux/err.h>
36#include <linux/interrupt.h>
37#include <linux/workqueue.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090038#include <linux/slab.h>
Martin Schwidefsky1534c382006-09-20 15:58:25 +020039#include <linux/notifier.h>
40#include <linux/kthread.h>
41#include <linux/mutex.h>
Ralph Wuerthner85eca852006-12-08 15:54:07 +010042#include <asm/reset.h>
Felix Beckcb17a632008-12-25 13:38:41 +010043#include <asm/airq.h>
Arun Sharma600634972011-07-26 16:09:06 -070044#include <linux/atomic.h>
Felix Beckcb17a632008-12-25 13:38:41 +010045#include <asm/isc.h>
Felix Beckfe137232008-07-14 09:59:08 +020046#include <linux/hrtimer.h>
47#include <linux/ktime.h>
David Howellsa0616cd2012-03-28 18:30:02 +010048#include <asm/facility.h>
Martin Schwidefsky1534c382006-09-20 15:58:25 +020049
50#include "ap_bus.h"
51
52/* Some prototypes. */
Al Viro4927b3f2006-12-06 19:18:20 +000053static void ap_scan_bus(struct work_struct *);
Martin Schwidefsky1534c382006-09-20 15:58:25 +020054static void ap_poll_all(unsigned long);
Felix Beckfe137232008-07-14 09:59:08 +020055static enum hrtimer_restart ap_poll_timeout(struct hrtimer *);
Martin Schwidefsky1534c382006-09-20 15:58:25 +020056static int ap_poll_thread_start(void);
57static void ap_poll_thread_stop(void);
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +020058static void ap_request_timeout(unsigned long);
Felix Beckcb17a632008-12-25 13:38:41 +010059static inline void ap_schedule_poll_timer(void);
Felix Beck772f5472009-06-22 12:08:16 +020060static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags);
61static int ap_device_remove(struct device *dev);
62static int ap_device_probe(struct device *dev);
63static void ap_interrupt_handler(void *unused1, void *unused2);
64static void ap_reset(struct ap_device *ap_dev);
65static void ap_config_timeout(unsigned long ptr);
Felix Beck5314af62009-09-22 22:58:51 +020066static int ap_select_domain(void);
Martin Schwidefsky1534c382006-09-20 15:58:25 +020067
Felix Beck1749a812008-04-17 07:46:28 +020068/*
Martin Schwidefsky1534c382006-09-20 15:58:25 +020069 * Module description.
70 */
71MODULE_AUTHOR("IBM Corporation");
72MODULE_DESCRIPTION("Adjunct Processor Bus driver, "
73 "Copyright 2006 IBM Corporation");
74MODULE_LICENSE("GPL");
75
Felix Beck1749a812008-04-17 07:46:28 +020076/*
Martin Schwidefsky1534c382006-09-20 15:58:25 +020077 * Module parameter
78 */
79int ap_domain_index = -1; /* Adjunct Processor Domain Index */
80module_param_named(domain, ap_domain_index, int, 0000);
81MODULE_PARM_DESC(domain, "domain index for ap devices");
82EXPORT_SYMBOL(ap_domain_index);
83
Felix Beckb90b34c2008-02-09 18:24:30 +010084static int ap_thread_flag = 0;
Martin Schwidefsky1534c382006-09-20 15:58:25 +020085module_param_named(poll_thread, ap_thread_flag, int, 0000);
Felix Beckb90b34c2008-02-09 18:24:30 +010086MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 0 (off).");
Martin Schwidefsky1534c382006-09-20 15:58:25 +020087
88static struct device *ap_root_device = NULL;
Christian Maaser43c207e62008-12-25 13:38:42 +010089static DEFINE_SPINLOCK(ap_device_list_lock);
Ralph Wuerthnercf352ce2007-03-19 13:19:14 +010090static LIST_HEAD(ap_device_list);
Martin Schwidefsky1534c382006-09-20 15:58:25 +020091
Felix Beck1749a812008-04-17 07:46:28 +020092/*
Martin Schwidefsky1534c382006-09-20 15:58:25 +020093 * Workqueue & timer for bus rescan.
94 */
95static struct workqueue_struct *ap_work_queue;
96static struct timer_list ap_config_timer;
97static int ap_config_time = AP_CONFIG_TIME;
Al Viro4927b3f2006-12-06 19:18:20 +000098static DECLARE_WORK(ap_config_work, ap_scan_bus);
Martin Schwidefsky1534c382006-09-20 15:58:25 +020099
Felix Beck1749a812008-04-17 07:46:28 +0200100/*
Felix Beckcb17a632008-12-25 13:38:41 +0100101 * Tasklet & timer for AP request polling and interrupts
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200102 */
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200103static DECLARE_TASKLET(ap_tasklet, ap_poll_all, 0);
104static atomic_t ap_poll_requests = ATOMIC_INIT(0);
105static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait);
106static struct task_struct *ap_poll_kthread = NULL;
107static DEFINE_MUTEX(ap_poll_thread_mutex);
Felix Beck93521312009-12-07 12:52:00 +0100108static DEFINE_SPINLOCK(ap_poll_timer_lock);
Felix Beckcb17a632008-12-25 13:38:41 +0100109static void *ap_interrupt_indicator;
Felix Beckfe137232008-07-14 09:59:08 +0200110static struct hrtimer ap_poll_timer;
111/* In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds.
112 * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/
113static unsigned long long poll_timeout = 250000;
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200114
Felix Beck772f5472009-06-22 12:08:16 +0200115/* Suspend flag */
116static int ap_suspend_flag;
Felix Beck5314af62009-09-22 22:58:51 +0200117/* Flag to check if domain was set through module parameter domain=. This is
118 * important when supsend and resume is done in a z/VM environment where the
119 * domain might change. */
120static int user_set_domain = 0;
Felix Beck772f5472009-06-22 12:08:16 +0200121static struct bus_type ap_bus_type;
122
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200123/**
Felix Beckcb17a632008-12-25 13:38:41 +0100124 * ap_using_interrupts() - Returns non-zero if interrupt support is
125 * available.
126 */
127static inline int ap_using_interrupts(void)
128{
129 return ap_interrupt_indicator != NULL;
130}
131
132/**
Felix Beck1749a812008-04-17 07:46:28 +0200133 * ap_intructions_available() - Test if AP instructions are available.
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200134 *
Felix Beck1749a812008-04-17 07:46:28 +0200135 * Returns 0 if the AP instructions are installed.
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200136 */
137static inline int ap_instructions_available(void)
138{
139 register unsigned long reg0 asm ("0") = AP_MKQID(0,0);
140 register unsigned long reg1 asm ("1") = -ENODEV;
141 register unsigned long reg2 asm ("2") = 0UL;
142
143 asm volatile(
144 " .long 0xb2af0000\n" /* PQAP(TAPQ) */
145 "0: la %1,0\n"
146 "1:\n"
147 EX_TABLE(0b, 1b)
148 : "+d" (reg0), "+d" (reg1), "+d" (reg2) : : "cc" );
149 return reg1;
150}
151
152/**
Felix Beckcb17a632008-12-25 13:38:41 +0100153 * ap_interrupts_available(): Test if AP interrupts are available.
154 *
155 * Returns 1 if AP interrupts are available.
156 */
157static int ap_interrupts_available(void)
158{
Felix Beck53ec24b12011-01-05 12:46:44 +0100159 return test_facility(2) && test_facility(65);
Felix Beckcb17a632008-12-25 13:38:41 +0100160}
161
162/**
Felix Beck1749a812008-04-17 07:46:28 +0200163 * ap_test_queue(): Test adjunct processor queue.
164 * @qid: The AP queue number
165 * @queue_depth: Pointer to queue depth value
166 * @device_type: Pointer to device type value
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200167 *
Felix Beck1749a812008-04-17 07:46:28 +0200168 * Returns AP queue status structure.
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200169 */
170static inline struct ap_queue_status
171ap_test_queue(ap_qid_t qid, int *queue_depth, int *device_type)
172{
173 register unsigned long reg0 asm ("0") = qid;
174 register struct ap_queue_status reg1 asm ("1");
175 register unsigned long reg2 asm ("2") = 0UL;
176
177 asm volatile(".long 0xb2af0000" /* PQAP(TAPQ) */
178 : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc");
179 *device_type = (int) (reg2 >> 24);
180 *queue_depth = (int) (reg2 & 0xff);
181 return reg1;
182}
183
184/**
Felix Beck1749a812008-04-17 07:46:28 +0200185 * ap_reset_queue(): Reset adjunct processor queue.
186 * @qid: The AP queue number
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200187 *
Felix Beck1749a812008-04-17 07:46:28 +0200188 * Returns AP queue status structure.
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200189 */
190static inline struct ap_queue_status ap_reset_queue(ap_qid_t qid)
191{
192 register unsigned long reg0 asm ("0") = qid | 0x01000000UL;
193 register struct ap_queue_status reg1 asm ("1");
194 register unsigned long reg2 asm ("2") = 0UL;
195
196 asm volatile(
197 ".long 0xb2af0000" /* PQAP(RAPQ) */
198 : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc");
199 return reg1;
200}
201
Felix Beckcb17a632008-12-25 13:38:41 +0100202#ifdef CONFIG_64BIT
203/**
204 * ap_queue_interruption_control(): Enable interruption for a specific AP.
205 * @qid: The AP queue number
206 * @ind: The notification indicator byte
207 *
208 * Returns AP queue status.
209 */
210static inline struct ap_queue_status
211ap_queue_interruption_control(ap_qid_t qid, void *ind)
212{
213 register unsigned long reg0 asm ("0") = qid | 0x03000000UL;
214 register unsigned long reg1_in asm ("1") = 0x0000800000000000UL | AP_ISC;
215 register struct ap_queue_status reg1_out asm ("1");
216 register void *reg2 asm ("2") = ind;
217 asm volatile(
Holger Denglera7475af2012-05-16 14:10:26 +0200218 ".long 0xb2af0000" /* PQAP(AQIC) */
Felix Beckcb17a632008-12-25 13:38:41 +0100219 : "+d" (reg0), "+d" (reg1_in), "=d" (reg1_out), "+d" (reg2)
220 :
221 : "cc" );
222 return reg1_out;
223}
224#endif
225
Holger Dengler6bed05b2011-07-24 10:48:25 +0200226#ifdef CONFIG_64BIT
227static inline struct ap_queue_status
228__ap_query_functions(ap_qid_t qid, unsigned int *functions)
Felix Beckb1f933d2011-01-05 12:47:44 +0100229{
230 register unsigned long reg0 asm ("0") = 0UL | qid | (1UL << 23);
Holger Dengler6bed05b2011-07-24 10:48:25 +0200231 register struct ap_queue_status reg1 asm ("1") = AP_QUEUE_STATUS_INVALID;
232 register unsigned long reg2 asm ("2");
Felix Beckb1f933d2011-01-05 12:47:44 +0100233
234 asm volatile(
Holger Denglera7475af2012-05-16 14:10:26 +0200235 ".long 0xb2af0000\n" /* PQAP(TAPQ) */
Holger Dengler6bed05b2011-07-24 10:48:25 +0200236 "0:\n"
237 EX_TABLE(0b, 0b)
238 : "+d" (reg0), "+d" (reg1), "=d" (reg2)
Felix Beckb1f933d2011-01-05 12:47:44 +0100239 :
240 : "cc");
241
Holger Dengler6bed05b2011-07-24 10:48:25 +0200242 *functions = (unsigned int)(reg2 >> 32);
Felix Beckb1f933d2011-01-05 12:47:44 +0100243 return reg1;
244}
Holger Dengler6bed05b2011-07-24 10:48:25 +0200245#endif
246
247/**
248 * ap_query_functions(): Query supported functions.
249 * @qid: The AP queue number
250 * @functions: Pointer to functions field.
251 *
252 * Returns
253 * 0 on success.
254 * -ENODEV if queue not valid.
255 * -EBUSY if device busy.
256 * -EINVAL if query function is not supported
257 */
258static int ap_query_functions(ap_qid_t qid, unsigned int *functions)
259{
260#ifdef CONFIG_64BIT
261 struct ap_queue_status status;
262 int i;
263 status = __ap_query_functions(qid, functions);
264
265 for (i = 0; i < AP_MAX_RESET; i++) {
266 if (ap_queue_status_invalid_test(&status))
267 return -ENODEV;
268
269 switch (status.response_code) {
270 case AP_RESPONSE_NORMAL:
271 return 0;
272 case AP_RESPONSE_RESET_IN_PROGRESS:
273 case AP_RESPONSE_BUSY:
274 break;
275 case AP_RESPONSE_Q_NOT_AVAIL:
276 case AP_RESPONSE_DECONFIGURED:
277 case AP_RESPONSE_CHECKSTOPPED:
278 case AP_RESPONSE_INVALID_ADDRESS:
279 return -ENODEV;
280 case AP_RESPONSE_OTHERWISE_CHANGED:
281 break;
282 default:
283 break;
284 }
285 if (i < AP_MAX_RESET - 1) {
286 udelay(5);
287 status = __ap_query_functions(qid, functions);
288 }
289 }
290 return -EBUSY;
291#else
292 return -EINVAL;
293#endif
294}
Felix Beckb1f933d2011-01-05 12:47:44 +0100295
296/**
297 * ap_4096_commands_availablen(): Check for availability of 4096 bit RSA
298 * support.
299 * @qid: The AP queue number
300 *
301 * Returns 1 if 4096 bit RSA keys are support fo the AP, returns 0 if not.
302 */
303int ap_4096_commands_available(ap_qid_t qid)
304{
Holger Dengler6bed05b2011-07-24 10:48:25 +0200305 unsigned int functions;
Felix Beckb1f933d2011-01-05 12:47:44 +0100306
Holger Dengler6bed05b2011-07-24 10:48:25 +0200307 if (ap_query_functions(qid, &functions))
308 return 0;
309
310 return test_ap_facility(functions, 1) &&
311 test_ap_facility(functions, 2);
Felix Beckb1f933d2011-01-05 12:47:44 +0100312}
313EXPORT_SYMBOL(ap_4096_commands_available);
314
Felix Beckcb17a632008-12-25 13:38:41 +0100315/**
316 * ap_queue_enable_interruption(): Enable interruption on an AP.
317 * @qid: The AP queue number
318 * @ind: the notification indicator byte
319 *
320 * Enables interruption on AP queue via ap_queue_interruption_control(). Based
321 * on the return value it waits a while and tests the AP queue if interrupts
322 * have been switched on using ap_test_queue().
323 */
324static int ap_queue_enable_interruption(ap_qid_t qid, void *ind)
325{
326#ifdef CONFIG_64BIT
327 struct ap_queue_status status;
328 int t_depth, t_device_type, rc, i;
329
330 rc = -EBUSY;
331 status = ap_queue_interruption_control(qid, ind);
332
333 for (i = 0; i < AP_MAX_RESET; i++) {
334 switch (status.response_code) {
335 case AP_RESPONSE_NORMAL:
336 if (status.int_enabled)
337 return 0;
338 break;
339 case AP_RESPONSE_RESET_IN_PROGRESS:
340 case AP_RESPONSE_BUSY:
Holger Dengler8738e072012-07-02 12:39:59 +0200341 if (i < AP_MAX_RESET - 1) {
342 udelay(5);
343 status = ap_queue_interruption_control(qid,
344 ind);
345 continue;
346 }
Felix Beckcb17a632008-12-25 13:38:41 +0100347 break;
348 case AP_RESPONSE_Q_NOT_AVAIL:
349 case AP_RESPONSE_DECONFIGURED:
350 case AP_RESPONSE_CHECKSTOPPED:
351 case AP_RESPONSE_INVALID_ADDRESS:
352 return -ENODEV;
353 case AP_RESPONSE_OTHERWISE_CHANGED:
354 if (status.int_enabled)
355 return 0;
356 break;
357 default:
358 break;
359 }
360 if (i < AP_MAX_RESET - 1) {
361 udelay(5);
362 status = ap_test_queue(qid, &t_depth, &t_device_type);
363 }
364 }
365 return rc;
366#else
367 return -EINVAL;
368#endif
369}
370
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200371/**
Felix Beck1749a812008-04-17 07:46:28 +0200372 * __ap_send(): Send message to adjunct processor queue.
373 * @qid: The AP queue number
374 * @psmid: The program supplied message identifier
375 * @msg: The message text
376 * @length: The message length
Felix Becka6a5d732009-12-07 12:51:55 +0100377 * @special: Special Bit
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200378 *
Felix Beck1749a812008-04-17 07:46:28 +0200379 * Returns AP queue status structure.
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200380 * Condition code 1 on NQAP can't happen because the L bit is 1.
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200381 * Condition code 2 on NQAP also means the send is incomplete,
382 * because a segment boundary was reached. The NQAP is repeated.
383 */
384static inline struct ap_queue_status
Felix Becka6a5d732009-12-07 12:51:55 +0100385__ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length,
386 unsigned int special)
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200387{
388 typedef struct { char _[length]; } msgblock;
389 register unsigned long reg0 asm ("0") = qid | 0x40000000UL;
390 register struct ap_queue_status reg1 asm ("1");
391 register unsigned long reg2 asm ("2") = (unsigned long) msg;
392 register unsigned long reg3 asm ("3") = (unsigned long) length;
393 register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32);
394 register unsigned long reg5 asm ("5") = (unsigned int) psmid;
395
Felix Becka6a5d732009-12-07 12:51:55 +0100396 if (special == 1)
397 reg0 |= 0x400000UL;
398
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200399 asm volatile (
Holger Denglera7475af2012-05-16 14:10:26 +0200400 "0: .long 0xb2ad0042\n" /* NQAP */
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200401 " brc 2,0b"
402 : "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3)
403 : "d" (reg4), "d" (reg5), "m" (*(msgblock *) msg)
404 : "cc" );
405 return reg1;
406}
407
408int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length)
409{
410 struct ap_queue_status status;
411
Felix Becka6a5d732009-12-07 12:51:55 +0100412 status = __ap_send(qid, psmid, msg, length, 0);
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200413 switch (status.response_code) {
414 case AP_RESPONSE_NORMAL:
415 return 0;
416 case AP_RESPONSE_Q_FULL:
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200417 case AP_RESPONSE_RESET_IN_PROGRESS:
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200418 return -EBUSY;
Felix Becka6a5d732009-12-07 12:51:55 +0100419 case AP_RESPONSE_REQ_FAC_NOT_INST:
420 return -EINVAL;
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200421 default: /* Device is gone. */
422 return -ENODEV;
423 }
424}
425EXPORT_SYMBOL(ap_send);
426
Felix Beck1749a812008-04-17 07:46:28 +0200427/**
428 * __ap_recv(): Receive message from adjunct processor queue.
429 * @qid: The AP queue number
430 * @psmid: Pointer to program supplied message identifier
431 * @msg: The message text
432 * @length: The message length
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200433 *
Felix Beck1749a812008-04-17 07:46:28 +0200434 * Returns AP queue status structure.
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200435 * Condition code 1 on DQAP means the receive has taken place
436 * but only partially. The response is incomplete, hence the
437 * DQAP is repeated.
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200438 * Condition code 2 on DQAP also means the receive is incomplete,
439 * this time because a segment boundary was reached. Again, the
440 * DQAP is repeated.
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200441 * Note that gpr2 is used by the DQAP instruction to keep track of
442 * any 'residual' length, in case the instruction gets interrupted.
443 * Hence it gets zeroed before the instruction.
444 */
445static inline struct ap_queue_status
446__ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length)
447{
448 typedef struct { char _[length]; } msgblock;
449 register unsigned long reg0 asm("0") = qid | 0x80000000UL;
450 register struct ap_queue_status reg1 asm ("1");
451 register unsigned long reg2 asm("2") = 0UL;
452 register unsigned long reg4 asm("4") = (unsigned long) msg;
453 register unsigned long reg5 asm("5") = (unsigned long) length;
454 register unsigned long reg6 asm("6") = 0UL;
455 register unsigned long reg7 asm("7") = 0UL;
456
457
458 asm volatile(
Holger Denglera7475af2012-05-16 14:10:26 +0200459 "0: .long 0xb2ae0064\n" /* DQAP */
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200460 " brc 6,0b\n"
461 : "+d" (reg0), "=d" (reg1), "+d" (reg2),
462 "+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7),
463 "=m" (*(msgblock *) msg) : : "cc" );
464 *psmid = (((unsigned long long) reg6) << 32) + reg7;
465 return reg1;
466}
467
468int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length)
469{
470 struct ap_queue_status status;
471
472 status = __ap_recv(qid, psmid, msg, length);
473 switch (status.response_code) {
474 case AP_RESPONSE_NORMAL:
475 return 0;
476 case AP_RESPONSE_NO_PENDING_REPLY:
477 if (status.queue_empty)
478 return -ENOENT;
479 return -EBUSY;
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200480 case AP_RESPONSE_RESET_IN_PROGRESS:
481 return -EBUSY;
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200482 default:
483 return -ENODEV;
484 }
485}
486EXPORT_SYMBOL(ap_recv);
487
488/**
Felix Beck1749a812008-04-17 07:46:28 +0200489 * ap_query_queue(): Check if an AP queue is available.
490 * @qid: The AP queue number
491 * @queue_depth: Pointer to queue depth value
492 * @device_type: Pointer to device type value
493 *
494 * The test is repeated for AP_MAX_RESET times.
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200495 */
496static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type)
497{
498 struct ap_queue_status status;
499 int t_depth, t_device_type, rc, i;
500
501 rc = -EBUSY;
502 for (i = 0; i < AP_MAX_RESET; i++) {
503 status = ap_test_queue(qid, &t_depth, &t_device_type);
504 switch (status.response_code) {
505 case AP_RESPONSE_NORMAL:
506 *queue_depth = t_depth + 1;
507 *device_type = t_device_type;
508 rc = 0;
509 break;
510 case AP_RESPONSE_Q_NOT_AVAIL:
511 rc = -ENODEV;
512 break;
513 case AP_RESPONSE_RESET_IN_PROGRESS:
514 break;
515 case AP_RESPONSE_DECONFIGURED:
516 rc = -ENODEV;
517 break;
518 case AP_RESPONSE_CHECKSTOPPED:
519 rc = -ENODEV;
520 break;
Felix Beckcb17a632008-12-25 13:38:41 +0100521 case AP_RESPONSE_INVALID_ADDRESS:
522 rc = -ENODEV;
523 break;
524 case AP_RESPONSE_OTHERWISE_CHANGED:
525 break;
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200526 case AP_RESPONSE_BUSY:
527 break;
528 default:
529 BUG();
530 }
531 if (rc != -EBUSY)
532 break;
533 if (i < AP_MAX_RESET - 1)
534 udelay(5);
535 }
536 return rc;
537}
538
539/**
Felix Beck1749a812008-04-17 07:46:28 +0200540 * ap_init_queue(): Reset an AP queue.
541 * @qid: The AP queue number
542 *
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200543 * Reset an AP queue and wait for it to become available again.
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200544 */
545static int ap_init_queue(ap_qid_t qid)
546{
547 struct ap_queue_status status;
548 int rc, dummy, i;
549
550 rc = -ENODEV;
551 status = ap_reset_queue(qid);
552 for (i = 0; i < AP_MAX_RESET; i++) {
553 switch (status.response_code) {
554 case AP_RESPONSE_NORMAL:
555 if (status.queue_empty)
556 rc = 0;
557 break;
558 case AP_RESPONSE_Q_NOT_AVAIL:
559 case AP_RESPONSE_DECONFIGURED:
560 case AP_RESPONSE_CHECKSTOPPED:
561 i = AP_MAX_RESET; /* return with -ENODEV */
562 break;
563 case AP_RESPONSE_RESET_IN_PROGRESS:
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200564 rc = -EBUSY;
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200565 case AP_RESPONSE_BUSY:
566 default:
567 break;
568 }
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200569 if (rc != -ENODEV && rc != -EBUSY)
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200570 break;
571 if (i < AP_MAX_RESET - 1) {
572 udelay(5);
573 status = ap_test_queue(qid, &dummy, &dummy);
574 }
575 }
Felix Beckcb17a632008-12-25 13:38:41 +0100576 if (rc == 0 && ap_using_interrupts()) {
577 rc = ap_queue_enable_interruption(qid, ap_interrupt_indicator);
578 /* If interruption mode is supported by the machine,
579 * but an AP can not be enabled for interruption then
580 * the AP will be discarded. */
581 if (rc)
582 pr_err("Registering adapter interrupts for "
583 "AP %d failed\n", AP_QID_DEVICE(qid));
584 }
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200585 return rc;
586}
587
588/**
Felix Beck1749a812008-04-17 07:46:28 +0200589 * ap_increase_queue_count(): Arm request timeout.
590 * @ap_dev: Pointer to an AP device.
591 *
592 * Arm request timeout if an AP device was idle and a new request is submitted.
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200593 */
594static void ap_increase_queue_count(struct ap_device *ap_dev)
595{
596 int timeout = ap_dev->drv->request_timeout;
597
598 ap_dev->queue_count++;
599 if (ap_dev->queue_count == 1) {
600 mod_timer(&ap_dev->timeout, jiffies + timeout);
601 ap_dev->reset = AP_RESET_ARMED;
602 }
603}
604
605/**
Felix Beck1749a812008-04-17 07:46:28 +0200606 * ap_decrease_queue_count(): Decrease queue count.
607 * @ap_dev: Pointer to an AP device.
608 *
609 * If AP device is still alive, re-schedule request timeout if there are still
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200610 * pending requests.
611 */
612static void ap_decrease_queue_count(struct ap_device *ap_dev)
613{
614 int timeout = ap_dev->drv->request_timeout;
615
616 ap_dev->queue_count--;
617 if (ap_dev->queue_count > 0)
618 mod_timer(&ap_dev->timeout, jiffies + timeout);
619 else
Felix Beck1749a812008-04-17 07:46:28 +0200620 /*
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200621 * The timeout timer should to be disabled now - since
622 * del_timer_sync() is very expensive, we just tell via the
623 * reset flag to ignore the pending timeout timer.
624 */
625 ap_dev->reset = AP_RESET_IGNORE;
626}
627
Felix Beck1749a812008-04-17 07:46:28 +0200628/*
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200629 * AP device related attributes.
630 */
631static ssize_t ap_hwtype_show(struct device *dev,
632 struct device_attribute *attr, char *buf)
633{
634 struct ap_device *ap_dev = to_ap_dev(dev);
635 return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->device_type);
636}
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200637
Christian Maaser43c207e62008-12-25 13:38:42 +0100638static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL);
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200639static ssize_t ap_depth_show(struct device *dev, struct device_attribute *attr,
640 char *buf)
641{
642 struct ap_device *ap_dev = to_ap_dev(dev);
643 return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->queue_depth);
644}
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200645
Christian Maaser43c207e62008-12-25 13:38:42 +0100646static DEVICE_ATTR(depth, 0444, ap_depth_show, NULL);
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200647static ssize_t ap_request_count_show(struct device *dev,
648 struct device_attribute *attr,
649 char *buf)
650{
651 struct ap_device *ap_dev = to_ap_dev(dev);
652 int rc;
653
654 spin_lock_bh(&ap_dev->lock);
655 rc = snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->total_request_count);
656 spin_unlock_bh(&ap_dev->lock);
657 return rc;
658}
659
660static DEVICE_ATTR(request_count, 0444, ap_request_count_show, NULL);
661
662static ssize_t ap_modalias_show(struct device *dev,
663 struct device_attribute *attr, char *buf)
664{
665 return sprintf(buf, "ap:t%02X", to_ap_dev(dev)->device_type);
666}
667
668static DEVICE_ATTR(modalias, 0444, ap_modalias_show, NULL);
669
670static struct attribute *ap_dev_attrs[] = {
671 &dev_attr_hwtype.attr,
672 &dev_attr_depth.attr,
673 &dev_attr_request_count.attr,
674 &dev_attr_modalias.attr,
675 NULL
676};
677static struct attribute_group ap_dev_attr_group = {
678 .attrs = ap_dev_attrs
679};
680
681/**
Felix Beck1749a812008-04-17 07:46:28 +0200682 * ap_bus_match()
683 * @dev: Pointer to device
684 * @drv: Pointer to device_driver
685 *
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200686 * AP bus driver registration/unregistration.
687 */
688static int ap_bus_match(struct device *dev, struct device_driver *drv)
689{
690 struct ap_device *ap_dev = to_ap_dev(dev);
691 struct ap_driver *ap_drv = to_ap_drv(drv);
692 struct ap_device_id *id;
693
Felix Beck1749a812008-04-17 07:46:28 +0200694 /*
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200695 * Compare device type of the device with the list of
696 * supported types of the device_driver.
697 */
698 for (id = ap_drv->ids; id->match_flags; id++) {
699 if ((id->match_flags & AP_DEVICE_ID_MATCH_DEVICE_TYPE) &&
700 (id->dev_type != ap_dev->device_type))
701 continue;
702 return 1;
703 }
704 return 0;
705}
706
707/**
Felix Beck1749a812008-04-17 07:46:28 +0200708 * ap_uevent(): Uevent function for AP devices.
709 * @dev: Pointer to device
710 * @env: Pointer to kobj_uevent_env
711 *
712 * It sets up a single environment variable DEV_TYPE which contains the
713 * hardware device type.
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200714 */
Kay Sievers7eff2e72007-08-14 15:15:12 +0200715static int ap_uevent (struct device *dev, struct kobj_uevent_env *env)
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200716{
717 struct ap_device *ap_dev = to_ap_dev(dev);
Kay Sievers7eff2e72007-08-14 15:15:12 +0200718 int retval = 0;
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200719
720 if (!ap_dev)
721 return -ENODEV;
722
723 /* Set up DEV_TYPE environment variable. */
Kay Sievers7eff2e72007-08-14 15:15:12 +0200724 retval = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type);
Eric Rannaudbf624562007-03-30 22:23:12 -0700725 if (retval)
726 return retval;
727
Cornelia Huck66a4263b2006-12-04 15:40:10 +0100728 /* Add MODALIAS= */
Kay Sievers7eff2e72007-08-14 15:15:12 +0200729 retval = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type);
Eric Rannaudbf624562007-03-30 22:23:12 -0700730
Eric Rannaudbf624562007-03-30 22:23:12 -0700731 return retval;
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200732}
733
Felix Beck772f5472009-06-22 12:08:16 +0200734static int ap_bus_suspend(struct device *dev, pm_message_t state)
735{
736 struct ap_device *ap_dev = to_ap_dev(dev);
737 unsigned long flags;
738
739 if (!ap_suspend_flag) {
740 ap_suspend_flag = 1;
741
742 /* Disable scanning for devices, thus we do not want to scan
743 * for them after removing.
744 */
745 del_timer_sync(&ap_config_timer);
746 if (ap_work_queue != NULL) {
747 destroy_workqueue(ap_work_queue);
748 ap_work_queue = NULL;
749 }
Felix Beck5314af62009-09-22 22:58:51 +0200750
Felix Beck772f5472009-06-22 12:08:16 +0200751 tasklet_disable(&ap_tasklet);
752 }
753 /* Poll on the device until all requests are finished. */
754 do {
755 flags = 0;
Felix Beck95f15562009-09-11 10:28:51 +0200756 spin_lock_bh(&ap_dev->lock);
Felix Beck772f5472009-06-22 12:08:16 +0200757 __ap_poll_device(ap_dev, &flags);
Felix Beck95f15562009-09-11 10:28:51 +0200758 spin_unlock_bh(&ap_dev->lock);
Felix Beck772f5472009-06-22 12:08:16 +0200759 } while ((flags & 1) || (flags & 2));
760
Felix Beck5314af62009-09-22 22:58:51 +0200761 spin_lock_bh(&ap_dev->lock);
762 ap_dev->unregistered = 1;
763 spin_unlock_bh(&ap_dev->lock);
764
Felix Beck772f5472009-06-22 12:08:16 +0200765 return 0;
766}
767
768static int ap_bus_resume(struct device *dev)
769{
770 int rc = 0;
771 struct ap_device *ap_dev = to_ap_dev(dev);
772
773 if (ap_suspend_flag) {
774 ap_suspend_flag = 0;
775 if (!ap_interrupts_available())
776 ap_interrupt_indicator = NULL;
Felix Beck5314af62009-09-22 22:58:51 +0200777 if (!user_set_domain) {
778 ap_domain_index = -1;
779 ap_select_domain();
780 }
Felix Beck772f5472009-06-22 12:08:16 +0200781 init_timer(&ap_config_timer);
782 ap_config_timer.function = ap_config_timeout;
783 ap_config_timer.data = 0;
784 ap_config_timer.expires = jiffies + ap_config_time * HZ;
785 add_timer(&ap_config_timer);
786 ap_work_queue = create_singlethread_workqueue("kapwork");
787 if (!ap_work_queue)
788 return -ENOMEM;
789 tasklet_enable(&ap_tasklet);
790 if (!ap_using_interrupts())
791 ap_schedule_poll_timer();
792 else
793 tasklet_schedule(&ap_tasklet);
794 if (ap_thread_flag)
795 rc = ap_poll_thread_start();
Felix Beck772f5472009-06-22 12:08:16 +0200796 }
Felix Beck5314af62009-09-22 22:58:51 +0200797 if (AP_QID_QUEUE(ap_dev->qid) != ap_domain_index) {
798 spin_lock_bh(&ap_dev->lock);
799 ap_dev->qid = AP_MKQID(AP_QID_DEVICE(ap_dev->qid),
800 ap_domain_index);
801 spin_unlock_bh(&ap_dev->lock);
802 }
803 queue_work(ap_work_queue, &ap_config_work);
Felix Beck772f5472009-06-22 12:08:16 +0200804
805 return rc;
806}
807
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200808static struct bus_type ap_bus_type = {
809 .name = "ap",
810 .match = &ap_bus_match,
811 .uevent = &ap_uevent,
Felix Beck772f5472009-06-22 12:08:16 +0200812 .suspend = ap_bus_suspend,
813 .resume = ap_bus_resume
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200814};
815
816static int ap_device_probe(struct device *dev)
817{
818 struct ap_device *ap_dev = to_ap_dev(dev);
819 struct ap_driver *ap_drv = to_ap_drv(dev->driver);
820 int rc;
821
822 ap_dev->drv = ap_drv;
823 rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV;
Ralph Wuerthnerfaa582c2008-03-05 12:37:13 +0100824 if (!rc) {
Christian Maaser43c207e62008-12-25 13:38:42 +0100825 spin_lock_bh(&ap_device_list_lock);
Ralph Wuerthnerfaa582c2008-03-05 12:37:13 +0100826 list_add(&ap_dev->list, &ap_device_list);
Christian Maaser43c207e62008-12-25 13:38:42 +0100827 spin_unlock_bh(&ap_device_list_lock);
Ralph Wuerthnerfaa582c2008-03-05 12:37:13 +0100828 }
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200829 return rc;
830}
831
832/**
Felix Beck1749a812008-04-17 07:46:28 +0200833 * __ap_flush_queue(): Flush requests.
834 * @ap_dev: Pointer to the AP device
835 *
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200836 * Flush all requests from the request/pending queue of an AP device.
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200837 */
Heiko Carstens4d284ca2007-02-05 21:18:53 +0100838static void __ap_flush_queue(struct ap_device *ap_dev)
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200839{
840 struct ap_message *ap_msg, *next;
841
842 list_for_each_entry_safe(ap_msg, next, &ap_dev->pendingq, list) {
843 list_del_init(&ap_msg->list);
844 ap_dev->pendingq_count--;
Holger Dengler54a8f562012-05-16 14:08:22 +0200845 ap_msg->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200846 }
847 list_for_each_entry_safe(ap_msg, next, &ap_dev->requestq, list) {
848 list_del_init(&ap_msg->list);
849 ap_dev->requestq_count--;
Holger Dengler54a8f562012-05-16 14:08:22 +0200850 ap_msg->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200851 }
852}
853
854void ap_flush_queue(struct ap_device *ap_dev)
855{
856 spin_lock_bh(&ap_dev->lock);
857 __ap_flush_queue(ap_dev);
858 spin_unlock_bh(&ap_dev->lock);
859}
860EXPORT_SYMBOL(ap_flush_queue);
861
862static int ap_device_remove(struct device *dev)
863{
864 struct ap_device *ap_dev = to_ap_dev(dev);
865 struct ap_driver *ap_drv = ap_dev->drv;
866
Ralph Wuerthner4e562962006-10-04 20:02:05 +0200867 ap_flush_queue(ap_dev);
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200868 del_timer_sync(&ap_dev->timeout);
Christian Maaser43c207e62008-12-25 13:38:42 +0100869 spin_lock_bh(&ap_device_list_lock);
Ralph Wuerthnercf352ce2007-03-19 13:19:14 +0100870 list_del_init(&ap_dev->list);
Christian Maaser43c207e62008-12-25 13:38:42 +0100871 spin_unlock_bh(&ap_device_list_lock);
Ralph Wuerthnerfaa582c2008-03-05 12:37:13 +0100872 if (ap_drv->remove)
873 ap_drv->remove(ap_dev);
Ralph Wuerthnere675c0d2007-03-26 20:42:43 +0200874 spin_lock_bh(&ap_dev->lock);
875 atomic_sub(ap_dev->queue_count, &ap_poll_requests);
876 spin_unlock_bh(&ap_dev->lock);
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200877 return 0;
878}
879
880int ap_driver_register(struct ap_driver *ap_drv, struct module *owner,
881 char *name)
882{
883 struct device_driver *drv = &ap_drv->driver;
884
885 drv->bus = &ap_bus_type;
886 drv->probe = ap_device_probe;
887 drv->remove = ap_device_remove;
888 drv->owner = owner;
889 drv->name = name;
890 return driver_register(drv);
891}
892EXPORT_SYMBOL(ap_driver_register);
893
894void ap_driver_unregister(struct ap_driver *ap_drv)
895{
896 driver_unregister(&ap_drv->driver);
897}
898EXPORT_SYMBOL(ap_driver_unregister);
899
Felix Beck1749a812008-04-17 07:46:28 +0200900/*
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200901 * AP bus attributes.
902 */
903static ssize_t ap_domain_show(struct bus_type *bus, char *buf)
904{
905 return snprintf(buf, PAGE_SIZE, "%d\n", ap_domain_index);
906}
907
908static BUS_ATTR(ap_domain, 0444, ap_domain_show, NULL);
909
910static ssize_t ap_config_time_show(struct bus_type *bus, char *buf)
911{
912 return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time);
913}
914
Felix Beckcb17a632008-12-25 13:38:41 +0100915static ssize_t ap_interrupts_show(struct bus_type *bus, char *buf)
916{
917 return snprintf(buf, PAGE_SIZE, "%d\n",
918 ap_using_interrupts() ? 1 : 0);
919}
920
921static BUS_ATTR(ap_interrupts, 0444, ap_interrupts_show, NULL);
922
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200923static ssize_t ap_config_time_store(struct bus_type *bus,
924 const char *buf, size_t count)
925{
926 int time;
927
928 if (sscanf(buf, "%d\n", &time) != 1 || time < 5 || time > 120)
929 return -EINVAL;
930 ap_config_time = time;
931 if (!timer_pending(&ap_config_timer) ||
932 !mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ)) {
933 ap_config_timer.expires = jiffies + ap_config_time * HZ;
934 add_timer(&ap_config_timer);
935 }
936 return count;
937}
938
939static BUS_ATTR(config_time, 0644, ap_config_time_show, ap_config_time_store);
940
941static ssize_t ap_poll_thread_show(struct bus_type *bus, char *buf)
942{
943 return snprintf(buf, PAGE_SIZE, "%d\n", ap_poll_kthread ? 1 : 0);
944}
945
946static ssize_t ap_poll_thread_store(struct bus_type *bus,
947 const char *buf, size_t count)
948{
949 int flag, rc;
950
951 if (sscanf(buf, "%d\n", &flag) != 1)
952 return -EINVAL;
953 if (flag) {
954 rc = ap_poll_thread_start();
955 if (rc)
956 return rc;
957 }
958 else
959 ap_poll_thread_stop();
960 return count;
961}
962
963static BUS_ATTR(poll_thread, 0644, ap_poll_thread_show, ap_poll_thread_store);
964
Felix Beckfe137232008-07-14 09:59:08 +0200965static ssize_t poll_timeout_show(struct bus_type *bus, char *buf)
966{
967 return snprintf(buf, PAGE_SIZE, "%llu\n", poll_timeout);
968}
969
970static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf,
971 size_t count)
972{
973 unsigned long long time;
974 ktime_t hr_time;
975
976 /* 120 seconds = maximum poll interval */
Felix Beckcb17a632008-12-25 13:38:41 +0100977 if (sscanf(buf, "%llu\n", &time) != 1 || time < 1 ||
978 time > 120000000000ULL)
Felix Beckfe137232008-07-14 09:59:08 +0200979 return -EINVAL;
980 poll_timeout = time;
981 hr_time = ktime_set(0, poll_timeout);
982
983 if (!hrtimer_is_queued(&ap_poll_timer) ||
Arjan van de Ven6c644ea2008-09-01 15:20:30 -0700984 !hrtimer_forward(&ap_poll_timer, hrtimer_get_expires(&ap_poll_timer), hr_time)) {
985 hrtimer_set_expires(&ap_poll_timer, hr_time);
986 hrtimer_start_expires(&ap_poll_timer, HRTIMER_MODE_ABS);
Felix Beckfe137232008-07-14 09:59:08 +0200987 }
988 return count;
989}
990
991static BUS_ATTR(poll_timeout, 0644, poll_timeout_show, poll_timeout_store);
992
Martin Schwidefsky1534c382006-09-20 15:58:25 +0200993static struct bus_attribute *const ap_bus_attrs[] = {
994 &bus_attr_ap_domain,
995 &bus_attr_config_time,
996 &bus_attr_poll_thread,
Felix Beckcb17a632008-12-25 13:38:41 +0100997 &bus_attr_ap_interrupts,
Felix Beckfe137232008-07-14 09:59:08 +0200998 &bus_attr_poll_timeout,
999 NULL,
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001000};
1001
1002/**
Felix Beck1749a812008-04-17 07:46:28 +02001003 * ap_select_domain(): Select an AP domain.
1004 *
1005 * Pick one of the 16 AP domains.
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001006 */
Heiko Carstens4d284ca2007-02-05 21:18:53 +01001007static int ap_select_domain(void)
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001008{
1009 int queue_depth, device_type, count, max_count, best_domain;
1010 int rc, i, j;
1011
Felix Beck1749a812008-04-17 07:46:28 +02001012 /*
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001013 * We want to use a single domain. Either the one specified with
1014 * the "domain=" parameter or the domain with the maximum number
1015 * of devices.
1016 */
1017 if (ap_domain_index >= 0 && ap_domain_index < AP_DOMAINS)
1018 /* Domain has already been selected. */
1019 return 0;
1020 best_domain = -1;
1021 max_count = 0;
1022 for (i = 0; i < AP_DOMAINS; i++) {
1023 count = 0;
1024 for (j = 0; j < AP_DEVICES; j++) {
1025 ap_qid_t qid = AP_MKQID(j, i);
1026 rc = ap_query_queue(qid, &queue_depth, &device_type);
1027 if (rc)
1028 continue;
1029 count++;
1030 }
1031 if (count > max_count) {
1032 max_count = count;
1033 best_domain = i;
1034 }
1035 }
1036 if (best_domain >= 0){
1037 ap_domain_index = best_domain;
1038 return 0;
1039 }
1040 return -ENODEV;
1041}
1042
1043/**
Felix Beck1749a812008-04-17 07:46:28 +02001044 * ap_probe_device_type(): Find the device type of an AP.
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001045 * @ap_dev: pointer to the AP device.
Felix Beck1749a812008-04-17 07:46:28 +02001046 *
1047 * Find the device type if query queue returned a device type of 0.
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001048 */
1049static int ap_probe_device_type(struct ap_device *ap_dev)
1050{
1051 static unsigned char msg[] = {
1052 0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,
1053 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1054 0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,
1055 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1056 0x01,0x00,0x43,0x43,0x41,0x2d,0x41,0x50,
1057 0x50,0x4c,0x20,0x20,0x20,0x01,0x01,0x01,
1058 0x00,0x00,0x00,0x00,0x50,0x4b,0x00,0x00,
1059 0x00,0x00,0x01,0x1c,0x00,0x00,0x00,0x00,
1060 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1061 0x00,0x00,0x05,0xb8,0x00,0x00,0x00,0x00,
1062 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1063 0x70,0x00,0x41,0x00,0x00,0x00,0x00,0x00,
1064 0x00,0x00,0x54,0x32,0x01,0x00,0xa0,0x00,
1065 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1066 0x00,0x00,0x00,0x00,0xb8,0x05,0x00,0x00,
1067 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1068 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1069 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1070 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1071 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1072 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1073 0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,
1074 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1075 0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,
1076 0x49,0x43,0x53,0x46,0x20,0x20,0x20,0x20,
1077 0x50,0x4b,0x0a,0x00,0x50,0x4b,0x43,0x53,
1078 0x2d,0x31,0x2e,0x32,0x37,0x00,0x11,0x22,
1079 0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00,
1080 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,
1081 0x99,0x00,0x11,0x22,0x33,0x44,0x55,0x66,
1082 0x77,0x88,0x99,0x00,0x11,0x22,0x33,0x44,
1083 0x55,0x66,0x77,0x88,0x99,0x00,0x11,0x22,
1084 0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00,
1085 0x11,0x22,0x33,0x5d,0x00,0x5b,0x00,0x77,
1086 0x88,0x1e,0x00,0x00,0x57,0x00,0x00,0x00,
1087 0x00,0x04,0x00,0x00,0x4f,0x00,0x00,0x00,
1088 0x03,0x02,0x00,0x00,0x40,0x01,0x00,0x01,
1089 0xce,0x02,0x68,0x2d,0x5f,0xa9,0xde,0x0c,
1090 0xf6,0xd2,0x7b,0x58,0x4b,0xf9,0x28,0x68,
1091 0x3d,0xb4,0xf4,0xef,0x78,0xd5,0xbe,0x66,
1092 0x63,0x42,0xef,0xf8,0xfd,0xa4,0xf8,0xb0,
1093 0x8e,0x29,0xc2,0xc9,0x2e,0xd8,0x45,0xb8,
1094 0x53,0x8c,0x6f,0x4e,0x72,0x8f,0x6c,0x04,
1095 0x9c,0x88,0xfc,0x1e,0xc5,0x83,0x55,0x57,
1096 0xf7,0xdd,0xfd,0x4f,0x11,0x36,0x95,0x5d,
1097 };
1098 struct ap_queue_status status;
1099 unsigned long long psmid;
1100 char *reply;
1101 int rc, i;
1102
1103 reply = (void *) get_zeroed_page(GFP_KERNEL);
1104 if (!reply) {
1105 rc = -ENOMEM;
1106 goto out;
1107 }
1108
1109 status = __ap_send(ap_dev->qid, 0x0102030405060708ULL,
Felix Becka6a5d732009-12-07 12:51:55 +01001110 msg, sizeof(msg), 0);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001111 if (status.response_code != AP_RESPONSE_NORMAL) {
1112 rc = -ENODEV;
1113 goto out_free;
1114 }
1115
1116 /* Wait for the test message to complete. */
1117 for (i = 0; i < 6; i++) {
1118 mdelay(300);
1119 status = __ap_recv(ap_dev->qid, &psmid, reply, 4096);
1120 if (status.response_code == AP_RESPONSE_NORMAL &&
1121 psmid == 0x0102030405060708ULL)
1122 break;
1123 }
1124 if (i < 6) {
1125 /* Got an answer. */
1126 if (reply[0] == 0x00 && reply[1] == 0x86)
1127 ap_dev->device_type = AP_DEVICE_TYPE_PCICC;
1128 else
1129 ap_dev->device_type = AP_DEVICE_TYPE_PCICA;
1130 rc = 0;
1131 } else
1132 rc = -ENODEV;
1133
1134out_free:
1135 free_page((unsigned long) reply);
1136out:
1137 return rc;
1138}
1139
Felix Beckcb17a632008-12-25 13:38:41 +01001140static void ap_interrupt_handler(void *unused1, void *unused2)
1141{
Holger Dengler62d146f2011-01-05 12:47:38 +01001142 kstat_cpu(smp_processor_id()).irqs[IOINT_APB]++;
Felix Beckcb17a632008-12-25 13:38:41 +01001143 tasklet_schedule(&ap_tasklet);
1144}
1145
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001146/**
Felix Beck1749a812008-04-17 07:46:28 +02001147 * __ap_scan_bus(): Scan the AP bus.
1148 * @dev: Pointer to device
1149 * @data: Pointer to data
1150 *
1151 * Scan the AP bus for new devices.
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001152 */
1153static int __ap_scan_bus(struct device *dev, void *data)
1154{
1155 return to_ap_dev(dev)->qid == (ap_qid_t)(unsigned long) data;
1156}
1157
1158static void ap_device_release(struct device *dev)
1159{
1160 struct ap_device *ap_dev = to_ap_dev(dev);
1161
1162 kfree(ap_dev);
1163}
1164
Al Viro4927b3f2006-12-06 19:18:20 +00001165static void ap_scan_bus(struct work_struct *unused)
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001166{
1167 struct ap_device *ap_dev;
1168 struct device *dev;
1169 ap_qid_t qid;
1170 int queue_depth, device_type;
Holger Dengler6bed05b2011-07-24 10:48:25 +02001171 unsigned int device_functions;
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001172 int rc, i;
1173
1174 if (ap_select_domain() != 0)
1175 return;
1176 for (i = 0; i < AP_DEVICES; i++) {
1177 qid = AP_MKQID(i, ap_domain_index);
1178 dev = bus_find_device(&ap_bus_type, NULL,
1179 (void *)(unsigned long)qid,
1180 __ap_scan_bus);
Ralph Wuerthnerf3b017d2006-10-27 12:39:26 +02001181 rc = ap_query_queue(qid, &queue_depth, &device_type);
Ralph Wuerthnerc6a48262007-03-26 20:42:42 +02001182 if (dev) {
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +02001183 if (rc == -EBUSY) {
1184 set_current_state(TASK_UNINTERRUPTIBLE);
1185 schedule_timeout(AP_RESET_TIMEOUT);
1186 rc = ap_query_queue(qid, &queue_depth,
1187 &device_type);
1188 }
Ralph Wuerthnerc6a48262007-03-26 20:42:42 +02001189 ap_dev = to_ap_dev(dev);
1190 spin_lock_bh(&ap_dev->lock);
1191 if (rc || ap_dev->unregistered) {
1192 spin_unlock_bh(&ap_dev->lock);
Felix Beck5314af62009-09-22 22:58:51 +02001193 if (ap_dev->unregistered)
1194 i--;
Ralph Wuerthnerc6a48262007-03-26 20:42:42 +02001195 device_unregister(dev);
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +02001196 put_device(dev);
Ralph Wuerthnerc6a48262007-03-26 20:42:42 +02001197 continue;
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +02001198 }
1199 spin_unlock_bh(&ap_dev->lock);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001200 put_device(dev);
1201 continue;
1202 }
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001203 if (rc)
1204 continue;
1205 rc = ap_init_queue(qid);
1206 if (rc)
1207 continue;
1208 ap_dev = kzalloc(sizeof(*ap_dev), GFP_KERNEL);
1209 if (!ap_dev)
1210 break;
1211 ap_dev->qid = qid;
1212 ap_dev->queue_depth = queue_depth;
Ralph Wuerthner4e562962006-10-04 20:02:05 +02001213 ap_dev->unregistered = 1;
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001214 spin_lock_init(&ap_dev->lock);
1215 INIT_LIST_HEAD(&ap_dev->pendingq);
1216 INIT_LIST_HEAD(&ap_dev->requestq);
Ralph Wuerthnercf352ce2007-03-19 13:19:14 +01001217 INIT_LIST_HEAD(&ap_dev->list);
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +02001218 setup_timer(&ap_dev->timeout, ap_request_timeout,
1219 (unsigned long) ap_dev);
Holger Dengler6bed05b2011-07-24 10:48:25 +02001220 switch (device_type) {
1221 case 0:
Holger Denglercf2d0072011-05-23 10:24:30 +02001222 if (ap_probe_device_type(ap_dev)) {
1223 kfree(ap_dev);
1224 continue;
1225 }
Holger Dengler6bed05b2011-07-24 10:48:25 +02001226 break;
1227 case 10:
1228 if (ap_query_functions(qid, &device_functions)) {
1229 kfree(ap_dev);
1230 continue;
1231 }
1232 if (test_ap_facility(device_functions, 3))
1233 ap_dev->device_type = AP_DEVICE_TYPE_CEX3C;
1234 else if (test_ap_facility(device_functions, 4))
1235 ap_dev->device_type = AP_DEVICE_TYPE_CEX3A;
1236 else {
1237 kfree(ap_dev);
1238 continue;
1239 }
1240 break;
1241 default:
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001242 ap_dev->device_type = device_type;
Holger Dengler6bed05b2011-07-24 10:48:25 +02001243 }
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001244
1245 ap_dev->device.bus = &ap_bus_type;
1246 ap_dev->device.parent = ap_root_device;
Felix Beckedc44fa2009-09-11 10:28:52 +02001247 if (dev_set_name(&ap_dev->device, "card%02x",
1248 AP_QID_DEVICE(ap_dev->qid))) {
1249 kfree(ap_dev);
1250 continue;
1251 }
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001252 ap_dev->device.release = ap_device_release;
1253 rc = device_register(&ap_dev->device);
1254 if (rc) {
Sebastian Ottc6304932009-09-11 10:28:38 +02001255 put_device(&ap_dev->device);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001256 continue;
1257 }
1258 /* Add device attributes. */
1259 rc = sysfs_create_group(&ap_dev->device.kobj,
1260 &ap_dev_attr_group);
Ralph Wuerthner4e562962006-10-04 20:02:05 +02001261 if (!rc) {
1262 spin_lock_bh(&ap_dev->lock);
1263 ap_dev->unregistered = 0;
1264 spin_unlock_bh(&ap_dev->lock);
1265 }
1266 else
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001267 device_unregister(&ap_dev->device);
1268 }
1269}
1270
1271static void
1272ap_config_timeout(unsigned long ptr)
1273{
1274 queue_work(ap_work_queue, &ap_config_work);
1275 ap_config_timer.expires = jiffies + ap_config_time * HZ;
1276 add_timer(&ap_config_timer);
1277}
1278
1279/**
Holger Denglerbc615de2011-11-14 11:19:04 +01001280 * __ap_schedule_poll_timer(): Schedule poll timer.
Felix Beck1749a812008-04-17 07:46:28 +02001281 *
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001282 * Set up the timer to run the poll tasklet
1283 */
Holger Denglerbc615de2011-11-14 11:19:04 +01001284static inline void __ap_schedule_poll_timer(void)
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001285{
Felix Beck8d406c62009-07-24 12:39:53 +02001286 ktime_t hr_time;
Felix Beck93521312009-12-07 12:52:00 +01001287
1288 spin_lock_bh(&ap_poll_timer_lock);
Holger Denglerbc615de2011-11-14 11:19:04 +01001289 if (hrtimer_is_queued(&ap_poll_timer) || ap_suspend_flag)
Felix Beck93521312009-12-07 12:52:00 +01001290 goto out;
Felix Beck8d406c62009-07-24 12:39:53 +02001291 if (ktime_to_ns(hrtimer_expires_remaining(&ap_poll_timer)) <= 0) {
1292 hr_time = ktime_set(0, poll_timeout);
1293 hrtimer_forward_now(&ap_poll_timer, hr_time);
1294 hrtimer_restart(&ap_poll_timer);
1295 }
Felix Beck93521312009-12-07 12:52:00 +01001296out:
1297 spin_unlock_bh(&ap_poll_timer_lock);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001298}
1299
1300/**
Holger Denglerbc615de2011-11-14 11:19:04 +01001301 * ap_schedule_poll_timer(): Schedule poll timer.
1302 *
1303 * Set up the timer to run the poll tasklet
1304 */
1305static inline void ap_schedule_poll_timer(void)
1306{
1307 if (ap_using_interrupts())
1308 return;
1309 __ap_schedule_poll_timer();
1310}
1311
1312/**
Felix Beck1749a812008-04-17 07:46:28 +02001313 * ap_poll_read(): Receive pending reply messages from an AP device.
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001314 * @ap_dev: pointer to the AP device
1315 * @flags: pointer to control flags, bit 2^0 is set if another poll is
1316 * required, bit 2^1 is set if the poll timer needs to get armed
Felix Beck1749a812008-04-17 07:46:28 +02001317 *
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001318 * Returns 0 if the device is still present, -ENODEV if not.
1319 */
Heiko Carstens4d284ca2007-02-05 21:18:53 +01001320static int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001321{
1322 struct ap_queue_status status;
1323 struct ap_message *ap_msg;
1324
1325 if (ap_dev->queue_count <= 0)
1326 return 0;
1327 status = __ap_recv(ap_dev->qid, &ap_dev->reply->psmid,
1328 ap_dev->reply->message, ap_dev->reply->length);
1329 switch (status.response_code) {
1330 case AP_RESPONSE_NORMAL:
1331 atomic_dec(&ap_poll_requests);
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +02001332 ap_decrease_queue_count(ap_dev);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001333 list_for_each_entry(ap_msg, &ap_dev->pendingq, list) {
1334 if (ap_msg->psmid != ap_dev->reply->psmid)
1335 continue;
1336 list_del_init(&ap_msg->list);
1337 ap_dev->pendingq_count--;
Holger Dengler54a8f562012-05-16 14:08:22 +02001338 ap_msg->receive(ap_dev, ap_msg, ap_dev->reply);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001339 break;
1340 }
1341 if (ap_dev->queue_count > 0)
1342 *flags |= 1;
1343 break;
1344 case AP_RESPONSE_NO_PENDING_REPLY:
1345 if (status.queue_empty) {
1346 /* The card shouldn't forget requests but who knows. */
Ralph Wuerthnere675c0d2007-03-26 20:42:43 +02001347 atomic_sub(ap_dev->queue_count, &ap_poll_requests);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001348 ap_dev->queue_count = 0;
1349 list_splice_init(&ap_dev->pendingq, &ap_dev->requestq);
1350 ap_dev->requestq_count += ap_dev->pendingq_count;
1351 ap_dev->pendingq_count = 0;
1352 } else
1353 *flags |= 2;
1354 break;
1355 default:
1356 return -ENODEV;
1357 }
1358 return 0;
1359}
1360
1361/**
Felix Beck1749a812008-04-17 07:46:28 +02001362 * ap_poll_write(): Send messages from the request queue to an AP device.
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001363 * @ap_dev: pointer to the AP device
1364 * @flags: pointer to control flags, bit 2^0 is set if another poll is
1365 * required, bit 2^1 is set if the poll timer needs to get armed
Felix Beck1749a812008-04-17 07:46:28 +02001366 *
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001367 * Returns 0 if the device is still present, -ENODEV if not.
1368 */
Heiko Carstens4d284ca2007-02-05 21:18:53 +01001369static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001370{
1371 struct ap_queue_status status;
1372 struct ap_message *ap_msg;
1373
1374 if (ap_dev->requestq_count <= 0 ||
1375 ap_dev->queue_count >= ap_dev->queue_depth)
1376 return 0;
1377 /* Start the next request on the queue. */
1378 ap_msg = list_entry(ap_dev->requestq.next, struct ap_message, list);
1379 status = __ap_send(ap_dev->qid, ap_msg->psmid,
Felix Becka6a5d732009-12-07 12:51:55 +01001380 ap_msg->message, ap_msg->length, ap_msg->special);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001381 switch (status.response_code) {
1382 case AP_RESPONSE_NORMAL:
1383 atomic_inc(&ap_poll_requests);
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +02001384 ap_increase_queue_count(ap_dev);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001385 list_move_tail(&ap_msg->list, &ap_dev->pendingq);
1386 ap_dev->requestq_count--;
1387 ap_dev->pendingq_count++;
1388 if (ap_dev->queue_count < ap_dev->queue_depth &&
1389 ap_dev->requestq_count > 0)
1390 *flags |= 1;
1391 *flags |= 2;
1392 break;
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +02001393 case AP_RESPONSE_RESET_IN_PROGRESS:
Holger Denglerbc615de2011-11-14 11:19:04 +01001394 __ap_schedule_poll_timer();
1395 case AP_RESPONSE_Q_FULL:
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001396 *flags |= 2;
1397 break;
1398 case AP_RESPONSE_MESSAGE_TOO_BIG:
Felix Becka6a5d732009-12-07 12:51:55 +01001399 case AP_RESPONSE_REQ_FAC_NOT_INST:
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001400 return -EINVAL;
1401 default:
1402 return -ENODEV;
1403 }
1404 return 0;
1405}
1406
1407/**
Felix Beck1749a812008-04-17 07:46:28 +02001408 * ap_poll_queue(): Poll AP device for pending replies and send new messages.
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001409 * @ap_dev: pointer to the bus device
1410 * @flags: pointer to control flags, bit 2^0 is set if another poll is
1411 * required, bit 2^1 is set if the poll timer needs to get armed
Felix Beck1749a812008-04-17 07:46:28 +02001412 *
1413 * Poll AP device for pending replies and send new messages. If either
1414 * ap_poll_read or ap_poll_write returns -ENODEV unregister the device.
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001415 * Returns 0.
1416 */
1417static inline int ap_poll_queue(struct ap_device *ap_dev, unsigned long *flags)
1418{
1419 int rc;
1420
1421 rc = ap_poll_read(ap_dev, flags);
1422 if (rc)
1423 return rc;
1424 return ap_poll_write(ap_dev, flags);
1425}
1426
1427/**
Felix Beck1749a812008-04-17 07:46:28 +02001428 * __ap_queue_message(): Queue a message to a device.
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001429 * @ap_dev: pointer to the AP device
1430 * @ap_msg: the message to be queued
Felix Beck1749a812008-04-17 07:46:28 +02001431 *
1432 * Queue a message to a device. Returns 0 if successful.
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001433 */
1434static int __ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg)
1435{
1436 struct ap_queue_status status;
1437
1438 if (list_empty(&ap_dev->requestq) &&
1439 ap_dev->queue_count < ap_dev->queue_depth) {
1440 status = __ap_send(ap_dev->qid, ap_msg->psmid,
Felix Becka6a5d732009-12-07 12:51:55 +01001441 ap_msg->message, ap_msg->length,
1442 ap_msg->special);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001443 switch (status.response_code) {
1444 case AP_RESPONSE_NORMAL:
1445 list_add_tail(&ap_msg->list, &ap_dev->pendingq);
1446 atomic_inc(&ap_poll_requests);
1447 ap_dev->pendingq_count++;
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +02001448 ap_increase_queue_count(ap_dev);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001449 ap_dev->total_request_count++;
1450 break;
1451 case AP_RESPONSE_Q_FULL:
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +02001452 case AP_RESPONSE_RESET_IN_PROGRESS:
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001453 list_add_tail(&ap_msg->list, &ap_dev->requestq);
1454 ap_dev->requestq_count++;
1455 ap_dev->total_request_count++;
1456 return -EBUSY;
Felix Becka6a5d732009-12-07 12:51:55 +01001457 case AP_RESPONSE_REQ_FAC_NOT_INST:
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001458 case AP_RESPONSE_MESSAGE_TOO_BIG:
Holger Dengler54a8f562012-05-16 14:08:22 +02001459 ap_msg->receive(ap_dev, ap_msg, ERR_PTR(-EINVAL));
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001460 return -EINVAL;
1461 default: /* Device is gone. */
Holger Dengler54a8f562012-05-16 14:08:22 +02001462 ap_msg->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001463 return -ENODEV;
1464 }
1465 } else {
1466 list_add_tail(&ap_msg->list, &ap_dev->requestq);
1467 ap_dev->requestq_count++;
1468 ap_dev->total_request_count++;
1469 return -EBUSY;
1470 }
1471 ap_schedule_poll_timer();
1472 return 0;
1473}
1474
1475void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg)
1476{
1477 unsigned long flags;
1478 int rc;
1479
Holger Dengler54a8f562012-05-16 14:08:22 +02001480 /* For asynchronous message handling a valid receive-callback
1481 * is required. */
1482 BUG_ON(!ap_msg->receive);
1483
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001484 spin_lock_bh(&ap_dev->lock);
1485 if (!ap_dev->unregistered) {
1486 /* Make room on the queue by polling for finished requests. */
1487 rc = ap_poll_queue(ap_dev, &flags);
1488 if (!rc)
1489 rc = __ap_queue_message(ap_dev, ap_msg);
1490 if (!rc)
1491 wake_up(&ap_poll_wait);
Ralph Wuerthner4e562962006-10-04 20:02:05 +02001492 if (rc == -ENODEV)
1493 ap_dev->unregistered = 1;
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001494 } else {
Holger Dengler54a8f562012-05-16 14:08:22 +02001495 ap_msg->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
Ralph Wuerthnerc6a48262007-03-26 20:42:42 +02001496 rc = -ENODEV;
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001497 }
1498 spin_unlock_bh(&ap_dev->lock);
1499 if (rc == -ENODEV)
1500 device_unregister(&ap_dev->device);
1501}
1502EXPORT_SYMBOL(ap_queue_message);
1503
1504/**
Felix Beck1749a812008-04-17 07:46:28 +02001505 * ap_cancel_message(): Cancel a crypto request.
1506 * @ap_dev: The AP device that has the message queued
1507 * @ap_msg: The message that is to be removed
1508 *
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001509 * Cancel a crypto request. This is done by removing the request
Felix Beck1749a812008-04-17 07:46:28 +02001510 * from the device pending or request queue. Note that the
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001511 * request stays on the AP queue. When it finishes the message
1512 * reply will be discarded because the psmid can't be found.
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001513 */
1514void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg)
1515{
1516 struct ap_message *tmp;
1517
1518 spin_lock_bh(&ap_dev->lock);
1519 if (!list_empty(&ap_msg->list)) {
1520 list_for_each_entry(tmp, &ap_dev->pendingq, list)
1521 if (tmp->psmid == ap_msg->psmid) {
1522 ap_dev->pendingq_count--;
1523 goto found;
1524 }
1525 ap_dev->requestq_count--;
1526 found:
1527 list_del_init(&ap_msg->list);
1528 }
1529 spin_unlock_bh(&ap_dev->lock);
1530}
1531EXPORT_SYMBOL(ap_cancel_message);
1532
1533/**
Felix Beck1749a812008-04-17 07:46:28 +02001534 * ap_poll_timeout(): AP receive polling for finished AP requests.
Felix Beckfe137232008-07-14 09:59:08 +02001535 * @unused: Unused pointer.
Felix Beck1749a812008-04-17 07:46:28 +02001536 *
Felix Beckfe137232008-07-14 09:59:08 +02001537 * Schedules the AP tasklet using a high resolution timer.
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001538 */
Felix Beckfe137232008-07-14 09:59:08 +02001539static enum hrtimer_restart ap_poll_timeout(struct hrtimer *unused)
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001540{
1541 tasklet_schedule(&ap_tasklet);
Felix Beckfe137232008-07-14 09:59:08 +02001542 return HRTIMER_NORESTART;
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001543}
1544
1545/**
Felix Beck1749a812008-04-17 07:46:28 +02001546 * ap_reset(): Reset a not responding AP device.
1547 * @ap_dev: Pointer to the AP device
1548 *
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +02001549 * Reset a not responding AP device and move all requests from the
1550 * pending queue to the request queue.
1551 */
1552static void ap_reset(struct ap_device *ap_dev)
1553{
1554 int rc;
1555
1556 ap_dev->reset = AP_RESET_IGNORE;
1557 atomic_sub(ap_dev->queue_count, &ap_poll_requests);
1558 ap_dev->queue_count = 0;
1559 list_splice_init(&ap_dev->pendingq, &ap_dev->requestq);
1560 ap_dev->requestq_count += ap_dev->pendingq_count;
1561 ap_dev->pendingq_count = 0;
1562 rc = ap_init_queue(ap_dev->qid);
1563 if (rc == -ENODEV)
1564 ap_dev->unregistered = 1;
Holger Dengler75464962011-12-01 13:32:23 +01001565 else
1566 __ap_schedule_poll_timer();
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +02001567}
1568
Christian Maaser43c207e62008-12-25 13:38:42 +01001569static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags)
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001570{
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001571 if (!ap_dev->unregistered) {
Ralph Wuerthnerc6a48262007-03-26 20:42:42 +02001572 if (ap_poll_queue(ap_dev, flags))
Ralph Wuerthner4e562962006-10-04 20:02:05 +02001573 ap_dev->unregistered = 1;
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +02001574 if (ap_dev->reset == AP_RESET_DO)
1575 ap_reset(ap_dev);
Ralph Wuerthnerc6a48262007-03-26 20:42:42 +02001576 }
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001577 return 0;
1578}
1579
Felix Beck1749a812008-04-17 07:46:28 +02001580/**
1581 * ap_poll_all(): Poll all AP devices.
1582 * @dummy: Unused variable
1583 *
1584 * Poll all AP devices on the bus in a round robin fashion. Continue
1585 * polling until bit 2^0 of the control flags is not set. If bit 2^1
1586 * of the control flags has been set arm the poll timer.
1587 */
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001588static void ap_poll_all(unsigned long dummy)
1589{
1590 unsigned long flags;
Ralph Wuerthnercf352ce2007-03-19 13:19:14 +01001591 struct ap_device *ap_dev;
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001592
Felix Beckcb17a632008-12-25 13:38:41 +01001593 /* Reset the indicator if interrupts are used. Thus new interrupts can
1594 * be received. Doing it in the beginning of the tasklet is therefor
1595 * important that no requests on any AP get lost.
1596 */
1597 if (ap_using_interrupts())
1598 xchg((u8 *)ap_interrupt_indicator, 0);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001599 do {
1600 flags = 0;
Christian Maaser43c207e62008-12-25 13:38:42 +01001601 spin_lock(&ap_device_list_lock);
Ralph Wuerthnercf352ce2007-03-19 13:19:14 +01001602 list_for_each_entry(ap_dev, &ap_device_list, list) {
Felix Beck95f15562009-09-11 10:28:51 +02001603 spin_lock(&ap_dev->lock);
Christian Maaser43c207e62008-12-25 13:38:42 +01001604 __ap_poll_device(ap_dev, &flags);
Felix Beck95f15562009-09-11 10:28:51 +02001605 spin_unlock(&ap_dev->lock);
Ralph Wuerthnercf352ce2007-03-19 13:19:14 +01001606 }
Christian Maaser43c207e62008-12-25 13:38:42 +01001607 spin_unlock(&ap_device_list_lock);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001608 } while (flags & 1);
1609 if (flags & 2)
1610 ap_schedule_poll_timer();
1611}
1612
1613/**
Felix Beck1749a812008-04-17 07:46:28 +02001614 * ap_poll_thread(): Thread that polls for finished requests.
1615 * @data: Unused pointer
1616 *
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001617 * AP bus poll thread. The purpose of this thread is to poll for
1618 * finished requests in a loop if there is a "free" cpu - that is
1619 * a cpu that doesn't have anything better to do. The polling stops
1620 * as soon as there is another task or if all messages have been
1621 * delivered.
1622 */
1623static int ap_poll_thread(void *data)
1624{
1625 DECLARE_WAITQUEUE(wait, current);
1626 unsigned long flags;
1627 int requests;
Ralph Wuerthnercf352ce2007-03-19 13:19:14 +01001628 struct ap_device *ap_dev;
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001629
Christian Borntraegerd83682b2006-10-06 16:38:22 +02001630 set_user_nice(current, 19);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001631 while (1) {
Felix Beck772f5472009-06-22 12:08:16 +02001632 if (ap_suspend_flag)
1633 return 0;
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001634 if (need_resched()) {
1635 schedule();
1636 continue;
1637 }
1638 add_wait_queue(&ap_poll_wait, &wait);
1639 set_current_state(TASK_INTERRUPTIBLE);
1640 if (kthread_should_stop())
1641 break;
1642 requests = atomic_read(&ap_poll_requests);
1643 if (requests <= 0)
1644 schedule();
1645 set_current_state(TASK_RUNNING);
1646 remove_wait_queue(&ap_poll_wait, &wait);
1647
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001648 flags = 0;
Christian Maaser43c207e62008-12-25 13:38:42 +01001649 spin_lock_bh(&ap_device_list_lock);
Ralph Wuerthnercf352ce2007-03-19 13:19:14 +01001650 list_for_each_entry(ap_dev, &ap_device_list, list) {
Felix Beck95f15562009-09-11 10:28:51 +02001651 spin_lock(&ap_dev->lock);
Christian Maaser43c207e62008-12-25 13:38:42 +01001652 __ap_poll_device(ap_dev, &flags);
Felix Beck95f15562009-09-11 10:28:51 +02001653 spin_unlock(&ap_dev->lock);
Ralph Wuerthnercf352ce2007-03-19 13:19:14 +01001654 }
Christian Maaser43c207e62008-12-25 13:38:42 +01001655 spin_unlock_bh(&ap_device_list_lock);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001656 }
1657 set_current_state(TASK_RUNNING);
1658 remove_wait_queue(&ap_poll_wait, &wait);
1659 return 0;
1660}
1661
1662static int ap_poll_thread_start(void)
1663{
1664 int rc;
1665
Felix Beck772f5472009-06-22 12:08:16 +02001666 if (ap_using_interrupts() || ap_suspend_flag)
Felix Beckcb17a632008-12-25 13:38:41 +01001667 return 0;
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001668 mutex_lock(&ap_poll_thread_mutex);
1669 if (!ap_poll_kthread) {
1670 ap_poll_kthread = kthread_run(ap_poll_thread, NULL, "appoll");
1671 rc = IS_ERR(ap_poll_kthread) ? PTR_ERR(ap_poll_kthread) : 0;
1672 if (rc)
1673 ap_poll_kthread = NULL;
1674 }
1675 else
1676 rc = 0;
1677 mutex_unlock(&ap_poll_thread_mutex);
1678 return rc;
1679}
1680
1681static void ap_poll_thread_stop(void)
1682{
1683 mutex_lock(&ap_poll_thread_mutex);
1684 if (ap_poll_kthread) {
1685 kthread_stop(ap_poll_kthread);
1686 ap_poll_kthread = NULL;
1687 }
1688 mutex_unlock(&ap_poll_thread_mutex);
1689}
1690
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +02001691/**
Felix Beck1749a812008-04-17 07:46:28 +02001692 * ap_request_timeout(): Handling of request timeouts
1693 * @data: Holds the AP device.
1694 *
1695 * Handles request timeouts.
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +02001696 */
1697static void ap_request_timeout(unsigned long data)
1698{
1699 struct ap_device *ap_dev = (struct ap_device *) data;
1700
Felix Beckcb17a632008-12-25 13:38:41 +01001701 if (ap_dev->reset == AP_RESET_ARMED) {
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +02001702 ap_dev->reset = AP_RESET_DO;
Felix Beckcb17a632008-12-25 13:38:41 +01001703
1704 if (ap_using_interrupts())
1705 tasklet_schedule(&ap_tasklet);
1706 }
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +02001707}
1708
Ralph Wuerthner13e742b2006-12-15 17:18:17 +01001709static void ap_reset_domain(void)
1710{
1711 int i;
1712
Ralph Wuerthner39aa7cf2007-10-12 16:11:29 +02001713 if (ap_domain_index != -1)
1714 for (i = 0; i < AP_DEVICES; i++)
1715 ap_reset_queue(AP_MKQID(i, ap_domain_index));
Ralph Wuerthner13e742b2006-12-15 17:18:17 +01001716}
1717
1718static void ap_reset_all(void)
Ralph Wuerthner85eca852006-12-08 15:54:07 +01001719{
1720 int i, j;
1721
1722 for (i = 0; i < AP_DOMAINS; i++)
1723 for (j = 0; j < AP_DEVICES; j++)
1724 ap_reset_queue(AP_MKQID(j, i));
1725}
1726
1727static struct reset_call ap_reset_call = {
Ralph Wuerthner13e742b2006-12-15 17:18:17 +01001728 .fn = ap_reset_all,
Ralph Wuerthner85eca852006-12-08 15:54:07 +01001729};
1730
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001731/**
Felix Beck1749a812008-04-17 07:46:28 +02001732 * ap_module_init(): The module initialization code.
1733 *
1734 * Initializes the module.
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001735 */
1736int __init ap_module_init(void)
1737{
1738 int rc, i;
1739
1740 if (ap_domain_index < -1 || ap_domain_index >= AP_DOMAINS) {
Martin Schwidefsky136f7a12008-12-25 13:39:46 +01001741 pr_warning("%d is not a valid cryptographic domain\n",
1742 ap_domain_index);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001743 return -EINVAL;
1744 }
Felix Beck5314af62009-09-22 22:58:51 +02001745 /* In resume callback we need to know if the user had set the domain.
1746 * If so, we can not just reset it.
1747 */
1748 if (ap_domain_index >= 0)
1749 user_set_domain = 1;
1750
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001751 if (ap_instructions_available() != 0) {
Martin Schwidefsky136f7a12008-12-25 13:39:46 +01001752 pr_warning("The hardware system does not support "
1753 "AP instructions\n");
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001754 return -ENODEV;
1755 }
Felix Beckcb17a632008-12-25 13:38:41 +01001756 if (ap_interrupts_available()) {
1757 isc_register(AP_ISC);
1758 ap_interrupt_indicator = s390_register_adapter_interrupt(
1759 &ap_interrupt_handler, NULL, AP_ISC);
1760 if (IS_ERR(ap_interrupt_indicator)) {
1761 ap_interrupt_indicator = NULL;
1762 isc_unregister(AP_ISC);
1763 }
1764 }
1765
Ralph Wuerthner85eca852006-12-08 15:54:07 +01001766 register_reset_call(&ap_reset_call);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001767
1768 /* Create /sys/bus/ap. */
1769 rc = bus_register(&ap_bus_type);
1770 if (rc)
1771 goto out;
1772 for (i = 0; ap_bus_attrs[i]; i++) {
1773 rc = bus_create_file(&ap_bus_type, ap_bus_attrs[i]);
1774 if (rc)
1775 goto out_bus;
1776 }
1777
1778 /* Create /sys/devices/ap. */
Mark McLoughlin035da162008-12-15 12:58:29 +00001779 ap_root_device = root_device_register("ap");
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001780 rc = IS_ERR(ap_root_device) ? PTR_ERR(ap_root_device) : 0;
1781 if (rc)
1782 goto out_bus;
1783
1784 ap_work_queue = create_singlethread_workqueue("kapwork");
1785 if (!ap_work_queue) {
1786 rc = -ENOMEM;
1787 goto out_root;
1788 }
1789
1790 if (ap_select_domain() == 0)
1791 ap_scan_bus(NULL);
1792
Felix Beck1749a812008-04-17 07:46:28 +02001793 /* Setup the AP bus rescan timer. */
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001794 init_timer(&ap_config_timer);
1795 ap_config_timer.function = ap_config_timeout;
1796 ap_config_timer.data = 0;
1797 ap_config_timer.expires = jiffies + ap_config_time * HZ;
1798 add_timer(&ap_config_timer);
1799
Felix Beckfe137232008-07-14 09:59:08 +02001800 /* Setup the high resultion poll timer.
1801 * If we are running under z/VM adjust polling to z/VM polling rate.
1802 */
1803 if (MACHINE_IS_VM)
1804 poll_timeout = 1500000;
Felix Beck93521312009-12-07 12:52:00 +01001805 spin_lock_init(&ap_poll_timer_lock);
Felix Beckfe137232008-07-14 09:59:08 +02001806 hrtimer_init(&ap_poll_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
1807 ap_poll_timer.function = ap_poll_timeout;
1808
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001809 /* Start the low priority AP bus poll thread. */
1810 if (ap_thread_flag) {
1811 rc = ap_poll_thread_start();
1812 if (rc)
1813 goto out_work;
1814 }
1815
1816 return 0;
1817
1818out_work:
1819 del_timer_sync(&ap_config_timer);
Felix Beckfe137232008-07-14 09:59:08 +02001820 hrtimer_cancel(&ap_poll_timer);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001821 destroy_workqueue(ap_work_queue);
1822out_root:
Mark McLoughlin035da162008-12-15 12:58:29 +00001823 root_device_unregister(ap_root_device);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001824out_bus:
1825 while (i--)
1826 bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);
1827 bus_unregister(&ap_bus_type);
1828out:
Ralph Wuerthner85eca852006-12-08 15:54:07 +01001829 unregister_reset_call(&ap_reset_call);
Felix Beckcb17a632008-12-25 13:38:41 +01001830 if (ap_using_interrupts()) {
1831 s390_unregister_adapter_interrupt(ap_interrupt_indicator, AP_ISC);
1832 isc_unregister(AP_ISC);
1833 }
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001834 return rc;
1835}
1836
1837static int __ap_match_all(struct device *dev, void *data)
1838{
1839 return 1;
1840}
1841
1842/**
Felix Beck1749a812008-04-17 07:46:28 +02001843 * ap_modules_exit(): The module termination code
1844 *
1845 * Terminates the module.
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001846 */
1847void ap_module_exit(void)
1848{
1849 int i;
1850 struct device *dev;
1851
Ralph Wuerthner13e742b2006-12-15 17:18:17 +01001852 ap_reset_domain();
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001853 ap_poll_thread_stop();
1854 del_timer_sync(&ap_config_timer);
Felix Beckfe137232008-07-14 09:59:08 +02001855 hrtimer_cancel(&ap_poll_timer);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001856 destroy_workqueue(ap_work_queue);
Ralph Wuerthner13e742b2006-12-15 17:18:17 +01001857 tasklet_kill(&ap_tasklet);
Mark McLoughlin035da162008-12-15 12:58:29 +00001858 root_device_unregister(ap_root_device);
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001859 while ((dev = bus_find_device(&ap_bus_type, NULL, NULL,
1860 __ap_match_all)))
1861 {
1862 device_unregister(dev);
1863 put_device(dev);
1864 }
1865 for (i = 0; ap_bus_attrs[i]; i++)
1866 bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);
1867 bus_unregister(&ap_bus_type);
Ralph Wuerthner85eca852006-12-08 15:54:07 +01001868 unregister_reset_call(&ap_reset_call);
Felix Beckcb17a632008-12-25 13:38:41 +01001869 if (ap_using_interrupts()) {
1870 s390_unregister_adapter_interrupt(ap_interrupt_indicator, AP_ISC);
1871 isc_unregister(AP_ISC);
1872 }
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001873}
1874
Martin Schwidefsky1534c382006-09-20 15:58:25 +02001875module_init(ap_module_init);
1876module_exit(ap_module_exit);