xref: /linux/drivers/s390/cio/qdio_setup.c (revision bbd50e172f75b1d12ef9b1bcf593b51a44199016)
1779e6e1cSJan Glauber /*
2779e6e1cSJan Glauber  * driver/s390/cio/qdio_setup.c
3779e6e1cSJan Glauber  *
4779e6e1cSJan Glauber  * qdio queue initialization
5779e6e1cSJan Glauber  *
6779e6e1cSJan Glauber  * Copyright (C) IBM Corp. 2008
7779e6e1cSJan Glauber  * Author(s): Jan Glauber <jang@linux.vnet.ibm.com>
8779e6e1cSJan Glauber  */
9779e6e1cSJan Glauber #include <linux/kernel.h>
10779e6e1cSJan Glauber #include <linux/slab.h>
11779e6e1cSJan Glauber #include <asm/qdio.h>
12779e6e1cSJan Glauber 
13779e6e1cSJan Glauber #include "cio.h"
14779e6e1cSJan Glauber #include "css.h"
15779e6e1cSJan Glauber #include "device.h"
16779e6e1cSJan Glauber #include "ioasm.h"
17779e6e1cSJan Glauber #include "chsc.h"
18779e6e1cSJan Glauber #include "qdio.h"
19779e6e1cSJan Glauber #include "qdio_debug.h"
20779e6e1cSJan Glauber 
21779e6e1cSJan Glauber static struct kmem_cache *qdio_q_cache;
22779e6e1cSJan Glauber 
23779e6e1cSJan Glauber /*
24779e6e1cSJan Glauber  * qebsm is only available under 64bit but the adapter sets the feature
25779e6e1cSJan Glauber  * flag anyway, so we manually override it.
26779e6e1cSJan Glauber  */
27779e6e1cSJan Glauber static inline int qebsm_possible(void)
28779e6e1cSJan Glauber {
29779e6e1cSJan Glauber #ifdef CONFIG_64BIT
30779e6e1cSJan Glauber 	return css_general_characteristics.qebsm;
31779e6e1cSJan Glauber #endif
32779e6e1cSJan Glauber 	return 0;
33779e6e1cSJan Glauber }
34779e6e1cSJan Glauber 
35779e6e1cSJan Glauber /*
36779e6e1cSJan Glauber  * qib_param_field: pointer to 128 bytes or NULL, if no param field
37779e6e1cSJan Glauber  * nr_input_qs: pointer to nr_queues*128 words of data or NULL
38779e6e1cSJan Glauber  */
39779e6e1cSJan Glauber static void set_impl_params(struct qdio_irq *irq_ptr,
40779e6e1cSJan Glauber 			    unsigned int qib_param_field_format,
41779e6e1cSJan Glauber 			    unsigned char *qib_param_field,
42779e6e1cSJan Glauber 			    unsigned long *input_slib_elements,
43779e6e1cSJan Glauber 			    unsigned long *output_slib_elements)
44779e6e1cSJan Glauber {
45779e6e1cSJan Glauber 	struct qdio_q *q;
46779e6e1cSJan Glauber 	int i, j;
47779e6e1cSJan Glauber 
48779e6e1cSJan Glauber 	if (!irq_ptr)
49779e6e1cSJan Glauber 		return;
50779e6e1cSJan Glauber 
51779e6e1cSJan Glauber 	WARN_ON((unsigned long)&irq_ptr->qib & 0xff);
52779e6e1cSJan Glauber 	irq_ptr->qib.pfmt = qib_param_field_format;
53779e6e1cSJan Glauber 	if (qib_param_field)
54779e6e1cSJan Glauber 		memcpy(irq_ptr->qib.parm, qib_param_field,
55779e6e1cSJan Glauber 		       QDIO_MAX_BUFFERS_PER_Q);
56779e6e1cSJan Glauber 
57779e6e1cSJan Glauber 	if (!input_slib_elements)
58779e6e1cSJan Glauber 		goto output;
59779e6e1cSJan Glauber 
60779e6e1cSJan Glauber 	for_each_input_queue(irq_ptr, q, i) {
61779e6e1cSJan Glauber 		for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++)
62779e6e1cSJan Glauber 			q->slib->slibe[j].parms =
63779e6e1cSJan Glauber 				input_slib_elements[i * QDIO_MAX_BUFFERS_PER_Q + j];
64779e6e1cSJan Glauber 	}
65779e6e1cSJan Glauber output:
66779e6e1cSJan Glauber 	if (!output_slib_elements)
67779e6e1cSJan Glauber 		return;
68779e6e1cSJan Glauber 
69779e6e1cSJan Glauber 	for_each_output_queue(irq_ptr, q, i) {
70779e6e1cSJan Glauber 		for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++)
71779e6e1cSJan Glauber 			q->slib->slibe[j].parms =
72779e6e1cSJan Glauber 				output_slib_elements[i * QDIO_MAX_BUFFERS_PER_Q + j];
73779e6e1cSJan Glauber 	}
74779e6e1cSJan Glauber }
75779e6e1cSJan Glauber 
76779e6e1cSJan Glauber static int __qdio_allocate_qs(struct qdio_q **irq_ptr_qs, int nr_queues)
77779e6e1cSJan Glauber {
78779e6e1cSJan Glauber 	struct qdio_q *q;
79779e6e1cSJan Glauber 	int i;
80779e6e1cSJan Glauber 
81779e6e1cSJan Glauber 	for (i = 0; i < nr_queues; i++) {
82779e6e1cSJan Glauber 		q = kmem_cache_alloc(qdio_q_cache, GFP_KERNEL);
83779e6e1cSJan Glauber 		if (!q)
84779e6e1cSJan Glauber 			return -ENOMEM;
85779e6e1cSJan Glauber 		WARN_ON((unsigned long)q & 0xff);
86779e6e1cSJan Glauber 
87779e6e1cSJan Glauber 		q->slib = (struct slib *) __get_free_page(GFP_KERNEL);
88779e6e1cSJan Glauber 		if (!q->slib) {
89779e6e1cSJan Glauber 			kmem_cache_free(qdio_q_cache, q);
90779e6e1cSJan Glauber 			return -ENOMEM;
91779e6e1cSJan Glauber 		}
92779e6e1cSJan Glauber 		WARN_ON((unsigned long)q->slib & 0x7ff);
93779e6e1cSJan Glauber 		irq_ptr_qs[i] = q;
94779e6e1cSJan Glauber 	}
95779e6e1cSJan Glauber 	return 0;
96779e6e1cSJan Glauber }
97779e6e1cSJan Glauber 
98779e6e1cSJan Glauber int qdio_allocate_qs(struct qdio_irq *irq_ptr, int nr_input_qs, int nr_output_qs)
99779e6e1cSJan Glauber {
100779e6e1cSJan Glauber 	int rc;
101779e6e1cSJan Glauber 
102779e6e1cSJan Glauber 	rc = __qdio_allocate_qs(irq_ptr->input_qs, nr_input_qs);
103779e6e1cSJan Glauber 	if (rc)
104779e6e1cSJan Glauber 		return rc;
105779e6e1cSJan Glauber 	rc = __qdio_allocate_qs(irq_ptr->output_qs, nr_output_qs);
106779e6e1cSJan Glauber 	return rc;
107779e6e1cSJan Glauber }
108779e6e1cSJan Glauber 
109779e6e1cSJan Glauber static void setup_queues_misc(struct qdio_q *q, struct qdio_irq *irq_ptr,
110779e6e1cSJan Glauber 			      qdio_handler_t *handler, int i)
111779e6e1cSJan Glauber {
112779e6e1cSJan Glauber 	/* must be cleared by every qdio_establish */
113779e6e1cSJan Glauber 	memset(q, 0, ((char *)&q->slib) - ((char *)q));
114779e6e1cSJan Glauber 	memset(q->slib, 0, PAGE_SIZE);
115779e6e1cSJan Glauber 
116779e6e1cSJan Glauber 	q->irq_ptr = irq_ptr;
117779e6e1cSJan Glauber 	q->mask = 1 << (31 - i);
118779e6e1cSJan Glauber 	q->nr = i;
119779e6e1cSJan Glauber 	q->handler = handler;
120779e6e1cSJan Glauber }
121779e6e1cSJan Glauber 
122779e6e1cSJan Glauber static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr,
123779e6e1cSJan Glauber 				void **sbals_array, char *dbf_text, int i)
124779e6e1cSJan Glauber {
125779e6e1cSJan Glauber 	struct qdio_q *prev;
126779e6e1cSJan Glauber 	int j;
127779e6e1cSJan Glauber 
128779e6e1cSJan Glauber 	QDIO_DBF_TEXT0(0, setup, dbf_text);
129779e6e1cSJan Glauber 	QDIO_DBF_HEX0(0, setup, &q, sizeof(void *));
130779e6e1cSJan Glauber 
131779e6e1cSJan Glauber 	q->sl = (struct sl *)((char *)q->slib + PAGE_SIZE / 2);
132779e6e1cSJan Glauber 
133779e6e1cSJan Glauber 	/* fill in sbal */
134779e6e1cSJan Glauber 	for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) {
135779e6e1cSJan Glauber 		q->sbal[j] = *sbals_array++;
136779e6e1cSJan Glauber 		WARN_ON((unsigned long)q->sbal[j] & 0xff);
137779e6e1cSJan Glauber 	}
138779e6e1cSJan Glauber 
139779e6e1cSJan Glauber 	/* fill in slib */
140779e6e1cSJan Glauber 	if (i > 0) {
141779e6e1cSJan Glauber 		prev = (q->is_input_q) ? irq_ptr->input_qs[i - 1]
142779e6e1cSJan Glauber 			: irq_ptr->output_qs[i - 1];
143779e6e1cSJan Glauber 		prev->slib->nsliba = (unsigned long)q->slib;
144779e6e1cSJan Glauber 	}
145779e6e1cSJan Glauber 
146779e6e1cSJan Glauber 	q->slib->sla = (unsigned long)q->sl;
147779e6e1cSJan Glauber 	q->slib->slsba = (unsigned long)&q->slsb.val[0];
148779e6e1cSJan Glauber 
149779e6e1cSJan Glauber 	/* fill in sl */
150779e6e1cSJan Glauber 	for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++)
151779e6e1cSJan Glauber 		q->sl->element[j].sbal = (unsigned long)q->sbal[j];
152779e6e1cSJan Glauber 
153779e6e1cSJan Glauber 	QDIO_DBF_TEXT2(0, setup, "sl-sb-b0");
154779e6e1cSJan Glauber 	QDIO_DBF_HEX2(0, setup, q->sl, sizeof(void *));
155779e6e1cSJan Glauber 	QDIO_DBF_HEX2(0, setup, &q->slsb, sizeof(void *));
156779e6e1cSJan Glauber 	QDIO_DBF_HEX2(0, setup, q->sbal, sizeof(void *));
157779e6e1cSJan Glauber }
158779e6e1cSJan Glauber 
159779e6e1cSJan Glauber static void setup_queues(struct qdio_irq *irq_ptr,
160779e6e1cSJan Glauber 			 struct qdio_initialize *qdio_init)
161779e6e1cSJan Glauber {
162779e6e1cSJan Glauber 	char dbf_text[20];
163779e6e1cSJan Glauber 	struct qdio_q *q;
164779e6e1cSJan Glauber 	void **input_sbal_array = qdio_init->input_sbal_addr_array;
165779e6e1cSJan Glauber 	void **output_sbal_array = qdio_init->output_sbal_addr_array;
166779e6e1cSJan Glauber 	int i;
167779e6e1cSJan Glauber 
16858eb27cdSJan Glauber 	sprintf(dbf_text, "qset%4x", qdio_init->cdev->private->schid.sch_no);
169779e6e1cSJan Glauber 	QDIO_DBF_TEXT0(0, setup, dbf_text);
170779e6e1cSJan Glauber 
171779e6e1cSJan Glauber 	for_each_input_queue(irq_ptr, q, i) {
172779e6e1cSJan Glauber 		sprintf(dbf_text, "in-q%4x", i);
173779e6e1cSJan Glauber 		setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i);
174779e6e1cSJan Glauber 
175779e6e1cSJan Glauber 		q->is_input_q = 1;
176779e6e1cSJan Glauber 		spin_lock_init(&q->u.in.lock);
177779e6e1cSJan Glauber 		setup_storage_lists(q, irq_ptr, input_sbal_array, dbf_text, i);
178779e6e1cSJan Glauber 		input_sbal_array += QDIO_MAX_BUFFERS_PER_Q;
179779e6e1cSJan Glauber 
180779e6e1cSJan Glauber 		if (is_thinint_irq(irq_ptr))
181779e6e1cSJan Glauber 			tasklet_init(&q->tasklet, tiqdio_inbound_processing,
182779e6e1cSJan Glauber 				     (unsigned long) q);
183779e6e1cSJan Glauber 		else
184779e6e1cSJan Glauber 			tasklet_init(&q->tasklet, qdio_inbound_processing,
185779e6e1cSJan Glauber 				     (unsigned long) q);
186779e6e1cSJan Glauber 	}
187779e6e1cSJan Glauber 
188779e6e1cSJan Glauber 	for_each_output_queue(irq_ptr, q, i) {
189779e6e1cSJan Glauber 		sprintf(dbf_text, "outq%4x", i);
190779e6e1cSJan Glauber 		setup_queues_misc(q, irq_ptr, qdio_init->output_handler, i);
191779e6e1cSJan Glauber 
192779e6e1cSJan Glauber 		q->is_input_q = 0;
193779e6e1cSJan Glauber 		setup_storage_lists(q, irq_ptr, output_sbal_array,
194779e6e1cSJan Glauber 				    dbf_text, i);
195779e6e1cSJan Glauber 		output_sbal_array += QDIO_MAX_BUFFERS_PER_Q;
196779e6e1cSJan Glauber 
197779e6e1cSJan Glauber 		tasklet_init(&q->tasklet, qdio_outbound_processing,
198779e6e1cSJan Glauber 			     (unsigned long) q);
199779e6e1cSJan Glauber 		setup_timer(&q->u.out.timer, (void(*)(unsigned long))
200779e6e1cSJan Glauber 			    &qdio_outbound_timer, (unsigned long)q);
201779e6e1cSJan Glauber 	}
202779e6e1cSJan Glauber }
203779e6e1cSJan Glauber 
204779e6e1cSJan Glauber static void process_ac_flags(struct qdio_irq *irq_ptr, unsigned char qdioac)
205779e6e1cSJan Glauber {
206779e6e1cSJan Glauber 	if (qdioac & AC1_SIGA_INPUT_NEEDED)
207779e6e1cSJan Glauber 		irq_ptr->siga_flag.input = 1;
208779e6e1cSJan Glauber 	if (qdioac & AC1_SIGA_OUTPUT_NEEDED)
209779e6e1cSJan Glauber 		irq_ptr->siga_flag.output = 1;
210779e6e1cSJan Glauber 	if (qdioac & AC1_SIGA_SYNC_NEEDED)
211779e6e1cSJan Glauber 		irq_ptr->siga_flag.sync = 1;
212779e6e1cSJan Glauber 	if (qdioac & AC1_AUTOMATIC_SYNC_ON_THININT)
213779e6e1cSJan Glauber 		irq_ptr->siga_flag.no_sync_ti = 1;
214779e6e1cSJan Glauber 	if (qdioac & AC1_AUTOMATIC_SYNC_ON_OUT_PCI)
215779e6e1cSJan Glauber 		irq_ptr->siga_flag.no_sync_out_pci = 1;
216779e6e1cSJan Glauber 
217779e6e1cSJan Glauber 	if (irq_ptr->siga_flag.no_sync_out_pci &&
218779e6e1cSJan Glauber 	    irq_ptr->siga_flag.no_sync_ti)
219779e6e1cSJan Glauber 		irq_ptr->siga_flag.no_sync_out_ti = 1;
220779e6e1cSJan Glauber }
221779e6e1cSJan Glauber 
222779e6e1cSJan Glauber static void check_and_setup_qebsm(struct qdio_irq *irq_ptr,
223779e6e1cSJan Glauber 				  unsigned char qdioac, unsigned long token)
224779e6e1cSJan Glauber {
225779e6e1cSJan Glauber 	char dbf_text[15];
226779e6e1cSJan Glauber 
227779e6e1cSJan Glauber 	if (!(irq_ptr->qib.rflags & QIB_RFLAGS_ENABLE_QEBSM))
228779e6e1cSJan Glauber 		goto no_qebsm;
229779e6e1cSJan Glauber 	if (!(qdioac & AC1_SC_QEBSM_AVAILABLE) ||
230779e6e1cSJan Glauber 	    (!(qdioac & AC1_SC_QEBSM_ENABLED)))
231779e6e1cSJan Glauber 		goto no_qebsm;
232779e6e1cSJan Glauber 
233779e6e1cSJan Glauber 	irq_ptr->sch_token = token;
234779e6e1cSJan Glauber 
235779e6e1cSJan Glauber 	QDIO_DBF_TEXT0(0, setup, "V=V:1");
236779e6e1cSJan Glauber 	sprintf(dbf_text, "%8lx", irq_ptr->sch_token);
237779e6e1cSJan Glauber 	QDIO_DBF_TEXT0(0, setup, dbf_text);
238779e6e1cSJan Glauber 	return;
239779e6e1cSJan Glauber 
240779e6e1cSJan Glauber no_qebsm:
241779e6e1cSJan Glauber 	irq_ptr->sch_token = 0;
242779e6e1cSJan Glauber 	irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM;
243779e6e1cSJan Glauber 	QDIO_DBF_TEXT0(0, setup, "noV=V");
244779e6e1cSJan Glauber }
245779e6e1cSJan Glauber 
246*bbd50e17SJan Glauber /*
247*bbd50e17SJan Glauber  * If there is a qdio_irq we use the chsc_page and store the information
248*bbd50e17SJan Glauber  * in the qdio_irq, otherwise we copy it to the specified structure.
249*bbd50e17SJan Glauber  */
250*bbd50e17SJan Glauber int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr,
251*bbd50e17SJan Glauber 			struct subchannel_id *schid,
252*bbd50e17SJan Glauber 			struct qdio_ssqd_desc *data)
253779e6e1cSJan Glauber {
254779e6e1cSJan Glauber 	struct chsc_ssqd_area *ssqd;
255779e6e1cSJan Glauber 	int rc;
256779e6e1cSJan Glauber 
257779e6e1cSJan Glauber 	QDIO_DBF_TEXT0(0, setup, "getssqd");
258*bbd50e17SJan Glauber 	if (irq_ptr != NULL)
259779e6e1cSJan Glauber 		ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page;
260*bbd50e17SJan Glauber 	else
261*bbd50e17SJan Glauber 		ssqd = (struct chsc_ssqd_area *)__get_free_page(GFP_KERNEL);
262779e6e1cSJan Glauber 	memset(ssqd, 0, PAGE_SIZE);
263779e6e1cSJan Glauber 
264779e6e1cSJan Glauber 	ssqd->request = (struct chsc_header) {
265779e6e1cSJan Glauber 		.length = 0x0010,
266779e6e1cSJan Glauber 		.code	= 0x0024,
267779e6e1cSJan Glauber 	};
268*bbd50e17SJan Glauber 	ssqd->first_sch = schid->sch_no;
269*bbd50e17SJan Glauber 	ssqd->last_sch = schid->sch_no;
270*bbd50e17SJan Glauber 	ssqd->ssid = schid->ssid;
271779e6e1cSJan Glauber 
272779e6e1cSJan Glauber 	if (chsc(ssqd))
273779e6e1cSJan Glauber 		return -EIO;
274779e6e1cSJan Glauber 	rc = chsc_error_from_response(ssqd->response.code);
275779e6e1cSJan Glauber 	if (rc)
276779e6e1cSJan Glauber 		return rc;
277779e6e1cSJan Glauber 
278779e6e1cSJan Glauber 	if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) ||
279779e6e1cSJan Glauber 	    !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) ||
280*bbd50e17SJan Glauber 	    (ssqd->qdio_ssqd.sch != schid->sch_no))
281779e6e1cSJan Glauber 		return -EINVAL;
282779e6e1cSJan Glauber 
283*bbd50e17SJan Glauber 	if (irq_ptr != NULL)
284779e6e1cSJan Glauber 		memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd,
285779e6e1cSJan Glauber 		       sizeof(struct qdio_ssqd_desc));
286*bbd50e17SJan Glauber 	else {
287*bbd50e17SJan Glauber 		memcpy(data, &ssqd->qdio_ssqd,
288*bbd50e17SJan Glauber 		       sizeof(struct qdio_ssqd_desc));
289*bbd50e17SJan Glauber 		free_page((unsigned long)ssqd);
290*bbd50e17SJan Glauber 	}
291779e6e1cSJan Glauber 	return 0;
292779e6e1cSJan Glauber }
293779e6e1cSJan Glauber 
294779e6e1cSJan Glauber void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr)
295779e6e1cSJan Glauber {
296779e6e1cSJan Glauber 	unsigned char qdioac;
297779e6e1cSJan Glauber 	char dbf_text[15];
298779e6e1cSJan Glauber 	int rc;
299779e6e1cSJan Glauber 
300*bbd50e17SJan Glauber 	rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, NULL);
301779e6e1cSJan Glauber 	if (rc) {
302779e6e1cSJan Glauber 		QDIO_DBF_TEXT2(0, setup, "ssqdasig");
30358eb27cdSJan Glauber 		sprintf(dbf_text, "schn%4x", irq_ptr->schid.sch_no);
304779e6e1cSJan Glauber 		QDIO_DBF_TEXT2(0, setup, dbf_text);
305779e6e1cSJan Glauber 		sprintf(dbf_text, "rc:%d", rc);
306779e6e1cSJan Glauber 		QDIO_DBF_TEXT2(0, setup, dbf_text);
307779e6e1cSJan Glauber 		/* all flags set, worst case */
308779e6e1cSJan Glauber 		qdioac = AC1_SIGA_INPUT_NEEDED | AC1_SIGA_OUTPUT_NEEDED |
309779e6e1cSJan Glauber 			 AC1_SIGA_SYNC_NEEDED;
310779e6e1cSJan Glauber 	} else
311779e6e1cSJan Glauber 		qdioac = irq_ptr->ssqd_desc.qdioac1;
312779e6e1cSJan Glauber 
313779e6e1cSJan Glauber 	check_and_setup_qebsm(irq_ptr, qdioac, irq_ptr->ssqd_desc.sch_token);
314779e6e1cSJan Glauber 	process_ac_flags(irq_ptr, qdioac);
315779e6e1cSJan Glauber 
316779e6e1cSJan Glauber 	sprintf(dbf_text, "qdioac%2x", qdioac);
317779e6e1cSJan Glauber 	QDIO_DBF_TEXT2(0, setup, dbf_text);
318779e6e1cSJan Glauber }
319779e6e1cSJan Glauber 
320779e6e1cSJan Glauber void qdio_release_memory(struct qdio_irq *irq_ptr)
321779e6e1cSJan Glauber {
322779e6e1cSJan Glauber 	struct qdio_q *q;
323779e6e1cSJan Glauber 	int i;
324779e6e1cSJan Glauber 
325779e6e1cSJan Glauber 	/*
326779e6e1cSJan Glauber 	 * Must check queue array manually since irq_ptr->nr_input_queues /
327779e6e1cSJan Glauber 	 * irq_ptr->nr_input_queues may not yet be set.
328779e6e1cSJan Glauber 	 */
329779e6e1cSJan Glauber 	for (i = 0; i < QDIO_MAX_QUEUES_PER_IRQ; i++) {
330779e6e1cSJan Glauber 		q = irq_ptr->input_qs[i];
331779e6e1cSJan Glauber 		if (q) {
332779e6e1cSJan Glauber 			free_page((unsigned long) q->slib);
333779e6e1cSJan Glauber 			kmem_cache_free(qdio_q_cache, q);
334779e6e1cSJan Glauber 		}
335779e6e1cSJan Glauber 	}
336779e6e1cSJan Glauber 	for (i = 0; i < QDIO_MAX_QUEUES_PER_IRQ; i++) {
337779e6e1cSJan Glauber 		q = irq_ptr->output_qs[i];
338779e6e1cSJan Glauber 		if (q) {
339779e6e1cSJan Glauber 			free_page((unsigned long) q->slib);
340779e6e1cSJan Glauber 			kmem_cache_free(qdio_q_cache, q);
341779e6e1cSJan Glauber 		}
342779e6e1cSJan Glauber 	}
3433b8e3004SJan Glauber 	free_page((unsigned long) irq_ptr->qdr);
344779e6e1cSJan Glauber 	free_page(irq_ptr->chsc_page);
345779e6e1cSJan Glauber 	free_page((unsigned long) irq_ptr);
346779e6e1cSJan Glauber }
347779e6e1cSJan Glauber 
348779e6e1cSJan Glauber static void __qdio_allocate_fill_qdr(struct qdio_irq *irq_ptr,
349779e6e1cSJan Glauber 				     struct qdio_q **irq_ptr_qs,
350779e6e1cSJan Glauber 				     int i, int nr)
351779e6e1cSJan Glauber {
352779e6e1cSJan Glauber 	irq_ptr->qdr->qdf0[i + nr].sliba =
353779e6e1cSJan Glauber 		(unsigned long)irq_ptr_qs[i]->slib;
354779e6e1cSJan Glauber 
355779e6e1cSJan Glauber 	irq_ptr->qdr->qdf0[i + nr].sla =
356779e6e1cSJan Glauber 		(unsigned long)irq_ptr_qs[i]->sl;
357779e6e1cSJan Glauber 
358779e6e1cSJan Glauber 	irq_ptr->qdr->qdf0[i + nr].slsba =
359779e6e1cSJan Glauber 		(unsigned long)&irq_ptr_qs[i]->slsb.val[0];
360779e6e1cSJan Glauber 
361779e6e1cSJan Glauber 	irq_ptr->qdr->qdf0[i + nr].akey = PAGE_DEFAULT_KEY;
362779e6e1cSJan Glauber 	irq_ptr->qdr->qdf0[i + nr].bkey = PAGE_DEFAULT_KEY;
363779e6e1cSJan Glauber 	irq_ptr->qdr->qdf0[i + nr].ckey = PAGE_DEFAULT_KEY;
364779e6e1cSJan Glauber 	irq_ptr->qdr->qdf0[i + nr].dkey = PAGE_DEFAULT_KEY;
365779e6e1cSJan Glauber }
366779e6e1cSJan Glauber 
367779e6e1cSJan Glauber static void setup_qdr(struct qdio_irq *irq_ptr,
368779e6e1cSJan Glauber 		      struct qdio_initialize *qdio_init)
369779e6e1cSJan Glauber {
370779e6e1cSJan Glauber 	int i;
371779e6e1cSJan Glauber 
372779e6e1cSJan Glauber 	irq_ptr->qdr->qfmt = qdio_init->q_format;
373779e6e1cSJan Glauber 	irq_ptr->qdr->iqdcnt = qdio_init->no_input_qs;
374779e6e1cSJan Glauber 	irq_ptr->qdr->oqdcnt = qdio_init->no_output_qs;
375779e6e1cSJan Glauber 	irq_ptr->qdr->iqdsz = sizeof(struct qdesfmt0) / 4; /* size in words */
376779e6e1cSJan Glauber 	irq_ptr->qdr->oqdsz = sizeof(struct qdesfmt0) / 4;
377779e6e1cSJan Glauber 	irq_ptr->qdr->qiba = (unsigned long)&irq_ptr->qib;
378779e6e1cSJan Glauber 	irq_ptr->qdr->qkey = PAGE_DEFAULT_KEY;
379779e6e1cSJan Glauber 
380779e6e1cSJan Glauber 	for (i = 0; i < qdio_init->no_input_qs; i++)
381779e6e1cSJan Glauber 		__qdio_allocate_fill_qdr(irq_ptr, irq_ptr->input_qs, i, 0);
382779e6e1cSJan Glauber 
383779e6e1cSJan Glauber 	for (i = 0; i < qdio_init->no_output_qs; i++)
384779e6e1cSJan Glauber 		__qdio_allocate_fill_qdr(irq_ptr, irq_ptr->output_qs, i,
385779e6e1cSJan Glauber 					 qdio_init->no_input_qs);
386779e6e1cSJan Glauber }
387779e6e1cSJan Glauber 
388779e6e1cSJan Glauber static void setup_qib(struct qdio_irq *irq_ptr,
389779e6e1cSJan Glauber 		      struct qdio_initialize *init_data)
390779e6e1cSJan Glauber {
391779e6e1cSJan Glauber 	if (qebsm_possible())
392779e6e1cSJan Glauber 		irq_ptr->qib.rflags |= QIB_RFLAGS_ENABLE_QEBSM;
393779e6e1cSJan Glauber 
394779e6e1cSJan Glauber 	irq_ptr->qib.qfmt = init_data->q_format;
395779e6e1cSJan Glauber 	if (init_data->no_input_qs)
396779e6e1cSJan Glauber 		irq_ptr->qib.isliba =
397779e6e1cSJan Glauber 			(unsigned long)(irq_ptr->input_qs[0]->slib);
398779e6e1cSJan Glauber 	if (init_data->no_output_qs)
399779e6e1cSJan Glauber 		irq_ptr->qib.osliba =
400779e6e1cSJan Glauber 			(unsigned long)(irq_ptr->output_qs[0]->slib);
401779e6e1cSJan Glauber 	memcpy(irq_ptr->qib.ebcnam, init_data->adapter_name, 8);
402779e6e1cSJan Glauber }
403779e6e1cSJan Glauber 
404779e6e1cSJan Glauber int qdio_setup_irq(struct qdio_initialize *init_data)
405779e6e1cSJan Glauber {
406779e6e1cSJan Glauber 	struct ciw *ciw;
407779e6e1cSJan Glauber 	struct qdio_irq *irq_ptr = init_data->cdev->private->qdio_data;
408779e6e1cSJan Glauber 	int rc;
409779e6e1cSJan Glauber 
410779e6e1cSJan Glauber 	memset(irq_ptr, 0, ((char *)&irq_ptr->qdr) - ((char *)irq_ptr));
411779e6e1cSJan Glauber 	/* wipes qib.ac, required by ar7063 */
412779e6e1cSJan Glauber 	memset(irq_ptr->qdr, 0, sizeof(struct qdr));
413779e6e1cSJan Glauber 
414779e6e1cSJan Glauber 	irq_ptr->int_parm = init_data->int_parm;
415779e6e1cSJan Glauber 	irq_ptr->nr_input_qs = init_data->no_input_qs;
416779e6e1cSJan Glauber 	irq_ptr->nr_output_qs = init_data->no_output_qs;
417779e6e1cSJan Glauber 
418779e6e1cSJan Glauber 	irq_ptr->schid = ccw_device_get_subchannel_id(init_data->cdev);
419779e6e1cSJan Glauber 	irq_ptr->cdev = init_data->cdev;
420779e6e1cSJan Glauber 	setup_queues(irq_ptr, init_data);
421779e6e1cSJan Glauber 
422779e6e1cSJan Glauber 	setup_qib(irq_ptr, init_data);
423779e6e1cSJan Glauber 	qdio_setup_thinint(irq_ptr);
424779e6e1cSJan Glauber 	set_impl_params(irq_ptr, init_data->qib_param_field_format,
425779e6e1cSJan Glauber 			init_data->qib_param_field,
426779e6e1cSJan Glauber 			init_data->input_slib_elements,
427779e6e1cSJan Glauber 			init_data->output_slib_elements);
428779e6e1cSJan Glauber 
429779e6e1cSJan Glauber 	/* fill input and output descriptors */
430779e6e1cSJan Glauber 	setup_qdr(irq_ptr, init_data);
431779e6e1cSJan Glauber 
432779e6e1cSJan Glauber 	/* qdr, qib, sls, slsbs, slibs, sbales are filled now */
433779e6e1cSJan Glauber 
434779e6e1cSJan Glauber 	/* get qdio commands */
435779e6e1cSJan Glauber 	ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_EQUEUE);
436779e6e1cSJan Glauber 	if (!ciw) {
437779e6e1cSJan Glauber 		QDIO_DBF_TEXT2(1, setup, "no eq");
438779e6e1cSJan Glauber 		rc = -EINVAL;
439779e6e1cSJan Glauber 		goto out_err;
440779e6e1cSJan Glauber 	}
441779e6e1cSJan Glauber 	irq_ptr->equeue = *ciw;
442779e6e1cSJan Glauber 
443779e6e1cSJan Glauber 	ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_AQUEUE);
444779e6e1cSJan Glauber 	if (!ciw) {
445779e6e1cSJan Glauber 		QDIO_DBF_TEXT2(1, setup, "no aq");
446779e6e1cSJan Glauber 		rc = -EINVAL;
447779e6e1cSJan Glauber 		goto out_err;
448779e6e1cSJan Glauber 	}
449779e6e1cSJan Glauber 	irq_ptr->aqueue = *ciw;
450779e6e1cSJan Glauber 
451779e6e1cSJan Glauber 	/* set new interrupt handler */
452779e6e1cSJan Glauber 	irq_ptr->orig_handler = init_data->cdev->handler;
453779e6e1cSJan Glauber 	init_data->cdev->handler = qdio_int_handler;
454779e6e1cSJan Glauber 	return 0;
455779e6e1cSJan Glauber out_err:
456779e6e1cSJan Glauber 	qdio_release_memory(irq_ptr);
457779e6e1cSJan Glauber 	return rc;
458779e6e1cSJan Glauber }
459779e6e1cSJan Glauber 
460779e6e1cSJan Glauber void qdio_print_subchannel_info(struct qdio_irq *irq_ptr,
461779e6e1cSJan Glauber 				struct ccw_device *cdev)
462779e6e1cSJan Glauber {
463779e6e1cSJan Glauber 	char s[80];
464779e6e1cSJan Glauber 
46575f62761SJan Glauber 	sprintf(s, "qdio: %s ", dev_name(&cdev->dev));
466779e6e1cSJan Glauber 	switch (irq_ptr->qib.qfmt) {
467779e6e1cSJan Glauber 	case QDIO_QETH_QFMT:
46875f62761SJan Glauber 		sprintf(s + strlen(s), "OSA ");
469779e6e1cSJan Glauber 		break;
470779e6e1cSJan Glauber 	case QDIO_ZFCP_QFMT:
471779e6e1cSJan Glauber 		sprintf(s + strlen(s), "ZFCP ");
472779e6e1cSJan Glauber 		break;
473779e6e1cSJan Glauber 	case QDIO_IQDIO_QFMT:
47475f62761SJan Glauber 		sprintf(s + strlen(s), "HS ");
475779e6e1cSJan Glauber 		break;
476779e6e1cSJan Glauber 	}
47775f62761SJan Glauber 	sprintf(s + strlen(s), "on SC %x using ", irq_ptr->schid.sch_no);
47875f62761SJan Glauber 	sprintf(s + strlen(s), "AI:%d ", is_thinint_irq(irq_ptr));
47975f62761SJan Glauber 	sprintf(s + strlen(s), "QEBSM:%d ", (irq_ptr->sch_token) ? 1 : 0);
48075f62761SJan Glauber 	sprintf(s + strlen(s), "PCI:%d ",
48175f62761SJan Glauber 		(irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) ? 1 : 0);
48275f62761SJan Glauber 	sprintf(s + strlen(s), "TDD:%d ", css_general_characteristics.aif_tdd);
48375f62761SJan Glauber 	sprintf(s + strlen(s), "SIGA:");
48475f62761SJan Glauber 	sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.input) ? "R" : " ");
48575f62761SJan Glauber 	sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.output) ? "W" : " ");
48675f62761SJan Glauber 	sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.sync) ? "S" : " ");
48775f62761SJan Glauber 	sprintf(s + strlen(s), "%s",
48875f62761SJan Glauber 		(!irq_ptr->siga_flag.no_sync_ti) ? "A" : " ");
48975f62761SJan Glauber 	sprintf(s + strlen(s), "%s",
49075f62761SJan Glauber 		(!irq_ptr->siga_flag.no_sync_out_ti) ? "O" : " ");
49175f62761SJan Glauber 	sprintf(s + strlen(s), "%s",
49275f62761SJan Glauber 		(!irq_ptr->siga_flag.no_sync_out_pci) ? "P" : " ");
493779e6e1cSJan Glauber 	sprintf(s + strlen(s), "\n");
49475f62761SJan Glauber 	printk(KERN_INFO "%s", s);
495779e6e1cSJan Glauber }
496779e6e1cSJan Glauber 
497779e6e1cSJan Glauber int __init qdio_setup_init(void)
498779e6e1cSJan Glauber {
499779e6e1cSJan Glauber 	char dbf_text[15];
500779e6e1cSJan Glauber 
501779e6e1cSJan Glauber 	qdio_q_cache = kmem_cache_create("qdio_q", sizeof(struct qdio_q),
502779e6e1cSJan Glauber 					 256, 0, NULL);
503779e6e1cSJan Glauber 	if (!qdio_q_cache)
504779e6e1cSJan Glauber 		return -ENOMEM;
505779e6e1cSJan Glauber 
506779e6e1cSJan Glauber 	/* Check for OSA/FCP thin interrupts (bit 67). */
507779e6e1cSJan Glauber 	sprintf(dbf_text, "thini%1x",
508779e6e1cSJan Glauber 		(css_general_characteristics.aif_osa) ? 1 : 0);
509779e6e1cSJan Glauber 	QDIO_DBF_TEXT0(0, setup, dbf_text);
510779e6e1cSJan Glauber 
511779e6e1cSJan Glauber 	/* Check for QEBSM support in general (bit 58). */
512779e6e1cSJan Glauber 	sprintf(dbf_text, "cssQBS:%1x",
513779e6e1cSJan Glauber 		(qebsm_possible()) ? 1 : 0);
514779e6e1cSJan Glauber 	QDIO_DBF_TEXT0(0, setup, dbf_text);
515779e6e1cSJan Glauber 	return 0;
516779e6e1cSJan Glauber }
517779e6e1cSJan Glauber 
5183f1934bcSHeiko Carstens void qdio_setup_exit(void)
519779e6e1cSJan Glauber {
520779e6e1cSJan Glauber 	kmem_cache_destroy(qdio_q_cache);
521779e6e1cSJan Glauber }
522