qdio_setup.c 15.3 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
J
Jan Glauber 已提交
2 3 4
/*
 * qdio queue initialization
 *
5
 * Copyright IBM Corp. 2008
J
Jan Glauber 已提交
6 7 8 9
 * Author(s): Jan Glauber <jang@linux.vnet.ibm.com>
 */
#include <linux/kernel.h>
#include <linux/slab.h>
10
#include <linux/export.h>
J
Jan Glauber 已提交
11 12 13 14 15 16 17 18 19 20
#include <asm/qdio.h>

#include "cio.h"
#include "css.h"
#include "device.h"
#include "ioasm.h"
#include "chsc.h"
#include "qdio.h"
#include "qdio_debug.h"

21 22
#define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer))

J
Jan Glauber 已提交
23
static struct kmem_cache *qdio_q_cache;
24 25
static struct kmem_cache *qdio_aob_cache;

26
struct qaob *qdio_allocate_aob(void)
27
{
28
	return kmem_cache_zalloc(qdio_aob_cache, GFP_ATOMIC);
29 30 31 32 33 34 35 36
}
EXPORT_SYMBOL_GPL(qdio_allocate_aob);

void qdio_release_aob(struct qaob *aob)
{
	kmem_cache_free(qdio_aob_cache, aob);
}
EXPORT_SYMBOL_GPL(qdio_release_aob);
J
Jan Glauber 已提交
37

38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
/**
 * qdio_free_buffers() - free qdio buffers
 * @buf: array of pointers to qdio buffers
 * @count: number of qdio buffers to free
 */
void qdio_free_buffers(struct qdio_buffer **buf, unsigned int count)
{
	int pos;

	for (pos = 0; pos < count; pos += QBUFF_PER_PAGE)
		free_page((unsigned long) buf[pos]);
}
EXPORT_SYMBOL_GPL(qdio_free_buffers);

/**
 * qdio_alloc_buffers() - allocate qdio buffers
 * @buf: array of pointers to qdio buffers
 * @count: number of qdio buffers to allocate
 */
int qdio_alloc_buffers(struct qdio_buffer **buf, unsigned int count)
{
	int pos;

	for (pos = 0; pos < count; pos += QBUFF_PER_PAGE) {
		buf[pos] = (void *) get_zeroed_page(GFP_KERNEL);
		if (!buf[pos]) {
			qdio_free_buffers(buf, count);
			return -ENOMEM;
		}
	}
	for (pos = 0; pos < count; pos++)
		if (pos % QBUFF_PER_PAGE)
			buf[pos] = buf[pos - 1] + 1;
	return 0;
}
EXPORT_SYMBOL_GPL(qdio_alloc_buffers);

/**
 * qdio_reset_buffers() - reset qdio buffers
 * @buf: array of pointers to qdio buffers
 * @count: number of qdio buffers that will be zeroed
 */
void qdio_reset_buffers(struct qdio_buffer **buf, unsigned int count)
{
	int pos;

	for (pos = 0; pos < count; pos++)
		memset(buf[pos], 0, sizeof(struct qdio_buffer));
}
EXPORT_SYMBOL_GPL(qdio_reset_buffers);

J
Jan Glauber 已提交
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
/*
 * qebsm is only available under 64bit but the adapter sets the feature
 * flag anyway, so we manually override it.
 */
static inline int qebsm_possible(void)
{
	return css_general_characteristics.qebsm;
}

/*
 * qib_param_field: pointer to 128 bytes or NULL, if no param field
 * nr_input_qs: pointer to nr_queues*128 words of data or NULL
 */
static void set_impl_params(struct qdio_irq *irq_ptr,
			    unsigned int qib_param_field_format,
			    unsigned char *qib_param_field,
			    unsigned long *input_slib_elements,
			    unsigned long *output_slib_elements)
{
	struct qdio_q *q;
	int i, j;

	if (!irq_ptr)
		return;

	irq_ptr->qib.pfmt = qib_param_field_format;
	if (qib_param_field)
		memcpy(irq_ptr->qib.parm, qib_param_field,
		       QDIO_MAX_BUFFERS_PER_Q);

	if (!input_slib_elements)
		goto output;

	for_each_input_queue(irq_ptr, q, i) {
		for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++)
			q->slib->slibe[j].parms =
				input_slib_elements[i * QDIO_MAX_BUFFERS_PER_Q + j];
	}
output:
	if (!output_slib_elements)
		return;

	for_each_output_queue(irq_ptr, q, i) {
		for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++)
			q->slib->slibe[j].parms =
				output_slib_elements[i * QDIO_MAX_BUFFERS_PER_Q + j];
	}
}

static int __qdio_allocate_qs(struct qdio_q **irq_ptr_qs, int nr_queues)
{
	struct qdio_q *q;
	int i;

	for (i = 0; i < nr_queues; i++) {
		q = kmem_cache_alloc(qdio_q_cache, GFP_KERNEL);
		if (!q)
			return -ENOMEM;

		q->slib = (struct slib *) __get_free_page(GFP_KERNEL);
		if (!q->slib) {
			kmem_cache_free(qdio_q_cache, q);
			return -ENOMEM;
		}
		irq_ptr_qs[i] = q;
	}
	return 0;
}

int qdio_allocate_qs(struct qdio_irq *irq_ptr, int nr_input_qs, int nr_output_qs)
{
	int rc;

	rc = __qdio_allocate_qs(irq_ptr->input_qs, nr_input_qs);
	if (rc)
		return rc;
	rc = __qdio_allocate_qs(irq_ptr->output_qs, nr_output_qs);
	return rc;
}

static void setup_queues_misc(struct qdio_q *q, struct qdio_irq *irq_ptr,
			      qdio_handler_t *handler, int i)
{
J
Jan Glauber 已提交
172
	struct slib *slib = q->slib;
J
Jan Glauber 已提交
173

J
Jan Glauber 已提交
174 175 176 177
	/* queue must be cleared for qdio_establish */
	memset(q, 0, sizeof(*q));
	memset(slib, 0, PAGE_SIZE);
	q->slib = slib;
J
Jan Glauber 已提交
178 179 180 181 182 183 184
	q->irq_ptr = irq_ptr;
	q->mask = 1 << (31 - i);
	q->nr = i;
	q->handler = handler;
}

static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr,
185
				void **sbals_array, int i)
J
Jan Glauber 已提交
186 187 188 189
{
	struct qdio_q *prev;
	int j;

190
	DBF_HEX(&q, sizeof(void *));
J
Jan Glauber 已提交
191 192 193
	q->sl = (struct sl *)((char *)q->slib + PAGE_SIZE / 2);

	/* fill in sbal */
194
	for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++)
J
Jan Glauber 已提交
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
		q->sbal[j] = *sbals_array++;

	/* fill in slib */
	if (i > 0) {
		prev = (q->is_input_q) ? irq_ptr->input_qs[i - 1]
			: irq_ptr->output_qs[i - 1];
		prev->slib->nsliba = (unsigned long)q->slib;
	}

	q->slib->sla = (unsigned long)q->sl;
	q->slib->slsba = (unsigned long)&q->slsb.val[0];

	/* fill in sl */
	for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++)
		q->sl->element[j].sbal = (unsigned long)q->sbal[j];
}

static void setup_queues(struct qdio_irq *irq_ptr,
			 struct qdio_initialize *qdio_init)
{
	struct qdio_q *q;
	void **input_sbal_array = qdio_init->input_sbal_addr_array;
	void **output_sbal_array = qdio_init->output_sbal_addr_array;
218 219
	struct qdio_outbuf_state *output_sbal_state_array =
				  qdio_init->output_sbal_state_array;
J
Jan Glauber 已提交
220 221 222
	int i;

	for_each_input_queue(irq_ptr, q, i) {
223
		DBF_EVENT("inq:%1d", i);
J
Jan Glauber 已提交
224 225 226
		setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i);

		q->is_input_q = 1;
227 228
		q->u.in.queue_start_poll = qdio_init->queue_start_poll_array ?
				qdio_init->queue_start_poll_array[i] : NULL;
229

230
		setup_storage_lists(q, irq_ptr, input_sbal_array, i);
J
Jan Glauber 已提交
231 232
		input_sbal_array += QDIO_MAX_BUFFERS_PER_Q;

233
		if (is_thinint_irq(irq_ptr)) {
J
Jan Glauber 已提交
234 235
			tasklet_init(&q->tasklet, tiqdio_inbound_processing,
				     (unsigned long) q);
236
		} else {
J
Jan Glauber 已提交
237 238
			tasklet_init(&q->tasklet, qdio_inbound_processing,
				     (unsigned long) q);
239
		}
J
Jan Glauber 已提交
240 241 242
	}

	for_each_output_queue(irq_ptr, q, i) {
243
		DBF_EVENT("outq:%1d", i);
J
Jan Glauber 已提交
244 245
		setup_queues_misc(q, irq_ptr, qdio_init->output_handler, i);

246 247 248
		q->u.out.sbal_state = output_sbal_state_array;
		output_sbal_state_array += QDIO_MAX_BUFFERS_PER_Q;

J
Jan Glauber 已提交
249
		q->is_input_q = 0;
250
		q->u.out.scan_threshold = qdio_init->scan_threshold;
251
		setup_storage_lists(q, irq_ptr, output_sbal_array, i);
J
Jan Glauber 已提交
252 253 254 255
		output_sbal_array += QDIO_MAX_BUFFERS_PER_Q;

		tasklet_init(&q->tasklet, qdio_outbound_processing,
			     (unsigned long) q);
256
		timer_setup(&q->u.out.timer, qdio_outbound_timer, 0);
J
Jan Glauber 已提交
257 258 259 260 261 262 263 264 265 266 267
	}
}

static void process_ac_flags(struct qdio_irq *irq_ptr, unsigned char qdioac)
{
	if (qdioac & AC1_SIGA_INPUT_NEEDED)
		irq_ptr->siga_flag.input = 1;
	if (qdioac & AC1_SIGA_OUTPUT_NEEDED)
		irq_ptr->siga_flag.output = 1;
	if (qdioac & AC1_SIGA_SYNC_NEEDED)
		irq_ptr->siga_flag.sync = 1;
J
Jan Glauber 已提交
268 269 270 271
	if (!(qdioac & AC1_AUTOMATIC_SYNC_ON_THININT))
		irq_ptr->siga_flag.sync_after_ai = 1;
	if (!(qdioac & AC1_AUTOMATIC_SYNC_ON_OUT_PCI))
		irq_ptr->siga_flag.sync_out_after_pci = 1;
J
Jan Glauber 已提交
272 273 274 275 276 277 278 279 280 281 282 283 284
}

static void check_and_setup_qebsm(struct qdio_irq *irq_ptr,
				  unsigned char qdioac, unsigned long token)
{
	if (!(irq_ptr->qib.rflags & QIB_RFLAGS_ENABLE_QEBSM))
		goto no_qebsm;
	if (!(qdioac & AC1_SC_QEBSM_AVAILABLE) ||
	    (!(qdioac & AC1_SC_QEBSM_ENABLED)))
		goto no_qebsm;

	irq_ptr->sch_token = token;

285 286
	DBF_EVENT("V=V:1");
	DBF_EVENT("%8lx", irq_ptr->sch_token);
J
Jan Glauber 已提交
287 288 289 290 291
	return;

no_qebsm:
	irq_ptr->sch_token = 0;
	irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM;
292
	DBF_EVENT("noV=V");
J
Jan Glauber 已提交
293 294
}

295 296 297 298 299 300 301
/*
 * If there is a qdio_irq we use the chsc_page and store the information
 * in the qdio_irq, otherwise we copy it to the specified structure.
 */
int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr,
			struct subchannel_id *schid,
			struct qdio_ssqd_desc *data)
J
Jan Glauber 已提交
302 303 304 305
{
	struct chsc_ssqd_area *ssqd;
	int rc;

306
	DBF_EVENT("getssqd:%4x", schid->sch_no);
307
	if (!irq_ptr) {
308
		ssqd = (struct chsc_ssqd_area *)__get_free_page(GFP_KERNEL);
309 310 311 312 313 314 315
		if (!ssqd)
			return -ENOMEM;
	} else {
		ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page;
	}

	rc = chsc_ssqd(*schid, ssqd);
J
Jan Glauber 已提交
316
	if (rc)
317
		goto out;
J
Jan Glauber 已提交
318 319 320

	if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) ||
	    !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) ||
321
	    (ssqd->qdio_ssqd.sch != schid->sch_no))
322 323 324 325 326 327 328
		rc = -EINVAL;

	if (!rc)
		memcpy(data, &ssqd->qdio_ssqd, sizeof(*data));

out:
	if (!irq_ptr)
329
		free_page((unsigned long)ssqd);
330 331

	return rc;
J
Jan Glauber 已提交
332 333 334 335 336 337 338
}

void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr)
{
	unsigned char qdioac;
	int rc;

339
	rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, &irq_ptr->ssqd_desc);
J
Jan Glauber 已提交
340
	if (rc) {
341 342
		DBF_ERROR("%4x ssqd ERR", irq_ptr->schid.sch_no);
		DBF_ERROR("rc:%x", rc);
J
Jan Glauber 已提交
343 344 345 346 347 348 349 350
		/* all flags set, worst case */
		qdioac = AC1_SIGA_INPUT_NEEDED | AC1_SIGA_OUTPUT_NEEDED |
			 AC1_SIGA_SYNC_NEEDED;
	} else
		qdioac = irq_ptr->ssqd_desc.qdioac1;

	check_and_setup_qebsm(irq_ptr, qdioac, irq_ptr->ssqd_desc.sch_token);
	process_ac_flags(irq_ptr, qdioac);
351 352
	DBF_EVENT("ac 1:%2x 2:%4x", qdioac, irq_ptr->ssqd_desc.qdioac2);
	DBF_EVENT("3:%4x qib:%4x", irq_ptr->ssqd_desc.qdioac3, irq_ptr->qib.ac);
J
Jan Glauber 已提交
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
}

void qdio_release_memory(struct qdio_irq *irq_ptr)
{
	struct qdio_q *q;
	int i;

	/*
	 * Must check queue array manually since irq_ptr->nr_input_queues /
	 * irq_ptr->nr_input_queues may not yet be set.
	 */
	for (i = 0; i < QDIO_MAX_QUEUES_PER_IRQ; i++) {
		q = irq_ptr->input_qs[i];
		if (q) {
			free_page((unsigned long) q->slib);
			kmem_cache_free(qdio_q_cache, q);
		}
	}
	for (i = 0; i < QDIO_MAX_QUEUES_PER_IRQ; i++) {
		q = irq_ptr->output_qs[i];
		if (q) {
374 375 376 377 378 379 380 381 382 383 384 385 386
			if (q->u.out.use_cq) {
				int n;

				for (n = 0; n < QDIO_MAX_BUFFERS_PER_Q; ++n) {
					struct qaob *aob = q->u.out.aobs[n];
					if (aob) {
						qdio_release_aob(aob);
						q->u.out.aobs[n] = NULL;
					}
				}

				qdio_disable_async_operation(&q->u.out);
			}
J
Jan Glauber 已提交
387 388 389 390
			free_page((unsigned long) q->slib);
			kmem_cache_free(qdio_q_cache, q);
		}
	}
391
	free_page((unsigned long) irq_ptr->qdr);
J
Jan Glauber 已提交
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
	free_page(irq_ptr->chsc_page);
	free_page((unsigned long) irq_ptr);
}

static void __qdio_allocate_fill_qdr(struct qdio_irq *irq_ptr,
				     struct qdio_q **irq_ptr_qs,
				     int i, int nr)
{
	irq_ptr->qdr->qdf0[i + nr].sliba =
		(unsigned long)irq_ptr_qs[i]->slib;

	irq_ptr->qdr->qdf0[i + nr].sla =
		(unsigned long)irq_ptr_qs[i]->sl;

	irq_ptr->qdr->qdf0[i + nr].slsba =
		(unsigned long)&irq_ptr_qs[i]->slsb.val[0];

409 410 411 412
	irq_ptr->qdr->qdf0[i + nr].akey = PAGE_DEFAULT_KEY >> 4;
	irq_ptr->qdr->qdf0[i + nr].bkey = PAGE_DEFAULT_KEY >> 4;
	irq_ptr->qdr->qdf0[i + nr].ckey = PAGE_DEFAULT_KEY >> 4;
	irq_ptr->qdr->qdf0[i + nr].dkey = PAGE_DEFAULT_KEY >> 4;
J
Jan Glauber 已提交
413 414 415 416 417 418 419 420
}

static void setup_qdr(struct qdio_irq *irq_ptr,
		      struct qdio_initialize *qdio_init)
{
	int i;

	irq_ptr->qdr->qfmt = qdio_init->q_format;
421
	irq_ptr->qdr->ac = qdio_init->qdr_ac;
J
Jan Glauber 已提交
422 423 424 425 426
	irq_ptr->qdr->iqdcnt = qdio_init->no_input_qs;
	irq_ptr->qdr->oqdcnt = qdio_init->no_output_qs;
	irq_ptr->qdr->iqdsz = sizeof(struct qdesfmt0) / 4; /* size in words */
	irq_ptr->qdr->oqdsz = sizeof(struct qdesfmt0) / 4;
	irq_ptr->qdr->qiba = (unsigned long)&irq_ptr->qib;
427
	irq_ptr->qdr->qkey = PAGE_DEFAULT_KEY >> 4;
J
Jan Glauber 已提交
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442

	for (i = 0; i < qdio_init->no_input_qs; i++)
		__qdio_allocate_fill_qdr(irq_ptr, irq_ptr->input_qs, i, 0);

	for (i = 0; i < qdio_init->no_output_qs; i++)
		__qdio_allocate_fill_qdr(irq_ptr, irq_ptr->output_qs, i,
					 qdio_init->no_input_qs);
}

static void setup_qib(struct qdio_irq *irq_ptr,
		      struct qdio_initialize *init_data)
{
	if (qebsm_possible())
		irq_ptr->qib.rflags |= QIB_RFLAGS_ENABLE_QEBSM;

443 444
	irq_ptr->qib.rflags |= init_data->qib_rflags;

J
Jan Glauber 已提交
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
	irq_ptr->qib.qfmt = init_data->q_format;
	if (init_data->no_input_qs)
		irq_ptr->qib.isliba =
			(unsigned long)(irq_ptr->input_qs[0]->slib);
	if (init_data->no_output_qs)
		irq_ptr->qib.osliba =
			(unsigned long)(irq_ptr->output_qs[0]->slib);
	memcpy(irq_ptr->qib.ebcnam, init_data->adapter_name, 8);
}

int qdio_setup_irq(struct qdio_initialize *init_data)
{
	struct ciw *ciw;
	struct qdio_irq *irq_ptr = init_data->cdev->private->qdio_data;
	int rc;

461 462 463 464 465 466 467 468 469
	memset(&irq_ptr->qib, 0, sizeof(irq_ptr->qib));
	memset(&irq_ptr->siga_flag, 0, sizeof(irq_ptr->siga_flag));
	memset(&irq_ptr->ccw, 0, sizeof(irq_ptr->ccw));
	memset(&irq_ptr->ssqd_desc, 0, sizeof(irq_ptr->ssqd_desc));
	memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));

	irq_ptr->debugfs_dev = irq_ptr->debugfs_perf = NULL;
	irq_ptr->sch_token = irq_ptr->state = irq_ptr->perf_stat_enabled = 0;

J
Jan Glauber 已提交
470 471 472 473 474 475 476
	/* wipes qib.ac, required by ar7063 */
	memset(irq_ptr->qdr, 0, sizeof(struct qdr));

	irq_ptr->int_parm = init_data->int_parm;
	irq_ptr->nr_input_qs = init_data->no_input_qs;
	irq_ptr->nr_output_qs = init_data->no_output_qs;
	irq_ptr->cdev = init_data->cdev;
S
Sebastian Ott 已提交
477
	ccw_device_get_schid(irq_ptr->cdev, &irq_ptr->schid);
J
Jan Glauber 已提交
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
	setup_queues(irq_ptr, init_data);

	setup_qib(irq_ptr, init_data);
	qdio_setup_thinint(irq_ptr);
	set_impl_params(irq_ptr, init_data->qib_param_field_format,
			init_data->qib_param_field,
			init_data->input_slib_elements,
			init_data->output_slib_elements);

	/* fill input and output descriptors */
	setup_qdr(irq_ptr, init_data);

	/* qdr, qib, sls, slsbs, slibs, sbales are filled now */

	/* get qdio commands */
	ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_EQUEUE);
	if (!ciw) {
495
		DBF_ERROR("%4x NO EQ", irq_ptr->schid.sch_no);
J
Jan Glauber 已提交
496 497 498 499 500 501 502
		rc = -EINVAL;
		goto out_err;
	}
	irq_ptr->equeue = *ciw;

	ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_AQUEUE);
	if (!ciw) {
503
		DBF_ERROR("%4x NO AQ", irq_ptr->schid.sch_no);
J
Jan Glauber 已提交
504 505 506 507 508 509
		rc = -EINVAL;
		goto out_err;
	}
	irq_ptr->aqueue = *ciw;

	/* set new interrupt handler */
510
	spin_lock_irq(get_ccwdev_lock(irq_ptr->cdev));
J
Jan Glauber 已提交
511 512
	irq_ptr->orig_handler = init_data->cdev->handler;
	init_data->cdev->handler = qdio_int_handler;
513
	spin_unlock_irq(get_ccwdev_lock(irq_ptr->cdev));
J
Jan Glauber 已提交
514 515 516 517 518 519 520 521 522 523 524
	return 0;
out_err:
	qdio_release_memory(irq_ptr);
	return rc;
}

void qdio_print_subchannel_info(struct qdio_irq *irq_ptr,
				struct ccw_device *cdev)
{
	char s[80];

525
	snprintf(s, 80, "qdio: %s %s on SC %x using "
526
		 "AI:%d QEBSM:%d PRI:%d TDD:%d SIGA:%s%s%s%s%s\n",
527 528 529 530 531 532 533 534 535 536 537
		 dev_name(&cdev->dev),
		 (irq_ptr->qib.qfmt == QDIO_QETH_QFMT) ? "OSA" :
			((irq_ptr->qib.qfmt == QDIO_ZFCP_QFMT) ? "ZFCP" : "HS"),
		 irq_ptr->schid.sch_no,
		 is_thinint_irq(irq_ptr),
		 (irq_ptr->sch_token) ? 1 : 0,
		 (irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) ? 1 : 0,
		 css_general_characteristics.aif_tdd,
		 (irq_ptr->siga_flag.input) ? "R" : " ",
		 (irq_ptr->siga_flag.output) ? "W" : " ",
		 (irq_ptr->siga_flag.sync) ? "S" : " ",
J
Jan Glauber 已提交
538 539
		 (irq_ptr->siga_flag.sync_after_ai) ? "A" : " ",
		 (irq_ptr->siga_flag.sync_out_after_pci) ? "P" : " ");
J
Jan Glauber 已提交
540
	printk(KERN_INFO "%s", s);
J
Jan Glauber 已提交
541 542
}

543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
int qdio_enable_async_operation(struct qdio_output_q *outq)
{
	outq->aobs = kzalloc(sizeof(struct qaob *) * QDIO_MAX_BUFFERS_PER_Q,
			     GFP_ATOMIC);
	if (!outq->aobs) {
		outq->use_cq = 0;
		return -ENOMEM;
	}
	outq->use_cq = 1;
	return 0;
}

void qdio_disable_async_operation(struct qdio_output_q *q)
{
	kfree(q->aobs);
	q->aobs = NULL;
	q->use_cq = 0;
}

J
Jan Glauber 已提交
562 563
int __init qdio_setup_init(void)
{
564 565
	int rc;

J
Jan Glauber 已提交
566 567 568 569 570
	qdio_q_cache = kmem_cache_create("qdio_q", sizeof(struct qdio_q),
					 256, 0, NULL);
	if (!qdio_q_cache)
		return -ENOMEM;

571 572 573 574 575 576 577 578 579 580
	qdio_aob_cache = kmem_cache_create("qdio_aob",
					sizeof(struct qaob),
					sizeof(struct qaob),
					0,
					NULL);
	if (!qdio_aob_cache) {
		rc = -ENOMEM;
		goto free_qdio_q_cache;
	}

J
Jan Glauber 已提交
581
	/* Check for OSA/FCP thin interrupts (bit 67). */
582 583
	DBF_EVENT("thinint:%1d",
		  (css_general_characteristics.aif_osa) ? 1 : 0);
J
Jan Glauber 已提交
584 585

	/* Check for QEBSM support in general (bit 58). */
586
	DBF_EVENT("cssQEBSM:%1d", (qebsm_possible()) ? 1 : 0);
587 588 589 590 591 592
	rc = 0;
out:
	return rc;
free_qdio_q_cache:
	kmem_cache_destroy(qdio_q_cache);
	goto out;
J
Jan Glauber 已提交
593 594
}

595
void qdio_setup_exit(void)
J
Jan Glauber 已提交
596
{
597
	kmem_cache_destroy(qdio_aob_cache);
J
Jan Glauber 已提交
598 599
	kmem_cache_destroy(qdio_q_cache);
}