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

📄 qdio.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
		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->irq=irq_ptr->irq;		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 */		for (j=0;j<QDIO_MAX_BUFFERS_PER_Q;j++) {			set_slsb(&q->slsb.acc.val[j],		   		 SLSB_P_OUTPUT_NOT_INIT);/*			q->sbal[j]->element[1].sbalf.i1.key=QDIO_STORAGE_KEY;*/		}	}}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->irq,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(int irq, struct irb *irb){	char dbf_text[15];	if (irb->esw.esw0.erw.cons) {		sprintf(dbf_text,"sens%4x",irq);		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){	struct qdio_irq *irq_ptr;	char dbf_text[15];	QDIO_DBF_TEXT2(0, trace, "qtoh");	sprintf(dbf_text, "%s", cdev->dev.bus_id);	QDIO_DBF_TEXT2(0, trace, dbf_text);	irq_ptr = cdev->private->qdio_data;	sprintf(dbf_text, "state:%d", irq_ptr->state);	QDIO_DBF_TEXT2(0, trace, dbf_text);	switch (irq_ptr->state) {	case QDIO_IRQ_STATE_INACTIVE:		QDIO_PRINT_ERR("establish queues on irq %04x: timed out\n",			       irq_ptr->irq);		QDIO_DBF_TEXT2(1,setup,"eq:timeo");		qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR);		break;	case QDIO_IRQ_STATE_CLEANUP:		QDIO_PRINT_INFO("Did not get interrupt on cleanup, irq=0x%x.\n",				irq_ptr->irq);		qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR);		break;	case QDIO_IRQ_STATE_ESTABLISHED:	case QDIO_IRQ_STATE_ACTIVE:		/* I/O has been terminated by common I/O layer. */		QDIO_PRINT_INFO("Queues on irq %04x killed by cio.\n",				irq_ptr->irq);		QDIO_DBF_TEXT2(1, trace, "cio:term");		qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED);		if (get_device(&cdev->dev)) {			/* Can't call shutdown from interrupt context. */			PREPARE_WORK(&cdev->private->kick_work,				     qdio_call_shutdown, (void *)cdev);			queue_work(ccw_device_work, &cdev->private->kick_work);		}		break;	default:		BUG();	}	ccw_device_set_timeout(cdev, 0);	wake_up(&cdev->private->wait_q);}static voidqdio_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb){	struct qdio_irq *irq_ptr;	int cstat,dstat;	char dbf_text[15];#ifdef CONFIG_QDIO_DEBUG	QDIO_DBF_TEXT4(0, trace, "qint");	sprintf(dbf_text, "%s", cdev->dev.bus_id);	QDIO_DBF_TEXT4(0, trace, dbf_text);#endif /* CONFIG_QDIO_DEBUG */		if (!intparm) {		QDIO_PRINT_ERR("got unsolicited interrupt in qdio " \				  "handler, device %s\n", cdev->dev.bus_id);		return;	}	irq_ptr = cdev->private->qdio_data;	if (!irq_ptr) {		QDIO_DBF_TEXT2(1, trace, "uint");		sprintf(dbf_text,"%s", cdev->dev.bus_id);		QDIO_DBF_TEXT2(1,trace,dbf_text);		QDIO_PRINT_ERR("received interrupt on unused device %s!\n",			       cdev->dev.bus_id);		return;	}	if (IS_ERR(irb)) {		/* Currently running i/o is in error. */		switch (PTR_ERR(irb)) {		case -EIO:			QDIO_PRINT_ERR("i/o error on device %s\n",				       cdev->dev.bus_id);			return;		case -ETIMEDOUT:			qdio_timeout_handler(cdev);			return;		default:			QDIO_PRINT_ERR("unknown error state %ld on device %s\n",				       PTR_ERR(irb), cdev->dev.bus_id);			return;		}	}	qdio_irq_check_sense(irq_ptr->irq, irb);#ifdef CONFIG_QDIO_DEBUG	sprintf(dbf_text, "state:%d", irq_ptr->state);	QDIO_DBF_TEXT4(0, trace, dbf_text);#endif /* CONFIG_QDIO_DEBUG */        cstat = irb->scsw.cstat;        dstat = irb->scsw.dstat;	switch (irq_ptr->state) {	case QDIO_IRQ_STATE_INACTIVE:		qdio_establish_handle_irq(cdev, cstat, dstat);		break;	case QDIO_IRQ_STATE_CLEANUP:		qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE);		break;	case QDIO_IRQ_STATE_ESTABLISHED:	case QDIO_IRQ_STATE_ACTIVE:		if (cstat & SCHN_STAT_PCI) {			qdio_handle_pci(irq_ptr);			break;		}		if ((cstat&~SCHN_STAT_PCI)||dstat) {			qdio_handle_activate_check(cdev, intparm, cstat, dstat);			break;		}	default:		QDIO_PRINT_ERR("got interrupt for queues in state %d on " \			       "device %s?!\n",			       irq_ptr->state, cdev->dev.bus_id);	}	wake_up(&cdev->private->wait_q);}intqdio_synchronize(struct ccw_device *cdev, unsigned int flags,		 unsigned int queue_number){	int cc;	struct qdio_q *q;	struct qdio_irq *irq_ptr;	void *ptr;#ifdef CONFIG_QDIO_DEBUG	char dbf_text[15]="SyncXXXX";#endif	irq_ptr = cdev->private->qdio_data;	if (!irq_ptr)		return -ENODEV;#ifdef CONFIG_QDIO_DEBUG	*((int*)(&dbf_text[4])) = irq_ptr->irq;	QDIO_DBF_HEX4(0,trace,dbf_text,QDIO_DBF_TRACE_LEN);	*((int*)(&dbf_text[0]))=flags;	*((int*)(&dbf_text[4]))=queue_number;	QDIO_DBF_HEX4(0,trace,dbf_text,QDIO_DBF_TRACE_LEN);#endif /* CONFIG_QDIO_DEBUG */	if (flags&QDIO_FLAG_SYNC_INPUT) {		q=irq_ptr->input_qs[queue_number];		if (!q)			return -EINVAL;		cc = do_siga_sync(q->irq, 0, q->mask);	} else if (flags&QDIO_FLAG_SYNC_OUTPUT) {		q=irq_ptr->output_qs[queue_number];		if (!q)			return -EINVAL;		cc = do_siga_sync(q->irq, q->mask, 0);	} else 		return -EINVAL;	ptr=&cc;	if (cc)		QDIO_DBF_HEX3(0,trace,&ptr,sizeof(int));	return cc;}static unsigned charqdio_check_siga_needs(int sch){	int result;	unsigned char qdioac;	struct {		struct chsc_header request;		u16 reserved1;		u16 first_sch;		u16 reserved2;		u16 last_sch;		u32 reserved3;		struct chsc_header response;		u32 reserved4;		u8  flags;		u8  reserved5;		u16 sch;		u8  qfmt;		u8  reserved6;		u8  qdioac;		u8  sch_class;		u8  reserved7;		u8  icnt;		u8  reserved8;		u8  ocnt;	} *ssqd_area;	ssqd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);	if (!ssqd_area) {	        QDIO_PRINT_WARN("Could not get memory for chsc. Using all " \				"SIGAs for sch x%x.\n", sch);		return CHSC_FLAG_SIGA_INPUT_NECESSARY ||			CHSC_FLAG_SIGA_OUTPUT_NECESSARY ||			CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */	}	ssqd_area->request = (struct chsc_header) {		.length = 0x0010,		.code   = 0x0024,	};	ssqd_area->first_sch = sch;	ssqd_area->last_sch = sch;	result=chsc(ssqd_area);	if (result) {		QDIO_PRINT_WARN("CHSC returned cc %i. Using all " \				"SIGAs for sch x%x.\n",				result,sch);		qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY ||			CHSC_FLAG_SIGA_OUTPUT_NECESSARY ||			CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */		goto out;	}	if (ssqd_area->response.code != QDIO_CHSC_RESPONSE_CODE_OK) {		QDIO_PRINT_WARN("response upon checking SIGA needs " \				"is 0x%x. Using all SIGAs for sch x%x.\n",				ssqd_area->response.code, sch);		qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY ||			CHSC_FLAG_SIGA_OUTPUT_NECESSARY ||			CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */		goto out;	}	if (!(ssqd_area->flags & CHSC_FLAG_QDIO_CAPABILITY) ||	    !(ssqd_area->flags & CHSC_FLAG_VALIDITY) ||	    (ssqd_area->sch != sch)) {		QDIO_PRINT_WARN("huh? problems checking out sch x%x... " \				"using all SIGAs.\n",sch);		qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY |			CHSC_FLAG_SIGA_OUTPUT_NECESSARY |			CHSC_FLAG_SIGA_SYNC_NECESSARY; /* worst case */		goto out;	}	qdioac = ssqd_area->qdioac;out:	free_page ((unsigned long) ssqd_area);	return qdioac;}static unsigned inttiqdio_check_chsc_availability(void){	char dbf_text[15];	if (!css_characteristics_avail)		return -EIO;	/* Check for bit 41. */	if (!css_general_characteristics.aif) {		QDIO_PRINT_WARN("Adapter interruption facility not " \				"installed.\n");		return -ENOENT;	}	/* Check for bits 107 and 108. */	if (!css_chsc_characteristics.scssc ||	    !css_chsc_characteristics.scsscf) {		QDIO_PRINT_WARN("Set Chan Subsys. Char. & Fast-CHSCs " \				"not available.\n");		return -ENOENT;	}	/* Check for OSA/FCP thin interrupts (bit 67). */	hydra_thinints = css_general_characteristics.aif_osa;	sprintf(dbf_text,"hydrati%1x", hydra_thinints);	QDIO_DBF_TEXT0(0,setup,dbf_text);

⌨️ 快捷键说明

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