1 /* 2 * linux/drivers/s390/cio/thinint_qdio.c 3 * 4 * thin interrupt support for qdio 5 * 6 * Copyright 2000-2008 IBM Corp. 7 * Author(s): Utz Bacher <utz.bacher@de.ibm.com> 8 * Cornelia Huck <cornelia.huck@de.ibm.com> 9 * Jan Glauber <jang@linux.vnet.ibm.com> 10 */ 11 #include <linux/io.h> 12 #include <asm/atomic.h> 13 #include <asm/debug.h> 14 #include <asm/qdio.h> 15 #include <asm/airq.h> 16 #include <asm/isc.h> 17 18 #include "cio.h" 19 #include "ioasm.h" 20 #include "qdio.h" 21 #include "qdio_debug.h" 22 #include "qdio_perf.h" 23 24 /* 25 * Restriction: only 63 iqdio subchannels would have its own indicator, 26 * after that, subsequent subchannels share one indicator 27 */ 28 #define TIQDIO_NR_NONSHARED_IND 63 29 #define TIQDIO_NR_INDICATORS (TIQDIO_NR_NONSHARED_IND + 1) 30 #define TIQDIO_SHARED_IND 63 31 32 /* list of thin interrupt input queues */ 33 static LIST_HEAD(tiq_list); 34 35 /* adapter local summary indicator */ 36 static unsigned char *tiqdio_alsi; 37 38 /* device state change indicators */ 39 struct indicator_t { 40 u32 ind; /* u32 because of compare-and-swap performance */ 41 atomic_t count; /* use count, 0 or 1 for non-shared indicators */ 42 }; 43 static struct indicator_t *q_indicators; 44 45 static void tiqdio_tasklet_fn(unsigned long data); 46 static DECLARE_TASKLET(tiqdio_tasklet, tiqdio_tasklet_fn, 0); 47 48 static int css_qdio_omit_svs; 49 50 static inline unsigned long do_clear_global_summary(void) 51 { 52 register unsigned long __fn asm("1") = 3; 53 register unsigned long __tmp asm("2"); 54 register unsigned long __time asm("3"); 55 56 asm volatile( 57 " .insn rre,0xb2650000,2,0" 58 : "+d" (__fn), "=d" (__tmp), "=d" (__time)); 59 return __time; 60 } 61 62 /* returns addr for the device state change indicator */ 63 static u32 *get_indicator(void) 64 { 65 int i; 66 67 for (i = 0; i < TIQDIO_NR_NONSHARED_IND; i++) 68 if (!atomic_read(&q_indicators[i].count)) { 69 atomic_set(&q_indicators[i].count, 1); 70 return &q_indicators[i].ind; 71 } 72 73 /* use the shared indicator */ 74 atomic_inc(&q_indicators[TIQDIO_SHARED_IND].count); 75 return &q_indicators[TIQDIO_SHARED_IND].ind; 76 } 77 78 static void put_indicator(u32 *addr) 79 { 80 int i; 81 82 if (!addr) 83 return; 84 i = ((unsigned long)addr - (unsigned long)q_indicators) / 85 sizeof(struct indicator_t); 86 atomic_dec(&q_indicators[i].count); 87 } 88 89 void tiqdio_add_input_queues(struct qdio_irq *irq_ptr) 90 { 91 struct qdio_q *q; 92 int i; 93 94 /* No TDD facility? If we must use SIGA-s we can also omit SVS. */ 95 if (!css_qdio_omit_svs && irq_ptr->siga_flag.sync) 96 css_qdio_omit_svs = 1; 97 98 for_each_input_queue(irq_ptr, q, i) { 99 list_add_rcu(&q->entry, &tiq_list); 100 synchronize_rcu(); 101 } 102 xchg(irq_ptr->dsci, 1); 103 tasklet_schedule(&tiqdio_tasklet); 104 } 105 106 /* 107 * we cannot stop the tiqdio tasklet here since it is for all 108 * thinint qdio devices and it must run as long as there is a 109 * thinint device left 110 */ 111 void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) 112 { 113 struct qdio_q *q; 114 int i; 115 116 for (i = 0; i < irq_ptr->nr_input_qs; i++) { 117 q = irq_ptr->input_qs[i]; 118 /* if establish triggered an error */ 119 if (!q || !q->entry.prev || !q->entry.next) 120 continue; 121 list_del_rcu(&q->entry); 122 synchronize_rcu(); 123 } 124 } 125 126 static inline int tiqdio_inbound_q_done(struct qdio_q *q) 127 { 128 unsigned char state; 129 130 if (!atomic_read(&q->nr_buf_used)) 131 return 1; 132 133 qdio_siga_sync_q(q); 134 get_buf_state(q, q->first_to_check, &state); 135 136 if (state == SLSB_P_INPUT_PRIMED) 137 /* more work coming */ 138 return 0; 139 return 1; 140 } 141 142 static inline int shared_ind(struct qdio_irq *irq_ptr) 143 { 144 return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind; 145 } 146 147 static void __tiqdio_inbound_processing(struct qdio_q *q) 148 { 149 qdio_perf_stat_inc(&perf_stats.thinint_inbound); 150 qdio_sync_after_thinint(q); 151 152 /* 153 * Maybe we have work on our outbound queues... at least 154 * we have to check the PCI capable queues. 155 */ 156 qdio_check_outbound_after_thinint(q); 157 158 again: 159 if (!qdio_inbound_q_moved(q)) 160 return; 161 162 qdio_kick_inbound_handler(q); 163 164 if (!tiqdio_inbound_q_done(q)) { 165 qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop); 166 goto again; 167 } 168 169 qdio_stop_polling(q); 170 /* 171 * We need to check again to not lose initiative after 172 * resetting the ACK state. 173 */ 174 if (!tiqdio_inbound_q_done(q)) { 175 qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop2); 176 goto again; 177 } 178 } 179 180 void tiqdio_inbound_processing(unsigned long data) 181 { 182 struct qdio_q *q = (struct qdio_q *)data; 183 184 __tiqdio_inbound_processing(q); 185 } 186 187 /* check for work on all inbound thinint queues */ 188 static void tiqdio_tasklet_fn(unsigned long data) 189 { 190 struct qdio_q *q; 191 192 qdio_perf_stat_inc(&perf_stats.tasklet_thinint); 193 again: 194 195 /* protect tiq_list entries, only changed in activate or shutdown */ 196 rcu_read_lock(); 197 198 list_for_each_entry_rcu(q, &tiq_list, entry) 199 /* only process queues from changed sets */ 200 if (*q->irq_ptr->dsci) { 201 202 /* only clear it if the indicator is non-shared */ 203 if (!shared_ind(q->irq_ptr)) 204 xchg(q->irq_ptr->dsci, 0); 205 /* 206 * don't call inbound processing directly since 207 * that could starve other thinint queues 208 */ 209 tasklet_schedule(&q->tasklet); 210 } 211 212 rcu_read_unlock(); 213 214 /* 215 * if we used the shared indicator clear it now after all queues 216 * were processed 217 */ 218 if (atomic_read(&q_indicators[TIQDIO_SHARED_IND].count)) { 219 xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0); 220 221 /* prevent racing */ 222 if (*tiqdio_alsi) 223 xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 1); 224 } 225 226 /* check for more work */ 227 if (*tiqdio_alsi) { 228 xchg(tiqdio_alsi, 0); 229 qdio_perf_stat_inc(&perf_stats.tasklet_thinint_loop); 230 goto again; 231 } 232 } 233 234 /** 235 * tiqdio_thinint_handler - thin interrupt handler for qdio 236 * @ind: pointer to adapter local summary indicator 237 * @drv_data: NULL 238 */ 239 static void tiqdio_thinint_handler(void *ind, void *drv_data) 240 { 241 qdio_perf_stat_inc(&perf_stats.thin_int); 242 243 /* 244 * SVS only when needed: issue SVS to benefit from iqdio interrupt 245 * avoidance (SVS clears adapter interrupt suppression overwrite) 246 */ 247 if (!css_qdio_omit_svs) 248 do_clear_global_summary(); 249 250 /* 251 * reset local summary indicator (tiqdio_alsi) to stop adapter 252 * interrupts for now, the tasklet will clean all dsci's 253 */ 254 xchg((u8 *)ind, 0); 255 tasklet_hi_schedule(&tiqdio_tasklet); 256 } 257 258 static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) 259 { 260 struct scssc_area *scssc_area; 261 char dbf_text[15]; 262 void *ptr; 263 int rc; 264 265 scssc_area = (struct scssc_area *)irq_ptr->chsc_page; 266 memset(scssc_area, 0, PAGE_SIZE); 267 268 if (reset) { 269 scssc_area->summary_indicator_addr = 0; 270 scssc_area->subchannel_indicator_addr = 0; 271 } else { 272 scssc_area->summary_indicator_addr = virt_to_phys(tiqdio_alsi); 273 scssc_area->subchannel_indicator_addr = 274 virt_to_phys(irq_ptr->dsci); 275 } 276 277 scssc_area->request = (struct chsc_header) { 278 .length = 0x0fe0, 279 .code = 0x0021, 280 }; 281 scssc_area->operation_code = 0; 282 scssc_area->ks = PAGE_DEFAULT_KEY; 283 scssc_area->kc = PAGE_DEFAULT_KEY; 284 scssc_area->isc = QDIO_AIRQ_ISC; 285 scssc_area->schid = irq_ptr->schid; 286 287 /* enable the time delay disablement facility */ 288 if (css_general_characteristics.aif_tdd) 289 scssc_area->word_with_d_bit = 0x10000000; 290 291 rc = chsc(scssc_area); 292 if (rc) 293 return -EIO; 294 295 rc = chsc_error_from_response(scssc_area->response.code); 296 if (rc) { 297 sprintf(dbf_text, "sidR%4x", scssc_area->response.code); 298 QDIO_DBF_TEXT1(0, trace, dbf_text); 299 QDIO_DBF_TEXT1(0, setup, dbf_text); 300 ptr = &scssc_area->response; 301 QDIO_DBF_HEX2(1, setup, &ptr, QDIO_DBF_SETUP_LEN); 302 return rc; 303 } 304 305 QDIO_DBF_TEXT2(0, setup, "setscind"); 306 QDIO_DBF_HEX2(0, setup, &scssc_area->summary_indicator_addr, 307 sizeof(unsigned long)); 308 QDIO_DBF_HEX2(0, setup, &scssc_area->subchannel_indicator_addr, 309 sizeof(unsigned long)); 310 return 0; 311 } 312 313 /* allocate non-shared indicators and shared indicator */ 314 int __init tiqdio_allocate_memory(void) 315 { 316 q_indicators = kzalloc(sizeof(struct indicator_t) * TIQDIO_NR_INDICATORS, 317 GFP_KERNEL); 318 if (!q_indicators) 319 return -ENOMEM; 320 return 0; 321 } 322 323 void tiqdio_free_memory(void) 324 { 325 kfree(q_indicators); 326 } 327 328 int __init tiqdio_register_thinints(void) 329 { 330 char dbf_text[20]; 331 332 isc_register(QDIO_AIRQ_ISC); 333 tiqdio_alsi = s390_register_adapter_interrupt(&tiqdio_thinint_handler, 334 NULL, QDIO_AIRQ_ISC); 335 if (IS_ERR(tiqdio_alsi)) { 336 sprintf(dbf_text, "regthn%lx", PTR_ERR(tiqdio_alsi)); 337 QDIO_DBF_TEXT0(0, setup, dbf_text); 338 tiqdio_alsi = NULL; 339 isc_unregister(QDIO_AIRQ_ISC); 340 return -ENOMEM; 341 } 342 return 0; 343 } 344 345 int qdio_establish_thinint(struct qdio_irq *irq_ptr) 346 { 347 if (!is_thinint_irq(irq_ptr)) 348 return 0; 349 350 /* Check for aif time delay disablement. If installed, 351 * omit SVS even under LPAR 352 */ 353 if (css_general_characteristics.aif_tdd) 354 css_qdio_omit_svs = 1; 355 return set_subchannel_ind(irq_ptr, 0); 356 } 357 358 void qdio_setup_thinint(struct qdio_irq *irq_ptr) 359 { 360 if (!is_thinint_irq(irq_ptr)) 361 return; 362 irq_ptr->dsci = get_indicator(); 363 QDIO_DBF_HEX1(0, setup, &irq_ptr->dsci, sizeof(void *)); 364 } 365 366 void qdio_shutdown_thinint(struct qdio_irq *irq_ptr) 367 { 368 if (!is_thinint_irq(irq_ptr)) 369 return; 370 371 /* reset adapter interrupt indicators */ 372 put_indicator(irq_ptr->dsci); 373 set_subchannel_ind(irq_ptr, 1); 374 } 375 376 void __exit tiqdio_unregister_thinints(void) 377 { 378 tasklet_disable(&tiqdio_tasklet); 379 380 if (tiqdio_alsi) { 381 s390_unregister_adapter_interrupt(tiqdio_alsi, QDIO_AIRQ_ISC); 382 isc_unregister(QDIO_AIRQ_ISC); 383 } 384 } 385