| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 1 | /* | 
 | 2 |  * driver/s390/cio/qdio_setup.c | 
 | 3 |  * | 
 | 4 |  * qdio queue initialization | 
 | 5 |  * | 
 | 6 |  * Copyright (C) IBM Corp. 2008 | 
 | 7 |  * Author(s): Jan Glauber <jang@linux.vnet.ibm.com> | 
 | 8 |  */ | 
 | 9 | #include <linux/kernel.h> | 
 | 10 | #include <linux/slab.h> | 
 | 11 | #include <asm/qdio.h> | 
 | 12 |  | 
 | 13 | #include "cio.h" | 
 | 14 | #include "css.h" | 
 | 15 | #include "device.h" | 
 | 16 | #include "ioasm.h" | 
 | 17 | #include "chsc.h" | 
 | 18 | #include "qdio.h" | 
 | 19 | #include "qdio_debug.h" | 
 | 20 |  | 
 | 21 | static struct kmem_cache *qdio_q_cache; | 
 | 22 |  | 
 | 23 | /* | 
 | 24 |  * qebsm is only available under 64bit but the adapter sets the feature | 
 | 25 |  * flag anyway, so we manually override it. | 
 | 26 |  */ | 
 | 27 | static inline int qebsm_possible(void) | 
 | 28 | { | 
 | 29 | #ifdef CONFIG_64BIT | 
 | 30 | 	return css_general_characteristics.qebsm; | 
 | 31 | #endif | 
 | 32 | 	return 0; | 
 | 33 | } | 
 | 34 |  | 
 | 35 | /* | 
 | 36 |  * qib_param_field: pointer to 128 bytes or NULL, if no param field | 
 | 37 |  * nr_input_qs: pointer to nr_queues*128 words of data or NULL | 
 | 38 |  */ | 
 | 39 | static void set_impl_params(struct qdio_irq *irq_ptr, | 
 | 40 | 			    unsigned int qib_param_field_format, | 
 | 41 | 			    unsigned char *qib_param_field, | 
 | 42 | 			    unsigned long *input_slib_elements, | 
 | 43 | 			    unsigned long *output_slib_elements) | 
 | 44 | { | 
 | 45 | 	struct qdio_q *q; | 
 | 46 | 	int i, j; | 
 | 47 |  | 
 | 48 | 	if (!irq_ptr) | 
 | 49 | 		return; | 
 | 50 |  | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 51 | 	irq_ptr->qib.pfmt = qib_param_field_format; | 
 | 52 | 	if (qib_param_field) | 
 | 53 | 		memcpy(irq_ptr->qib.parm, qib_param_field, | 
 | 54 | 		       QDIO_MAX_BUFFERS_PER_Q); | 
 | 55 |  | 
 | 56 | 	if (!input_slib_elements) | 
 | 57 | 		goto output; | 
 | 58 |  | 
 | 59 | 	for_each_input_queue(irq_ptr, q, i) { | 
 | 60 | 		for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) | 
 | 61 | 			q->slib->slibe[j].parms = | 
 | 62 | 				input_slib_elements[i * QDIO_MAX_BUFFERS_PER_Q + j]; | 
 | 63 | 	} | 
 | 64 | output: | 
 | 65 | 	if (!output_slib_elements) | 
 | 66 | 		return; | 
 | 67 |  | 
 | 68 | 	for_each_output_queue(irq_ptr, q, i) { | 
 | 69 | 		for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) | 
 | 70 | 			q->slib->slibe[j].parms = | 
 | 71 | 				output_slib_elements[i * QDIO_MAX_BUFFERS_PER_Q + j]; | 
 | 72 | 	} | 
 | 73 | } | 
 | 74 |  | 
 | 75 | static int __qdio_allocate_qs(struct qdio_q **irq_ptr_qs, int nr_queues) | 
 | 76 | { | 
 | 77 | 	struct qdio_q *q; | 
 | 78 | 	int i; | 
 | 79 |  | 
 | 80 | 	for (i = 0; i < nr_queues; i++) { | 
 | 81 | 		q = kmem_cache_alloc(qdio_q_cache, GFP_KERNEL); | 
 | 82 | 		if (!q) | 
 | 83 | 			return -ENOMEM; | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 84 |  | 
 | 85 | 		q->slib = (struct slib *) __get_free_page(GFP_KERNEL); | 
 | 86 | 		if (!q->slib) { | 
 | 87 | 			kmem_cache_free(qdio_q_cache, q); | 
 | 88 | 			return -ENOMEM; | 
 | 89 | 		} | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 90 | 		irq_ptr_qs[i] = q; | 
 | 91 | 	} | 
 | 92 | 	return 0; | 
 | 93 | } | 
 | 94 |  | 
 | 95 | int qdio_allocate_qs(struct qdio_irq *irq_ptr, int nr_input_qs, int nr_output_qs) | 
 | 96 | { | 
 | 97 | 	int rc; | 
 | 98 |  | 
 | 99 | 	rc = __qdio_allocate_qs(irq_ptr->input_qs, nr_input_qs); | 
 | 100 | 	if (rc) | 
 | 101 | 		return rc; | 
 | 102 | 	rc = __qdio_allocate_qs(irq_ptr->output_qs, nr_output_qs); | 
 | 103 | 	return rc; | 
 | 104 | } | 
 | 105 |  | 
 | 106 | static void setup_queues_misc(struct qdio_q *q, struct qdio_irq *irq_ptr, | 
 | 107 | 			      qdio_handler_t *handler, int i) | 
 | 108 | { | 
| Jan Glauber | 5382fe1 | 2010-05-17 10:00:16 +0200 | [diff] [blame] | 109 | 	struct slib *slib = q->slib; | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 110 |  | 
| Jan Glauber | 5382fe1 | 2010-05-17 10:00:16 +0200 | [diff] [blame] | 111 | 	/* queue must be cleared for qdio_establish */ | 
 | 112 | 	memset(q, 0, sizeof(*q)); | 
 | 113 | 	memset(slib, 0, PAGE_SIZE); | 
 | 114 | 	q->slib = slib; | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 115 | 	q->irq_ptr = irq_ptr; | 
 | 116 | 	q->mask = 1 << (31 - i); | 
 | 117 | 	q->nr = i; | 
 | 118 | 	q->handler = handler; | 
 | 119 | } | 
 | 120 |  | 
 | 121 | static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr, | 
| Jan Glauber | 22f9934 | 2008-12-25 13:38:46 +0100 | [diff] [blame] | 122 | 				void **sbals_array, int i) | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 123 | { | 
 | 124 | 	struct qdio_q *prev; | 
 | 125 | 	int j; | 
 | 126 |  | 
| Jan Glauber | 22f9934 | 2008-12-25 13:38:46 +0100 | [diff] [blame] | 127 | 	DBF_HEX(&q, sizeof(void *)); | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 128 | 	q->sl = (struct sl *)((char *)q->slib + PAGE_SIZE / 2); | 
 | 129 |  | 
 | 130 | 	/* fill in sbal */ | 
 | 131 | 	for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) { | 
 | 132 | 		q->sbal[j] = *sbals_array++; | 
| Jan Glauber | 7883097 | 2009-12-18 17:43:25 +0100 | [diff] [blame] | 133 | 		BUG_ON((unsigned long)q->sbal[j] & 0xff); | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 134 | 	} | 
 | 135 |  | 
 | 136 | 	/* fill in slib */ | 
 | 137 | 	if (i > 0) { | 
 | 138 | 		prev = (q->is_input_q) ? irq_ptr->input_qs[i - 1] | 
 | 139 | 			: irq_ptr->output_qs[i - 1]; | 
 | 140 | 		prev->slib->nsliba = (unsigned long)q->slib; | 
 | 141 | 	} | 
 | 142 |  | 
 | 143 | 	q->slib->sla = (unsigned long)q->sl; | 
 | 144 | 	q->slib->slsba = (unsigned long)&q->slsb.val[0]; | 
 | 145 |  | 
 | 146 | 	/* fill in sl */ | 
 | 147 | 	for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) | 
 | 148 | 		q->sl->element[j].sbal = (unsigned long)q->sbal[j]; | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 149 | } | 
 | 150 |  | 
 | 151 | static void setup_queues(struct qdio_irq *irq_ptr, | 
 | 152 | 			 struct qdio_initialize *qdio_init) | 
 | 153 | { | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 154 | 	struct qdio_q *q; | 
 | 155 | 	void **input_sbal_array = qdio_init->input_sbal_addr_array; | 
 | 156 | 	void **output_sbal_array = qdio_init->output_sbal_addr_array; | 
 | 157 | 	int i; | 
 | 158 |  | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 159 | 	for_each_input_queue(irq_ptr, q, i) { | 
| Jan Glauber | 22f9934 | 2008-12-25 13:38:46 +0100 | [diff] [blame] | 160 | 		DBF_EVENT("in-q:%1d", i); | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 161 | 		setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i); | 
 | 162 |  | 
 | 163 | 		q->is_input_q = 1; | 
| Jan Glauber | 22f9934 | 2008-12-25 13:38:46 +0100 | [diff] [blame] | 164 | 		setup_storage_lists(q, irq_ptr, input_sbal_array, i); | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 165 | 		input_sbal_array += QDIO_MAX_BUFFERS_PER_Q; | 
 | 166 |  | 
 | 167 | 		if (is_thinint_irq(irq_ptr)) | 
 | 168 | 			tasklet_init(&q->tasklet, tiqdio_inbound_processing, | 
 | 169 | 				     (unsigned long) q); | 
 | 170 | 		else | 
 | 171 | 			tasklet_init(&q->tasklet, qdio_inbound_processing, | 
 | 172 | 				     (unsigned long) q); | 
 | 173 | 	} | 
 | 174 |  | 
 | 175 | 	for_each_output_queue(irq_ptr, q, i) { | 
| Jan Glauber | 22f9934 | 2008-12-25 13:38:46 +0100 | [diff] [blame] | 176 | 		DBF_EVENT("outq:%1d", i); | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 177 | 		setup_queues_misc(q, irq_ptr, qdio_init->output_handler, i); | 
 | 178 |  | 
 | 179 | 		q->is_input_q = 0; | 
| Jan Glauber | 22f9934 | 2008-12-25 13:38:46 +0100 | [diff] [blame] | 180 | 		setup_storage_lists(q, irq_ptr, output_sbal_array, i); | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 181 | 		output_sbal_array += QDIO_MAX_BUFFERS_PER_Q; | 
 | 182 |  | 
 | 183 | 		tasklet_init(&q->tasklet, qdio_outbound_processing, | 
 | 184 | 			     (unsigned long) q); | 
 | 185 | 		setup_timer(&q->u.out.timer, (void(*)(unsigned long)) | 
 | 186 | 			    &qdio_outbound_timer, (unsigned long)q); | 
 | 187 | 	} | 
 | 188 | } | 
 | 189 |  | 
 | 190 | static void process_ac_flags(struct qdio_irq *irq_ptr, unsigned char qdioac) | 
 | 191 | { | 
 | 192 | 	if (qdioac & AC1_SIGA_INPUT_NEEDED) | 
 | 193 | 		irq_ptr->siga_flag.input = 1; | 
 | 194 | 	if (qdioac & AC1_SIGA_OUTPUT_NEEDED) | 
 | 195 | 		irq_ptr->siga_flag.output = 1; | 
 | 196 | 	if (qdioac & AC1_SIGA_SYNC_NEEDED) | 
 | 197 | 		irq_ptr->siga_flag.sync = 1; | 
 | 198 | 	if (qdioac & AC1_AUTOMATIC_SYNC_ON_THININT) | 
 | 199 | 		irq_ptr->siga_flag.no_sync_ti = 1; | 
 | 200 | 	if (qdioac & AC1_AUTOMATIC_SYNC_ON_OUT_PCI) | 
 | 201 | 		irq_ptr->siga_flag.no_sync_out_pci = 1; | 
 | 202 |  | 
 | 203 | 	if (irq_ptr->siga_flag.no_sync_out_pci && | 
 | 204 | 	    irq_ptr->siga_flag.no_sync_ti) | 
 | 205 | 		irq_ptr->siga_flag.no_sync_out_ti = 1; | 
 | 206 | } | 
 | 207 |  | 
 | 208 | static void check_and_setup_qebsm(struct qdio_irq *irq_ptr, | 
 | 209 | 				  unsigned char qdioac, unsigned long token) | 
 | 210 | { | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 211 | 	if (!(irq_ptr->qib.rflags & QIB_RFLAGS_ENABLE_QEBSM)) | 
 | 212 | 		goto no_qebsm; | 
 | 213 | 	if (!(qdioac & AC1_SC_QEBSM_AVAILABLE) || | 
 | 214 | 	    (!(qdioac & AC1_SC_QEBSM_ENABLED))) | 
 | 215 | 		goto no_qebsm; | 
 | 216 |  | 
 | 217 | 	irq_ptr->sch_token = token; | 
 | 218 |  | 
| Jan Glauber | 22f9934 | 2008-12-25 13:38:46 +0100 | [diff] [blame] | 219 | 	DBF_EVENT("V=V:1"); | 
 | 220 | 	DBF_EVENT("%8lx", irq_ptr->sch_token); | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 221 | 	return; | 
 | 222 |  | 
 | 223 | no_qebsm: | 
 | 224 | 	irq_ptr->sch_token = 0; | 
 | 225 | 	irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM; | 
| Jan Glauber | 22f9934 | 2008-12-25 13:38:46 +0100 | [diff] [blame] | 226 | 	DBF_EVENT("noV=V"); | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 227 | } | 
 | 228 |  | 
| Jan Glauber | bbd50e1 | 2008-12-25 13:38:43 +0100 | [diff] [blame] | 229 | /* | 
 | 230 |  * If there is a qdio_irq we use the chsc_page and store the information | 
 | 231 |  * in the qdio_irq, otherwise we copy it to the specified structure. | 
 | 232 |  */ | 
 | 233 | int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr, | 
 | 234 | 			struct subchannel_id *schid, | 
 | 235 | 			struct qdio_ssqd_desc *data) | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 236 | { | 
 | 237 | 	struct chsc_ssqd_area *ssqd; | 
 | 238 | 	int rc; | 
 | 239 |  | 
| Jan Glauber | 22f9934 | 2008-12-25 13:38:46 +0100 | [diff] [blame] | 240 | 	DBF_EVENT("getssqd:%4x", schid->sch_no); | 
| Jan Glauber | bbd50e1 | 2008-12-25 13:38:43 +0100 | [diff] [blame] | 241 | 	if (irq_ptr != NULL) | 
 | 242 | 		ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; | 
 | 243 | 	else | 
 | 244 | 		ssqd = (struct chsc_ssqd_area *)__get_free_page(GFP_KERNEL); | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 245 | 	memset(ssqd, 0, PAGE_SIZE); | 
 | 246 |  | 
 | 247 | 	ssqd->request = (struct chsc_header) { | 
 | 248 | 		.length = 0x0010, | 
 | 249 | 		.code	= 0x0024, | 
 | 250 | 	}; | 
| Jan Glauber | bbd50e1 | 2008-12-25 13:38:43 +0100 | [diff] [blame] | 251 | 	ssqd->first_sch = schid->sch_no; | 
 | 252 | 	ssqd->last_sch = schid->sch_no; | 
 | 253 | 	ssqd->ssid = schid->ssid; | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 254 |  | 
 | 255 | 	if (chsc(ssqd)) | 
 | 256 | 		return -EIO; | 
 | 257 | 	rc = chsc_error_from_response(ssqd->response.code); | 
 | 258 | 	if (rc) | 
 | 259 | 		return rc; | 
 | 260 |  | 
 | 261 | 	if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) || | 
 | 262 | 	    !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) || | 
| Jan Glauber | bbd50e1 | 2008-12-25 13:38:43 +0100 | [diff] [blame] | 263 | 	    (ssqd->qdio_ssqd.sch != schid->sch_no)) | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 264 | 		return -EINVAL; | 
 | 265 |  | 
| Jan Glauber | bbd50e1 | 2008-12-25 13:38:43 +0100 | [diff] [blame] | 266 | 	if (irq_ptr != NULL) | 
 | 267 | 		memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, | 
 | 268 | 		       sizeof(struct qdio_ssqd_desc)); | 
 | 269 | 	else { | 
 | 270 | 		memcpy(data, &ssqd->qdio_ssqd, | 
 | 271 | 		       sizeof(struct qdio_ssqd_desc)); | 
 | 272 | 		free_page((unsigned long)ssqd); | 
 | 273 | 	} | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 274 | 	return 0; | 
 | 275 | } | 
 | 276 |  | 
 | 277 | void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) | 
 | 278 | { | 
 | 279 | 	unsigned char qdioac; | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 280 | 	int rc; | 
 | 281 |  | 
| Jan Glauber | bbd50e1 | 2008-12-25 13:38:43 +0100 | [diff] [blame] | 282 | 	rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, NULL); | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 283 | 	if (rc) { | 
| Jan Glauber | 22f9934 | 2008-12-25 13:38:46 +0100 | [diff] [blame] | 284 | 		DBF_ERROR("%4x ssqd ERR", irq_ptr->schid.sch_no); | 
 | 285 | 		DBF_ERROR("rc:%x", rc); | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 286 | 		/* all flags set, worst case */ | 
 | 287 | 		qdioac = AC1_SIGA_INPUT_NEEDED | AC1_SIGA_OUTPUT_NEEDED | | 
 | 288 | 			 AC1_SIGA_SYNC_NEEDED; | 
 | 289 | 	} else | 
 | 290 | 		qdioac = irq_ptr->ssqd_desc.qdioac1; | 
 | 291 |  | 
 | 292 | 	check_and_setup_qebsm(irq_ptr, qdioac, irq_ptr->ssqd_desc.sch_token); | 
 | 293 | 	process_ac_flags(irq_ptr, qdioac); | 
| Jan Glauber | 22f9934 | 2008-12-25 13:38:46 +0100 | [diff] [blame] | 294 | 	DBF_EVENT("qdioac:%4x", qdioac); | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 295 | } | 
 | 296 |  | 
 | 297 | void qdio_release_memory(struct qdio_irq *irq_ptr) | 
 | 298 | { | 
 | 299 | 	struct qdio_q *q; | 
 | 300 | 	int i; | 
 | 301 |  | 
 | 302 | 	/* | 
 | 303 | 	 * Must check queue array manually since irq_ptr->nr_input_queues / | 
 | 304 | 	 * irq_ptr->nr_input_queues may not yet be set. | 
 | 305 | 	 */ | 
 | 306 | 	for (i = 0; i < QDIO_MAX_QUEUES_PER_IRQ; i++) { | 
 | 307 | 		q = irq_ptr->input_qs[i]; | 
 | 308 | 		if (q) { | 
 | 309 | 			free_page((unsigned long) q->slib); | 
 | 310 | 			kmem_cache_free(qdio_q_cache, q); | 
 | 311 | 		} | 
 | 312 | 	} | 
 | 313 | 	for (i = 0; i < QDIO_MAX_QUEUES_PER_IRQ; i++) { | 
 | 314 | 		q = irq_ptr->output_qs[i]; | 
 | 315 | 		if (q) { | 
 | 316 | 			free_page((unsigned long) q->slib); | 
 | 317 | 			kmem_cache_free(qdio_q_cache, q); | 
 | 318 | 		} | 
 | 319 | 	} | 
| Jan Glauber | 3b8e300 | 2008-08-01 16:39:17 +0200 | [diff] [blame] | 320 | 	free_page((unsigned long) irq_ptr->qdr); | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 321 | 	free_page(irq_ptr->chsc_page); | 
 | 322 | 	free_page((unsigned long) irq_ptr); | 
 | 323 | } | 
 | 324 |  | 
 | 325 | static void __qdio_allocate_fill_qdr(struct qdio_irq *irq_ptr, | 
 | 326 | 				     struct qdio_q **irq_ptr_qs, | 
 | 327 | 				     int i, int nr) | 
 | 328 | { | 
 | 329 | 	irq_ptr->qdr->qdf0[i + nr].sliba = | 
 | 330 | 		(unsigned long)irq_ptr_qs[i]->slib; | 
 | 331 |  | 
 | 332 | 	irq_ptr->qdr->qdf0[i + nr].sla = | 
 | 333 | 		(unsigned long)irq_ptr_qs[i]->sl; | 
 | 334 |  | 
 | 335 | 	irq_ptr->qdr->qdf0[i + nr].slsba = | 
 | 336 | 		(unsigned long)&irq_ptr_qs[i]->slsb.val[0]; | 
 | 337 |  | 
| Heiko Carstens | d1bf859 | 2010-02-26 22:37:30 +0100 | [diff] [blame] | 338 | 	irq_ptr->qdr->qdf0[i + nr].akey = PAGE_DEFAULT_KEY >> 4; | 
 | 339 | 	irq_ptr->qdr->qdf0[i + nr].bkey = PAGE_DEFAULT_KEY >> 4; | 
 | 340 | 	irq_ptr->qdr->qdf0[i + nr].ckey = PAGE_DEFAULT_KEY >> 4; | 
 | 341 | 	irq_ptr->qdr->qdf0[i + nr].dkey = PAGE_DEFAULT_KEY >> 4; | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 342 | } | 
 | 343 |  | 
 | 344 | static void setup_qdr(struct qdio_irq *irq_ptr, | 
 | 345 | 		      struct qdio_initialize *qdio_init) | 
 | 346 | { | 
 | 347 | 	int i; | 
 | 348 |  | 
 | 349 | 	irq_ptr->qdr->qfmt = qdio_init->q_format; | 
 | 350 | 	irq_ptr->qdr->iqdcnt = qdio_init->no_input_qs; | 
 | 351 | 	irq_ptr->qdr->oqdcnt = qdio_init->no_output_qs; | 
 | 352 | 	irq_ptr->qdr->iqdsz = sizeof(struct qdesfmt0) / 4; /* size in words */ | 
 | 353 | 	irq_ptr->qdr->oqdsz = sizeof(struct qdesfmt0) / 4; | 
 | 354 | 	irq_ptr->qdr->qiba = (unsigned long)&irq_ptr->qib; | 
| Heiko Carstens | d1bf859 | 2010-02-26 22:37:30 +0100 | [diff] [blame] | 355 | 	irq_ptr->qdr->qkey = PAGE_DEFAULT_KEY >> 4; | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 356 |  | 
 | 357 | 	for (i = 0; i < qdio_init->no_input_qs; i++) | 
 | 358 | 		__qdio_allocate_fill_qdr(irq_ptr, irq_ptr->input_qs, i, 0); | 
 | 359 |  | 
 | 360 | 	for (i = 0; i < qdio_init->no_output_qs; i++) | 
 | 361 | 		__qdio_allocate_fill_qdr(irq_ptr, irq_ptr->output_qs, i, | 
 | 362 | 					 qdio_init->no_input_qs); | 
 | 363 | } | 
 | 364 |  | 
 | 365 | static void setup_qib(struct qdio_irq *irq_ptr, | 
 | 366 | 		      struct qdio_initialize *init_data) | 
 | 367 | { | 
 | 368 | 	if (qebsm_possible()) | 
 | 369 | 		irq_ptr->qib.rflags |= QIB_RFLAGS_ENABLE_QEBSM; | 
 | 370 |  | 
| Christof Schmitt | dcc18f4 | 2010-07-16 15:37:41 +0200 | [diff] [blame] | 371 | 	irq_ptr->qib.rflags |= init_data->qib_rflags; | 
 | 372 |  | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 373 | 	irq_ptr->qib.qfmt = init_data->q_format; | 
 | 374 | 	if (init_data->no_input_qs) | 
 | 375 | 		irq_ptr->qib.isliba = | 
 | 376 | 			(unsigned long)(irq_ptr->input_qs[0]->slib); | 
 | 377 | 	if (init_data->no_output_qs) | 
 | 378 | 		irq_ptr->qib.osliba = | 
 | 379 | 			(unsigned long)(irq_ptr->output_qs[0]->slib); | 
 | 380 | 	memcpy(irq_ptr->qib.ebcnam, init_data->adapter_name, 8); | 
 | 381 | } | 
 | 382 |  | 
 | 383 | int qdio_setup_irq(struct qdio_initialize *init_data) | 
 | 384 | { | 
 | 385 | 	struct ciw *ciw; | 
 | 386 | 	struct qdio_irq *irq_ptr = init_data->cdev->private->qdio_data; | 
 | 387 | 	int rc; | 
 | 388 |  | 
| Jan Glauber | 432ac5e | 2010-02-26 22:37:37 +0100 | [diff] [blame] | 389 | 	memset(&irq_ptr->qib, 0, sizeof(irq_ptr->qib)); | 
 | 390 | 	memset(&irq_ptr->siga_flag, 0, sizeof(irq_ptr->siga_flag)); | 
 | 391 | 	memset(&irq_ptr->ccw, 0, sizeof(irq_ptr->ccw)); | 
 | 392 | 	memset(&irq_ptr->ssqd_desc, 0, sizeof(irq_ptr->ssqd_desc)); | 
 | 393 | 	memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat)); | 
 | 394 |  | 
 | 395 | 	irq_ptr->debugfs_dev = irq_ptr->debugfs_perf = NULL; | 
 | 396 | 	irq_ptr->sch_token = irq_ptr->state = irq_ptr->perf_stat_enabled = 0; | 
 | 397 |  | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 398 | 	/* wipes qib.ac, required by ar7063 */ | 
 | 399 | 	memset(irq_ptr->qdr, 0, sizeof(struct qdr)); | 
 | 400 |  | 
 | 401 | 	irq_ptr->int_parm = init_data->int_parm; | 
 | 402 | 	irq_ptr->nr_input_qs = init_data->no_input_qs; | 
 | 403 | 	irq_ptr->nr_output_qs = init_data->no_output_qs; | 
 | 404 |  | 
 | 405 | 	irq_ptr->schid = ccw_device_get_subchannel_id(init_data->cdev); | 
 | 406 | 	irq_ptr->cdev = init_data->cdev; | 
 | 407 | 	setup_queues(irq_ptr, init_data); | 
 | 408 |  | 
 | 409 | 	setup_qib(irq_ptr, init_data); | 
 | 410 | 	qdio_setup_thinint(irq_ptr); | 
 | 411 | 	set_impl_params(irq_ptr, init_data->qib_param_field_format, | 
 | 412 | 			init_data->qib_param_field, | 
 | 413 | 			init_data->input_slib_elements, | 
 | 414 | 			init_data->output_slib_elements); | 
 | 415 |  | 
 | 416 | 	/* fill input and output descriptors */ | 
 | 417 | 	setup_qdr(irq_ptr, init_data); | 
 | 418 |  | 
 | 419 | 	/* qdr, qib, sls, slsbs, slibs, sbales are filled now */ | 
 | 420 |  | 
 | 421 | 	/* get qdio commands */ | 
 | 422 | 	ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_EQUEUE); | 
 | 423 | 	if (!ciw) { | 
| Jan Glauber | 22f9934 | 2008-12-25 13:38:46 +0100 | [diff] [blame] | 424 | 		DBF_ERROR("%4x NO EQ", irq_ptr->schid.sch_no); | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 425 | 		rc = -EINVAL; | 
 | 426 | 		goto out_err; | 
 | 427 | 	} | 
 | 428 | 	irq_ptr->equeue = *ciw; | 
 | 429 |  | 
 | 430 | 	ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_AQUEUE); | 
 | 431 | 	if (!ciw) { | 
| Jan Glauber | 22f9934 | 2008-12-25 13:38:46 +0100 | [diff] [blame] | 432 | 		DBF_ERROR("%4x NO AQ", irq_ptr->schid.sch_no); | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 433 | 		rc = -EINVAL; | 
 | 434 | 		goto out_err; | 
 | 435 | 	} | 
 | 436 | 	irq_ptr->aqueue = *ciw; | 
 | 437 |  | 
 | 438 | 	/* set new interrupt handler */ | 
 | 439 | 	irq_ptr->orig_handler = init_data->cdev->handler; | 
 | 440 | 	init_data->cdev->handler = qdio_int_handler; | 
 | 441 | 	return 0; | 
 | 442 | out_err: | 
 | 443 | 	qdio_release_memory(irq_ptr); | 
 | 444 | 	return rc; | 
 | 445 | } | 
 | 446 |  | 
 | 447 | void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, | 
 | 448 | 				struct ccw_device *cdev) | 
 | 449 | { | 
 | 450 | 	char s[80]; | 
 | 451 |  | 
| Jan Glauber | 22f9934 | 2008-12-25 13:38:46 +0100 | [diff] [blame] | 452 | 	snprintf(s, 80, "qdio: %s %s on SC %x using " | 
 | 453 | 		 "AI:%d QEBSM:%d PCI:%d TDD:%d SIGA:%s%s%s%s%s%s\n", | 
 | 454 | 		 dev_name(&cdev->dev), | 
 | 455 | 		 (irq_ptr->qib.qfmt == QDIO_QETH_QFMT) ? "OSA" : | 
 | 456 | 			((irq_ptr->qib.qfmt == QDIO_ZFCP_QFMT) ? "ZFCP" : "HS"), | 
 | 457 | 		 irq_ptr->schid.sch_no, | 
 | 458 | 		 is_thinint_irq(irq_ptr), | 
 | 459 | 		 (irq_ptr->sch_token) ? 1 : 0, | 
 | 460 | 		 (irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) ? 1 : 0, | 
 | 461 | 		 css_general_characteristics.aif_tdd, | 
 | 462 | 		 (irq_ptr->siga_flag.input) ? "R" : " ", | 
 | 463 | 		 (irq_ptr->siga_flag.output) ? "W" : " ", | 
 | 464 | 		 (irq_ptr->siga_flag.sync) ? "S" : " ", | 
 | 465 | 		 (!irq_ptr->siga_flag.no_sync_ti) ? "A" : " ", | 
 | 466 | 		 (!irq_ptr->siga_flag.no_sync_out_ti) ? "O" : " ", | 
 | 467 | 		 (!irq_ptr->siga_flag.no_sync_out_pci) ? "P" : " "); | 
| Jan Glauber | 75f6276 | 2008-10-03 21:55:00 +0200 | [diff] [blame] | 468 | 	printk(KERN_INFO "%s", s); | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 469 | } | 
 | 470 |  | 
 | 471 | int __init qdio_setup_init(void) | 
 | 472 | { | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 473 | 	qdio_q_cache = kmem_cache_create("qdio_q", sizeof(struct qdio_q), | 
 | 474 | 					 256, 0, NULL); | 
 | 475 | 	if (!qdio_q_cache) | 
 | 476 | 		return -ENOMEM; | 
 | 477 |  | 
 | 478 | 	/* Check for OSA/FCP thin interrupts (bit 67). */ | 
| Jan Glauber | 22f9934 | 2008-12-25 13:38:46 +0100 | [diff] [blame] | 479 | 	DBF_EVENT("thinint:%1d", | 
 | 480 | 		  (css_general_characteristics.aif_osa) ? 1 : 0); | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 481 |  | 
 | 482 | 	/* Check for QEBSM support in general (bit 58). */ | 
| Jan Glauber | 22f9934 | 2008-12-25 13:38:46 +0100 | [diff] [blame] | 483 | 	DBF_EVENT("cssQEBSM:%1d", (qebsm_possible()) ? 1 : 0); | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 484 | 	return 0; | 
 | 485 | } | 
 | 486 |  | 
| Heiko Carstens | 3f1934b | 2008-08-01 16:39:20 +0200 | [diff] [blame] | 487 | void qdio_setup_exit(void) | 
| Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 488 | { | 
 | 489 | 	kmem_cache_destroy(qdio_q_cache); | 
 | 490 | } |