📄 qdio.c
字号:
count=0; while (1) { count++; if (i==end) break; i=(i+1)&(QDIO_MAX_BUFFERS_PER_Q-1); }#ifdef CONFIG_QDIO_DEBUG sprintf(dbf_text,"s=%2xc=%2x",start,count); QDIO_DBF_TEXT4(0,trace,dbf_text);#endif /* CONFIG_QDIO_DEBUG */ if (likely(q->state==QDIO_IRQ_STATE_ACTIVE)) q->handler(q->cdev, QDIO_STATUS_INBOUND_INT|q->error_status_flags, q->qdio_error,q->siga_error,q->q_no,start,count, q->int_parm); /* for the next time: */ q->first_element_to_kick=real_end; q->qdio_error=0; q->siga_error=0; q->error_status_flags=0;#ifdef QDIO_PERFORMANCE_STATS perf_stats.inbound_time+=NOW-perf_stats.start_time_inbound; perf_stats.inbound_cnt++;#endif /* QDIO_PERFORMANCE_STATS */}static inline void__tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set){ struct qdio_irq *irq_ptr; struct qdio_q *oq; int i; QDIO_DBF_TEXT4(0,trace,"iqinproc"); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); /* * we first want to reserve the q, so that we know, that we don't * interrupt ourselves and call qdio_unmark_q, as is_in_shutdown might * be set */ if (unlikely(qdio_reserve_q(q))) { qdio_release_q(q);#ifdef QDIO_PERFORMANCE_STATS ii_p_c++;#endif /* QDIO_PERFORMANCE_STATS */ /* * as we might just be about to stop polling, we make * sure that we check again at least once more */ tiqdio_sched_tl(); return; }#ifdef QDIO_PERFORMANCE_STATS ii_p_nc++;#endif /* QDIO_PERFORMANCE_STATS */ if (unlikely(atomic_read(&q->is_in_shutdown))) { qdio_unmark_q(q); goto out; } /* * we reset spare_ind_was_set, when the queue does not use the * spare indicator */ if (spare_ind_was_set) spare_ind_was_set = (q->dev_st_chg_ind == &spare_indicator); if (!(*(q->dev_st_chg_ind)) && !spare_ind_was_set) goto out; /* * q->dev_st_chg_ind is the indicator, be it shared or not. * only clear it, if indicator is non-shared */ if (!spare_ind_was_set) tiqdio_clear_summary_bit((__u32*)q->dev_st_chg_ind); if (q->hydra_gives_outbound_pcis) { if (!q->siga_sync_done_on_thinints) { SYNC_MEMORY_ALL; } else if ((!q->siga_sync_done_on_outb_tis)&& (q->hydra_gives_outbound_pcis)) { SYNC_MEMORY_ALL_OUTB; } } else { SYNC_MEMORY; } /* * maybe we have to do work on our outbound queues... at least * we have to check the outbound-int-capable thinint-capable * queues */ if (q->hydra_gives_outbound_pcis) { irq_ptr = (struct qdio_irq*)q->irq_ptr; for (i=0;i<irq_ptr->no_output_qs;i++) { oq = irq_ptr->output_qs[i];#ifdef QDIO_PERFORMANCE_STATS perf_stats.tl_runs--;#endif /* QDIO_PERFORMANCE_STATS */ if (!qdio_is_outbound_q_done(oq)) __qdio_outbound_processing(oq); } } if (!qdio_has_inbound_q_moved(q)) goto out; qdio_kick_inbound_handler(q); if (tiqdio_is_inbound_q_done(q)) if (!qdio_stop_polling(q)) { /* * we set the flags to get into the stuff next time, * see also comment in qdio_stop_polling */ tiqdio_set_summary_bit((__u32*)q->dev_st_chg_ind); tiqdio_sched_tl(); }out: qdio_release_q(q);}static voidtiqdio_inbound_processing(struct qdio_q *q){ __tiqdio_inbound_processing(q, atomic_read(&spare_indicator_usecount));}static inline void__qdio_inbound_processing(struct qdio_q *q){ int q_laps=0; QDIO_DBF_TEXT4(0,trace,"qinproc"); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); if (unlikely(qdio_reserve_q(q))) { qdio_release_q(q);#ifdef QDIO_PERFORMANCE_STATS i_p_c++;#endif /* QDIO_PERFORMANCE_STATS */ /* as we're sissies, we'll check next time */ if (likely(!atomic_read(&q->is_in_shutdown))) { qdio_mark_q(q); QDIO_DBF_TEXT4(0,trace,"busy,agn"); } return; }#ifdef QDIO_PERFORMANCE_STATS i_p_nc++; perf_stats.tl_runs++;#endif /* QDIO_PERFORMANCE_STATS */again: if (qdio_has_inbound_q_moved(q)) { qdio_kick_inbound_handler(q); if (!qdio_stop_polling(q)) { q_laps++; if (q_laps<QDIO_Q_LAPS) goto again; } qdio_mark_q(q); } else { if (!qdio_is_inbound_q_done(q)) /* means poll time is not yet over */ qdio_mark_q(q); } qdio_release_q(q);}static voidqdio_inbound_processing(struct qdio_q *q){ __qdio_inbound_processing(q);}/************************* MAIN ROUTINES *******************************/#ifdef QDIO_USE_PROCESSING_STATEstatic inline inttiqdio_reset_processing_state(struct qdio_q *q, int q_laps){ if (!q) { tiqdio_sched_tl(); return 0; } /* * under VM, we have not used the PROCESSING state, so no * need to stop polling */ if (q->siga_sync) return 2; if (unlikely(qdio_reserve_q(q))) { qdio_release_q(q);#ifdef QDIO_PERFORMANCE_STATS ii_p_c++;#endif /* QDIO_PERFORMANCE_STATS */ /* * as we might just be about to stop polling, we make * sure that we check again at least once more */ /* * sanity -- we'd get here without setting the * dev st chg ind */ tiqdio_set_summary_bit((__u32*)q->dev_st_chg_ind); tiqdio_sched_tl(); return 0; } if (qdio_stop_polling(q)) { qdio_release_q(q); return 2; } if (q_laps<QDIO_Q_LAPS-1) { qdio_release_q(q); return 3; } /* * we set the flags to get into the stuff * next time, see also comment in qdio_stop_polling */ tiqdio_set_summary_bit((__u32*)q->dev_st_chg_ind); tiqdio_sched_tl(); qdio_release_q(q); return 1; }#endif /* QDIO_USE_PROCESSING_STATE */static inline voidtiqdio_inbound_checks(void){ struct qdio_q *q; int spare_ind_was_set=0;#ifdef QDIO_USE_PROCESSING_STATE int q_laps=0;#endif /* QDIO_USE_PROCESSING_STATE */ QDIO_DBF_TEXT4(0,trace,"iqdinbck"); QDIO_DBF_TEXT5(0,trace,"iqlocsum");#ifdef QDIO_USE_PROCESSING_STATEagain:#endif /* QDIO_USE_PROCESSING_STATE */ /* when the spare indicator is used and set, save that and clear it */ if ((atomic_read(&spare_indicator_usecount)) && spare_indicator) { spare_ind_was_set = 1; tiqdio_clear_summary_bit((__u32*)&spare_indicator); } q=(struct qdio_q*)tiq_list; do { if (!q) break; __tiqdio_inbound_processing(q, spare_ind_was_set); q=(struct qdio_q*)q->list_next; } while (q!=(struct qdio_q*)tiq_list);#ifdef QDIO_USE_PROCESSING_STATE q=(struct qdio_q*)tiq_list; do { int ret; ret = tiqdio_reset_processing_state(q, q_laps); switch (ret) { case 0: return; case 1: q_laps++; case 2: q = (struct qdio_q*)q->list_next; break; default: q_laps++; goto again; } } while (q!=(struct qdio_q*)tiq_list);#endif /* QDIO_USE_PROCESSING_STATE */}static voidtiqdio_tl(unsigned long data){ QDIO_DBF_TEXT4(0,trace,"iqdio_tl");#ifdef QDIO_PERFORMANCE_STATS perf_stats.tl_runs++;#endif /* QDIO_PERFORMANCE_STATS */ tiqdio_inbound_checks();}/********************* GENERAL HELPER_ROUTINES ***********************/static voidqdio_release_irq_memory(struct qdio_irq *irq_ptr){ int i; for (i=0;i<QDIO_MAX_QUEUES_PER_IRQ;i++) { if (!irq_ptr->input_qs[i]) goto next; kfree(irq_ptr->input_qs[i]->slib); kfree(irq_ptr->input_qs[i]);next: if (!irq_ptr->output_qs[i]) continue; kfree(irq_ptr->output_qs[i]->slib); kfree(irq_ptr->output_qs[i]); } kfree(irq_ptr->qdr); kfree(irq_ptr);}static voidqdio_set_impl_params(struct qdio_irq *irq_ptr, unsigned int qib_param_field_format, /* pointer to 128 bytes or NULL, if no param field */ unsigned char *qib_param_field, /* pointer to no_queues*128 words of data or NULL */ unsigned int no_input_qs, unsigned int no_output_qs, unsigned long *input_slib_elements, unsigned long *output_slib_elements){ int i,j; if (!irq_ptr) return; 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) for (i=0;i<no_input_qs;i++) { for (j=0;j<QDIO_MAX_BUFFERS_PER_Q;j++) irq_ptr->input_qs[i]->slib->slibe[j].parms= input_slib_elements[ i*QDIO_MAX_BUFFERS_PER_Q+j]; } if (output_slib_elements) for (i=0;i<no_output_qs;i++) { for (j=0;j<QDIO_MAX_BUFFERS_PER_Q;j++) irq_ptr->output_qs[i]->slib->slibe[j].parms= output_slib_elements[ i*QDIO_MAX_BUFFERS_PER_Q+j]; }}static intqdio_alloc_qs(struct qdio_irq *irq_ptr, int no_input_qs, int no_output_qs){ int i; struct qdio_q *q; int result=-ENOMEM; for (i=0;i<no_input_qs;i++) { q=kmalloc(sizeof(struct qdio_q),GFP_KERNEL); if (!q) { QDIO_PRINT_ERR("kmalloc of q failed!\n"); goto out; } memset(q,0,sizeof(struct qdio_q)); q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL); if (!q->slib) { QDIO_PRINT_ERR("kmalloc of slib failed!\n"); goto out; } irq_ptr->input_qs[i]=q; } for (i=0;i<no_output_qs;i++) { q=kmalloc(sizeof(struct qdio_q),GFP_KERNEL); if (!q) { goto out; } memset(q,0,sizeof(struct qdio_q)); q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL); if (!q->slib) { QDIO_PRINT_ERR("kmalloc of slib failed!\n"); goto out; } irq_ptr->output_qs[i]=q; } result=0;out: return result;}static voidqdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev, int no_input_qs, int no_output_qs, qdio_handler_t *input_handler, qdio_handler_t *output_handler, unsigned long int_parm,int q_format, unsigned long flags, void **inbound_sbals_array, void **outbound_sbals_array){ struct qdio_q *q; int i,j; char dbf_text[20]; /* see qdio_initialize */ void *ptr; int available; sprintf(dbf_text,"qfqs%4x",cdev->private->irq); QDIO_DBF_TEXT0(0,setup,dbf_text); for (i=0;i<no_input_qs;i++) { q=irq_ptr->input_qs[i]; memset(q,0,((char*)&q->slib)-((char*)q)); sprintf(dbf_text,"in-q%4x",i); QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_DBF_HEX0(0,setup,&q,sizeof(void*)); memset(q->slib,0,PAGE_SIZE); q->sl=(struct sl*)(((char*)q->slib)+PAGE_SIZE/2); available=0; for (j=0;j<QDIO_MAX_BUFFERS_PER_Q;j++) q->sbal[j]=*(inbound_sbals_array++); q->queue_type=q_format; q->int_parm=int_parm; q->irq=irq_ptr->irq; q->irq_ptr = irq_ptr; q->cdev = cdev; q->mask=1<<(31-i); q->q_no=i; q->is_input_q=1; q->first_to_check=0; q->last_move_ftc=0; q->handler=input_handler; q->dev_st_chg_ind=irq_ptr->dev_st_chg_ind; q->tasklet.data=(unsigned long)q; /* q->is_thinint_q isn't valid at this time, but * irq_ptr->is_thinint_irq is */ q->tasklet.func=(void(*)(unsigned long)) ((irq_ptr->is_thinint_irq)?&tiqdio_inbound_processing: &qdio_inbound_processing); /* actually this is not used for inbound queues. yet. */ atomic_set(&q->busy_siga_counter,0); q->timing.busy_start=0;/* for (j=0;j<QDIO_STATS_NUMBER;j++) q->timing.last_transfer_times[j]=(qdio_get_micros()/ QDIO_STATS_NUMBER)*j; q->timing.last_transfer_index=QDIO_STATS_NUMBER-1;*/ /* fill in slib */ if (i>0) irq_ptr->input_qs[i-1]->slib->nsliba= (unsigned long)(q->slib); q->slib->sla=(unsigned long)(q->sl); q->slib->slsba=(unsigned long)(&q->slsb.acc.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]); QDIO_DBF_TEXT2(0,setup,"sl-sb-b0"); ptr=(void*)q->sl; QDIO_DBF_HEX2(0,setup,&ptr,sizeof(void*)); ptr=(void*)&q->slsb; QDIO_DBF_HEX2(0,setup,&ptr,sizeof(void*)); ptr=(void*)q->sbal[0]; QDIO_DBF_HEX2(0,setup,&ptr,sizeof(void*)); /* fill in slsb */ for (j=0;j<QDIO_MAX_BUFFERS_PER_Q;j++) { set_slsb(&q->slsb.acc.val[j], SLSB_P_INPUT_NOT_INIT);/* q->sbal[j]->element[1].sbalf.i1.key=QDIO_STORAGE_KEY;*/ } } for (i=0;i<no_output_qs;i++) { q=irq_ptr->output_qs[i]; memset(q,0,((char*)&q->slib)-((char*)q)); sprintf(dbf_text,"outq%4x",i); QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_DBF_HEX0(0,setup,&q,sizeof(void*)); memset(q->slib,0,PAGE_SIZE); q->sl=(struct sl*)(((char*)q->slib)+PAGE_SIZE/2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -