qdio.c
来自「linux 内核源代码」· C语言 代码 · 共 2,563 行 · 第 1/5 页
C
2,563 行
} 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 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"); qdio_perf_stat_inc(&perf_stats.tl_runs); tiqdio_inbound_checks();}/********************* GENERAL HELPER_ROUTINES ***********************/static voidqdio_release_irq_memory(struct qdio_irq *irq_ptr){ int i; struct qdio_q *q; for (i = 0; i < QDIO_MAX_QUEUES_PER_IRQ; i++) { q = irq_ptr->input_qs[i]; if (q) { free_page((unsigned long) q->slib); kmem_cache_free(qdio_q_cache, q); } q = irq_ptr->output_qs[i]; if (q) { free_page((unsigned long) q->slib); kmem_cache_free(qdio_q_cache, q); } } free_page((unsigned long) 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; for (i = 0; i < no_input_qs; i++) { q = kmem_cache_alloc(qdio_q_cache, GFP_KERNEL); if (!q) return -ENOMEM; memset(q, 0, sizeof(*q)); q->slib = (struct slib *) __get_free_page(GFP_KERNEL); if (!q->slib) { kmem_cache_free(qdio_q_cache, q); return -ENOMEM; } irq_ptr->input_qs[i]=q; } for (i = 0; i < no_output_qs; i++) { q = kmem_cache_alloc(qdio_q_cache, GFP_KERNEL); if (!q) return -ENOMEM; memset(q, 0, sizeof(*q)); q->slib = (struct slib *) __get_free_page(GFP_KERNEL); if (!q->slib) { kmem_cache_free(qdio_q_cache, q); return -ENOMEM; } irq_ptr->output_qs[i]=q; } return 0;}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->schid.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->is_thinint_q isn't valid at this time, but * irq_ptr->is_thinint_irq is */ if (irq_ptr->is_thinint_irq) tasklet_init(&q->tasklet, tiqdio_inbound_processing, (unsigned long) q); else tasklet_init(&q->tasklet, qdio_inbound_processing, (unsigned long) q); /* 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; if ((q->queue_type == QDIO_IQDIO_QFMT) && (no_output_qs > 1) && (i == no_output_qs-1)) q->queue_type = QDIO_IQDIO_QFMT_ASYNCH; q->int_parm=int_parm; q->is_input_q=0; q->is_pci_out = 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; tasklet_init(&q->tasklet, qdio_outbound_processing, (unsigned long) q); setup_timer(&q->timer, qdio_outbound_processing, (unsigned long) q); 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"); qdio_perf_stat_inc(&perf_stats.thinints); /* 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 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"); QDIO_HEXDUMP16(WARN,"irb: ",irb); QDIO_HEXDUMP16(WARN,"sense data: ",irb->ecw); } }static voidqdio_handle_pci(struct qdio_irq *irq_ptr){ int i; struct qdio_q *q; qdio_perf_stat_inc(&perf_stats.pcis); 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 { qdio_perf_stat_dec(&perf_stats.tl_runs); __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]; if (qdio_is_outbound_q_done(q)) continue; qdio_perf_stat_dec(&perf_stats.tl_runs); 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 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(struct work_struct *work){ struct ccw_device_private *priv; struct ccw_device *cdev; priv = container_of(work, struct ccw_device_private, kick_work); cdev = priv->cdev; qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR); put_device(&cdev->dev);}static voidqdio_timeout_handler(struct ccw_device *cdev){ struct qdio_irq *irq_ptr; char dbf_text[15];
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?