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 + -
显示快捷键?