⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qdio.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
{	int no_used;#ifdef CONFIG_QDIO_DEBUG	char dbf_text[15];#endif	no_used=atomic_read(&q->number_of_buffers_used);#ifdef CONFIG_QDIO_DEBUG	if (no_used) {		sprintf(dbf_text,"oqisnt%02x",no_used);		QDIO_DBF_TEXT4(0,trace,dbf_text);	} else {		QDIO_DBF_TEXT4(0,trace,"oqisdone");	}	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));#endif /* CONFIG_QDIO_DEBUG */	return (no_used==0);}static inline intqdio_has_outbound_q_moved(struct qdio_q *q){	int i;	i=qdio_get_outbound_buffer_frontier(q);	if ( (i!=GET_SAVED_FRONTIER(q)) ||	     (q->error_status_flags&QDIO_STATUS_LOOK_FOR_ERROR) ) {		SAVE_FRONTIER(q,i);		QDIO_DBF_TEXT4(0,trace,"oqhasmvd");		QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));		return 1;	} else {		QDIO_DBF_TEXT4(0,trace,"oqhsntmv");		QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));		return 0;	}}static inline voidqdio_kick_outbound_q(struct qdio_q *q){	int result;#ifdef CONFIG_QDIO_DEBUG	char dbf_text[15];	QDIO_DBF_TEXT4(0,trace,"kickoutq");	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));#endif /* CONFIG_QDIO_DEBUG */	if (!q->siga_out)		return;	/* here's the story with cc=2 and busy bit set (thanks, Rick):	 * VM's CP could present us cc=2 and busy bit set on SIGA-write	 * during reconfiguration of their Guest LAN (only in HIPERS mode,	 * QDIO mode is asynchronous -- cc=2 and busy bit there will take	 * the queues down immediately; and not being under VM we have a	 * problem on cc=2 and busy bit set right away).	 *	 * Therefore qdio_siga_output will try for a short time constantly,	 * if such a condition occurs. If it doesn't change, it will	 * increase the busy_siga_counter and save the timestamp, and	 * schedule the queue for later processing (via mark_q, using the	 * queue tasklet). __qdio_outbound_processing will check out the	 * counter. If non-zero, it will call qdio_kick_outbound_q as often	 * as the value of the counter. This will attempt further SIGA	 * instructions. For each successful SIGA, the counter is	 * decreased, for failing SIGAs the counter remains the same, after	 * all.	 * After some time of no movement, qdio_kick_outbound_q will	 * finally fail and reflect corresponding error codes to call	 * the upper layer module and have it take the queues down.	 *	 * Note that this is a change from the original HiperSockets design	 * (saying cc=2 and busy bit means take the queues down), but in	 * these days Guest LAN didn't exist... excessive cc=2 with busy bit	 * conditions will still take the queues down, but the threshold is	 * higher due to the Guest LAN environment.	 */	result=qdio_siga_output(q);		switch (result) {		case 0:			/* went smooth this time, reset timestamp */#ifdef CONFIG_QDIO_DEBUG			QDIO_DBF_TEXT3(0,trace,"cc2reslv");			sprintf(dbf_text,"%4x%2x%2x",q->irq,q->q_no,				atomic_read(&q->busy_siga_counter));			QDIO_DBF_TEXT3(0,trace,dbf_text);#endif /* CONFIG_QDIO_DEBUG */			q->timing.busy_start=0;			break;		case (2|QDIO_SIGA_ERROR_B_BIT_SET):			/* cc=2 and busy bit: */			atomic_inc(&q->busy_siga_counter);			/* if the last siga was successful, save			 * timestamp here */			if (!q->timing.busy_start)				q->timing.busy_start=NOW;			/* if we're in time, don't touch error_status_flags			 * and siga_error */			if (NOW-q->timing.busy_start<QDIO_BUSY_BIT_GIVE_UP) {				qdio_mark_q(q);				break;			}			QDIO_DBF_TEXT2(0,trace,"cc2REPRT");#ifdef CONFIG_QDIO_DEBUG			sprintf(dbf_text,"%4x%2x%2x",q->irq,q->q_no,				atomic_read(&q->busy_siga_counter));			QDIO_DBF_TEXT3(0,trace,dbf_text);#endif /* CONFIG_QDIO_DEBUG */			/* else fallthrough and report error */		default:			/* for plain cc=1, 2 or 3: */			if (q->siga_error)				q->error_status_flags|=					QDIO_STATUS_MORE_THAN_ONE_SIGA_ERROR;			q->error_status_flags|=				QDIO_STATUS_LOOK_FOR_ERROR;			q->siga_error=result;		}}static inline voidqdio_kick_outbound_handler(struct qdio_q *q){	int start, end, real_end, count;#ifdef CONFIG_QDIO_DEBUG	char dbf_text[15];#endif	start = q->first_element_to_kick;	/* last_move_ftc was just updated */	real_end = GET_SAVED_FRONTIER(q);	end = (real_end+QDIO_MAX_BUFFERS_PER_Q-1)&		(QDIO_MAX_BUFFERS_PER_Q-1);	count = (end+QDIO_MAX_BUFFERS_PER_Q+1-start)&		(QDIO_MAX_BUFFERS_PER_Q-1);#ifdef CONFIG_QDIO_DEBUG	QDIO_DBF_TEXT4(0,trace,"kickouth");	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));	sprintf(dbf_text,"s=%2xc=%2x",start,count);	QDIO_DBF_TEXT4(0,trace,dbf_text);#endif /* CONFIG_QDIO_DEBUG */	if (q->state==QDIO_IRQ_STATE_ACTIVE)		q->handler(q->cdev,QDIO_STATUS_OUTBOUND_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;}static inline void__qdio_outbound_processing(struct qdio_q *q){	int siga_attempts;	QDIO_DBF_TEXT4(0,trace,"qoutproc");	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));	if (unlikely(qdio_reserve_q(q))) {		qdio_release_q(q);#ifdef QDIO_PERFORMANCE_STATS		o_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	o_p_nc++;	perf_stats.tl_runs++;#endif /* QDIO_PERFORMANCE_STATS */	/* see comment in qdio_kick_outbound_q */	siga_attempts=atomic_read(&q->busy_siga_counter);	while (siga_attempts) {		atomic_dec(&q->busy_siga_counter);		qdio_kick_outbound_q(q);		siga_attempts--;	}	if (qdio_has_outbound_q_moved(q))		qdio_kick_outbound_handler(q);	if (q->is_iqdio_q) {		/* 		 * for asynchronous queues, we better check, if the fill		 * level is too high. for synchronous queues, the fill		 * level will never be that high. 		 */		if (atomic_read(&q->number_of_buffers_used)>		    IQDIO_FILL_LEVEL_TO_POLL)			qdio_mark_q(q);	} else if (!q->hydra_gives_outbound_pcis)		if (!qdio_is_outbound_q_done(q))			qdio_mark_q(q);	qdio_release_q(q);}static voidqdio_outbound_processing(struct qdio_q *q){	__qdio_outbound_processing(q);}/************************* INBOUND ROUTINES *******************************/static inline intqdio_get_inbound_buffer_frontier(struct qdio_q *q){	int f,f_mod_no;	volatile char *slsb;	int first_not_to_check;#ifdef CONFIG_QDIO_DEBUG	char dbf_text[15];#endif /* CONFIG_QDIO_DEBUG */#ifdef QDIO_USE_PROCESSING_STATE	int last_position=-1;#endif /* QDIO_USE_PROCESSING_STATE */	QDIO_DBF_TEXT4(0,trace,"getibfro");	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));	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(&slsb[f_mod_no],SLSB_P_INPUT_NOT_INIT);		} 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(&slsb[last_position],					 SLSB_P_INPUT_NOT_INIT);			atomic_set(&q->polling,1);			last_position=f_mod_no;		}#else /* QDIO_USE_PROCESSING_STATE */		set_slsb(&slsb[f_mod_no],SLSB_P_INPUT_NOT_INIT);#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(&slsb[f_mod_no],SLSB_P_INPUT_NOT_INIT);		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(&slsb[last_position],SLSB_P_INPUT_PROCESSING);#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;#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)		/* we'll check for more primed buffers in qeth_stop_polling */		return 0;	if (q->slsb.acc.val[q->first_to_check]!=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;#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 (q->slsb.acc.val[q->first_to_check]==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;

⌨️ 快捷键说明

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