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

📄 s390io.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
				ioinfo[irq]->devstat.dstat   = 0;				ioinfo[irq]->devstat.lpum    = 0;				ioinfo[irq]->devstat.flag    = DEVSTAT_CLEAR_FUNCTION;				ioinfo[irq]->devstat.scnt    = 0;			}			else			{				ioinfo[irq]->devstat.flag   |= DEVSTAT_CLEAR_FUNCTION;			} /* endif */			/*			 * If synchronous I/O processing is requested, we have			 *  to wait for the corresponding interrupt to occur by			 *  polling the interrupt condition. However, as multiple			 *  interrupts may be outstanding, we must not just wait			 *  for the first interrupt, but must poll until ours			 *  pops up.			 */			if ( flag & DOIO_WAIT_FOR_INTERRUPT )			{				int              io_sub;				__u32            io_parm;				psw_t            io_new_psw;				int              ccode;  					int              ready = 0;				struct _lowcore *lc    = NULL;				/*				 * We shouldn't perform a TPI loop, waiting for				 *  an interrupt to occur, but should load a				 *  WAIT PSW instead. Otherwise we may keep the				 *  channel subsystem busy, not able to present				 *  the interrupt. When our sync. interrupt				 *  arrived we reset the I/O old PSW to its				 *  original value.				 */				memcpy( &io_new_psw,				        &lc->io_new_psw,				        sizeof(psw_t));				ccode = iac();				switch (ccode) {				case 0:  		// primary-space					io_sync_wait.mask =   _IO_PSW_MASK					                    | _PSW_PRIM_SPACE_MODE					                    | _PSW_IO_WAIT;					break;				case 1:			// secondary-space					io_sync_wait.mask =   _IO_PSW_MASK					                    | _PSW_SEC_SPACE_MODE					                    | _PSW_IO_WAIT;					break;				case 2:			// access-register					io_sync_wait.mask =   _IO_PSW_MASK					                    | _PSW_ACC_REG_MODE					                    | _PSW_IO_WAIT;					break;				case 3:			// home-space						io_sync_wait.mask =   _IO_PSW_MASK					                    | _PSW_HOME_SPACE_MODE					                    | _PSW_IO_WAIT;					break;				default:					panic( "halt_IO() : unexpected "					       "address-space-control %d\n",					       ccode);					break;				} /* endswitch */				io_sync_wait.addr = FIX_PSW(&&cio_wakeup);				/*				 * Martin didn't like modifying the new PSW, now we take				 *  a fast exit in do_IRQ() instead				 */				*(__u32 *)__LC_SYNC_IO_WORD  = 1;				do				{	      		asm volatile ( "lpsw %0" : : "m" (io_sync_wait) );cio_wakeup:				   io_parm = *(__u32 *)__LC_IO_INT_PARM;				   io_sub  = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;				   ready = s390_process_IRQ( io_sub );				} while ( !((io_sub == irq) && (ready == 1)) );				*(__u32 *)__LC_SYNC_IO_WORD = 0;			} /* endif */			ret = 0;			break;		case 1 :            /* status pending */				ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;			/*			 * initialize the device driver specific devstat irb area			 */			memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,			        '\0', sizeof( irb_t) );			/*			 * Let the common interrupt handler process the pending			 *  status. However, we must avoid calling the user			 *  action handler, as it won't be prepared to handle                        *  a pending status during do_IO() processing inline.			 *  This also implies that s390_process_IRQ must			 *  terminate synchronously - especially if device			 *  sensing is required.			 */			ioinfo[irq]->ui.flags.s_pend   = 1;			ioinfo[irq]->ui.flags.busy     = 1;			ioinfo[irq]->ui.flags.doio     = 1;			s390_process_IRQ( irq );						ioinfo[irq]->ui.flags.s_pend   = 0;			ioinfo[irq]->ui.flags.busy     = 0;			ioinfo[irq]->ui.flags.doio     = 0;			ioinfo[irq]->ui.flags.repall   = 0;			ioinfo[irq]->ui.flags.w4final  = 0;			ioinfo[irq]->devstat.flag     |= DEVSTAT_FINAL_STATUS;			/*			 * In multipath mode a condition code 3 implies the last			 *  path has gone, except we have previously restricted			 *  the I/O to a particular path. A condition code 1			 *  (0 won't occur) results in return code EIO as well			 *  as 3 with another path than the one used (i.e. path available mask is non-zero).			 */			if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 )			{				ret                         = -ENODEV;				ioinfo[irq]->devstat.flag  |= DEVSTAT_NOT_OPER;				ioinfo[irq]->ui.flags.oper  = 0;			}			else			{				ret                         = -EIO;				ioinfo[irq]->devstat.flag  &= ~DEVSTAT_NOT_OPER;				ioinfo[irq]->ui.flags.oper  = 1;			} /* endif */			break;		case 2 :            /* busy */			ret = -EBUSY;			break;		default:            /* device not operational */			ret = -ENODEV;			break;		} /* endswitch */		if (    ( flag & DOIO_WAIT_FOR_INTERRUPT )	   	  && ( sync_isc_locked                ) )		{			sync_isc_locked              = 0;    // local setting		   ioinfo[irq]->ui.flags.syncio = 0;    // global setting  				disable_cpu_sync_isc( irq );  				spin_unlock_irqrestore( &sync_isc, psw_flags);  			} /* endif */	} /* endif */	return( ret );}/* * do_IRQ() handles all normal I/O device IRQ's (the special *          SMP cross-CPU interrupts have their own specific *          handlers). * * Returns: 0 - no ending status received, no further action taken *          1 - interrupt handler was called with ending status */asmlinkage void do_IRQ( struct pt_regs regs,                        unsigned int   irq,                        __u32          s390_intparm ){#ifdef CONFIG_FAST_IRQ	int			ccode;	tpi_info_t 	tpi_info;	int			new_irq;#endif	int			use_irq     = irq;//	__u32       use_intparm = s390_intparm;	//	// fix me !!!	//	// We need to schedule device recognition, the interrupt stays	//  pending. We need to dynamically allocate an ioinfo structure.	//	if ( ioinfo[irq] == INVALID_STORAGE_AREA )	{		return;	/* this keeps the device boxed ... */	}	/*	 * take fast exit if CPU is in sync. I/O state	 *	 * Note: we have to turn off the WAIT bit and re-disable	 *       interrupts prior to return as this was the initial	 *       entry condition to synchronous I/O.	 */ 	if (    *(__u32 *)__LC_SYNC_IO_WORD )	{		regs.psw.mask &= ~(_PSW_WAIT_MASK_BIT | _PSW_IO_MASK_BIT);      return;	} /* endif */	s390irq_spin_lock(use_irq);#ifdef CONFIG_FAST_IRQ	do {#endif /*  CONFIG_FAST_IRQ */		s390_process_IRQ( use_irq );#ifdef CONFIG_FAST_IRQ		/*		 * more interrupts pending ?		 */		ccode = tpi( &tpi_info );		if ( ! ccode )			break;  	// no, leave ...		new_irq     = tpi_info.irq;//		use_intparm = tpi_info.intparm;		/*		 * if the interrupt is for a different irq we		 *  release the current irq lock and obtain		 *  a new one ...		 */		if ( new_irq != use_irq )      {			s390irq_spin_unlock(use_irq);         use_irq = new_irq;			s390irq_spin_lock(use_irq);      } /* endif */	} while ( 1 );#endif /*  CONFIG_FAST_IRQ */	s390irq_spin_unlock(use_irq);	return;}/* * s390_process_IRQ() handles status pending situations and interrupts * * Called by : do_IRQ()             - for "real" interrupts *             s390_start_IO, halt_IO() *                                  - status pending cond. after SSCH, or HSCH *             disable_subchannel() - status pending conditions (after MSCH) * * Returns: 0 - no ending status received, no further action taken *          1 - interrupt handler was called with ending status */int s390_process_IRQ( unsigned int irq ){	int               ccode;      /* condition code from tsch() operation */	int               irb_cc;     /* condition code from irb */	int               sdevstat;   /* effective struct devstat size to copy */	unsigned int      fctl;       /* function control */	unsigned int      stctl;      /* status   control */	unsigned int      actl;       /* activity control */	struct irqaction *action;	struct pt_regs    regs;       /* for interface compatibility only */	int               issense         = 0;	int               ending_status   = 0;	int               allow4handler   = 1;	int               chnchk          = 0;#if 0	int               cpu             = smp_processor_id();	kstat.irqs[cpu][irq]++;#endif	action = ioinfo[irq]->irq_desc.action;	/*	 * It might be possible that a device was not-oper. at the time	 *  of free_irq() processing. This means the handler is no longer	 *  available when the device possibly becomes ready again. In	 *  this case we perform delayed disable_subchannel() processing.	 */	if ( action == NULL )	{		if ( !ioinfo[irq]->ui.flags.d_disable )		{			printk( KERN_CRIT"s390_process_IRQ(%04X) "			        "- no interrupt handler registered"					  "for device %04X !\n",			        irq,			        ioinfo[irq]->devstat.devno);		} /* endif */	} /* endif */	/*	 * retrieve the i/o interrupt information (irb),	 *  update the device specific status information	 *  and possibly call the interrupt handler.	 *	 * Note 1: At this time we don't process the resulting	 *         condition code (ccode) from tsch(), although	 *         we probably should.	 *	 * Note 2: Here we will have to check for channel	 *         check conditions and call a channel check	 *         handler.	 *	 * Note 3: If a start function was issued, the interruption	 *         parameter relates to it. If a halt function was	 *         issued for an idle device, the intparm must not	 *         be taken from lowcore, but from the devstat area.	 */	ccode = tsch( irq, &(ioinfo[irq]->devstat.ii.irb) );	//	// We must only accumulate the status if initiated by do_IO() or halt_IO()	//	if ( ioinfo[irq]->ui.flags.busy )	{		ioinfo[irq]->devstat.dstat |= ioinfo[irq]->devstat.ii.irb.scsw.dstat;		ioinfo[irq]->devstat.cstat |= ioinfo[irq]->devstat.ii.irb.scsw.cstat;	}	else	{		ioinfo[irq]->devstat.dstat  = ioinfo[irq]->devstat.ii.irb.scsw.dstat;		ioinfo[irq]->devstat.cstat  = ioinfo[irq]->devstat.ii.irb.scsw.cstat;		ioinfo[irq]->devstat.flag   = 0;   // reset status flags	} /* endif */	ioinfo[irq]->devstat.lpum = ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum;	if ( ioinfo[irq]->ui.flags.busy)	{		ioinfo[irq]->devstat.intparm  = ioinfo[irq]->u_intparm;	} /* endif */	/*	 * reset device-busy bit if no longer set in irb	 */	if (   (ioinfo[irq]->devstat.dstat & DEV_STAT_BUSY                   )	    && ((ioinfo[irq]->devstat.ii.irb.scsw.dstat & DEV_STAT_BUSY) == 0))	{		ioinfo[irq]->devstat.dstat &= ~DEV_STAT_BUSY;	} /* endif */	/*	 * Save residual count and CCW information in case primary and	 *  secondary status are presented with different interrupts.	 */	if ( ioinfo[irq]->devstat.ii.irb.scsw.stctl & SCSW_STCTL_PRIM_STATUS )	{		ioinfo[irq]->devstat.rescnt = ioinfo[irq]->devstat.ii.irb.scsw.count;#if CONFIG_DEBUG_IO      if ( irq != cons_dev )         printk( "s390_process_IRQ( %04X ) : "                 "residual count from irb after tsch() %d\n",                 irq, ioinfo[irq]->devstat.rescnt );#endif	} /* endif */	if ( ioinfo[irq]->devstat.ii.irb.scsw.cpa != 0 )	{		ioinfo[irq]->devstat.cpa = ioinfo[irq]->devstat.ii.irb.scsw.cpa;	} /* endif */	irb_cc = ioinfo[irq]->devstat.ii.irb.scsw.cc;	//	// check for any kind of channel or interface control check but don't	//  issue the message for the console device	//	if (    (ioinfo[irq]->devstat.ii.irb.scsw.cstat	            & (  SCHN_STAT_CHN_DATA_CHK	               | SCHN_STAT_CHN_CTRL_CHK	               | SCHN_STAT_INTF_CTRL_CHK )       )	     && (irq != cons_dev                         ) )	{		printk( "Channel-Check or Interface-Control-Check "		        "received\n"		        " ... device %04X on subchannel %04X, dev_stat "		        ": %02X sch_stat : %02X\n",		        ioinfo[irq]->devstat.devno,		        irq,		        ioinfo[irq]->devstat.dstat,		        ioinfo[irq]->devstat.cstat);		chnchk = 1;	} /* endif */	issense = ioinfo[irq]->devstat.ii.irb.esw.esw0.erw.cons;	if ( issense )	{		ioinfo[irq]->devstat.scnt  =		             ioinfo[irq]->devstat.ii.irb.esw.esw0.erw.scnt;		ioinfo[irq]->devstat.flag |=		             DEVSTAT_FLAG_SENSE_AVAIL;                  			sdevstat = sizeof( devstat_t);#if CONFIG_DEBUG_IO      if ( irq != cons_dev )         printk( "s390_process_IRQ( %04X ) : "                 "concurrent sense bytes avail %d\n",                 irq, ioinfo[irq]->devstat.scnt );#endif	}	else	{		/* don't copy the sense data area ! */		sdevstat = sizeof( devstat_t) - SENSE_MAX_COUNT;	} /* endif */	switch ( irb_cc ) {	case 1:      /* status pending */		ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;	case 0:      /* normal i/o interruption */		fctl  = ioinfo[irq]->devstat.ii.irb.scsw.fctl;		stctl = ioinfo[irq]->devstat.ii.irb.scsw.stctl;		actl  = ioinfo[irq]->devstat.ii.irb.scsw.actl;		if ( chnchk && (ioinfo[irq]->senseid.cu_type == 0x3088))		{			char buffer[80];   				sprintf( buffer, "s390_process_IRQ(%04X) - irb for "			         "device %04X after channel check\n",			         irq,			         ioinfo[irq]->devstat.devno );			s390_displayhex( buffer,			                 &(ioinfo[irq]->devstat.ii.irb) ,			                 sizeof(irb_t));		} /* endif */					ioinfo[irq]->stctl |= stctl;		ending_status =    ( stctl & SCSW_STCTL_SEC_STATUS                          )			|| ( stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)         )		   || ( (fctl == SCSW_FCTL_HALT_FUNC)  && (stctl == SCSW_STCTL_STATUS_PEND) );		/*		 * Check for unsolicited interrupts - for debug purposes only		 *		 * We only consider an interrupt as unsolicited, if the device was not		 *  actively in use (busy) and an interrupt other than an ALERT status		 *  was received.		 *		 * Note: We must not issue a message to the console, if the		 *       unsolicited interrupt applies to the console device		 *       itself !		 */#if CONFIG_DEBUG_IO		if (     ( irq != cons_dev                 )			 && !( stctl & SCSW_STCTL_ALERT_STATUS )			 &&  ( ioinfo[irq]->ui.flags.busy == 0  ) )		{	      char buffer[80];			printk( "Unsolicited interrupt received for device %04X on subchannel %04X\n"				" ... device status : %02X subchannel status : %02X\n",				ioinfo[irq]->devstat.devno,				irq,				ioinfo[irq]->devstat.dstat,				ioinfo[irq]->devstat.cstat);   	   sprintf( buffer, "s390_process_IRQ(%04X) - irb for "			         "device %04X, ending_status %d\n",			         irq,			         ioinfo[irq]->devstat.devno,		   	      ending_status);			s390_displayhex( buffer,			                 &(ioinfo[irq]->devstat.ii.irb) ,			                 sizeof(irb_t));		} /* endif */		/*		 * take fast exit if no handler is available		 */		if ( !action )			return( ending_status );     		#endif

⌨️ 快捷键说明

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