Blame view

drivers/s390/cio/qdio_setup.c 15.3 KB
779e6e1c7   Jan Glauber   [S390] qdio: new ...
1
  /*
779e6e1c7   Jan Glauber   [S390] qdio: new ...
2
3
   * qdio queue initialization
   *
a53c8fab3   Heiko Carstens   s390/comments: un...
4
   * Copyright IBM Corp. 2008
779e6e1c7   Jan Glauber   [S390] qdio: new ...
5
6
7
8
   * Author(s): Jan Glauber <jang@linux.vnet.ibm.com>
   */
  #include <linux/kernel.h>
  #include <linux/slab.h>
3a4c5d596   Heiko Carstens   s390: add missing...
9
  #include <linux/export.h>
779e6e1c7   Jan Glauber   [S390] qdio: new ...
10
11
12
13
14
15
16
17
18
  #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"
5245c924c   Sebastian Ott   s390/qdio: add he...
19
  #define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer))
779e6e1c7   Jan Glauber   [S390] qdio: new ...
20
  static struct kmem_cache *qdio_q_cache;
104ea556e   frank.blaschka@de.ibm.com   qdio: support asy...
21
  static struct kmem_cache *qdio_aob_cache;
400d82915   Heiko Carstens   [S390] qdio: fix ...
22
  struct qaob *qdio_allocate_aob(void)
104ea556e   frank.blaschka@de.ibm.com   qdio: support asy...
23
  {
400d82915   Heiko Carstens   [S390] qdio: fix ...
24
  	return kmem_cache_zalloc(qdio_aob_cache, GFP_ATOMIC);
104ea556e   frank.blaschka@de.ibm.com   qdio: support asy...
25
26
27
28
29
30
31
32
  }
  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);
779e6e1c7   Jan Glauber   [S390] qdio: new ...
33

5245c924c   Sebastian Ott   s390/qdio: add he...
34
35
36
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
  /**
   * 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);
779e6e1c7   Jan Glauber   [S390] qdio: new ...
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  /*
   * 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)
  {
  #ifdef CONFIG_64BIT
  	return css_general_characteristics.qebsm;
  #endif
  	return 0;
  }
  
  /*
   * 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;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
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
  	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;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
144
145
146
147
148
149
  
  		q->slib = (struct slib *) __get_free_page(GFP_KERNEL);
  		if (!q->slib) {
  			kmem_cache_free(qdio_q_cache, q);
  			return -ENOMEM;
  		}
779e6e1c7   Jan Glauber   [S390] qdio: new ...
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
  		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)
  {
5382fe11d   Jan Glauber   [S390] qdio: remo...
169
  	struct slib *slib = q->slib;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
170

5382fe11d   Jan Glauber   [S390] qdio: remo...
171
172
173
174
  	/* queue must be cleared for qdio_establish */
  	memset(q, 0, sizeof(*q));
  	memset(slib, 0, PAGE_SIZE);
  	q->slib = slib;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
175
176
177
178
179
180
181
  	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,
22f993476   Jan Glauber   [S390] qdio: rewo...
182
  				void **sbals_array, int i)
779e6e1c7   Jan Glauber   [S390] qdio: new ...
183
184
185
  {
  	struct qdio_q *prev;
  	int j;
22f993476   Jan Glauber   [S390] qdio: rewo...
186
  	DBF_HEX(&q, sizeof(void *));
779e6e1c7   Jan Glauber   [S390] qdio: new ...
187
188
189
  	q->sl = (struct sl *)((char *)q->slib + PAGE_SIZE / 2);
  
  	/* fill in sbal */
ce1d80146   Jan Glauber   s390/qdio: rework...
190
  	for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++)
779e6e1c7   Jan Glauber   [S390] qdio: new ...
191
  		q->sbal[j] = *sbals_array++;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
192
193
194
195
196
197
198
199
200
201
202
203
204
205
  
  	/* 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];
779e6e1c7   Jan Glauber   [S390] qdio: new ...
206
207
208
209
210
  }
  
  static void setup_queues(struct qdio_irq *irq_ptr,
  			 struct qdio_initialize *qdio_init)
  {
779e6e1c7   Jan Glauber   [S390] qdio: new ...
211
212
213
  	struct qdio_q *q;
  	void **input_sbal_array = qdio_init->input_sbal_addr_array;
  	void **output_sbal_array = qdio_init->output_sbal_addr_array;
104ea556e   frank.blaschka@de.ibm.com   qdio: support asy...
214
215
  	struct qdio_outbuf_state *output_sbal_state_array =
  				  qdio_init->output_sbal_state_array;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
216
  	int i;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
217
  	for_each_input_queue(irq_ptr, q, i) {
104ea556e   frank.blaschka@de.ibm.com   qdio: support asy...
218
  		DBF_EVENT("inq:%1d", i);
779e6e1c7   Jan Glauber   [S390] qdio: new ...
219
220
221
  		setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i);
  
  		q->is_input_q = 1;
e58b0d902   Steffen Maier   [S390] qdio: fix ...
222
223
  		q->u.in.queue_start_poll = qdio_init->queue_start_poll_array ?
  				qdio_init->queue_start_poll_array[i] : NULL;
104ea556e   frank.blaschka@de.ibm.com   qdio: support asy...
224

22f993476   Jan Glauber   [S390] qdio: rewo...
225
  		setup_storage_lists(q, irq_ptr, input_sbal_array, i);
779e6e1c7   Jan Glauber   [S390] qdio: new ...
226
  		input_sbal_array += QDIO_MAX_BUFFERS_PER_Q;
104ea556e   frank.blaschka@de.ibm.com   qdio: support asy...
227
  		if (is_thinint_irq(irq_ptr)) {
779e6e1c7   Jan Glauber   [S390] qdio: new ...
228
229
  			tasklet_init(&q->tasklet, tiqdio_inbound_processing,
  				     (unsigned long) q);
104ea556e   frank.blaschka@de.ibm.com   qdio: support asy...
230
  		} else {
779e6e1c7   Jan Glauber   [S390] qdio: new ...
231
232
  			tasklet_init(&q->tasklet, qdio_inbound_processing,
  				     (unsigned long) q);
104ea556e   frank.blaschka@de.ibm.com   qdio: support asy...
233
  		}
779e6e1c7   Jan Glauber   [S390] qdio: new ...
234
235
236
  	}
  
  	for_each_output_queue(irq_ptr, q, i) {
22f993476   Jan Glauber   [S390] qdio: rewo...
237
  		DBF_EVENT("outq:%1d", i);
779e6e1c7   Jan Glauber   [S390] qdio: new ...
238
  		setup_queues_misc(q, irq_ptr, qdio_init->output_handler, i);
104ea556e   frank.blaschka@de.ibm.com   qdio: support asy...
239
240
  		q->u.out.sbal_state = output_sbal_state_array;
  		output_sbal_state_array += QDIO_MAX_BUFFERS_PER_Q;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
241
  		q->is_input_q = 0;
3d6c76ff3   Jan Glauber   [S390] qdio: outb...
242
  		q->u.out.scan_threshold = qdio_init->scan_threshold;
22f993476   Jan Glauber   [S390] qdio: rewo...
243
  		setup_storage_lists(q, irq_ptr, output_sbal_array, i);
779e6e1c7   Jan Glauber   [S390] qdio: new ...
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
  		output_sbal_array += QDIO_MAX_BUFFERS_PER_Q;
  
  		tasklet_init(&q->tasklet, qdio_outbound_processing,
  			     (unsigned long) q);
  		setup_timer(&q->u.out.timer, (void(*)(unsigned long))
  			    &qdio_outbound_timer, (unsigned long)q);
  	}
  }
  
  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;
90adac58d   Jan Glauber   [S390] qdio: clea...
261
262
263
264
  	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;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
265
266
267
268
269
  }
  
  static void check_and_setup_qebsm(struct qdio_irq *irq_ptr,
  				  unsigned char qdioac, unsigned long token)
  {
779e6e1c7   Jan Glauber   [S390] qdio: new ...
270
271
272
273
274
275
276
  	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;
22f993476   Jan Glauber   [S390] qdio: rewo...
277
278
  	DBF_EVENT("V=V:1");
  	DBF_EVENT("%8lx", irq_ptr->sch_token);
779e6e1c7   Jan Glauber   [S390] qdio: new ...
279
280
281
282
283
  	return;
  
  no_qebsm:
  	irq_ptr->sch_token = 0;
  	irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM;
22f993476   Jan Glauber   [S390] qdio: rewo...
284
  	DBF_EVENT("noV=V");
779e6e1c7   Jan Glauber   [S390] qdio: new ...
285
  }
bbd50e172   Jan Glauber   [S390] qdio: fix ...
286
287
288
289
290
291
292
  /*
   * 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)
779e6e1c7   Jan Glauber   [S390] qdio: new ...
293
294
295
  {
  	struct chsc_ssqd_area *ssqd;
  	int rc;
22f993476   Jan Glauber   [S390] qdio: rewo...
296
  	DBF_EVENT("getssqd:%4x", schid->sch_no);
da5b6cb16   Sebastian Ott   s390/qdio: cleanu...
297
  	if (!irq_ptr) {
bbd50e172   Jan Glauber   [S390] qdio: fix ...
298
  		ssqd = (struct chsc_ssqd_area *)__get_free_page(GFP_KERNEL);
da5b6cb16   Sebastian Ott   s390/qdio: cleanu...
299
300
301
302
303
304
305
  		if (!ssqd)
  			return -ENOMEM;
  	} else {
  		ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page;
  	}
  
  	rc = chsc_ssqd(*schid, ssqd);
779e6e1c7   Jan Glauber   [S390] qdio: new ...
306
  	if (rc)
da5b6cb16   Sebastian Ott   s390/qdio: cleanu...
307
  		goto out;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
308
309
310
  
  	if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) ||
  	    !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) ||
bbd50e172   Jan Glauber   [S390] qdio: fix ...
311
  	    (ssqd->qdio_ssqd.sch != schid->sch_no))
da5b6cb16   Sebastian Ott   s390/qdio: cleanu...
312
313
314
315
316
317
318
  		rc = -EINVAL;
  
  	if (!rc)
  		memcpy(data, &ssqd->qdio_ssqd, sizeof(*data));
  
  out:
  	if (!irq_ptr)
bbd50e172   Jan Glauber   [S390] qdio: fix ...
319
  		free_page((unsigned long)ssqd);
da5b6cb16   Sebastian Ott   s390/qdio: cleanu...
320
321
  
  	return rc;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
322
323
324
325
326
  }
  
  void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr)
  {
  	unsigned char qdioac;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
327
  	int rc;
da5b6cb16   Sebastian Ott   s390/qdio: cleanu...
328
  	rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, &irq_ptr->ssqd_desc);
779e6e1c7   Jan Glauber   [S390] qdio: new ...
329
  	if (rc) {
22f993476   Jan Glauber   [S390] qdio: rewo...
330
331
  		DBF_ERROR("%4x ssqd ERR", irq_ptr->schid.sch_no);
  		DBF_ERROR("rc:%x", rc);
779e6e1c7   Jan Glauber   [S390] qdio: new ...
332
333
334
335
336
337
338
339
  		/* 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);
61d84979a   Jan Glauber   [S390] qdio: log ...
340
341
  	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);
779e6e1c7   Jan Glauber   [S390] qdio: new ...
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
  }
  
  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) {
104ea556e   frank.blaschka@de.ibm.com   qdio: support asy...
363
364
365
366
367
368
369
370
371
372
373
374
375
  			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);
  			}
779e6e1c7   Jan Glauber   [S390] qdio: new ...
376
377
378
379
  			free_page((unsigned long) q->slib);
  			kmem_cache_free(qdio_q_cache, q);
  		}
  	}
3b8e3004a   Jan Glauber   [S390] qdio: make...
380
  	free_page((unsigned long) irq_ptr->qdr);
779e6e1c7   Jan Glauber   [S390] qdio: new ...
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
  	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];
d1bf85902   Heiko Carstens   [S390] cio: fix s...
397
398
399
400
  	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;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
401
402
403
404
405
406
407
408
  }
  
  static void setup_qdr(struct qdio_irq *irq_ptr,
  		      struct qdio_initialize *qdio_init)
  {
  	int i;
  
  	irq_ptr->qdr->qfmt = qdio_init->q_format;
dfe5bb506   Swen Schillig   [SCSI] qdio: base...
409
  	irq_ptr->qdr->ac = qdio_init->qdr_ac;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
410
411
412
413
414
  	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;
d1bf85902   Heiko Carstens   [S390] cio: fix s...
415
  	irq_ptr->qdr->qkey = PAGE_DEFAULT_KEY >> 4;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
416
417
418
419
420
421
422
423
424
425
426
427
428
429
  
  	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;
dcc18f48a   Christof Schmitt   [SCSI] zfcp: Enab...
430
  	irq_ptr->qib.rflags |= init_data->qib_rflags;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
  	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;
432ac5e04   Jan Glauber   [S390] qdio: opti...
446
447
448
449
450
451
452
453
  	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;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
454
455
456
457
458
459
  	/* 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;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
460
  	irq_ptr->cdev = init_data->cdev;
287a09332   Sebastian Ott   s390: use ccw_dev...
461
  	ccw_device_get_schid(irq_ptr->cdev, &irq_ptr->schid);
779e6e1c7   Jan Glauber   [S390] qdio: new ...
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
  	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) {
22f993476   Jan Glauber   [S390] qdio: rewo...
479
  		DBF_ERROR("%4x NO EQ", irq_ptr->schid.sch_no);
779e6e1c7   Jan Glauber   [S390] qdio: new ...
480
481
482
483
484
485
486
  		rc = -EINVAL;
  		goto out_err;
  	}
  	irq_ptr->equeue = *ciw;
  
  	ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_AQUEUE);
  	if (!ciw) {
22f993476   Jan Glauber   [S390] qdio: rewo...
487
  		DBF_ERROR("%4x NO AQ", irq_ptr->schid.sch_no);
779e6e1c7   Jan Glauber   [S390] qdio: new ...
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
  		rc = -EINVAL;
  		goto out_err;
  	}
  	irq_ptr->aqueue = *ciw;
  
  	/* set new interrupt handler */
  	irq_ptr->orig_handler = init_data->cdev->handler;
  	init_data->cdev->handler = qdio_int_handler;
  	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];
22f993476   Jan Glauber   [S390] qdio: rewo...
506
  	snprintf(s, 80, "qdio: %s %s on SC %x using "
6726a807c   Jan Glauber   s390/qdio: rename...
507
508
  		 "AI:%d QEBSM:%d PRI:%d TDD:%d SIGA:%s%s%s%s%s
  ",
22f993476   Jan Glauber   [S390] qdio: rewo...
509
510
511
512
513
514
515
516
517
518
519
  		 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" : " ",
90adac58d   Jan Glauber   [S390] qdio: clea...
520
521
  		 (irq_ptr->siga_flag.sync_after_ai) ? "A" : " ",
  		 (irq_ptr->siga_flag.sync_out_after_pci) ? "P" : " ");
75f627618   Jan Glauber   [S390] qdio: prev...
522
  	printk(KERN_INFO "%s", s);
779e6e1c7   Jan Glauber   [S390] qdio: new ...
523
  }
104ea556e   frank.blaschka@de.ibm.com   qdio: support asy...
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
  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;
  }
779e6e1c7   Jan Glauber   [S390] qdio: new ...
542
543
  int __init qdio_setup_init(void)
  {
104ea556e   frank.blaschka@de.ibm.com   qdio: support asy...
544
  	int rc;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
545
546
547
548
  	qdio_q_cache = kmem_cache_create("qdio_q", sizeof(struct qdio_q),
  					 256, 0, NULL);
  	if (!qdio_q_cache)
  		return -ENOMEM;
104ea556e   frank.blaschka@de.ibm.com   qdio: support asy...
549
550
551
552
553
554
555
556
557
  	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;
  	}
779e6e1c7   Jan Glauber   [S390] qdio: new ...
558
  	/* Check for OSA/FCP thin interrupts (bit 67). */
22f993476   Jan Glauber   [S390] qdio: rewo...
559
560
  	DBF_EVENT("thinint:%1d",
  		  (css_general_characteristics.aif_osa) ? 1 : 0);
779e6e1c7   Jan Glauber   [S390] qdio: new ...
561
562
  
  	/* Check for QEBSM support in general (bit 58). */
22f993476   Jan Glauber   [S390] qdio: rewo...
563
  	DBF_EVENT("cssQEBSM:%1d", (qebsm_possible()) ? 1 : 0);
104ea556e   frank.blaschka@de.ibm.com   qdio: support asy...
564
565
566
567
568
569
  	rc = 0;
  out:
  	return rc;
  free_qdio_q_cache:
  	kmem_cache_destroy(qdio_q_cache);
  	goto out;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
570
  }
3f1934bc1   Heiko Carstens   [S390] qdio: fix ...
571
  void qdio_setup_exit(void)
779e6e1c7   Jan Glauber   [S390] qdio: new ...
572
  {
104ea556e   frank.blaschka@de.ibm.com   qdio: support asy...
573
  	kmem_cache_destroy(qdio_aob_cache);
779e6e1c7   Jan Glauber   [S390] qdio: new ...
574
575
  	kmem_cache_destroy(qdio_q_cache);
  }