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

📄 cio.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
				break;		}	}	sprintf (dbf_txt, "ret:%d", ret);	CIO_TRACE_EVENT (2, dbf_txt);	return ret;}/* * Disable subchannel. */intcio_disable_subchannel (struct subchannel *sch){	char dbf_txt[15];	int ccode;	int retry;	int ret;	CIO_TRACE_EVENT (2, "dissch");	CIO_TRACE_EVENT (2, sch->dev.bus_id);	ccode = stsch (sch->schid, &sch->schib);	if (ccode == 3)		/* Not operational. */		return -ENODEV;	if (sch->schib.scsw.actl != 0)		/*		 * the disable function must not be called while there are		 *  requests pending for completion !		 */		return -EBUSY;	for (retry = 5, ret = 0; retry > 0; retry--) {		sch->schib.pmcw.ena = 0;		ret = cio_modify(sch);		if (ret == -ENODEV)			break;		if (ret == -EBUSY)			/*			 * The subchannel is busy or status pending.			 * We'll disable when the next interrupt was delivered			 * via the state machine.			 */			break;		if (ret == 0) {			stsch (sch->schid, &sch->schib);			if (!sch->schib.pmcw.ena)				break;		}	}	sprintf (dbf_txt, "ret:%d", ret);	CIO_TRACE_EVENT (2, dbf_txt);	return ret;}/* * cio_validate_subchannel() * * Find out subchannel type and initialize struct subchannel. * Return codes: *   SUBCHANNEL_TYPE_IO for a normal io subchannel *   SUBCHANNEL_TYPE_CHSC for a chsc subchannel *   SUBCHANNEL_TYPE_MESSAGE for a messaging subchannel *   SUBCHANNEL_TYPE_ADM for a adm(?) subchannel *   -ENXIO for non-defined subchannels *   -ENODEV for subchannels with invalid device number or blacklisted devices */intcio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid){	char dbf_txt[15];	int ccode;	sprintf (dbf_txt, "valsch%x", schid.sch_no);	CIO_TRACE_EVENT (4, dbf_txt);	/* Nuke all fields. */	memset(sch, 0, sizeof(struct subchannel));	spin_lock_init(&sch->lock);	/* Set a name for the subchannel */	snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", schid.ssid,		  schid.sch_no);	/*	 * The first subchannel that is not-operational (ccode==3)	 *  indicates that there aren't any more devices available.	 * If stsch gets an exception, it means the current subchannel set	 *  is not valid.	 */	ccode = stsch_err (schid, &sch->schib);	if (ccode)		return (ccode == 3) ? -ENXIO : ccode;	sch->schid = schid;	/* Copy subchannel type from path management control word. */	sch->st = sch->schib.pmcw.st;	/*	 * ... just being curious we check for non I/O subchannels	 */	if (sch->st != 0) {		CIO_DEBUG(KERN_INFO, 0,			  "Subchannel 0.%x.%04x reports "			  "non-I/O subchannel type %04X\n",			  sch->schid.ssid, sch->schid.sch_no, sch->st);		/* We stop here for non-io subchannels. */		return sch->st;	}	/* Initialization for io subchannels. */	if (!sch->schib.pmcw.dnv)		/* io subchannel but device number is invalid. */		return -ENODEV;	/* Devno is valid. */	if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) {		/*		 * This device must not be known to Linux. So we simply		 * say that there is no device and return ENODEV.		 */		CIO_MSG_EVENT(0, "Blacklisted device detected "			      "at devno %04X, subchannel set %x\n",			      sch->schib.pmcw.dev, sch->schid.ssid);		return -ENODEV;	}	sch->opm = 0xff;	if (!cio_is_console(sch->schid))		chsc_validate_chpids(sch);	sch->lpm = sch->schib.pmcw.pim &		sch->schib.pmcw.pam &		sch->schib.pmcw.pom &		sch->opm;	CIO_DEBUG(KERN_INFO, 0,		  "Detected device %04x on subchannel 0.%x.%04X"		  " - PIM = %02X, PAM = %02X, POM = %02X\n",		  sch->schib.pmcw.dev, sch->schid.ssid,		  sch->schid.sch_no, sch->schib.pmcw.pim,		  sch->schib.pmcw.pam, sch->schib.pmcw.pom);	/*	 * We now have to initially ...	 *  ... set "interruption subclass"	 *  ... enable "concurrent sense"	 *  ... enable "multipath mode" if more than one	 *	  CHPID is available. This is done regardless	 *	  whether multiple paths are available for us.	 */	sch->schib.pmcw.isc = 3;	/* could be smth. else */	sch->schib.pmcw.csense = 1;	/* concurrent sense */	sch->schib.pmcw.ena = 0;	if ((sch->lpm & (sch->lpm - 1)) != 0)		sch->schib.pmcw.mp = 1;	/* multipath mode */	return 0;}/* * do_IRQ() handles all normal I/O device IRQ's (the special *	    SMP cross-CPU interrupts have their own specific *	    handlers). * */voiddo_IRQ (struct pt_regs *regs){	struct tpi_info *tpi_info;	struct subchannel *sch;	struct irb *irb;	irq_enter ();	asm volatile ("mc 0,0");	if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer)		/**		 * Make sure that the i/o interrupt did not "overtake"		 * the last HZ timer interrupt.		 */		account_ticks(regs);	/*	 * Get interrupt information from lowcore	 */	tpi_info = (struct tpi_info *) __LC_SUBCHANNEL_ID;	irb = (struct irb *) __LC_IRB;	do {		kstat_cpu(smp_processor_id()).irqs[IO_INTERRUPT]++;		/*		 * Non I/O-subchannel thin interrupts are processed differently		 */		if (tpi_info->adapter_IO == 1 &&		    tpi_info->int_type == IO_INTERRUPT_TYPE) {			do_adapter_IO();			continue;		}		sch = (struct subchannel *)(unsigned long)tpi_info->intparm;		if (sch)			spin_lock(&sch->lock);		/* Store interrupt response block to lowcore. */		if (tsch (tpi_info->schid, irb) == 0 && sch) {			/* Keep subchannel information word up to date. */			memcpy (&sch->schib.scsw, &irb->scsw,				sizeof (irb->scsw));			/* Call interrupt handler if there is one. */			if (sch->driver && sch->driver->irq)				sch->driver->irq(&sch->dev);		}		if (sch)			spin_unlock(&sch->lock);		/*		 * Are more interrupts pending?		 * If so, the tpi instruction will update the lowcore		 * to hold the info for the next interrupt.		 * We don't do this for VM because a tpi drops the cpu		 * out of the sie which costs more cycles than it saves.		 */	} while (!MACHINE_IS_VM && tpi (NULL) != 0);	irq_exit ();}#ifdef CONFIG_CCW_CONSOLEstatic struct subchannel console_subchannel;static int console_subchannel_in_use;/* * busy wait for the next interrupt on the console */voidwait_cons_dev (void){	unsigned long cr6      __attribute__ ((aligned (8)));	unsigned long save_cr6 __attribute__ ((aligned (8)));	/* 	 * before entering the spinlock we may already have	 * processed the interrupt on a different CPU...	 */	if (!console_subchannel_in_use)		return;	/* disable all but isc 7 (console device) */	__ctl_store (save_cr6, 6, 6);	cr6 = 0x01000000;	__ctl_load (cr6, 6, 6);	do {		spin_unlock(&console_subchannel.lock);		if (!cio_tpi())			cpu_relax();		spin_lock(&console_subchannel.lock);	} while (console_subchannel.schib.scsw.actl != 0);	/*	 * restore previous isc value	 */	__ctl_load (save_cr6, 6, 6);}static intcio_test_for_console(struct subchannel_id schid, void *data){	if (stsch_err(schid, &console_subchannel.schib) != 0)		return -ENXIO;	if (console_subchannel.schib.pmcw.dnv &&	    console_subchannel.schib.pmcw.dev ==	    console_devno) {		console_irq = schid.sch_no;		return 1; /* found */	}	return 0;}static intcio_get_console_sch_no(void){	struct subchannel_id schid;		init_subchannel_id(&schid);	if (console_irq != -1) {		/* VM provided us with the irq number of the console. */		schid.sch_no = console_irq;		if (stsch(schid, &console_subchannel.schib) != 0 ||		    !console_subchannel.schib.pmcw.dnv)			return -1;		console_devno = console_subchannel.schib.pmcw.dev;	} else if (console_devno != -1) {		/* At least the console device number is known. */		for_each_subchannel(cio_test_for_console, NULL);		if (console_irq == -1)			return -1;	} else {		/* unlike in 2.4, we cannot autoprobe here, since		 * the channel subsystem is not fully initialized.		 * With some luck, the HWC console can take over */		printk(KERN_WARNING "No ccw console found!\n");		return -1;	}	return console_irq;}struct subchannel *cio_probe_console(void){	int sch_no, ret;	struct subchannel_id schid;	if (xchg(&console_subchannel_in_use, 1) != 0)		return ERR_PTR(-EBUSY);	sch_no = cio_get_console_sch_no();	if (sch_no == -1) {		console_subchannel_in_use = 0;		return ERR_PTR(-ENODEV);	}	memset(&console_subchannel, 0, sizeof(struct subchannel));	init_subchannel_id(&schid);	schid.sch_no = sch_no;	ret = cio_validate_subchannel(&console_subchannel, schid);	if (ret) {		console_subchannel_in_use = 0;		return ERR_PTR(-ENODEV);	}	/*	 * enable console I/O-interrupt subclass 7	 */	ctl_set_bit(6, 24);	console_subchannel.schib.pmcw.isc = 7;	console_subchannel.schib.pmcw.intparm =		(__u32)(unsigned long)&console_subchannel;	ret = cio_modify(&console_subchannel);	if (ret) {		console_subchannel_in_use = 0;		return ERR_PTR(ret);	}	return &console_subchannel;}voidcio_release_console(void){	console_subchannel.schib.pmcw.intparm = 0;	cio_modify(&console_subchannel);	ctl_clear_bit(6, 24);	console_subchannel_in_use = 0;}/* Bah... hack to catch console special sausages. */intcio_is_console(struct subchannel_id schid){	if (!console_subchannel_in_use)		return 0;	return schid_equal(&schid, &console_subchannel.schid);}struct subchannel *cio_get_console_subchannel(void){	if (!console_subchannel_in_use)		return 0;	return &console_subchannel;}#endifstatic inline int__disable_subchannel_easy(struct subchannel_id schid, struct schib *schib){	int retry, cc;	cc = 0;	for (retry=0;retry<3;retry++) {		schib->pmcw.ena = 0;		cc = msch(schid, schib);		if (cc)			return (cc==3?-ENODEV:-EBUSY);		stsch(schid, schib);		if (!schib->pmcw.ena)			return 0;	}	return -EBUSY; /* uhm... */}static inline int__clear_subchannel_easy(struct subchannel_id schid){	int retry;	if (csch(schid))		return -ENODEV;	for (retry=0;retry<20;retry++) {		struct tpi_info ti;		if (tpi(&ti)) {			tsch(ti.schid, (struct irb *)__LC_IRB);			if (schid_equal(&ti.schid, &schid))				return 0;		}		udelay(100);	}	return -EBUSY;}extern void do_reipl(unsigned long devno);static int__shutdown_subchannel_easy(struct subchannel_id schid, void *data){	struct schib schib;	if (stsch_err(schid, &schib))		return -ENXIO;	if (!schib.pmcw.ena)		return 0;	switch(__disable_subchannel_easy(schid, &schib)) {	case 0:	case -ENODEV:		break;	default: /* -EBUSY */		if (__clear_subchannel_easy(schid))			break; /* give up... */		stsch(schid, &schib);		__disable_subchannel_easy(schid, &schib);	}	return 0;}voidclear_all_subchannels(void){	local_irq_disable();	for_each_subchannel(__shutdown_subchannel_easy, NULL);}/* Make sure all subchannels are quiet before we re-ipl an lpar. */voidreipl(unsigned long devno){	clear_all_subchannels();	do_reipl(devno);}

⌨️ 快捷键说明

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