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