qdio.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 2,574 行 · 第 1/5 页
C
2,574 行
* 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); free_page((unsigned long) 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 = kzalloc(sizeof(struct qdio_q), GFP_KERNEL); if (!q) { QDIO_PRINT_ERR("kmalloc of q failed!\n"); goto out; } 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 = kzalloc(sizeof(struct qdio_q), GFP_KERNEL); if (!q) { goto out; } 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->sch_no); 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->schid = irq_ptr->schid; 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 */ if (!irq_ptr->is_qebsm) { unsigned int count = 1; for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) set_slsb(q, &j, SLSB_P_INPUT_NOT_INIT, &count); } } 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); available=0; for (j=0;j<QDIO_MAX_BUFFERS_PER_Q;j++) q->sbal[j]=*(outbound_sbals_array++); q->queue_type=q_format; q->int_parm=int_parm; q->is_input_q=0; q->schid = irq_ptr->schid; q->cdev = cdev; q->irq_ptr = irq_ptr; q->mask=1<<(31-i); q->q_no=i; q->first_to_check=0; q->last_move_ftc=0; q->handler=output_handler; q->tasklet.data=(unsigned long)q; q->tasklet.func=(void(*)(unsigned long)) &qdio_outbound_processing; atomic_set(&q->busy_siga_counter,0); q->timing.busy_start=0; /* fill in slib */ if (i>0) irq_ptr->output_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 */ if (!irq_ptr->is_qebsm) { unsigned int count = 1; for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) set_slsb(q, &j, SLSB_P_OUTPUT_NOT_INIT, &count); } }}static voidqdio_fill_thresholds(struct qdio_irq *irq_ptr, unsigned int no_input_qs, unsigned int no_output_qs, unsigned int min_input_threshold, unsigned int max_input_threshold, unsigned int min_output_threshold, unsigned int max_output_threshold){ int i; struct qdio_q *q; for (i=0;i<no_input_qs;i++) { q=irq_ptr->input_qs[i]; q->timing.threshold=max_input_threshold;/* for (j=0;j<QDIO_STATS_CLASSES;j++) { q->threshold_classes[j].threshold= min_input_threshold+ (max_input_threshold-min_input_threshold)/ QDIO_STATS_CLASSES; } qdio_use_thresholds(q,QDIO_STATS_CLASSES/2);*/ } for (i=0;i<no_output_qs;i++) { q=irq_ptr->output_qs[i]; q->timing.threshold=max_output_threshold;/* for (j=0;j<QDIO_STATS_CLASSES;j++) { q->threshold_classes[j].threshold= min_output_threshold+ (max_output_threshold-min_output_threshold)/ QDIO_STATS_CLASSES; } qdio_use_thresholds(q,QDIO_STATS_CLASSES/2);*/ }}static inttiqdio_thinint_handler(void){ QDIO_DBF_TEXT4(0,trace,"thin_int");#ifdef QDIO_PERFORMANCE_STATS perf_stats.thinints++; perf_stats.start_time_inbound=NOW;#endif /* QDIO_PERFORMANCE_STATS */ /* SVS only when needed: * issue SVS to benefit from iqdio interrupt avoidance * (SVS clears AISOI)*/ if (!omit_svs) tiqdio_clear_global_summary(); tiqdio_inbound_checks(); return 0;}static voidqdio_set_state(struct qdio_irq *irq_ptr, enum qdio_irq_states state){ int i;#ifdef CONFIG_QDIO_DEBUG char dbf_text[15]; QDIO_DBF_TEXT5(0,trace,"newstate"); sprintf(dbf_text,"%4x%4x",irq_ptr->schid.sch_no,state); QDIO_DBF_TEXT5(0,trace,dbf_text);#endif /* CONFIG_QDIO_DEBUG */ irq_ptr->state=state; for (i=0;i<irq_ptr->no_input_qs;i++) irq_ptr->input_qs[i]->state=state; for (i=0;i<irq_ptr->no_output_qs;i++) irq_ptr->output_qs[i]->state=state; mb();}static inline voidqdio_irq_check_sense(struct subchannel_id schid, struct irb *irb){ char dbf_text[15]; if (irb->esw.esw0.erw.cons) { sprintf(dbf_text,"sens%4x",schid.sch_no); QDIO_DBF_TEXT2(1,trace,dbf_text); QDIO_DBF_HEX0(0,sense,irb,QDIO_DBF_SENSE_LEN); QDIO_PRINT_WARN("sense data available on qdio channel.\n"); HEXDUMP16(WARN,"irb: ",irb); HEXDUMP16(WARN,"sense data: ",irb->ecw); } }static inline voidqdio_handle_pci(struct qdio_irq *irq_ptr){ int i; struct qdio_q *q;#ifdef QDIO_PERFORMANCE_STATS perf_stats.pcis++; perf_stats.start_time_inbound=NOW;#endif /* QDIO_PERFORMANCE_STATS */ for (i=0;i<irq_ptr->no_input_qs;i++) { q=irq_ptr->input_qs[i]; if (q->is_input_q&QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT) qdio_mark_q(q); else {#ifdef QDIO_PERFORMANCE_STATS perf_stats.tl_runs--;#endif /* QDIO_PERFORMANCE_STATS */ __qdio_inbound_processing(q); } } if (!irq_ptr->hydra_gives_outbound_pcis) return; for (i=0;i<irq_ptr->no_output_qs;i++) { q=irq_ptr->output_qs[i];#ifdef QDIO_PERFORMANCE_STATS perf_stats.tl_runs--;#endif /* QDIO_PERFORMANCE_STATS */ if (qdio_is_outbound_q_done(q)) continue; if (!irq_ptr->sync_done_on_outb_pcis) SYNC_MEMORY; __qdio_outbound_processing(q); }}static void qdio_establish_handle_irq(struct ccw_device*, int, int);static inline voidqdio_handle_activate_check(struct ccw_device *cdev, unsigned long intparm, int cstat, int dstat){ struct qdio_irq *irq_ptr; struct qdio_q *q; char dbf_text[15]; irq_ptr = cdev->private->qdio_data; QDIO_DBF_TEXT2(1, trace, "ick2"); sprintf(dbf_text,"%s", cdev->dev.bus_id); QDIO_DBF_TEXT2(1,trace,dbf_text); QDIO_DBF_HEX2(0,trace,&intparm,sizeof(int)); QDIO_DBF_HEX2(0,trace,&dstat,sizeof(int)); QDIO_DBF_HEX2(0,trace,&cstat,sizeof(int)); QDIO_PRINT_ERR("received check condition on activate " \ "queues on device %s (cs=x%x, ds=x%x).\n", cdev->dev.bus_id, cstat, dstat); if (irq_ptr->no_input_qs) { q=irq_ptr->input_qs[0]; } else if (irq_ptr->no_output_qs) { q=irq_ptr->output_qs[0]; } else { QDIO_PRINT_ERR("oops... no queue registered for device %s!?\n", cdev->dev.bus_id); goto omit_handler_call; } q->handler(q->cdev,QDIO_STATUS_ACTIVATE_CHECK_CONDITION| QDIO_STATUS_LOOK_FOR_ERROR, 0,0,0,-1,-1,q->int_parm);omit_handler_call: qdio_set_state(irq_ptr,QDIO_IRQ_STATE_STOPPED);}static voidqdio_call_shutdown(void *data){ struct ccw_device *cdev; cdev = (struct ccw_device *)data; qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR); put_device(&cdev->dev);}static voidqdio_timeout_handler(struct ccw_device *cdev){
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?