qdio.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 2,574 行 · 第 1/5 页

C
2,574
字号
	slsb=&q->slsb.acc.val[0];	f_mod_no=f=q->first_to_check;	/* 	 * we don't check 128 buffers, as otherwise qdio_has_inbound_q_moved	 * would return 0 	 */	first_not_to_check=f+qdio_min(atomic_read(&q->number_of_buffers_used),				      (QDIO_MAX_BUFFERS_PER_Q-1));	/* 	 * we don't use this one, as a PCI or we after a thin interrupt	 * will sync the queues	 */	/* SYNC_MEMORY;*/check_next:	f_mod_no=f&(QDIO_MAX_BUFFERS_PER_Q-1);	if (f==first_not_to_check) 		goto out;	switch (slsb[f_mod_no]) {	/* CU_EMPTY means frontier is reached */	case SLSB_CU_INPUT_EMPTY:		QDIO_DBF_TEXT5(0,trace,"inptempt");		break;	/* P_PRIMED means set slsb to P_PROCESSING and move on */	case SLSB_P_INPUT_PRIMED:		QDIO_DBF_TEXT5(0,trace,"inptprim");#ifdef QDIO_USE_PROCESSING_STATE		/* 		 * as soon as running under VM, polling the input queues will		 * kill VM in terms of CP overhead 		 */		if (q->siga_sync) {			set_slsb(q, &f_mod_no, SLSB_P_INPUT_NOT_INIT, &count);		} else {			/* set the previous buffer to NOT_INIT. The current			 * buffer will be set to PROCESSING at the end of			 * this function to avoid further interrupts. */			if (last_position>=0)				set_slsb(q, &last_position,					 SLSB_P_INPUT_NOT_INIT, &count);			atomic_set(&q->polling,1);			last_position=f_mod_no;		}#else /* QDIO_USE_PROCESSING_STATE */		set_slsb(q, &f_mod_no, SLSB_P_INPUT_NOT_INIT, &count);#endif /* QDIO_USE_PROCESSING_STATE */		/* 		 * not needed, as the inbound queue will be synced on the next		 * siga-r, resp. tiqdio_is_inbound_q_done will do the siga-s		 */		/*SYNC_MEMORY;*/		f++;		atomic_dec(&q->number_of_buffers_used);		goto check_next;	case SLSB_P_INPUT_NOT_INIT:	case SLSB_P_INPUT_PROCESSING:		QDIO_DBF_TEXT5(0,trace,"inpnipro");		break;	/* P_ERROR means frontier is reached, break and report error */	case SLSB_P_INPUT_ERROR:#ifdef CONFIG_QDIO_DEBUG		sprintf(dbf_text,"inperr%2x",f_mod_no);		QDIO_DBF_TEXT3(1,trace,dbf_text);#endif /* CONFIG_QDIO_DEBUG */		QDIO_DBF_HEX2(1,sbal,q->sbal[f_mod_no],256);		/* kind of process the buffer */		set_slsb(q, &f_mod_no, SLSB_P_INPUT_NOT_INIT, &count);		if (q->qdio_error)			q->error_status_flags|=				QDIO_STATUS_MORE_THAN_ONE_QDIO_ERROR;		q->qdio_error=SLSB_P_INPUT_ERROR;		q->error_status_flags|=QDIO_STATUS_LOOK_FOR_ERROR;		/* we increment the frontier, as this buffer		 * was processed obviously */		f_mod_no=(f_mod_no+1)&(QDIO_MAX_BUFFERS_PER_Q-1);		atomic_dec(&q->number_of_buffers_used);#ifdef QDIO_USE_PROCESSING_STATE		last_position=-1;#endif /* QDIO_USE_PROCESSING_STATE */		break;	/* everything else means frontier not changed (HALTED or so) */	default: 		break;	}out:	q->first_to_check=f_mod_no;#ifdef QDIO_USE_PROCESSING_STATE	if (last_position>=0)		set_slsb(q, &last_position, SLSB_P_INPUT_NOT_INIT, &count);#endif /* QDIO_USE_PROCESSING_STATE */	QDIO_DBF_HEX4(0,trace,&q->first_to_check,sizeof(int));	return q->first_to_check;}static inline intqdio_has_inbound_q_moved(struct qdio_q *q){	int i;#ifdef QDIO_PERFORMANCE_STATS	static int old_pcis=0;	static int old_thinints=0;	if ((old_pcis==perf_stats.pcis)&&(old_thinints==perf_stats.thinints))		perf_stats.start_time_inbound=NOW;	else		old_pcis=perf_stats.pcis;#endif /* QDIO_PERFORMANCE_STATS */	i=qdio_get_inbound_buffer_frontier(q);	if ( (i!=GET_SAVED_FRONTIER(q)) ||	     (q->error_status_flags&QDIO_STATUS_LOOK_FOR_ERROR) ) {		SAVE_FRONTIER(q,i);		if ((!q->siga_sync)&&(!q->hydra_gives_outbound_pcis))			SAVE_TIMESTAMP(q);		QDIO_DBF_TEXT4(0,trace,"inhasmvd");		QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));		return 1;	} else {		QDIO_DBF_TEXT4(0,trace,"inhsntmv");		QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));		return 0;	}}/* means, no more buffers to be filled */static inline inttiqdio_is_inbound_q_done(struct qdio_q *q){	int no_used;	unsigned int start_buf, count;	unsigned char state = 0;	struct qdio_irq *irq = (struct qdio_irq *) q->irq_ptr;#ifdef CONFIG_QDIO_DEBUG	char dbf_text[15];#endif	no_used=atomic_read(&q->number_of_buffers_used);	/* propagate the change from 82 to 80 through VM */	SYNC_MEMORY;#ifdef CONFIG_QDIO_DEBUG	if (no_used) {		sprintf(dbf_text,"iqisnt%02x",no_used);		QDIO_DBF_TEXT4(0,trace,dbf_text);	} else {		QDIO_DBF_TEXT4(0,trace,"iniqisdo");	}	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));#endif /* CONFIG_QDIO_DEBUG */	if (!no_used)		return 1;	if (!q->siga_sync && !irq->is_qebsm)		/* we'll check for more primed buffers in qeth_stop_polling */		return 0;	if (irq->is_qebsm) {		count = 1;		start_buf = q->first_to_check;		qdio_do_eqbs(q, &state, &start_buf, &count);	} else		state = q->slsb.acc.val[q->first_to_check];	if (state != SLSB_P_INPUT_PRIMED)		/* 		 * nothing more to do, if next buffer is not PRIMED.		 * note that we did a SYNC_MEMORY before, that there		 * has been a sychnronization.		 * we will return 0 below, as there is nothing to do		 * (stop_polling not necessary, as we have not been		 * using the PROCESSING state 		 */		return 0;	/* 	 * ok, the next input buffer is primed. that means, that device state 	 * change indicator and adapter local summary are set, so we will find	 * it next time.	 * we will return 0 below, as there is nothing to do, except scheduling	 * ourselves for the next time. 	 */	tiqdio_set_summary_bit((__u32*)q->dev_st_chg_ind);	tiqdio_sched_tl();	return 0;}static inline intqdio_is_inbound_q_done(struct qdio_q *q){	int no_used;	unsigned int start_buf, count;	unsigned char state = 0;	struct qdio_irq *irq = (struct qdio_irq *) q->irq_ptr;#ifdef CONFIG_QDIO_DEBUG	char dbf_text[15];#endif	no_used=atomic_read(&q->number_of_buffers_used);	/* 	 * we need that one for synchronization with the adapter, as it	 * does a kind of PCI avoidance 	 */	SYNC_MEMORY;	if (!no_used) {		QDIO_DBF_TEXT4(0,trace,"inqisdnA");		QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));		QDIO_DBF_TEXT4(0,trace,dbf_text);		return 1;	}	if (irq->is_qebsm) {		count = 1;		start_buf = q->first_to_check;		qdio_do_eqbs(q, &state, &start_buf, &count);	} else		state = q->slsb.acc.val[q->first_to_check];	if (state == SLSB_P_INPUT_PRIMED) {		/* we got something to do */		QDIO_DBF_TEXT4(0,trace,"inqisntA");		QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));		return 0;	}	/* on VM, we don't poll, so the q is always done here */	if (q->siga_sync)		return 1;	if (q->hydra_gives_outbound_pcis)		return 1;	/* 	 * at this point we know, that inbound first_to_check	 * has (probably) not moved (see qdio_inbound_processing) 	 */	if (NOW>GET_SAVED_TIMESTAMP(q)+q->timing.threshold) {#ifdef CONFIG_QDIO_DEBUG		QDIO_DBF_TEXT4(0,trace,"inqisdon");		QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));		sprintf(dbf_text,"pf%02xcn%02x",q->first_to_check,no_used);		QDIO_DBF_TEXT4(0,trace,dbf_text);#endif /* CONFIG_QDIO_DEBUG */		return 1;	} else {#ifdef CONFIG_QDIO_DEBUG		QDIO_DBF_TEXT4(0,trace,"inqisntd");		QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));		sprintf(dbf_text,"pf%02xcn%02x",q->first_to_check,no_used);		QDIO_DBF_TEXT4(0,trace,dbf_text);#endif /* CONFIG_QDIO_DEBUG */		return 0;	}}static inline voidqdio_kick_inbound_handler(struct qdio_q *q){	int count, start, end, real_end, i;#ifdef CONFIG_QDIO_DEBUG	char dbf_text[15];#endif	QDIO_DBF_TEXT4(0,trace,"kickinh");	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));  	start=q->first_element_to_kick; 	real_end=q->first_to_check; 	end=(real_end+QDIO_MAX_BUFFERS_PER_Q-1)&(QDIO_MAX_BUFFERS_PER_Q-1);  	i=start;	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

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?